系统api.png
如上图所示,PackageManager.getPermissionFlags()方法是被@SystemApi注解修饰过的方法,@SystemApi 只允许system app 调用或者用反射方法调用, 反射方法实例:
this.mPackageManager = context.getPackageManager(); try { Method method = mPackageManager.getClass(). getMethod("getPermissionFlags"); method.invoke(mPackageManager, permName, packageName, user); } catch (NoSuchMethodException e) { e.printStackTrace(); }
需要注意的是非 system app 用反射方法调用SystemApi,即使编译通过, 实际运行是还会遇到permission check。例如getPermissionFlags就需要GRANT_RUNTIME_PERMISSIONS,REVOKE_RUNTIME_PERMISSIONS,GET_RUNTIME_PERMISSIONS中的任意一个,如果应用没有申请这其中的任意一个权限,运行是也会报错。申请了以上三个中任意一个权限,就需要有系统签名。归根究底,要调用系统API就必须要系统签名,否则即使编译成功了,运行时也会报错。
2.源码编译模块
在使用mk文件编译的时候,会有LOCAL_PRIVATE_PLATFORM_APIS和LOCAL_SDK_VERSION参数选择,在mk文件中声明这两个参数的时候是互斥的,意思是只能声明其中一个。
- LOCAL_PRIVATE_PLATFORM_APIS设置之后,如果模块中有用到系统api,会使用sdk的hide的api来编译。
- LOCAL_SDK_VERSION设置之后,编译的应用不能访问hide的api,会报找不到该方法错误。
# 可以调用系统的api,但是需要给apk系统签名 # LOCAL_CERTIFICATE := platform LOCAL_PRIVATE_PLATFORM_APIS := true # 编译时忽略系统隐藏类(@hide) LOCAL_SDK_VERSION := current
源码编译时会用ProGuard混淆器做代码混淆、优化,过程中可能会删除掉个别类里的个别方法。
处理代码混淆问题有两个方法:
- 在mk文件里加上一句:LOCAL_PROGUARD_ENABLED := disabled,禁用混淆器。
- 在mk文件里加上一句:LOCAL_PROGUARD_FLAG_FILES := proguard.flags,然后创建一个配置文件"proguard.flags",配置部分类/方法/属性禁止混淆。(可以参照源码环境下的Settings里写法)