Android发包有许多坑的地方,下面对之前遇到过的问题进行总结,以期望将来不再出现这些令人不快的问题。
1. 代码混淆
代码混淆问题已经在发包流程中多次出现,其主要的原因是:靠反射执行的方法在代码混淆后会找不到反射的类导致该部分功能失效,甚至导致Crash。
这一问题在广告以及第三方SDK的使用中多次出现,尤其是在SDK升级或者接入新的SDK的时候特别要注意这个问题,另外在自己使用反射的时候也需要注意这个问题。
如何防范:
为了方便解决和验证这一问题,可以在Debug模式下开启混淆功能,以达到在Debug上进行测试混淆结果的目的。
对于日常QA测试来说,验证新广告的时候,所使用的包都需要进行混淆后测试,以验证广告混淆后的工作情况。
2. Manifest中的权限被覆盖
这一问题曾经出现在HyprMX SDK升级后,HyprMX SDK的内部在使用SDK读写权限的时候引入了maxSdkVersion这一属性,对SD卡读写权限进行了限制,导致引入该SDK后会让高版本系统的SD卡读写权限失效,进而影响所有与文件操作相关的功能。在Android studio包合并之后会将该属性合并到主的Manifest中,从而将该问题带入到整个Dingtone工程。
如何防范:
对于以后类似问题的处理,可以在接入新的SDK的时候,审查其Manifest和混淆文件的内容,避免被其坑到,尤其对于权限相关的操作限制。
另外,上包前的自动化case也需要足够全面,能执行对应的功能来检查其权限的情况
3. ContentProvider的用法错误
曾经在Kiip SDK升级的时候出现过该问题,新版本的Kiip demo指定添加Provider组件,但是在声明其authorities属性的时候将Dingtone和TalkU的属性设为了一样的了,这会导致手机中只能存在其中一个App,在安装另一个App的时候就会报错,这种情况在DN1和PN1也一样。
如何防范:
我们App基本不会使用ContentProvider,ContentProvider用于对外提供数据访问,我们App目前暂时不涉及到对其他App提供数据。如果有第三方SDK需要引入ContentProvider的时候,一定要注意了,首先确认该功能对于这类SDK的使用是否是必须的,比如Kiip要求我们声明provider,但实际上该功能对其正常使用没有任何的作用,且可能会存在把我们App数据暴露给其他App的风险,所以可以不需要集成。如果真的有必要使用该组件的话,则必须要让authorities属性在不同的App里面不一样,可以采用与包名对应的命名方式。
比如:${applicationId}.KEY
4. Manifest里uses-feature标签的required属性
uses-feature标签用于声明所需要的硬件需求,如果其required属性设置为ture的话,则App发布后,GooglePlay会对于不支持的设备不提供下载和升级的服务,这会导致用户下载量下降。
如何防范:
与#2点一样,无论是引入第三方SDK还是在自己集成的时候,一定要检查Manifest中的属性是否存在问题,对于 uses-feature 为true的属性,我们需要将其改为false,并且对于调用的功能的地方,需要手动判断设备是否支持这一硬件需求,之后决定要不要给用户提供对应的功能。
5. Manifest Application标签中的supportsRtl属性
该属性在现在的新版本的Android Studio中会自动添加,且值是true,这就会导致在阿拉伯地区,界面排版会出现从右往左进行的混乱的局面。对于我们这样的还没有进行阿拉伯地区界面排版适配的App来说,这个值需要手动设置为false
如何防范:
与#2点一样,无论是引入第三方SDK还是在自己集成的时候,一定要检查Manifest中的属性是否存在问题,对于supportsRtl属性,需要检查Application的标签属性是否正确。
针对Manifest这一系列的问题,我这边想到了一个方案是对比前后两个版本的Apk的Manifest文件,并标出涉及到权限属性方面的改动,以及时发现和预警权限相关的问题。我这边会提供一个检测的脚本工具,在每次发包之前及时进行这方面的检查工作,并且对于发现的有疑点的地方及时与相关的开发人员进行同步。
对于本次发现的问题,我们通过对比工具可以很明确发现检测到相关的一些特征标志
目前搜集的几点敏感特征如下:
required="true"
authorities=
supportsRtl="true"
maxSdkVersion
可以使用如下脚本对当前要发布的Apk以及之前老的Apk中的权限进行比对
# 命令用法
if [ $# -lt 2 ]; then
echo "apkDiff APK1 APK2"
exit 1
else
if [ ${1} == "--h" ]; then
echo "apkDiff APK1 APK2"
exit 1
fi
if [ ${1} == "--help" ]; then
echo "apkDiff APK1 APK2"
exit 1
fi
fi
# 解析两个Apk文件的Manifest文件
echo start deco ${1}
apktool d -o 1 ${1}
echo success deco ${1}
echo start deco ${2}
apktool d -o 2 ${2}
echo success deco ${2}
# 比较两个Mainifest的不同
diff 1/AndroidManifest.xml 2/AndroidManifest.xml >> diff.txt
# 匹配敏感权限
grep -E "required=\"true\"|authorities=|supportsRtl=\"true\"|maxSdkVersion" diff.txt >> result.txt
result=$(cat result.txt)
echo -e "\033[32m Differ length:${#result} \033[0m"
echo -e "\033[31m ${result} \033[0m"