给APP增加RSA签名

    RSA签名,Google主要用于APP的来源控制与结算。所谓的结算,也是就是控制了APP只有使用现在机子上登录的Google账户从Google市场曾经下载过该APP的才能够使用,这样也就达到了app销售的目的。

   
 
增加RSA签名主要分为以下几步骤
  1).添加License Verification Library(LVL)库
  2).发布一个测试版(BETA 版)到Google Play市场。
  3).代码中实现签名的认证功能并进行APP的权限控制。
 
以下所有操作都是在Android Studio里面完成。Eclipse可以进行对应参考。
 
一。添加第三方库License Verification Library(LVL)步骤
1,下载LVL库
      打开Android SDK Manager。在库列表Extras下面找到Google Play LIcensing Library。下载之。现在完成该Lib会存放在android-sdk-windows\extras\google\play_licensing\library。
2,添加LVL库到工程中
File---New---Import Module。选择SDK中LVL库。也就是android-sdk-windows\extras\google\play_licensing\library。选择正确,则会出现Module Name。可以自定义这个Lib名字。这里定义为lvl。
 
3,打开App的Grade file。注意:是App目录下的Grade File。一般命名为build.grade。对应位置(dependencies)添加
compile project(':lvl')
 
 4,点击Tools----Android-----Sync Project with Grade Files。完成了第三方库的添加。
 
 
 
二。发布一个测试版到Google 市场
     该步骤和正常发布一个App是一样的。只不过APK上传的时候,选择的是Beta版,非正式版。注意:点击右上角的发布之后才是完成,非上传完APK就算完成了。测试的APP需要添加测试账户到封闭的测试列表里面,也就是手机现已登录的Google账户需要添加到里面,不然无法进行测试。
 
三,实现与签名服务器的交互达到实现控制应用程序的权限的控制
    与签名服务器交互主要通过LicenseChecker这个类。通过LicenseChecker注册一个LicenseCheckerCallback的回调来达到控制APP的目的,一般都是在MainActivity进行与签名服务器的交互工作,在mLicenseCheckerCallback中,如果成功认证APP则继续往下走,否则可以提示退出。
    操作方法如下:
1,添加App的权限
<uses-permission android:name="com.android.vending.CHECK_LICENSE" />
2,在MainActivity定义一个20个随机字节的数组(供AESObfuscator使用),和一些变量。
private static final String BASE64_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjynFykMkHwAuVkL22mUo3Z2HkTXbtXzjAktR1xrIAudSnWCYWKoAeWsSGccS+KOinEyTK1/aMPbWFhjqUl08AtMAygaukoFD3OltfKan4At99AJH9BxKNWZCLAAilt7jW1+8PoiaintlLHZpyG2c6VqSET2VRyGCFCXzKq9BnnhJqkGxJagSRf43WhFXHl1nueDDDm4DdmGjAegY2loglRbYq9cuqxSGn8T1c/ebYE2IZn+OjtG0/9+ce6WwGabeTyQi3HVcvwerTVYwT8PAzujcX6epvhtL3Jfvp73QEWojR381e8Fpsw+Qvd+2rnSZNphbSY56f/4wg4OhPGG6twIDAQAB";
private static final byte[] SALT = new byte[] { 13, 32, 81, 65, 53, 82, 18, 100, -69, -17, 51, 81, -13, 86, -10, -40, 19, 45, 63, -7 };
private LicenseChecker mChecker;

 
private LicenseCheckerCallback mLicenseCheckerCallback;

 

3.定义一个内部LicenseCheckerCallback类
private class MyLicenseCheckerCallback implements LicenseCheckerCallback {
    @Override
    public void allow(int reason) {
    // Log.i("RSA", "success Code: " + reason);
    delayedHide(HIDE_DELAY_MILLIS);
    }
     
    @Override
    public void applicationError(int errorCode) {
    // Log.i("RSA", "Error Code: " + errorCode);
    haveNoLicence();
    }
     
     
    @Override
    public void dontAllow(int reason) {
        Log.i("RSA", "dontAllow Code: " + reason);
        if (reason !=Policy.LICENSED){ //not success
        haveNoLicence();
        }
    }
}
 

 

   在这个Callback类里面,访问返回方法是dontAllow。在成功的情况下才会调用allow。报错的情况下才会调用applicationError,报错不包括没有license,网络错误等。所以我这里直接是没有认证成功就执行没有权限的方法。
 
4,初始化LicenseChecker和LicenseCheckerCallback
String deviceId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
// Library calls this when it's done.
mLicenseCheckerCallback = new MyLicenseCheckerCallback();
// Construct the LicenseChecker with a policy.
mChecker = new LicenseChecker(this, new ServerManagedPolicy(this, new AESObfuscator(SALT, getPackageName(), deviceId)), Constants.RSA_KEY);
5,访问签名服务器进行校验。
mChecker.checkAccess(mLicenseCheckerCallback);

 

 
到这里,就完成了RSA的认证了。
 
可能会遇到的问题
1,报错,Error code 3。是由于Google市场没有上传APK。或者还没有发布完成。如果已经完成发布,请等待审核通过。估计24小时内可以通过审核。
2,切换Google账户或者更换应用中的RSA KEY。如果校验结果与想象的结果不相同,则需删除应用并且重启手机再进行测试。
3,其他错误代码列表如下:
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.0系统不允许隐式调用服务,导致LVL包绑定服务报错。报“Service Intent must be explicit Intent”错误,需修改代码如下:
com.google.android.vending.licensing中的LicenseChecker类中方法checkAccess中的代码:

                     boolean bindResult = mContext
                            .bindService(
                                    new Intent(
                                            new String(
                            Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U=")),
                                    this, // ServiceConnection.
                                    Context.BIND_AUTO_CREATE);

修改为显式调用:

                    String name = new String(
                            Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U="));
                    Intent serviceIntent = new Intent(name);
                    serviceIntent.setPackage("com.android.vending");
                    boolean bindResult = mContext.getApplicationContext().bindService(serviceIntent, this, Context.BIND_AUTO_CREATE);

 

 

posted on 2015-10-15 17:29  fengyun1989  阅读(1417)  评论(0编辑  收藏  举报