如何为Android应用实施Google Play许可?

时间:2013-08-20 00:07:19

标签: java android licensing android-lvl

我看到了Android-Developer许可库instructions,但概述似乎省略了流程中的几个关键步骤,无法完全解释如何使某些工作正常运行。

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

1 个答案:

答案 0 :(得分:149)

我一直在我的应用程序中实施许可已有一段时间了,并最终使其正常运行。我想分享一些我发现对入门有帮助的事情以及我发现的一些问题和解决方案。我在下面链接的android开发教程没问题,但它对我没什么用,所以我决定做一个教程。享受,我希望它可以帮到你!

链接到开发者页面here

<强> 1。入门

你需要的东西。

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

如何获得它:

一个。转到开发人员控制台。 Link.

湾如果您还没有为应用创建应用草稿,请立即执行。

℃。创建草稿后,最好将.apk上传为Alpha或Beta。保持未发表。

d。点击Services & APIs

即向下滚动并找到YOUR LICENSE KEY FOR THIS APPLICATION

F。将密钥复制到您的应用中,如下所示:

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

确保没有空格。

1.2盐

一个。什么是盐?

salt是随机数据,在散列密码时是附加输入。它们用于抵御dictionary attacksrainbow table攻击。

湾我怎么得到一个?

This是生成随机盐的好链接。应该有完全 20个随机整数,所以将20放入要生成的随机字符串数量,每个字符串应该是2个字符长(用于此示例,它没有必要)。检查数字,并检查是否允许相同的字符串。他们也可以是负数。尝试删除任何冗余,例如00 -> 0,为了保持一致。

℃。我在哪里放盐?

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

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

<强> 2。将LVL(许可)库导入Eclipse和您需要的代码

2.1导入库

一个。打开Android SDK Manager

湾转到Extras

℃。安装Google Play Licensing Library

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

即进入后,请导航至:<sdk>/extras/google/play_licensing

F。在eclipse中,单击file然后import,然后Existing Android Code Into Workspace,当它要求您输入文件路径时,请导航到play_licensing文件夹并单击library

克。导入名为library的项目后,右键单击它,然后点击properties。点击左侧的Android,然后导航到底部并点击Is Library,然后点击“应用”。这让eclipse知道你可以将这个项目代码用作库。

小时。右键单击要添加许可的应用程序,然后单击属性,然后单击Android。转到底部,然后单击library并将其添加到构建路径。这应该将库导入Android Dependencies文件夹。

我。您的项目已设置为进入下一步。

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的实施时,我读到如果您在使用许可方面遇到问题,可以将this中的第一个mChecker = 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

湾查找License Testing

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

d。现在,您可以将测试响应更改为您喜欢的任何测试响应以进行测试。应用应该做出相应的回应。请记住,如果您通过SharedPrefs保存数据,则每次测试时都需要清除应用数据。 确保在更改测试响应后单击“保存”,否则什么都不会发生!我多次忘记了这个问题,最后我找到了偏头痛,然后我看到了那个发臭的保存按钮。洛尔。

<强> 4。要尝试的事情

4.1条件许可检查

一个。如果要将didCheck数据保存在SharedPreferences

,则可以尝试使用此代码
 if(didCheck==false){
        Toast.makeText(this, "Checking application license...",     Toast.LENGTH_SHORT).show();
        doCheck();
        Log.i("Checking!", "Checking license!");
    }   

4.2使用SharedPreferences加密SecurePreferences

一个。转到此link

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

℃。请阅读ReadMe.md以获取有关实施此信息的信息。

<强> 5。故障排除

许可可能是令人头疼的问题,因为还有许多问题可能会出错。例如,可能存在网络问题或服务器问题,这些问题会让您想要扯掉头发。使用正确的日志记录将有助于此,如果出现问题,您还可以获取服务器响应代码,并且可以将其跟踪到服务器或应用程序。我不得不多次这样做。

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

可能的修复:

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

湾确保记录进度的每个步骤

℃。从许可服务中检查您的日志。找出出错的地方非常有用。

d。确保allow()dontAllow()以及applicationError()包含@Override个标记。

5.2无论我在测试回复中设置了什么,我的应用总是说LICENSEDNOT_LICENSED

一个。我对此有最好的治疗方法就是等待。看来如果你在很短的时间内做了很多测试,它总会发送服务器代码291,这是重试代码。我等了一夜,第二天早上一切正常。

湾您可以清除Google Play应用和Google Play服务应用的数据(不仅仅是缓存)。然后打开播放并接受所有许可证,然后重试。

℃。清除您的应用数据。

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房间更多!他们会来的!

我希望这可以帮助你们!我尽力与你分享我的头痛和修复,我希望这有帮助!

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

相关问题