一段时间以来,我一直致力于在我的应用程序中实施许可,并终于让它发挥作用。我想与大家分享一些我发现对入门有帮助的东西以及我发现的一些问题和解决方案。我在下面链接的 android 开发教程还可以,但对我来说没那么有用,所以我决定制作一个教程。享受吧,希望对您有帮助!
链接到开发者页面here https://developer.android.com/google/play/licensing/index.html.
1. 入门
你需要的东西。
1.1 您的 Base64 唯一应用程序密钥
如何获得:
A。转到您的开发者控制台。Link. https://play.google.com/apps/publish
b.如果您尚未为您的应用创建申请草案,请立即创建。
C。创建草稿后,最好上传您的草稿.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。什么是盐?
A salt https://en.wikipedia.org/wiki/Salt_%28cryptography%29是散列密码时附加输入的随机数据。它们被用来防御字典攻击 https://en.wikipedia.org/wiki/Dictionary_attacks and 彩虹桌 https://en.wikipedia.org/wiki/Rainbow_table攻击。
b.我怎样才能得到一个?
This http://www.random.org/strings/是生成随机盐的一个很好的链接。应该有exactly20个随机整数,所以输入20
对于要生成的随机字符串的数量,每个字符串应该是2
字符长(用于本示例,但不一定如此)。检查数字,并检查是否允许相同的字符串。它们也可以是负数。尝试删除任何冗余,例如00 -> 0
,为了保持一致性。
C。我该把盐放在哪里?
声明变量时,只需放入此代码即可,除非使用随机盐。
private static final byte[] SALT = new byte[] {YOUR RANDOM SALT, COMMA SEPARATED, 20 INTEGERS};
2.将LVL(Licensing)库导入到Eclipse中以及你需要的代码
2.1 导入库
a. Open Android SDK Manager
b.去Extras
C。安装Google Play Licensing Library
d.找你的SDK
安装路径列在 SDK 管理器的顶部。
e.到达那里后,导航至:<sdk>/extras/google/play_licensing
F。在日食中,单击file
then import
, then Existing Android Code Into Workspace
当它询问您文件路径时,导航到play_licensing
文件夹并单击library
.
G。一旦项目命名为library
已导入,右键单击它,然后点击properties
. Click Android
在左侧并导航到底部并检查Is Library
,然后点击应用。这让 Eclipse 知道您可以将此项目代码用作库。
H。右键单击要添加许可的应用程序,然后单击“属性”,然后单击Android
。转到底部并单击library
并将其添加到构建路径中。这应该将库导入到Android Dependencies
folder.
我。您的项目已设置好进入下一步。
2.2 随你的声明一起声明的变量SALT
and KEY
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 创建许可证检查器
A。在您致电之前doCheck();
您必须将此代码放入您的应用程序中,以确保正确创建所有内容。
mHandler = new Handler();
mLicenseCheckerCallback = new MyLicenseCheckerCallback();
mChecker = new LicenseChecker(this, new ServerManagedPolicy(this, new AESObfuscator(SALT, getPackageName(), deviceId)), BASE64_PUBLIC_KEY);
当我实施 LVL 时,我读到如果您遇到许可问题,您可以更改第一个this
in the mChecker = new LicenseChecker(this...
to getApplicationContext()
,我的似乎没有它就可以工作,但以防万一。
2.6 添加权限
A。您需要将两个权限添加到您的应用程序中manifest
file.
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.android.vending.CHECK_LICENSE"/>
2.7 确保您有正确的导入!
您可能已经这样做了,但我认为这将是您检查的好地方。
2.8 如何调用待检查的许可证
A。只需致电doCheck();
每当您想检查许可证时。例如,如果应用程序首次运行,请进行检查。
3. 在发布之前如何测试许可以确保其有效?
3.1 配置测试设备
A。我有我的个人电话,也用于测试。建议手机上只注册一个 Google 帐户,从历史上看,这会让事情变得更容易一些。您可以通过以下方式查看账户:Settings -> Accounts
.
3.2 配置开发者控制台
A。打开您的开发者控制台并转到Settings
在左手侧。
b. Find License Testing
C。确保您的电子邮件地址列在下面Gmail accounts with testing access
d.现在,您可以将测试响应更改为您喜欢的任何测试响应。应用程序应该做出相应的响应。请记住,如果您通过 SharedPrefs 保存数据,则每次测试时都需要清除应用程序数据。确保更改测试响应后单击“保存”,否则什么都不会发生!我多次忘记了这一点,最后我得了偏头痛,然后我看到了那个臭烘烘的保存按钮。哈哈。
4. 可以尝试的事情
4.1 有条件许可证检查
A。如果您要保存,可以尝试此代码didCheck
数据输入SharedPreferences
.
if(didCheck==false){
Toast.makeText(this, "Checking application license...", Toast.LENGTH_SHORT).show();
doCheck();
Log.i("Checking!", "Checking license!");
}
4.2 加密您的SharedPreferences
using SecurePreferences
A。转到这个link https://github.com/sveinungkb/encrypted-userprefs.
b.复制并粘贴代码SecurePreferences.java
到您的项目中具有完全相同名称的类。
C。阅读ReadMe.md
有关实施此操作的信息。
5. 故障排除
许可问题的解决可能是一件令人头疼的事情,因为有很多事情可能会出错。例如,可能存在网络问题或服务器问题,让您想抓狂。使用正确的日志记录将有助于解决此问题,如果出现问题,您还可以获取服务器响应代码,并且可以将其跟踪到服务器或您的应用程序。我曾多次不得不这样做。
5.1 我无法让我的应用程序从服务器返回任何内容
可能的修复:
A。确保您的应用程序具有正确的KEY
.
b.确保您记录了进度的每一步
C。检查您的日志中是否有来自许可服务的任何内容。它对于找出问题所在非常有用。
d.确保allow()
and dontAllow()
and applicationError()
have @Override
tags.
5.2 我的应用程序总是说LICENSED
or NOT_LICENSED
无论我在测试响应中将其设置为什么
A。我对此最好的治疗方法就是等待。似乎如果你在短时间内进行大量测试,它总是会向你发送服务器代码291
这是重试代码。我等了一夜,第二天早上一切正常。
b.您可以清除 Google Play 应用和 Google Play 服务应用的数据(不仅仅是缓存)。然后打开播放备份并接受所有许可证并重试。
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 空间更多!他们会来的!
我希望这对你们有帮助!我尽力与大家分享我的头痛问题和解决方法,希望这对您有所帮助!
如果我犯了任何错误,请务必告诉我,以便我尽快修复!