关闭。这个问题不符合 Stack Overflow guidelines 。它目前不接受答案。
想改善这个问题吗?更新问题,以便堆栈溢出为 on-topic。
7 天前关闭。
锁定。这个问题及其答案是 locked 因为这个问题是题外话但具有历史意义。它目前不接受新的答案或互动。
我看到了库存的 Android-Developer 许可库 instructions ,但概述似乎省略了该过程中的几个关键步骤,并且未能完全解释如何使某些工作正常工作。
有人可以提供一组明确的操作来在 Android 应用程序上设置许可库,以便它检查以确保用户在允许使用之前已在 Google Play 中为应用程序付费吗?
最佳答案
一段时间以来,我一直致力于在我的应用程序中实现许可,并最终使其正常工作。我想与大家分享我发现对入门有帮助的一些事情以及我发现的一些问题和解决方案。我在下面链接的 android 开发教程还可以,但对我来说不是那么有用,所以我决定制作一个教程。欣赏,希望对你有帮助!
链接到开发者页面 here 。
1. 入门
你需要的东西。
1.1 您的 Base64 唯一应用 key
如何获得:
一种。转到您的开发者控制台。 Link.
湾如果您尚未为您的应用创建应用程序草稿,请立即创建。
C。创建草稿后,最好将 .apk
上传为 Alpha 或 Beta。让它不公开。
d.点击 Services & APIs
e.向下滚动并找到 YOUR LICENSE KEY FOR THIS APPLICATION
F。将 key 复制到您的应用程序中,如下所示:
private static final String BASE64_PUBLIC_KEY = "YOUR LICENSE KEY FOR THIS APPLICATION";
确保没有空格。
1.2 盐
一种。什么是盐?
salt 是随机数据,是在对密码进行散列时额外输入的数据。它们用于防御 dictionary attacks 和 rainbow table 攻击。
湾我怎么得到一个?
This 是生成随机盐的好链接。应该有 正好是 20 个随机整数,因此将
20
放入要生成的随机字符串的数量,每个字符串应该是 0x251812411 个字符,例如,它没有使用 long 字符。检查数字,并检查允许使用相同的字符串。它们也可以是负数。尝试删除任何冗余,例如2
,为了一致性。C。我把盐放在哪里?
声明变量时只需输入此代码,除了随机盐。
private static final byte[] SALT = new byte[] {YOUR RANDOM SALT, COMMA SEPARATED, 20 INTEGERS};
2. 将LVL(Licensing)库和你需要的代码导入Eclipse
2.1 导入库
一种。打开
00 -> 0
湾转到
Android SDK Manager
C。安装
Extras
d.找到 SDK 管理器顶部列出的
Google Play Licensing Library
安装路径。e.到达后,导航至:
SDK
F。在 Eclipse 中,依次单击
<sdk>/extras/google/play_licensing
和 file
,然后单击 import
,当它询问您文件路径时,导航到 0x251812231343142223134314223131343141 文件夹和G。导入名为
Existing Android Code Into Workspace
的项目后,右键单击它,然后点击 play_licensing
。单击左侧的 library
并导航到底部并选中 library
,然后点击应用。这让 eclipse 知道您可以将此项目代码用作库。H。右键单击要向其添加许可的应用程序,然后单击属性,然后点击
properties
。转到底部并单击 Android
并将其添加到构建路径。这应该将库导入到 Is Library
文件夹。一世。您的项目已设置为进入下一步。
2.2 与您的
Android
和 library
一起声明的变量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 串行或
Android Dependencies
对此存在一些争论,但通常建议您使用以下代码来获取设备的 SALT
以获得最大兼容性。String deviceId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
Log.i("Device Id", deviceId); //AN EXAMPLE OF LOGGING THAT YOU SHOULD BE DOING :)
2.5 许可证检查器的创建
一种。在您调用
KEY
之前,您必须将此代码放入您的应用程序中,以确保正确创建所有内容。mHandler = new Handler();
mLicenseCheckerCallback = new MyLicenseCheckerCallback();
mChecker = new LicenseChecker(this, new ServerManagedPolicy(this, new AESObfuscator(SALT, getPackageName(), deviceId)), BASE64_PUBLIC_KEY);
当我在执行 LVL 时,我读到如果您在许可方面遇到问题,您可以将
TelephonyManager.getDeviceId();
中的第一个 ANDROID_ID
更改为 doCheck();
,但我的似乎可以在没有它的情况下工作。2.6 添加权限
一种。您需要向应用程序
this
文件添加两个权限。<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.android.vending.CHECK_LICENSE"/>
2.7 确保你有正确的进口!
您可能已经这样做了,但我认为这是您检查的好地方。
2.8 如何调用待查的license
一种。每当您想检查许可证时,只需致电
mChecker = new LicenseChecker(this...
。例如,如果应用程序是第一次运行,请进行检查。3. 如何在发布前测试许可以确保其有效?
3.1 配置测试设备
一种。我有我的个人手机,也用于测试。建议手机上只注册一个谷歌账户,从历史上看,这会让事情变得容易一些。您可以通过转到
getApplicationContext()
来查看帐户。3.2 配置开发者控制台
一种。打开您的开发者控制台并转到左侧的
manifest
。湾找到
doCheck();
C。确保您的电子邮件地址列在
Settings -> Accounts
下d.现在,您可以出于测试目的将测试响应更改为您喜欢的任何内容。该应用程序应做出相应的响应。请记住,如果您通过 SharedPrefs 保存数据,则每次测试时都需要清除应用程序数据。 确保在更改测试响应后单击保存,否则什么也不会发生! 我多次忘记这件事,最后我偏头痛,然后我看到了那个臭的保存按钮。哈哈。
4. 尝试的事情
4.1 条件许可检查
一种。如果您将
Settings
数据保存在 License Testing
中,则可以尝试此代码。 if(didCheck==false){
Toast.makeText(this, "Checking application license...", Toast.LENGTH_SHORT).show();
doCheck();
Log.i("Checking!", "Checking license!");
}
4.2 使用
Gmail accounts with testing access
加密您的 didCheck
一种。转到此 link 。
湾将
SharedPreferences
中的代码复制并粘贴到项目中具有完全相同名称的类中。C。阅读
SharedPreferences
以获取有关实现此功能的信息。5. 故障排除
许 cocoa 能是一个令人头疼的故障排除,仅仅是因为还有很多事情可能会出错。例如,可能存在网络问题或服务器问题,让您想脱发。使用正确的日志记录将对此有所帮助,如果出现问题,您还可以获得服务器响应代码,您可以将其跟踪到服务器或您的应用程序。我不得不多次这样做。
5.1 我无法让我的应用程序从服务器返回任何内容
可能的修复:
一种。确保您的应用具有正确的
SecurePreferences
。湾确保您正在记录进度的每一步
C。检查您的日志以获取许可服务中的任何内容。它对于找出哪里出了问题很有用。
d.确保
SecurePreferences.java
和 ReadMe.md
和 KEY
有 allow()
标签。5.2 我的应用程序总是说
dontAllow()
或 applicationError()
无论我在测试响应中将其设置为什么 一种。我对此最好的治疗方法就是等待。似乎如果您在短时间内进行大量测试,它总是会向您发送服务器代码
@Override
,这是重试代码。我等了一夜,第二天早上一切正常。湾您可以清除 Google Play 应用程序和 Google Play Services 应用程序的数据(不仅仅是缓存)。然后打开播放并接受所有许可证并重试。
C。清除您的应用数据。
5.3 调试用服务器响应码列表
如果你记录它们,你应该得到
LICENSED
的这些十进制值。使用此表来引用服务器实际发送到您的应用程序的内容。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 更多的空间!他们会来!
我希望这对你们有帮助!我试图尽我所能与你们分享我的头痛和修复,我希望这会有所帮助!
如果我犯了任何错误,请务必告诉我它们,以便我尽快修复它们!
关于java - 如何为 Android 应用实现 Google Play 许可?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18324963/