1. 程式人生 > >通過命令列實現Android工程資原始檔到apk的流程

通過命令列實現Android工程資原始檔到apk的流程

前言

我們在開發Android應用的時候,可能很少研究整個Apk生成的過程,一般如AS或者Eclipse的開發工具,在執行的時候會自動幫我們將程式碼與資原始檔打包並簽名,生成相應的apk檔案,不知道大家有沒有好奇整個apk的編譯、打包過程呢,下面通過這篇文章,一塊來了解一下一個Android的工程檔案是怎麼從程式碼、資原始檔變成最終的apk檔案的。

命令列演示Android工程專案資源的編譯打包流程

參考官方文件的流程圖,下面我們通過命令列手動的模擬一下整個流程:

本篇文章的環境

首先我的作業系統是基於Windows系統,JDK版本最終使用的是1.6(以上會出現異常),sdk-tools版本是21。

相關工具地址

建立Android工程檔案

進入tools資料夾:

cd D:\eclipse\sdk\tools

命令列:

[android.bat] --target [target_id] --name [project_name] --path [project_path] --package [package_name] --activity[activity_name]

這些引數代表的意思:

佔位符 描述 本文示例
target_id sdk版本 每個人電腦上面根據安裝的版本不同,id對應的版本也不同,我電腦上的的8,即API21
project_name 工程名稱 resource2apk
project_path 工程路徑 D:\CSDN\
package_name 包名 com.csdn.lhy
activity_name 建立Activity的名稱 MainActivity
D:\eclipse\sdk\tools\android.bat create project --target 8  --name source2apk --path D:\CSDN\ --package com.csdn.lhy --activity MainActivity

執行結果如下,可以看到在相應的目錄下,已經建立了該工程,注意此時是沒有gen目錄的,也就是說此時還沒有生成R檔案。

生成R.java

接下來,我們通過命令列處理相應的資原始檔,來生成R檔案。
命令列:

[aapt.exe] -f -m -J [gen_folder_path] -S [res_path] -I [android.jar_path] -M [manifest_path]

佔位符 描述 本文示例
aapt.exe aapt工具路徑 D:\eclipse\sdk\build-tools\build-tools-21.1.1\aapt.exe
gen_folder_path gen目錄路徑 D:\CSDN\gen
res_path res資原始檔路徑 D:\CSDN\res
android.jar_path 覆蓋引導類檔案的位置 D:\eclipse\sdk\platforms\android-21\android.jar
manifest_path AndroidManifest.xml檔案位置 D:\CSDN\AndroidManifest.xml
D:\eclipse\sdk\build-tools\build-tools-21.1.1\aapt.exe


D:\eclipse\sdk\build-tools\build-tools-21.1.1\aapt.exe package  -f -m -J D:\CSDN\gen -S D:\CSDN\res -I D:\eclipse\sdk\platforms\android-21\android.jar -M D:\CSDN\AndroidManifest.xml

執行之後看到如下,在相應的gen目錄下面,生成了R.java檔案,注意到第一次這個命令列執行失敗,需要人工建立一下gen目錄,第二次執行成功,開啟R檔案,看到裡面已經生成了相應的程式碼。

編譯.java2.class

編譯java檔案生成class ,不要忘記R.java檔案
注意:-bootclasspath是必須要設定的, 它表示覆蓋引導類檔案的位置,如果不設定會報錯,命令列如下:
javac -target [jdk_version] -bootclasspath [android.jar_path] -d [.java_path]

佔位符 描述 本文示例
jdk_version jdk的版本 1.6
android.jar_path 覆蓋引導類檔案的位置 D:\eclipse\sdk\platforms\android-21\android.jar
.java_path .java檔案的位置 即src檔案下的.java以及gen目錄下的R.java
javac -target 1.6 -bootclasspath D:\eclipse\sdk\platforms\android-21\android.jar -d D:\CSDN\bin D:\CSDN\src\com\csdn\lhy\*.java D:\CSDN\gen\com\csdn\lhy\R.java

執行成功的話,如下圖所示,在bin目錄下生成了相應的.class檔案,注意不要忽略了R.java

我們通過JD-GUI開啟看一下,發現可以正常的反編譯回來。

.class2.dex

class打包成dex,需要注意的是,dx工具最好使用建立專案中的sdk版本中的,與bootclasspath所用版本一致,命令列如下:

[dx.bat] --dex --output=[dex_path] [classes_path]

佔位符 描述 本文示例
dx.bat dx工具的位置 D:\eclipse\sdk\build-tools\build-tools-21.1.1\dx.bat
dex_path 打包後dex檔案的生成路徑 D:\CSDN\bin\classes.dex
classes_path 當前的.class位元組碼檔案路徑 D:\CSDN\bin\
D:\eclipse\sdk\build-tools\build-tools-21.1.1\dx.bat


D:\eclipse\sdk\build-tools\build-tools-21.1.1\dx.bat --dex --output= D:\CSDN\bin\classes.dex D:\CSDN\bin\

執行成功之後,結果如下圖,我們發現在bin目錄下已經生成了相應的dex檔案:

打包資原始檔

打包資原始檔,將資原始檔打包成resources.ap_檔案,命令列如下:

[aapt.exe] package -f -m -S [res_path] -I [android.jar_path] -M[manifest_path] -F[resources.ap_]

佔位符 描述 本文示例
aapt.exe aapt.exe路徑 D:\eclipse\sdk\build-tools\build-tools-21.1.1\aapt.exe
res_path 專案中res資原始檔位置 D:\eclipse\sdk\platforms\android-21\android.jar
android.jar_path 覆蓋引導類檔案的位置 D:\CSDN\bin\
manifest_path AndroidManifest.xml檔案路徑 D:\CSDN\AndroidManifest.xml
resources.ap_ 打包資原始檔生成的resources.ap_檔案路徑 D:\CSDN\bin\resources.ap_

D:\eclipse\sdk\build-tools\build-tools-21.1.1\aapt.exe package  -f -m -S D:\CSDN\res -I D:\eclipse\sdk\platforms\android-21\android.jar -M D:\CSDN\AndroidManifest.xml -F D:\CSDN\bin\resources.ap_

執行結果如下:

生成未簽名的apk

最終打包apk,需要使用apkbuilder.bat 必須放到tools資料夾下面:

[apkbuilder.bat] [unsigned_apk_path] -v -u -z [resources.ap_] -f [classes.dex] -rf [src_path]

佔位符 描述 本文示例
apkbuilder.bat apkbuilder.bat路徑 D:\eclipse\sdk\tools\apkbuilder.bat
unsigned_apk_path 生成的未簽名apk檔案路徑 D:\CSDN\bin\final.apk
resources.ap_ 打包資原始檔生成的resources.ap_檔案路徑 D:\CSDN\bin\resources.ap_
classes.dex classes.dex檔案路徑 D:\CSDN\bin\classes.dex
src_path src資料夾路徑 D:\CSDN\src
D:\eclipse\apkbuilder.bat 


D:\eclipse\sdk\tools\apkbuilder.bat D:\CSDN\bin\final.apk -v -u -z D:\CSDN\bin\resources.ap_ -f D:\CSDN\bin\classes.dex -rf D:\CSDN\src

我們可以看到執行成功後,在相應的檔案下生成了未簽名的apk檔案。

生成簽名祕鑰

建立密匙,會在當前C:\Users\使用者名稱\檔案下下生成相應的簽名證書檔案:

keytool -genkey -alias release -keyalg RSA -validity 20000 -keystore release.keystore

apk簽名

jarsigner -verbose -keystore [keystore_path] -storepass [password] -keypass [password] android -signedjar [signed_apk] [unsigned_apk] release

佔位符 描述 本文示例
keystore_path 簽名證書路徑 C:\Users\memphise\release.keystore
password 簽名中自己設定的密碼 我設定的是android
signed_apk 最終生成的簽名之後的apk檔案路徑 D:\CSDN\bin\resource2jar-signed.apk
unsigned_apk 需要簽名的apk檔案路徑 D:\CSDN\bin\final.apk
jarsigner -verbose -keystore C:\Users\memphise\release.keystore -storepass android -keypass android -signedjar D:\CSDN\bin\resource2jar-signed.apk D:\CSDN\bin\final.apk release

執行結果如圖,在bin目錄下,生成了剛才簽名的apk檔案。

我們在模擬器上安裝一下,可以看到執行成功,Hello World

異常總結

在將class檔案打包成dex檔案時候遇到:
com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)
這是由於jdk版本與dx工具版本不一致的問題,解決方案參考了stackoverflow ,原本我的JDK版本是1.8,這裡打包的時候就遇到了這個問題,最終降級到1.6之後解決了這個問題。
至於Eclipse,AS等工具,使用1.6版本以上的JDK仍然可以打包成功,有哪位大神可以告知一下麼?

參考文章