本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!
签名机制:
V1:7.0以前默认,使用META-INF目录下三个文件,MANIFEST.MF,CERT.MF,CERT.RSA来保证apk不被修改。
MANIFEST.MF:记录apk资源中除META-INF,所有文件的Base64编码的SHA1值。防止apk资源被修改。
CERT.MF:记录MANIFEST.MF中属性值的Base64。防止MANIFEST.MF被修改。
CERT.RSA:记录通过开发者私钥对CERT.MF计算得到的签名,和开发者公钥。
解析过程是通过PackageManagerService.java和PackageParser.java对上述过程进行逆向操作。如果签名验证成功,则安装成功,否则安装失败。
V2:7.0以后默认此类型签名方式,如不处理安装时显示无证书。V1缺点在于,签名可以被清除,重新签名。
安装时,不用每次再去解压校验每个文件,只需要检验整个APK的数据摘要,发明SigningBlock插入apk修改偏移量满足zip结构要求。安装速度是V1的3倍左右。
将数据摘要、数字证书、额外属性组装成类MF文件
用私钥将MF计算得到类SF文件
将类MF文件和类SF文件,以及开发者公钥,用私钥签名成V2。
结构如下图:
V2严格限制apk不能被重新签名,否则已安装的apk,再替换安装时,检验不通过。
重签名:保证安装。环境:jdk1.8,据说jdk1.7要加入“-digestalg SHA1 -sigalg MD5withRSA”几个参数(未验证)
将apk解压,删除META-INF文件夹,重新压缩成zip格式。
v1:jarsigner -verbose -keystore “jks路径” -storepass “存储密码” -keypass “键密码” -signedjar “输出apk 路径” “转换apk路径” “alias 别名”
v2:从build-tools/26.0.1左右的包里,拷贝apksigner.jar到tools文件夹内,并进入tools文件夹,执行如下命令
java -jar apksigner.jar sign --ks “jks路径” --ks-key-alias “alias 别名” --ks-pass pass:“存储密码” -key-pass pass:“键密码” --out “输出apk 路径” “转换apk路径”
验证v2签名:
java -jar apksigner.jar verify -v 输出apk 路径”
实验过程:将一个包含v1和v2签名的apk重签名,在签名前后分别安装。
实验结果:
1、不签名,手机提示“无法安装”
2、v1签名后,可安装所有sdk版本的手机。说明:7.0以下手机验证v1签名通过,7.0以上手机未找到v2签名,所以也验证了v1。
2、v2签名后,结论如上。说明v1和v2签名均生效。如果只有v2签名,则7.0以下手机会报“无证书”。
2017年初,Android7.0出现新的签名机制,如果不适配将出现无签名的问题,华为Mate8最先出现,取巧的方式是将该签名机制取消(它是向下兼容的),build.gradle的release设置如下
- release {
- // 如果要支持最新版的系统 Android 7.0
- // 这一行必须加,否则安装时会提示没有签名
- // 作用是只使用旧版签名,禁用V2版签名模式
- v2SigningEnabled false
接上篇:Ant、Gradle、Python三种打包方式的介绍
上一组的打包机制是修改META-INF,在它的目录下面,使用python快速复制apk,并添加一个channel文件,用来读取作为项目的渠道名,显然这样做是不够严谨的,一直在关注并期待有新的方式解决这两个问题,那么walle应运而生。
其原理:在signiture block里的ID-VALUE对象添加channel-huawei,这样的键值对,再来读取渠道号即可,避免开发者修改apk造成安全问题,同时开放接口给开发者为自己业务注入新的解决方案,walle就是一例。
操作方式:
1、配置build.gradle
在位于项目的根目录 build.gradle
文件中添加Walle Gradle插件的依赖, 如下:
buildscript {
dependencies {
classpath 'com.meituan.android.walle:plugin:1.0.3'
}
}
并在当前App的 build.gradle
文件中apply这个插件,并添加上用于读取渠道号的AAR
apply plugin: 'walle'
dependencies {
compile 'com.meituan.android.walle:library:1.0.3'
}
2、如何获取渠道信息
在需要渠道等信息时可以通过下面代码进行获取
String channel = WalleChannelReader.getChannel(this.getApplicationContext());
3、如何生成渠道包
生成渠道包的方式是和assemble指令结合,可以通过传入参数决定是否生成渠道包,渠道包的生成目录存放在 build/outputs/apk/
下面是各类用法示例:
- 生成单个渠道包
./gradlew clean assembleRelease -PchannelList=meituan
- 支持 productFlavors
./gradlew clean assembleMeituanRelease -PchannelList=meituan
- 生成多个渠道包
./gradlew clean assembleRelease -PchannelList=meituan,dianping
- 通过渠道配置文件来生成渠道包
./gradlew clean assembleRelease -PchannelFile=channel
渠道号设置两种方式:
第一种:在项目目录下新建一个channel文件,利用上面第4条通过配置文件生成渠道包
- samsungapps #三星
- hiapk
- anzhi
- xiaomi # 小米
- productFlavors {
- official {}
- baidu {}
- }
4、更多用法
插入额外信息
如果想插入除渠道以外的其他信息,请在生成渠道包时使用
./gradlew clean assembleRelease -PchannelList=meituan -PextraInfo=buildtime:20161212,hash:xxxxxxx
extraInfo以key:value
形式提供,多个以,
分隔。
注意:
- extraInfo需要搭配channelList或者channelFile使用,plugin不支持只写入extraInfo。
- extraInfo 不要出现以
channel
为key的情况
而对应的渠道信息获取方式如下:
ChannelInfo channelInfo= WalleChannelReader.getChannelInfo(this.getApplicationContext());
if (channelInfo != null) {
String channel = channelInfo.getChannel();
Map<String, String> extraInfo = channelInfo.getExtraInfo();
}
// 或者也可以直接根据key获取
String value = WalleChannelReader.get(context, "buildtime");
而对应的渠道信息获取方式如下:
应用签名方案APK Signature Scheme v2原理:http://tech.meituan.com/android-apk-v2-signature-scheme.html
官方地址:https://github.com/Meituan-Dianping/walle
PR:
walle最新版本是1.1.5支持flavor和walle两种配置渠道号的方式.
如果两者均存在build.gradle中,则使用gradle assembleReleaseChannels命令时,会报"Task 'assembleReleaseChannels' not found in root project".错误。
walle支持flavor,但flavor不支持walle。
如果想执行walle配置,则需要加入渠道号即gradle assembleXiaoMiReleaseChannels,则只会执行walle命令。
如果想执行flavor配置,则需要删除walle,执行gradle assembleReleaseChannels即可。
使用walle打包,则在数据统计时需要手动加入渠道号。
walle打包优点:打包速度快。一个母包打完,修改渠道号即要生成新包。
缺点:不能灵活修改应用的logo、包名等
flavor打包优点:可以灵活修改应用信息(http://blog.csdn.net/stimgo/article/details/77480154),
缺点:需要一个个打包,速度太慢;无法用脚本批量打包。
解决加固后无渠道号的问题:https://github.com/Meituan-Dianping/walle/tree/master/walle-cli
下载完walle-cli后,在其目录下执行 java -jar walle-cli-all.jar put -c 渠道号 目标apk即可。