Java 如何为 Android 应用实施 Google Play 许可?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18324963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I implement Google Play Licensing for an Android app?
提问by Code_Insanity
I saw the stock Android-Developer licensing library instructions, but the overview seems to omit several key steps in the process and fails to fully explain how to get something working.
我看到了库存的 Android-Developer 许可库说明,但概述似乎省略了该过程中的几个关键步骤,并且未能完全解释如何使某些工作正常工作。
Can someone provide an explicit set of operations that worked to get the licensing library set up on an Android app so it checks to ensure that a user has paid for an app in Google Play before allowing use?
有人可以提供一组明确的操作来在 Android 应用程序上设置许可库,以便它检查以确保用户在允许使用之前已在 Google Play 中为应用程序付费吗?
采纳答案by Code_Insanity
I have been working on implementing licensing in my app for some time now and finally have it working. I wanted to share some of the things I found helpful for getting started and some problems and solutions that I found with everyone. The android dev tutorial I have linked below is ok, but it wasn't that useful for me, so I decided to make a tutorial. Enjoy, and I hope it helps you!
一段时间以来,我一直致力于在我的应用程序中实施许可,并最终使其正常工作。我想与大家分享我发现对入门有帮助的一些事情以及我发现的一些问题和解决方案。我在下面链接的 android 开发教程还可以,但对我来说不是那么有用,所以我决定制作一个教程。欣赏,希望对你有帮助!
Link to developer page here.
此处链接到开发人员页面。
1. Getting started
1. 入门
Things you will need.
你需要的东西。
1.1 Your Base64 unique application key
1.1 您的 Base64 唯一应用密钥
How to get it:
如何获得:
a. Go to your developer console. Link.
一种。转到您的开发者控制台。关联。
b. If you haven't already created an application draft for your app, do it now.
湾 如果您尚未为您的应用创建应用程序草稿,请立即创建。
c. Once you have created the draft, it is a good idea to upload your .apk
as Alpha or Beta. Leave it unpublished.
C。创建草稿后,最好将您的.apk
Alpha 或 Beta 版上传。让它不公开。
d. Click Services & APIs
d. 点击Services & APIs
e. Scroll down and find YOUR LICENSE KEY FOR THIS APPLICATION
e. 向下滚动并找到YOUR LICENSE KEY FOR THIS APPLICATION
f. Copy the key into your app like this:
F。将密钥复制到您的应用程序中,如下所示:
private static final String BASE64_PUBLIC_KEY = "YOUR LICENSE KEY FOR THIS APPLICATION";
Make sure that there are no spaces.
确保没有空格。
1.2 A salt
1.2 盐
a. What is a salt?
一种。什么是盐?
A saltis random data that is additional input when hashing a password. They are used to defend against dictionary attacksand rainbow tableattacks.
甲酸盐是随机数据即附加的输入散列密码时。它们用于防御字典攻击和彩虹表攻击。
b. How do I get one?
湾 我怎么得到一个?
Thisis a good link to generate a random salt. There should be exactly20 random integers, so put 20
in for the amount of random strings to generate, each string should be 2
characters long (used for this example, it doesn't have to be). Check numeric digits, and check Identical strings are allowed. They can be negative numbers too. Try to remove any redundancy, e.g. 00 -> 0
, for the sake of consistency.
这是生成随机盐的好链接。应该正好有20 个随机整数,所以输入20
要生成的随机字符串的数量,每个字符串应该是2
字符长(用于本示例,它不一定是)。检查数字,并检查允许使用相同的字符串。它们也可以是负数。尝试删除任何冗余,例如00 -> 0
,为了一致性。
c. Where do I put the salt?
C。我把盐放在哪里?
When declaring variables just put this code in, except with your random salt.
声明变量时只需输入此代码,除了随机盐。
private static final byte[] SALT = new byte[] {YOUR RANDOM SALT, COMMA SEPARATED, 20 INTEGERS};
2. Importing the LVL (Licensing) library into Eclipse and the code you need
2. 将LVL(Licensing)库和你需要的代码导入Eclipse
2.1 Importing the library
2.1 导入库
a. Open Android SDK Manager
一种。打开Android SDK Manager
b. Go to Extras
湾 去Extras
c. Install Google Play Licensing Library
C。安装Google Play Licensing Library
d. Find your SDK
install path which is listed at the top of the SDK manager.
d. 找到SDK
在 SDK 管理器顶部列出的安装路径。
e. Once you are there, navigate to: <sdk>/extras/google/play_licensing
e. 到达后,导航到:<sdk>/extras/google/play_licensing
f. In eclipse, click file
then import
, then Existing Android Code Into Workspace
and when it asks you for the file path, navigate to the play_licensing
folder and click on library
.
F。在 Eclipse 中,单击file
then import
,然后Existing Android Code Into Workspace
当它询问您文件路径时,导航到该play_licensing
文件夹并单击library
。
g. Once the project named library
has been imported, right click it, then hit properties
. Click Android
on the left and navigate to the bottom and check Is Library
, then hit apply. This lets eclipse know that you can use this project code as a library.
G。library
导入命名的项目后,右键单击它,然后点击properties
。单击Android
左侧并导航到底部并选中Is Library
,然后点击应用。这让 eclipse 知道您可以将此项目代码用作库。
h. Right click on your app that you are adding licensing to, and click properties, then hit Android
. Go to the bottom and click library
and add it to the build path. This should import the library to the Android Dependencies
folder.
H。右键单击要向其添加许可的应用程序,然后单击属性,然后点击Android
。转到底部并单击library
并将其添加到构建路径。这应该将库导入到Android Dependencies
文件夹中。
i. Your project is set up to go to the next step.
一世。您的项目已设置为进入下一步。
2.2 Variables to declare along with your SALT
and KEY
2.2 与你SALT
和你一起声明的变量KEY
private Handler mHandler;
private LicenseChecker mChecker;
private LicenseCheckerCallback mLicenseCheckerCallback;
boolean licensed;
boolean checkingLicense;
boolean didCheck;
2.3 The code
2.3 代码
Paste this code near the bottom of your app. This implementation will notify the user if the license is not valid and prompt them to buy the app or exit it.
将此代码粘贴到应用底部附近。如果许可证无效,此实现将通知用户并提示他们购买应用程序或退出应用程序。
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 Getting your device id
2.4 获取您的设备 ID
There has been some debate about this in the past about whether or not to use the sim serial or TelephonyManager.getDeviceId();
but it is generally recommended you use the following code to get the ANDROID_ID
of your device for maximum compatibility.
过去曾有一些关于是否使用 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 Creation of the license checker
2.5 许可证检查器的创建
a. Before you call doCheck();
you must put this code in your app to make sure everything gets created properly.
一种。在您调用之前,doCheck();
您必须将此代码放入您的应用程序中,以确保所有内容都正确创建。
mHandler = new Handler();
mLicenseCheckerCallback = new MyLicenseCheckerCallback();
mChecker = new LicenseChecker(this, new ServerManagedPolicy(this, new AESObfuscator(SALT, getPackageName(), deviceId)), BASE64_PUBLIC_KEY);
When I was doing my implemetation of LVL, I read that if you are having problems with Licensing, you can change the first this
in the mChecker = new LicenseChecker(this...
to getApplicationContext()
, mine seemed to work without it, but just in case.
当我在做我的拉特implemetation,我读了,如果您有授权的问题,你可以第一个改变this
在mChecker = new LicenseChecker(this...
给getApplicationContext()
,雷似乎没有工作,但以防万一。
2.6 Adding permissions
2.6 添加权限
a. There are two permissions that you need to add to your applications manifest
file.
一种。您需要将两个权限添加到应用程序manifest
文件中。
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.android.vending.CHECK_LICENSE"/>
2.7 Make sure you have the proper imports!
2.7 确保你有正确的进口!
You have probably already done this, but I figured it would be a good place for you to check.
您可能已经这样做了,但我认为这是您检查的好地方。
2.8 How to call the license to be checked
2.8 如何调用被检查的License
a. Simply call doCheck();
whenever you want to check the license. For example if the app is on its first run, do the check.
一种。doCheck();
只要您想检查许可证,只需致电。例如,如果应用程序是第一次运行,请进行检查。
3. How do I test the licensing to make sure it works before publishing it?
3. 如何在发布前测试许可以确保其有效?
3.1 Configuring the testing device
3.1 配置测试设备
a. I have my personal phone that I also use for testing. It is recommended that there be only one Google account registered on the phone, historically it makes things a little easier. You can check the accounts by going to Settings -> Accounts
.
一种。我有我的个人手机,也用于测试。建议手机上只注册一个谷歌账户,从历史上看,这会让事情变得容易一些。您可以前往 查看账户Settings -> Accounts
。
3.2 Configuring the developer console
3.2 配置开发者控制台
a. Open your developer console and go to Settings
on the left hand side.
一种。打开您的开发者控制台并转到Settings
左侧。
b. Find License Testing
湾 找License Testing
c. Make sure that your email address is listed under Gmail accounts with testing access
C。确保您的电子邮件地址列在下面Gmail accounts with testing access
d. Now, you can change the test response to whatever you like for testing purposes. The app should respond accordingly. Remember that if you are saving the data via SharedPrefs you will need to clear your app data every time you test it. Make sure that you click save after you change the test response or nothing will happen!I forgot about this multiple times and I ended up with a migraine, then I saw that stinking save button. Lol.
d. 现在,您可以出于测试目的将测试响应更改为您喜欢的任何内容。该应用程序应做出相应的响应。请记住,如果您通过 SharedPrefs 保存数据,则每次测试时都需要清除应用程序数据。确保在更改测试响应后单击保存,否则什么也不会发生!我多次忘记了这一点,最后我偏头痛,然后我看到了那个臭烘烘的保存按钮。哈哈。
4. Things to try
4. 尝试的事情
4.1 Conditional license checking
4.1 有条件的许可证检查
a. You can try this code if you are saving the didCheck
data in SharedPreferences
.
一种。如果您将didCheck
数据保存在SharedPreferences
.
if(didCheck==false){
Toast.makeText(this, "Checking application license...", Toast.LENGTH_SHORT).show();
doCheck();
Log.i("Checking!", "Checking license!");
}
4.2 Encrypting your SharedPreferences
using SecurePreferences
4.2 加密您的SharedPreferences
使用SecurePreferences
a. Go to this link.
一种。转到此链接。
b. Copy and paste the code from SecurePreferences.java
into a class with the exact same name into your project.
湾 将代码复制并粘贴SecurePreferences.java
到具有完全相同名称的类中到您的项目中。
c. Read the ReadMe.md
for info on implementing this.
C。阅读ReadMe.md
有关实现这一点的信息。
5. Troubleshooting
5. 故障排除
Licensing can be one heck of a headache to troubleshoot, simply because there are many more things that can go wrong. For example, there could be network problems or server problems that make you want to rip your hair out. Use of proper logging will help with this, you can also get the server response codes if there is a problem and you can trace it to the server or your app. I have had to do this on multiple occasions.
许可可能是一个令人头疼的故障排除,仅仅是因为还有很多事情可能会出错。例如,可能存在网络问题或服务器问题,让您想脱发。使用正确的日志记录将对此有所帮助,如果出现问题,您还可以获得服务器响应代码,您可以将其跟踪到服务器或您的应用程序。我不得不多次这样做。
5.1 I can't get my app to return anything from the server
5.1 我无法让我的应用从服务器返回任何东西
Possible Fixes:
可能的修复:
a. Make sure that your app has the correct KEY
.
一种。确保您的应用程序具有正确的KEY
.
b. Make sure you are logging each step of the progress
湾 确保您正在记录进度的每一步
c. Check your log for anything from the licensing service. It can be useful for figuring out where something went wrong.
C。检查您的日志以获取许可服务中的任何内容。它对于找出哪里出了问题很有用。
d. Make sure allow()
and dontAllow()
and applicationError()
have @Override
tags.
d. 确保allow()
和dontAllow()
和applicationError()
有@Override
标签。
5.2 My app always says LICENSED
or NOT_LICENSED
no matter what I set it to in the test response
5.2 我的应用程序总是说LICENSED
或NOT_LICENSED
不管我在测试响应中设置了什么
a. The best cure I have for this is just to wait. It seems that if you do lots of testing in a short period of time, it will always send you server code 291
which is the retry code. I waited overnight and everything worked fine the next morning.
一种。我对此最好的治疗方法就是等待。似乎如果您在短时间内进行大量测试,它总是会向您发送服务器代码291
,即重试代码。我等了一夜,第二天早上一切正常。
b. You can clear the data (not just cache) of the Google Play app and the Google Play Services app. Then open play back up and accept all the licenses and try again.
湾 您可以清除 Google Play 应用程序和 Google Play Services 应用程序的数据(不仅仅是缓存)。然后打开播放并接受所有许可证并重试。
c. Clear your app data.
C。清除您的应用数据。
5.3 List of server response codes for debugging
5.3 用于调试的服务器响应码列表
You should get these decimal values for int reason
if you log them. Use this table to reference what the server is actually sending to your app.
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 Room for more! They will come!
5.4 更多的空间!他们会来的!
I hope this helps you guys! I tried to share my headaches and fixes with you guys as best I can and I hope this helps!
我希望这对你们有帮助!我试图尽我所能与你们分享我的头痛和修复,我希望这会有所帮助!
If I made any errors, be sure to tell me about them so I can get them fixed ASAP!
如果我犯了任何错误,请务必告诉我它们,以便我尽快修复它们!