本文將介紹如何在Mac系統下命令行編譯生成一個簡單的Apk程序。
準備工作
配置環境變量
aapt、dx、android.jar等工具或jar包本文采用SDK-26版本。
為了在mac系統下方便調用命令,需要添加環境變量:
命令 | 默認目錄 |
---|---|
adb | ~/Library/Android/sdk/platform-tools |
aapt、dx | ~/Library/Android/sdk/build-tools/26.0.2 |
android.jar | ~/Library/Android/sdk/platforms/android-26/android.jar |
sdklib-26.0.0-dev.jar | ~/Library/Android/sdk/tools/lib/sdklib-26.0.0-dev.jar |
這里只添加了adb、aapt、dx到環境變量中,jar包直接使用全路徑調用。環境變量進入控制臺如下配置:
//1.打開變量文件
cd ~
vim ~/.bash_profile
//2.增加如下變量
export PATH=${PATH}:~/Library/Android/sdk/platform-tools adb
export PATH=${PATH}:~/Library/Android/sdk/build-tools/26.0.2
//使用:wq!保存退出
//3.刷新變量文件
source .bash_profile
//4.重啟控制臺生效
創建項目
這里創建一個小型測試項目,用于生成apk。文件目錄如下:
test-app
-- AndroidManifest.xml
-- gen
-- out
-- res
---- layout
------ activity_main.xml
---- mipmap-xxhdpi
------ ic_launcher.png
---- values
------ strings.xml
-- src
---- java
------ MainActivity.java
這里創建的文件目錄完全是自定義的,你可以根據需要創建符合自己需求的目錄結構。我這里的目錄主要有如下用途:
目錄 | 用途 |
---|---|
gen | 存放后續生成的R.java文件 |
out | 存放后續生成的class、dex、apk文件 |
res | 存放項目資源文件 |
src | 存放代碼文件 |
這里AndroidManifest.xml代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dixon.test">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.java代碼如下:
package com.dixon.test;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
activity_main.xml代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.dixon.test.MainActivity">
<TextView
android:gravity="center"
android:text="Hello My App"
android:background="#FFFFFF"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
可以看出這只是一個單頁面的簡單項目,需要注意包名為com.dixon.test
。
命令行編譯
為了方便操作,這里cd到項目根目錄下。
生成R.java文件
1
aapt package -f -m -M AndroidManifest.xml -I ~/Library/Android/sdk/platforms/android-26/android.jar -S res/ -J gen/
aapt各參數意義如下:
參數 | 意義 |
---|---|
-f | 如果編譯出來的文件已經存在,強制覆蓋。 |
-m | 使生成的包的目錄放在-J參數指定的目錄。 |
-J | 指定生成的R.java的輸出目錄 |
-S | res文件夾路徑 |
-A | assert文件夾的路徑 |
-M | AndroidManifest.xml的路徑 |
-I | 某個版本平臺的android.jar的路徑 |
-F | 具體指定apk文件的輸出 |
此時項目gen目錄下會出現以下幾級目錄:
gen/com/dixon/test/R.java
正好對應包名+文件
,其中R.java代碼如下:
package com.dixon.test;
public final class R {
public static final class attr {
}
public static final class layout {
public static final int activity_main=0x7f030000;
}
public static final class mipmap {
public static final int ic_launcher=0x7f020000;
}
public static final class string {
public static final int app_name=0x7f040000;
}
}
生成class文件
這段命令會將java代碼(包括R.java)編譯為class文件輸出到out目錄下。
2
javac -encoding GBK -bootclasspath ~/Library/Android/sdk/platforms/android-26/android.jar -d out/ gen/com/dixon/test/*.java src/java/*.java
命令執行完畢后,可以看到如下新生成目錄:
out/com/dixon/test/xxx.class
生成dex文件
這段命令會將class文件轉為dex文件。
需要注意的是:這里class目錄只會識別包括包名在內的全文件路徑。即--output
的第二個參數不能為out/com/dixon/test,而應該是out/,否則會報路徑錯誤。
3
dx --dex --output=out/classes.dex out/
打包資源文件
4
aapt package -f -M AndroidManifest.xml -S res/ -I ~/Library/Android/sdk/platforms/android-26/android.jar -F out/Test.ap_
生成apk
下面命令將生成apk文件,并將資源文件、dex文件加入到apk中。
5
java -cp ~/Library/Android/sdk/tools/lib/sdklib-26.0.0-dev.jar com.android.sdklib.build.ApkBuilderMain out/Test.apk -v -u -z out/Test.ap_ -f out/classes.dex
過去可以使用apkbuilder生成apk,目前apkbuidler已經廢棄并且不能再用了。
這里使用如上方式生成apk,命令行仍會提示過期,但是實測可用(2018.11.25)。
如果有哪位大神知道不過期的apk生成命令,歡迎留言!
簽名
這里為方便,直接使用Android Studio自帶的debug簽名文件進行簽名。
6
jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android out/Test.apk androiddebugkey
安裝
經過上述步驟,就可以安裝out/目錄下生成的apk文件了。
adb install ~/Dixon-Project/test-app/out/Test.apk
可以看到這個apk文件只有12k不到。
總結
本文只是很粗淺的利用命令行生成一個簡單的apk,旨在初探apk的原理。
上述流程雖然走通了,但是在后續擴展的探索中,遇到了目前無法解決的問題:
我最初的AndroidManifest.xml是從一個項目中拷貝出來的,它設置了主題為AppTheme,其中AppTheme繼承自Theme.AppCompat.Light.DarkActionBar,它來自support-v7包。
于是問題來了,我在第一步生成R.java的時候,控制臺編譯不通過并做如下提示:
res/values/styles.xml:4: error: Error retrieving parent for item: No resource found that matches the given name 'Theme.AppCompat.Light.DarkActionBar'.
res/values/styles.xml:8: error: Error: No resource found that matches the given name: attr 'colorAccent'.
res/values/styles.xml:6: error: Error: No resource found that matches the given name: attr 'colorPrimary'.
res/values/styles.xml:7: error: Error: No resource found that matches the given name: attr 'colorPrimaryDark'.
生成R.java作為第一步,找不到資源很正常,因為此時還沒有引入support-v7包。于是我意識到生成R.java的命令行一定有引入jar包的參數。但是經過多方查詢,目前只找到一個類似的命令:
aapt package -m -J gen/ -M AndroidManifest.xml -S res/ -I ~/Library/Android/sdk/platforms/android-26/android.jar -I ~/Dixon-Project/test-app/lib/appcompat-v7-27.1.1-sources.jar
這個命令親測無效。
如果有哪位大神知道解決方案麻煩告知,不勝感激!
參考文章:
http://www.lxweimin.com/p/d2dc78eb7bd9
https://blog.csdn.net/zhangqiang_0/article/details/68068141
https://jingyan.baidu.com/album/14bd256e21b415bb6d26128b.html?picindex=2