最近一直在做公司的一个安卓开发框架,含so库,接近尾声了,领导提出一个需求,要求使用这个框架的开发者必须有我们的授权才可以,但是对方发布的应用后又不能被此授权限制——要不然所有的应用都来要授权那就麻烦了。
分析:
既然是限制开发者,那么就必须要区分debug版本和release版本,也就是框架的授权限制功能只对debug版本有效,而对release版本无效;然后就是需要一个调试设备的一个唯一ID,这样授权码是绑定在固定的设备的,只要有新的调试设备就需要新的授权码,一般公司里也就是十几个设备吧,这个申请量级完全可以接受。
思路:
因为正好这个框架需要so库的支持,这样在so库加载时的int JNI_OnLoad(JavaVM* jvm, void* reserved)方法中可以完成验证。
关于debug和release版本的区分,安卓系统提供了一个debugable属性可以实现,只要是从Eclipse或者ADT的集成环境里直接运行或者调试,都可以判断出是否是debug版本;
关于安卓设备的ID,安卓本身提供好几种ID的获取,我最终使用的是security类的ID, Settings.Secure.getString(ContentResolver,Settings.Secure.ANDROID_ID),这个ID是在安卓设备第一次启动的时候自动生成的,如果刷机的话则可能会改变。
授权码的存放位置就放在AndroidManifest中的application结点下,增加一个meta结点,并可以自定义信息的名称,那么现在就是准备工作就全了.
实现:
1. JNI层的int JNI_OnLoad(JavaVM* jvm, void* reserved)完成验证
2.JNI层判断程序是否为debug版本,为防止java代码被反编译,所以获取debug属性和判断都在JNI层进行,可以参考java层的如下代码,即将一下代码改编为C++代码:
public boolean isDebugMode(){ ApplicationInfo info = this.getApplicationInfo(); return (0!=((info.flags) & ApplicationInfo.FLAG_DEBUGGABLE)); }
3.JNI层获取安卓设备的唯一ID,可以参考java代码,即将一下代码改编为C++代码:
String id = Settings.Secure.getString(this.mainActivity.getContentResolver(), Settings.Secure.ANDROID_ID);
4.获取Manifest中的meta中的授权码,这个就没必要非得在JNI层实现了,可以在java层获取,然后传递给JNI层,参考是如下的java代码:
ApplicationInfo info=context.getPackageManager().getApplicationInfo(con.getPackageName(),PackageManager.GET_META_DATA); String key=info.metadata.getString("permissionKey");
5.接下来就是加密解密以及最后的适当加花加壳的取舍了,就不再细说了。