如何为 Android 应用实施 Google Play 许可?[已关闭]
我看到了Android-Developer许可库的库存说明,但概述似乎省略了该过程中的几个关键步骤,并且未能完全解释如何使某些东西正常工作。
有人可以提供一组明确的操作,以便在Android应用上设置许可库,以便检查以确保用户在允许使用之前已在Google Play中为应用付费?
我看到了Android-Developer许可库的库存说明,但概述似乎省略了该过程中的几个关键步骤,并且未能完全解释如何使某些东西正常工作。
有人可以提供一组明确的操作,以便在Android应用上设置许可库,以便检查以确保用户在允许使用之前已在Google Play中为应用付费?
一段时间以来,我一直在努力在我的应用程序中实现许可,并最终使其正常工作。我想与大家分享一些我发现对入门有帮助的事情,以及我发现的一些问题和解决方案。我在下面链接的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个随机整数,因此为了生成随机字符串的数量,每个字符串都应该是字符长(用于此示例,它不必是)。检查数字,并检查是否允许相同的字符串。它们也可以是负数。尝试删除任何冗余,例如,为了保持一致性。20
2
00 -> 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 中,单击 然后 ,然后当它要求您输入文件路径时,导航到该文件夹并单击 。file
import
Existing Android Code Into Workspace
play_licensing
library
g.导入名为 的项目后,右键单击它,然后单击 。单击左侧并导航到底部并选中,然后单击“应用”。这让 eclipse 知道您可以将此项目代码用作库。library
properties
Android
Is Library
h.右键单击要向其添加许可的应用程序,然后单击“属性”,然后单击 。转到底部,然后单击并将其添加到生成路径。这应该将库导入到该文件夹。Android
library
Android Dependencies
i. 您的项目已设置为转到下一步。
2.2 要与 SALT
和 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 创建许可证检查器
一个。在调用之前,必须将此代码放在应用中,以确保正确创建所有内容。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
b.找到License Testing
c. 确保您的电子邮件地址列在Gmail accounts with testing access
d.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 使用安全首选项加密共享
首选项
一个。转到此链接。
b.将代码从 复制并粘贴到具有完全相同名称的类中, 然后粘贴到项目中。SecurePreferences.java
c. 有关实现此内容的信息,请阅读 。ReadMe.md
5. 故障排除
许可可能是一个令人头疼的故障排除,仅仅是因为还有更多的事情可能会出错。例如,可能存在网络问题或服务器问题,使您想要扯掉头发。使用正确的日志记录将有助于解决这个问题,如果出现问题,您还可以获取服务器响应代码,并且可以将其跟踪到服务器或应用程序。我不得不在多个场合这样做。
5.1 我无法让我的应用从服务器返回任何内容
可能的修复:
一个。确保你的应用具有正确的 .KEY
b.确保记录进度的每个步骤
c. 检查日志中是否有来自许可服务的任何内容。它可用于找出问题所在。
d. 确保并有标签。allow()
dontAllow()
applicationError()
@Override
5.2 我的应用始终显示 LICENSED
或 NOT_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 更多空间!他们会来的!
我希望这对你们有所帮助!我试图与你们分享我的头痛和修复,尽我所能,我希望这有帮助!
如果我犯了任何错误,请务必告诉我,以便我可以尽快修复它们!