眼前多少难甘事,自古男儿当自强。这篇文章主要讲述Bash玩转脚本4之搞一套完整的Android反编译与分包工具相关的知识,希望能为你提供帮助。
一、前言
正在搞ios的微信支付和支付宝支付,焦头烂额之时,天上掉下来一个android分包工具的需求,觉得还蛮有意思,其实之前一直想搞一个类似的东西,正好趁着这次机会实践一下。[原文地址]
(http://blog.csdn.net/yang8456211/article/details/52513354 )
(先说清楚需求,这个分包工具要干什么)
从产品角度
拿到一个apk安装包,然后用这个包去生成n个包,这n个包需要有特定的标示,能够根据包的标示去收集信息,而且这个n个包彼此不能覆盖安装。
从技术角度
对于这个需求,关键点在于三个点
1. 怎么去生成n个包?
2. 怎么修改apk的标示?
3. 怎么使得这n个包不能覆盖安装?
二、Just do it2.1 首先我们自己制作一个简单的apk包这个apk包包含两个功能点:
- 获取一些包的基本信息,例如应用包名
- 获取一些Meta信息,用来区分我们所打的包
(获取应用包名)
PackageInfo info = null;
try {
// 获取包名
info = this.getPackageManager()
.getPackageInfo(this.getPackageName(), 0);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}// 当前版本的包名
pgName = info.packageName;
(获取Meta信息)
PackageManager pm = this.getPackageManager();
ApplicationInfo appInfo = null;
try {
appInfo = pm.getApplicationInfo(this.getPackageName(),
PackageManager.GET_META_DATA);
} catch (NameNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// 读取meta的内容
msg.append(appInfo.metaData.getString("SDK_CHANNEL"));
这里我们读取了SDK_CHANNEL这个信息作为包的标示,需要在Android Manifest中配置好相关的Meta data。
<
meta-data android:name="SDK_CHANNEL" android:value="https://www.songbingjia.com/android/天降正义" />
运行时截图
文章图片
可以看到现在的包名是com.example.testmultipac,渠道是天降正义~
接下来我们就开始着手一个一个解决问题三、开始处理我们的包3.1 怎么去生成这个n个包?想要生成多个包,必须涉及到需要把apk进行反编译,然后重新生成apk包的过程,因此我使用了apktool这个工具。
注:apktool 有1和2两个版本,两者语法有些许不同,在这里使用了apktool_2.1.0这个jar,当然你也可以使用apktool1;window可以直接调用apktool.bat的批处理,事实上也是调用了apktool.jar。
文章图片
apktool指令:
解开apk包:
java -jar apktool d -f 输入的apk路径 -o 输出的文件夹路径
重新生成apk包:
java -jar apktool b 上一步解出的文件夹路径 -o 输出apk路径
注:这里使用的apktool2,因此有-o这个参数,apktool是没有的,请注意。
了解了apktool的指令后,我们便可以方便的实现apk的解包和组包,在组包的会后通过修改包的名称,就可以生成多个不同名的包了。
例如:
do_repac(){outapk=$apkpacpath"/"$game_package_name".apk"# apktool重新回包 以免apktool的一些临时改动
java -jar ./tool/apktool/$APKTOOL_JAR b $unpacpath -o $outapk
}
上面的outapk即为 $apkpacpath”/”$game_package_name”.apk”
game_package_name为当前包的包名。(如果能做到包名不同,则生成的apk的名字便不同)
3.2 怎么修改apk的标示?目前例子来说,我们apk的标示是”SDK_CHANNEL”这个Meta字段,我们可以通过修改这个字段来实现我们对包的区分。当客户端对服务器发起请求的时候,带上这个字段,服务器便可以方便的知道是哪个包进行的请求了。
那我们要怎么修改这个字段呢?
在此我使用了sed,一个方便替换的文本的指令。
(想要见识sed对字符串的替换,可以看我的这篇文章)
Bash玩转脚本3之几个指令有趣的筛选京东评价
指令为:
sed -i ‘‘ "s~^.*<
meta-data android:name=\"SDK_CHANNEL\".*~<
meta-data android:name=\"SDK_CHANNEL\" android:value=https://www.songbingjia.com/""$game_channel"\"/>
~g" $manifest
在此我稍作解释,如果有兴趣的朋友可以去google或者百度才能系统的学习。
1)
sed "s~原字符串~新字符串~g" 文件路径
这是sed最基本的指令, “~”符号可以换成很多符号,三个”~”对应更换即可.2)sed -i
通过
man sed
可以查到sed的基本指令(OSX 系统)文章图片
意思是不备份,直接在原文件上面进行操作。
注:在linux上可以直接使用
sed -i
,而在Unix上需要sed -i ""
3)
^.*<
meta-data android:name=\"SDK_CHANNEL\".*
这一段是正则匹配,用于匹配到SDK_CHANNEL那一行,sed是一行一行进行扫描的,如果遇到能够匹配的就会进行替换。
4)
"$game_channel"
这个是bash的取值,相当于一个变量,这里我是取game_channel这个变量到现在,我们已经能够把包解出来,然后使用sed去修改里面的标示,看样子已经成功了一半了。
3.3 怎么使得这n个包不能覆盖安装?涉及到这个问题,我们需要对Android的基本知识进行一个简单回顾。
Android通过什么来保证应用的唯一性?
答案是包名和签名。
- 如果两个apk,包名相同,签名也相同,则会根据versionCode的值来决定是否会覆盖,如果后一个apk的versionCode比较大,才能够覆盖安装。
- 如果包名相同,签名不同,则会被识别为不安全的应用,会给予提示,安装的结果会是后一个apk会删掉前一个apk,然后进行安装。
- 如果包名不同,签名相同,则代表着同一个开发者的应用,被识别为不同的应用。(看来这样就可以实现我们的不覆盖安装了)
old_pacname=`cat $manifest | grep "package=" | head -n 1 | awk -F ‘package=\"‘ ‘{print $2}‘ | awk -F ‘\"‘ ‘{print $1}‘ |xargs echo `
echo "==>
"$old_pacname
sed -i ‘‘ "s~package=\""$old_pacname\""~package="\"$game_package_name\""~g" $manifest
讲一下思路:
1. 先把”package=”关键字的那一行抓出来(这里是为了抓包名)
2. 使用两次awk取出 package=后面的包名(得到当前的包名)
3. 当前的包名赋值给old_pacname
4 .使用sed替换旧的包名为新包名,新的包名为game_package_name这个变量的值。
【Bash玩转脚本4之搞一套完整的Android反编译与分包工具】至此我们已经弄清楚了其中的知识点,对于一些难点也有了一定处理办法,接下来我们便要开始做一个脚本去自动化实现Android的反编译和分包了。
3.4 来看看我们的流程
3.5 签名过程我们是通过jarsigner这个工具对apk进行签名的,如果不签名的应用可是无法安装的~
那个这个jarsigner是什么呢?其实这个是jdk自带的对jar包进行签名的工具,我们可以在安装的java指令的同级目录找到它。
文章图片
通过直接输入jarsigner指令,可以得到提示
用法:
#显示信息签名文件签名密码生成apk未签名apkalias
jarsigner -verbose -keystore $keystore_name -storepass $SIGN_PASS -signedjar $sign_apkname -digestalg SHA1 -sigalg MD5withRSA $unsign_apkname $SIGN_ALIAS
每个参数的意思注释都标志的很清楚了~
四、make Auto下面讲讲脚本的思路
4.1 实现两个调用模式第一种)所有的参数从外部传递调用,Mode为1时
第二种)读取本地的配置文件,Mode为0时,可以实现批处理生成多个包
功能说明:
help_info() {
cat <
<
ENTER
============= Auto pac For game =============
Version: 1.0
Date: 20160907
Usage: Auto repackage For the game, modify package name and subchannel
e.g.:
Mode0: sh autopac.sh inputApkPath gamename
Mode1: sh autopac.sh inputApkPath gamename channel outputApkPath
inputApkPath: 待分包的apk路径
gamename: 游戏名称英文首字母小写
channel: 渠道号
outputApkPath: 完成输出apk的路径
============= Auto pac For game =============
ENTER
}
参数由外部输入就不赘述了,简单的赋值即可。
对于Mode=0时的读取配置文件一般是通过awk来实现的。
4.2 使用awk读取配置文件例如配置文件的内容是这样
[package]
package1=d101
package2=d102
我们通过awk取出对应的d101,和102出来
read_config() {
inifile=$1 #$1为配置文件的位置
_readIni=`awk -F ‘=‘ ‘$1~/‘package[d]*‘/{print $2}‘ $inifile`
echo $_readIni
}
稍微解释一下:
1. awk -F ‘=’ 为按照’=’,进行字符串分割
2. package[d]*为正则表达式,用来匹配package1,package2这种类型的一行,所以配置文件中可以有很多个package
3. {print $2} 就是打印出用’=’分割的第二个字符串,即’=’号后面的内容。
(假如我的标示不止1个怎么办?)
例如我的标示有三个,channel、subchannel、payway分别对应着渠道号、子渠道、支付渠道,那这个时候怎么办呢?
我们可以把配置文件写成这样:
package1=d101:subchannel101:1
package1=d102:subchannel102:2
然后在按照上面的做法,我们取出了 ‘=’ 右边的值,例如d101:subchannel101:1
我们便可以通过bash的字符串分割来做:
game_payway=${1##*:}
temp=${1%:*}
game_subchannel=${temp##*:}
game_channel=${temp%:*}
这样便可以取出payway等值了,关于bash的字符串分割,可以自行百度
基本的东西都讲完了,我们来看看最终的效果:
五、实现效果以mode为1的批处理为例子:
1)配置文件配置了4个不同channel的包:
[package]package1=yingxiongbuxiu:英雄不朽
package2=wushiyidao:午时已到
package3=laidianyinyue:来点音乐
package4=ronghuohexin:熔火核心
2)执行脚本:
sh autopac.sh ./TestMultiPac.apk mszl
TestMutiPac.apk就是我们最开始生成的一个apk,mszl为游戏的名称
3)执行效果:
文章图片
看到已经生成了4个包:
文章图片
4)安装效果:
如图生成了5个包
文章图片
随便选取一个包的效果
文章图片
源码地址:
https://github.com/yang8456211/AutoPacAndroid
杨光(atany)原创,转载请注明博主与博文链接,未经博主允许,禁止任何商业用途。
博文地址:http://blog.csdn.net/yang8456211/article/details/52513354
博客地址:http://blog.csdn.net/yang8456211
本文遵循“署名-非商业用途-保持一致”创作公用协议
推荐阅读
- Android —— 内存泄漏检查
- Android控制ScrollView滚动
- 《ArcGIS Runtime SDK for Android开发笔记》——离在线一体化技术(离线矢量数据同步)
- 用android studio创建第一个安卓程序加载html5 页面
- 《ArcGIS Runtime SDK for Android开发笔记》——离在线一体化技术(离线矢量数据编辑)
- xp系统将excel文件转换成PDF文件的办法
- xp系统下百度杀毒会自动安装是怎样回事
- xp系统迅速恢复百度杀毒隔离区文件的办法
- xp系统在瑞星杀毒V17版本下加入云安全计划的办法