命令行編譯生成APK

本文將介紹如何在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不到。

截圖.png

總結

本文只是很粗淺的利用命令行生成一個簡單的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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374