前言
還是之前痛徹心扉的出包經(jīng)歷灭抑,出一點小問題就要重新出包,驗證問題及其麻煩漾稀,浪費了大量的非必要時間模闲。所以這里想盡可能的優(yōu)化步驟,提升效率崭捍。文檔如正文尸折,并且將下述步驟集成為shell文件,掛在附件缕贡,需要的話自取翁授。
包體拆包重構(gòu)
工具下載
1. apktool,用于包體的拆解與構(gòu)建晾咪,從apk中提取圖片和布局資源收擦。apktool下載
2. dex2jar,將可運行文件classes.dex反編譯為jar源碼文件,版本選擇上要選2.1谍倦,2.0以及2.0之前的不支持MultiDex塞赂。dex2jar_2.1下載
3. jd-gui,查看jar源碼文件昼蛀。jd-gui下載
工具安裝
apktool安裝
1. 根據(jù)apktool網(wǎng)站提示的下載方法宴猾,右擊wrapper script,鏈接存儲為apktool叼旋,不要帶拓展名
2. 下載apktool.jar仇哆,選擇第一個下載最新版本
3. 把apktool_2.3.3.jar重命名為apktool.jar,然后把apktool.jar和apktool一起拷貝到/usr/local/bin路徑下
4. 打開終端夫植,輸入apktool命令讹剔,看到相應(yīng)輸出及為安裝成功
dex2jar && jd-gui
下載完dex2jar和 jd-gui解壓一下就可以了油讯,復(fù)制到工作目錄方便操作。(順便對dex2jar提一下權(quán)限延欠,不然會報權(quán)限問題)
拆包與重構(gòu)
1. 終端輸入cd path..... 進(jìn)入到測試apk所在目錄
2. test.apk 將包體拆解
apktool.bat d -o <output_dir>
3. 根據(jù)各自需求陌兑,對文件夾內(nèi)的內(nèi)容進(jìn)行替換和修改
4. 將包體重構(gòu),此時包體未重簽過由捎,所以是安裝不了的兔综。
apktool.bat b -o <output.apk> <input_dir>
包體重簽
1. 將簽名文件移植到apk目錄下,方便操作
2. 確保機器上安裝了java環(huán)境
3. 終端進(jìn)入apk目錄下狞玛,執(zhí)行命令:
jarsigner -verbose -keystore [your_key_store_path] -signedjar [signed_apk_name] [usigned_apk_name] [your_key_store_alias] -digestalg SHA1 -sigalg MD5withRSA -storepass [StorePass]
****字段說明:****
- [your_key_store_path]:密鑰所在位置的路徑
- [signed_apk_name]:簽名后安裝包名稱
- [usigned_apk_name]:未簽名的安裝包名稱
- [your_key_store_alias]:密鑰的別名
- [StorePass]:keystore的密碼
重簽之后的apk包就是可以用的了
java代碼的抽取
代碼的抽取只是一句命令行:
sh dex2jar-2.1/d2j-dex2jar.sh apk_path
這里著重說下運行過程中遇到的問題:
問題一:資源包超兩個G
報錯如下:
Exception in thread "main" java.lang.OutOfMemoryError: Required array size too large
at java.nio.file.Files.readAllBytes(Files.java:3156)
at com.googlecode.dex2jar.tools.Dex2jarCmd.doCommandLine(Dex2jarCmd.java:108)
at com.googlecode.dex2jar.tools.BaseCmd.doMain(BaseCmd.java:290)
at com.googlecode.dex2jar.tools.Dex2jarCmd.main(Dex2jarCmd.java:33)
出現(xiàn)原因: Files.readAllBytes 方法最大支持 Integer.MAX_VALUE - 8 大小的文件软驰,也就是最大2GB的文件。一旦超過了這個限度为居,java 原生的方法就不能直接使用了碌宴。所以伴隨這個報錯的往往是游戲閃退杀狡。
解決辦法: 把文件分成多個子區(qū)域分多次讀取蒙畴,這就會有多種方法可以使用。
問題二:java堆空間溢出
報錯如下:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.nio.file.Files.read(Files.java:3099)
at java.nio.file.Files.readAllBytes(Files.java:3158)
at com.googlecode.dex2jar.tools.Dex2jarCmd.doCommandLine(Dex2jarCmd.java:108)
at com.googlecode.dex2jar.tools.BaseCmd.doMain(BaseCmd.java:290)
at com.googlecode.dex2jar.tools.Dex2jarCmd.main(Dex2jarCmd.java:33)
出現(xiàn)原因: 運行的java程序需要較大的內(nèi)存時呜象,可能會造成堆空間溢出膳凝。
解決方法: 將dex2jar-2.1/d2j-dex2jar.sh下的Xmx1024m改為Xmx4096m。Xmx表示jvm所需最大內(nèi)存,這里我們可以根據(jù)實際需要自己調(diào)整設(shè)置恭陡。
即:
java -Xms512m -Xmx1024m -classpath "${_classpath}" "com.googlecode.dex2jar.tools.Dex2jarCmd" "$@"
改為:
java -Xms512m -Xmx4096m -classpath "${_classpath}" "com.googlecode.dex2jar.tools.Dex2jarCmd" "$@"
問題三:dex2jar不支持MultiDex
出現(xiàn)原因: dex2jar版本為v2.1之前的版本,那么dex2jar就會默認(rèn)轉(zhuǎn)化第一個dex文件而忽略其他dex文件. 2.1版本開始支持multidex,會直接執(zhí)行
解決辦法: 下載2.1版本即可
shell腳本如下蹬音,只需將.sh與apk放在一起即可,具體操作請看注釋:
#!/bin/sh
#默認(rèn)填入數(shù)據(jù)休玩,不填可以不用管
# dex=1,拆解包體著淆,需付上apk路徑;
# dex=2拴疤,重構(gòu)包體永部,需付上keystore的文件名,Alias呐矾,簽名密碼苔埋,鑒于每個項目只有一個keystore,所以也可以寫死在文件內(nèi)蜒犯;
# dex=3组橄,反編譯java代碼,這里會生成.jar文件罚随,可以方便程序復(fù)查代碼
dex=None
oldApkPath=None;
keystore_name=None;
Alias=None;
StorePass=None;
if [ "$1" ]
then
dex="$1"
fi
if [ "$2" ]
then
if [ ${dex} = 2 ] ; then
keystore_name="$2"
echo "keystore_name~~~~~~~"
else
oldApkPath="$2"
echo "oldApkPath~~~~~~~"
fi
fi
if [ "$3" ]
then
Alias="$3"
fi
if [ "$4" ]
then
StorePass="$4"
fi
#當(dāng)前apk的絕對或相對路徑
APK_PATH=${oldApkPath}
#獲取當(dāng)前文件所在的絕對路徑
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
#操作類型
DEX=${dex}
echo "APK_PATH:", ${APK_PATH}
echo "SHELL_FOLDER:", ${SHELL_FOLDER}
echo "dex:", ${DEX}
time=$(date "+%Y_%m_%d_%H_%M_%S")
echo "${time}"
if [ ${APK_PATH} = None -a ${DEX} = 1 ] ; then
echo "apk沒傳玉工,退出~~~"
exit 0
fi
if [ ${keystore_name} = None -a ${DEX} = 2 ] ; then
echo "keystore_name沒有,無法重簽~~"
exit 0
fi
if [ ${Alias} = None -a ${DEX} = 2 ] ; then
echo "Alias無淘菩,無法重簽~~~"
exit 0
fi
if [ ${StorePass} = None -a ${DEX} = 2 ] ; then
echo "簽名密碼沒有遵班,無法重簽~~~"
exit 0
fi
if [ -x "usigned" -a ${DEX} = 1 ]
then
echo "Remove file usigned"
rm -rf "usigned"
fi
if [ -x "usigned.apk" -a ${DEX} = 2 ]
then
echo "Remove file usigned.apk"
rm -rf "usigned.apk"
fi
if [ ${DEX} = 1 ]; then
echo "開始拆解包體~~~"
apktool d -o usigned ${APK_PATH}
fi
if [ ${DEX} = 2 ]; then
echo "開始重構(gòu)包體~~~"
apktool b -o "usigned.apk" ${SHELL_FOLDER}"/usigned"
echo "開始重簽apk包體~~~~"
jarsigner -verbose -keystore ${keystore_name} -signedjar ${time}"_resign.apk" usigned.apk ${Alias} -digestalg SHA1 -sigalg MD5withRSA -storepass ${StorePass}
fi
if [ ${DEX} = 3 ]; then
echo "開始解析包體內(nèi)的Java代碼~~"
sh dex2jar-2.1/d2j-dex2jar.sh ${APK_PATH}
fi