android监听通知消息 脚本,Bash玩转脚本4之搞一套完整的Android反编译与分包工具...
一、前言
正在搞IOS的微信支付和支付寶支付,焦頭爛額之時,天上掉下來一個Android分包工具的需求,覺得還蠻有意思,其實之前一直想搞一個類似的東西,正好趁著這次機會實踐一下。
(先說清楚需求,這個分包工具要干什么)
從產(chǎn)品角度
拿到一個apk安裝包,然后用這個包去生成n個包,這n個包需要有特定的標(biāo)示,能夠根據(jù)包的標(biāo)示去收集信息,而且這個n個包彼此不能覆蓋安裝。
從技術(shù)角度
對于這個需求,關(guān)鍵點在于三個點
1. 怎么去生成n個包?
2. 怎么修改apk的標(biāo)示?
3. 怎么使得這n個包不能覆蓋安裝?
二、Just do it
2.1 首先我們自己制作一個簡單的apk包
這個apk包包含兩個功能點:
獲取一些包的基本信息,例如應(yīng)用包名
獲取一些Meta信息,用來區(qū)分我們所打的包
因為這篇文章主要在講bash和apk打包,對于Android代碼就不贅述了,貼出來參考。
(獲取應(yīng)用包名)
PackageInfo info = null;
try {
// 獲取包名
info = this.getPackageManager()
.getPackageInfo(this.getPackageName(), 0);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 當(dāng)前版本的包名
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的內(nèi)容
msg.append(appInfo.metaData.getString("SDK_CHANNEL"));
這里我們讀取了SDK_CHANNEL這個信息作為包的標(biāo)示,需要在Android Manifest中配置好相關(guān)的Meta data。
運行時截圖
可以看到現(xiàn)在的包名是com.example.testmultipac,渠道是天降正義~
接下來我們就開始著手一個一個解決問題
三、開始處理我們的包
3.1 怎么去生成這個n個包?
想要生成多個包,必須涉及到需要把apk進(jìn)行反編譯,然后重新生成apk包的過程,因此我使用了apktool這個工具。
注:apktool 有1和2兩個版本,兩者語法有些許不同,在這里使用了apktool_2.1.0這個jar,當(dāng)然你也可以使用apktool1;window可以直接調(diào)用apktool.bat的批處理,事實上也是調(diào)用了apktool.jar。
apktool指令:
解開apk包:
java -jar apktool d -f 輸入的apk路徑 -o 輸出的文件夾路徑
重新生成apk包:
java -jar apktool b 上一步解出的文件夾路徑 -o 輸出apk路徑
注:這里使用的apktool2,因此有-o這個參數(shù),apktool是沒有的,請注意。
了解了apktool的指令后,我們便可以方便的實現(xiàn)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為當(dāng)前包的包名。(如果能做到包名不同,則生成的apk的名字便不同)
3.2 怎么修改apk的標(biāo)示?
目前例子來說,我們apk的標(biāo)示是”SDK_CHANNEL”這個Meta字段,我們可以通過修改這個字段來實現(xiàn)我們對包的區(qū)分。當(dāng)客戶端對服務(wù)器發(fā)起請求的時候,帶上這個字段,服務(wù)器便可以方便的知道是哪個包進(jìn)行的請求了。
那我們要怎么修改這個字段呢?
在此我使用了sed,一個方便替換的文本的指令。
(想要見識sed對字符串的替換,可以看我的這篇文章)
Bash玩轉(zhuǎn)腳本3之幾個指令有趣的篩選京東評價
指令為:
sed -i ‘‘ "s~^.*~g" $manifest
在此我稍作解釋,如果有興趣的朋友可以去google或者百度才能系統(tǒng)的學(xué)習(xí)。
1)sed "s~原字符串~新字符串~g" 文件路徑 這是sed最基本的指令, “~”符號可以換成很多符號,三個”~”對應(yīng)更換即可.
2)sed -i
通過 man sed 可以查到sed的基本指令(OSX 系統(tǒng))
意思是不備份,直接在原文件上面進(jìn)行操作。
注:在linux上可以直接使用 sed -i,而在Unix上需要sed -i ""
3) ^.*
這一段是正則匹配,用于匹配到SDK_CHANNEL那一行,sed是一行一行進(jìn)行掃描的,如果遇到能夠匹配的就會進(jìn)行替換。
4)"$game_channel"這個是bash的取值,相當(dāng)于一個變量,這里我是取game_channel這個變量
到現(xiàn)在,我們已經(jīng)能夠把包解出來,然后使用sed去修改里面的標(biāo)示,看樣子已經(jīng)成功了一半了。
3.3 怎么使得這n個包不能覆蓋安裝?
涉及到這個問題,我們需要對Android的基本知識進(jìn)行一個簡單回顧。
Android通過什么來保證應(yīng)用的唯一性?
答案是包名和簽名。
如果兩個apk,包名相同,簽名也相同,則會根據(jù)versionCode的值來決定是否會覆蓋,如果后一個apk的versionCode比較大,才能夠覆蓋安裝。
如果包名相同,簽名不同,則會被識別為不安全的應(yīng)用,會給予提示,安裝的結(jié)果會是后一個apk會刪掉前一個apk,然后進(jìn)行安裝。
如果包名不同,簽名相同,則代表著同一個開發(fā)者的應(yīng)用,被識別為不同的應(yīng)用。(看來這樣就可以實現(xiàn)我們的不覆蓋安裝了)
在修改包名的時候,我同樣是用了一系列指令。(下意識寫的指令,并沒有考慮到是否最好,如果有更好的指令可以給我留言)
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=”關(guān)鍵字的那一行抓出來(這里是為了抓包名)
2. 使用兩次awk取出 package=后面的包名(得到當(dāng)前的包名)
3. 當(dāng)前的包名賦值給old_pacname
4 .使用sed替換舊的包名為新包名,新的包名為game_package_name這個變量的值。
至此我們已經(jīng)弄清楚了其中的知識點,對于一些難點也有了一定處理辦法,接下來我們便要開始做一個腳本去自動化實現(xiàn)Android的反編譯和分包了。
3.4 來看看我們的流程
Created with Rapha?l 2.1.0開始獲得參數(shù)apk解包修改包內(nèi)參數(shù)和包名apk組包簽名結(jié)束
可以發(fā)現(xiàn),在這個流程的最后一步,還有個簽名的過程,那怎么進(jìn)行簽名呢?
3.5 簽名過程
我們是通過jarsigner這個工具對apk進(jìn)行簽名的,如果不簽名的應(yīng)用可是無法安裝的~
那個這個jarsigner是什么呢?其實這個是jdk自帶的對jar包進(jìn)行簽名的工具,我們可以在安裝的java指令的同級目錄找到它。
通過直接輸入jarsigner指令,可以得到提示
用法:
# 顯示信息 簽名文件 簽名密碼 生成apk 未簽名apk alias
jarsigner -verbose -keystore $keystore_name -storepass $SIGN_PASS -signedjar $sign_apkname -digestalg SHA1 -sigalg MD5withRSA $unsign_apkname $SIGN_ALIAS
每個參數(shù)的意思注釋都標(biāo)志的很清楚了~
四、make Auto
下面講講腳本的思路
4.1 實現(xiàn)兩個調(diào)用模式
第一種)所有的參數(shù)從外部傳遞調(diào)用,Mode為1時
第二種)讀取本地的配置文件,Mode為0時,可以實現(xiàn)批處理生成多個包
功能說明:
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
}
參數(shù)由外部輸入就不贅述了,簡單的賦值即可。
對于Mode=0時的讀取配置文件一般是通過awk來實現(xiàn)的。
4.2 使用awk讀取配置文件
例如配置文件的內(nèi)容是這樣
[package]
package1=d101
package2=d102
我們通過awk取出對應(yīng)的d101,和102出來
read_config() {
inifile=$1 #$1為配置文件的位置
_readIni=`awk -F ‘=‘ ‘$1~/‘package[d]*‘/{print $2}‘ $inifile`
echo $_readIni
}
稍微解釋一下:
1. awk -F ‘=’ 為按照’=’,進(jìn)行字符串分割
2. package[d]*為正則表達(dá)式,用來匹配package1,package2這種類型的一行,所以配置文件中可以有很多個package
3. {print $2} 就是打印出用’=’分割的第二個字符串,即’=’號后面的內(nèi)容。
(假如我的標(biāo)示不止1個怎么辦?)
例如我的標(biāo)示有三個,channel、subchannel、payway分別對應(yīng)著渠道號、子渠道、支付渠道,那這個時候怎么辦呢?
我們可以把配置文件寫成這樣:
package1=d101:subchannel101:1
package1=d102:subchannel102:2
然后在按照上面的做法,我們?nèi)〕隽?‘=’ 右邊的值,例如d101:subchannel101:1
我們便可以通過bash的字符串分割來做:
game_payway=${1##*:}
temp=${1%:*}
game_subchannel=${temp##*:}
game_channel=${temp%:*}
這樣便可以取出payway等值了,關(guān)于bash的字符串分割,可以自行百度
基本的東西都講完了,我們來看看最終的效果:
五、實現(xiàn)效果
以mode為1的批處理為例子:
1)配置文件配置了4個不同channel的包:
[package]
package1=yingxiongbuxiu:英雄不朽
package2=wushiyidao:午時已到
package3=laidianyinyue:來點音樂
package4=ronghuohexin:熔火核心
2)執(zhí)行腳本:
sh autopac.sh ./TestMultiPac.apk mszl
TestMutiPac.apk就是我們最開始生成的一個apk,mszl為游戲的名稱
3)執(zhí)行效果:
看到已經(jīng)生成了4個包:
4)安裝效果:
如圖生成了5個包
隨便選取一個包的效果
總結(jié)
以上是生活随笔為你收集整理的android监听通知消息 脚本,Bash玩转脚本4之搞一套完整的Android反编译与分包工具...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pataca是哪个国家的钱?
- 下一篇: 安卓获取imei权限闪退_Android