如何为 Android 应用实施 Google Play 许可?[已关闭]

2022-08-31 23:46:17

我看到了Android-Developer许可库的库存说明,但概述似乎省略了该过程中的几个关键步骤,并且未能完全解释如何使某些东西正常工作。

有人可以提供一组明确的操作,以便在Android应用上设置许可库,以便检查以确保用户在允许使用之前已在Google Play中为应用付费?


答案 1

一段时间以来,我一直在努力在我的应用程序中实现许可,并最终使其正常工作。我想与大家分享一些我发现对入门有帮助的事情,以及我发现的一些问题和解决方案。我在下面链接的Android开发教程是可以的,但它对我来说并不那么有用,所以我决定做一个教程。享受,我希望它能帮助你!

在此处链接到开发人员页面。

1. 开始

你需要的东西。

1.1 您的 Base64 唯一应用程序密钥

如何获取:

一个。转到开发人员控制台。链接。

b.如果尚未为应用创建应用程序草稿,请立即创建。

c. 创建草稿后,最好将其上传为 Alpha 版或 Beta 版。将其保留为未发布状态。.apk

d. 单击Services & APIs

e.向下滚动并查找YOUR LICENSE KEY FOR THIS APPLICATION

f.将密钥复制到你的应用中,如下所示:

private static final String BASE64_PUBLIC_KEY = "YOUR LICENSE KEY FOR THIS APPLICATION"; 

确保没有空格。

1.2 A 盐

一个。什么是盐?

salt 是随机数据,是散列密码时的附加输入。它们用于防御字典攻击彩虹表攻击。

b.我如何获得一个?

这是生成随机盐的良好链接。应该正好有20个随机整数,因此为了生成随机字符串的数量,每个字符串都应该是字符长(用于此示例,它不必是)。检查数字,并检查是否允许相同的字符串。它们也可以是负数。尝试删除任何冗余,例如,为了保持一致性。20200 -> 0

c. 我把盐放在哪里?

声明变量时,只需输入此代码,除非使用随机盐。

private static final byte[] SALT = new byte[] {YOUR RANDOM SALT, COMMA SEPARATED, 20 INTEGERS};

2. 将 LVL(许可)库导入 Eclipse 和您需要的代码

2.1 导入库

一个。打开Android SDK Manager

b.转到(G)Extras

c. 安装Google Play Licensing Library

d. 找到 SDK 管理器顶部列出的安装路径。SDK

e.到达那里后,导航到:<sdk>/extras/google/play_licensing

f.在 Eclipse 中,单击 然后 ,然后当它要求您输入文件路径时,导航到该文件夹并单击 。fileimportExisting Android Code Into Workspaceplay_licensinglibrary

g.导入名为 的项目后,右键单击它,然后单击 。单击左侧并导航到底部并选中,然后单击“应用”。这让 eclipse 知道您可以将此项目代码用作库。librarypropertiesAndroidIs Library

h.右键单击要向其添加许可的应用程序,然后单击“属性”,然后单击 。转到底部,然后单击并将其添加到生成路径。这应该将库导入到该文件夹。AndroidlibraryAndroid Dependencies

i. 您的项目已设置为转到下一步。

2.2 要与 SALTKEY 一起声明的变量

private Handler mHandler;
private LicenseChecker mChecker;
private LicenseCheckerCallback mLicenseCheckerCallback;
boolean licensed;
boolean checkingLicense;
boolean didCheck;

2.3 代码

将此代码粘贴到应用底部附近。如果许可证无效,此实现将通知用户,并提示他们购买应用程序或退出应用程序。

    private void doCheck() {

        didCheck = false;
        checkingLicense = true;
        setProgressBarIndeterminateVisibility(true);

        mChecker.checkAccess(mLicenseCheckerCallback);
    }


    private class MyLicenseCheckerCallback implements LicenseCheckerCallback {

        @Override
        public void allow(int reason) {
            // TODO Auto-generated method stub
            if (isFinishing()) {
                // Don't update UI if Activity is finishing.
                return;
            }               
            Log.i("License","Accepted!");       

                //You can do other things here, like saving the licensed status to a
                //SharedPreference so the app only has to check the license once.

            licensed = true;
            checkingLicense = false;
            didCheck = true;

        }

        @SuppressWarnings("deprecation")
        @Override
        public void dontAllow(int reason) {
            // TODO Auto-generated method stub
             if (isFinishing()) {
                    // Don't update UI if Activity is finishing.
                    return;
                }
                Log.i("License","Denied!");
                Log.i("License","Reason for denial: "+reason);                                                                              

                        //You can do other things here, like saving the licensed status to a
                        //SharedPreference so the app only has to check the license once.

                licensed = false;
                checkingLicense = false;
                didCheck = true;               

                showDialog(0);

        }

        @SuppressWarnings("deprecation")
        @Override
        public void applicationError(int reason) {
            // TODO Auto-generated method stub
            Log.i("License", "Error: " + reason);
            if (isFinishing()) {
                // Don't update UI if Activity is finishing.
                return;
            }
            licensed = true;
            checkingLicense = false;
            didCheck = false;

            showDialog(0);
        }


    }

    protected Dialog onCreateDialog(int id) {
        // We have only one dialog.
        return new AlertDialog.Builder(this)
                .setTitle("UNLICENSED APPLICATION DIALOG TITLE")
                .setMessage("This application is not licensed, please buy it from the play store.")
                .setPositiveButton("Buy", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(
                                "http://market.android.com/details?id=" + getPackageName()));
                        startActivity(marketIntent);
                        finish();
                    }
                })
                .setNegativeButton("Exit", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                })
                .setNeutralButton("Re-Check", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        doCheck();
                    }
                })

                .setCancelable(false)
                .setOnKeyListener(new DialogInterface.OnKeyListener(){
                    public boolean onKey(DialogInterface dialogInterface, int i, KeyEvent keyEvent) {
                        Log.i("License", "Key Listener");
                        finish();
                        return true;
                    }
                })
                .create();

    }

2.4 获取设备 ID

过去关于是否使用sim串行或对此进行了一些争论,但通常建议您使用以下代码来获取设备以获得最大兼容性。TelephonyManager.getDeviceId();ANDROID_ID

String deviceId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
Log.i("Device Id", deviceId);  //AN EXAMPLE OF LOGGING THAT YOU SHOULD BE DOING :)

2.5 创建许可证检查器

一个。在调用之前,必须将此代码放在应用中,以确保正确创建所有内容。doCheck();

mHandler = new Handler();
mLicenseCheckerCallback = new MyLicenseCheckerCallback();
mChecker = new LicenseChecker(this, new ServerManagedPolicy(this, new   AESObfuscator(SALT, getPackageName(), deviceId)), BASE64_PUBLIC_KEY);

当我对LVL进行实施时,我读到,如果您在许可方面遇到问题,则可以将第一个更改为,我的似乎在没有它的情况下工作,但以防万一。thismChecker = new LicenseChecker(this...getApplicationContext()

2.6 添加权限

一个。您需要将两个权限添加到应用程序文件中。manifest

<uses-permission android:name="android.permission.INTERNET"/>  
<uses-permission android:name="com.android.vending.CHECK_LICENSE"/>        

2.7 确保你有正确的导入!

您可能已经这样做了,但我认为这将是您检查的好地方。

2.8 如何调用要检查的许可证

一个。只需在要检查许可证时致电即可。例如,如果应用首次运行,请执行检查。doCheck();

3. 在发布之前,如何测试许可以确保其正常工作?

3.1 配置测试设备

一个。我有我的个人手机,我也用它来测试。建议在手机上只注册一个Google帐户,从历史上看,它使事情变得容易一些。您可以通过转到来检查帐户。Settings -> Accounts

3.2 配置开发者控制台

一个。打开开发人员控制台,然后转到左侧。Settings

b.找到License Testing

c. 确保您的电子邮件地址列在Gmail accounts with testing access

d.d. 现在,您可以将测试响应更改为您喜欢的任何内容,以进行测试。应用应做出相应的响应。请记住,如果您通过 SharedPrefs 保存数据,则每次测试时都需要清除应用数据。请确保在更改测试响应后单击“保存”,否则不会发生任何事情!我多次忘记了这一点,最终我得了偏头痛,然后我看到了那个臭气熏天的保存按钮。不。。

4. 尝试的事项

4.1 有条件许可证检查

一个。如果要将数据保存在 中,则可以尝试此代码。didCheckSharedPreferences

 if(didCheck==false){
        Toast.makeText(this, "Checking application license...",     Toast.LENGTH_SHORT).show();
        doCheck();
        Log.i("Checking!", "Checking license!");
    }   

4.2 使用安全首选项加密共享首选项

一个。转到此链接

b.将代码从 复制并粘贴到具有完全相同名称的类中, 然后粘贴到项目中。SecurePreferences.java

c. 有关实现此内容的信息,请阅读 。ReadMe.md

5. 故障排除

许可可能是一个令人头疼的故障排除,仅仅是因为还有更多的事情可能会出错。例如,可能存在网络问题或服务器问题,使您想要扯掉头发。使用正确的日志记录将有助于解决这个问题,如果出现问题,您还可以获取服务器响应代码,并且可以将其跟踪到服务器或应用程序。我不得不在多个场合这样做。

5.1 我无法让我的应用从服务器返回任何内容

可能的修复:

一个。确保你的应用具有正确的 .KEY

b.确保记录进度的每个步骤

c. 检查日志中是否有来自许可服务的任何内容。它可用于找出问题所在。

d. 确保并有标签。allow()dontAllow()applicationError()@Override

5.2 我的应用始终显示 LICENSEDNOT_LICENSED,无论我在测试响应中将其设置为什么

一个。我对此最好的治疗方法就是等待。似乎如果您在短时间内进行大量测试,它将始终向您发送服务器代码,即重试代码。我等了一夜,第二天早上一切都很好。291

b.您可以清除 Google Play 应用和 Google Play Services 应用的数据(而不仅仅是缓存)。然后打开“播放备份”并接受所有许可证,然后重试。

c. 清除应用数据。

5.3 用于调试的服务器响应代码列表

如果您记录它们,则应获取这些十进制值。使用此表可以引用服务器实际发送到应用的内容。int reason

LICENSED = Hex: 0x0100, Decimal: 256
NOT_LICENSED = Hex: 0x0231, Decimal: 561
RETRY = Hex: 0x0123, Decimal: 291
LICENSED_OLD_KEY = Hex: 0x2, Decimal: 2
ERROR_NOT_MARKET_MANAGED = Hex: 0x3, Decimal: 3
ERROR_SERVER_FAILURE = Hex: 0x4, Decimal: 4
ERROR_OVER_QUOTA = Hex: 0x5, Decimal: 5
ERROR_CONTACTING_SERVER = Hex: 0x101, Decimal: 257
ERROR_INVALID_PACKAGE_NAME = Hex: 0x102, Decimal: 258 
ERROR_NON_MATCHING_UID = Hex: 0x103, Decimal: 259

5.4 更多空间!他们会来的!

我希望这对你们有所帮助!我试图与你们分享我的头痛和修复,尽我所能,我希望这有帮助!

如果我犯了任何错误,请务必告诉我,以便我可以尽快修复它们!


答案 2

推荐