使用 Jack for Android 6.0–8.1 編譯

Jack 是一個將 Java 源代碼編譯成 Android dex 字節碼的 Android 工具鏈。您不必做任何不同的事情來使用 Jack — 只需使用您的標準 makefile 命令來編譯樹或您的項目。 Android 8.1 是最後一個使用 Jack 的版本。

關於傑克

Jack 的工作方式如圖 1 所示。

傑克概述
圖 1. Jack 概覽

傑克庫格式

Jack 有自己的.jack文件格式,其中包含庫的預編譯 dex 代碼,允許更快的編譯(pre-dex)。

Jack 庫文件內容
圖 2. Jack 庫文件內容

吉爾

Jill 工具將現有的.jar庫轉換為新的庫格式,如下所示。

使用 Jill 導入 .jar 庫
圖 3.導入現有.jar庫的工作流程

傑克編譯服務器

第一次使用 Jack 時,它會在您的計算機上啟動本地 Jack 編譯服務器。該服務器:

  • 帶來內在的加速,因為它避免了啟動新的主機 JRE JVM、加載 Jack 代碼、初始化 Jack 以及在每次編譯時預熱 JIT。它還在小型編譯期間提供了非常好的編譯時間(例如,在增量模式下)。
  • 是控制並行 Jack 編譯數量的短期解決方案。服務器避免了計算機過載(內存或磁盤問題),因為它限制了並行編譯的數量。

Jack 服務器在沒有任何編譯的空閒時間後自行關閉。它在 localhost 接口上使用兩個 TCP 端口,並且在外部不可用。所有參數(並行編譯數、超時、端口號等)都可以通過編輯$HOME/.jack文件進行修改。

$HOME/.jack 文件

$HOME/.jack文件以完整的 bash 語法包含 Jack 服務器變量的以下設置:

  • SERVER=true啟用 Jack 的服務器功能。
  • SERVER_PORT_SERVICE=8072為編譯目的設置服務器的 TCP 端口號。
  • SERVER_PORT_ADMIN=8073設置服務器的 TCP 端口號用於管理目的。
  • SERVER_COUNT=1未使用。
  • SERVER_NB_COMPILE=4設置允許並行編譯的最大數量。
  • SERVER_TIMEOUT=60設置服務器在關閉之前必須等待的空閒秒數,無需任何編譯。
  • SERVER_LOG=${SERVER_LOG:=$SERVER_DIR/jack-$SERVER_PORT_SERVICE.log}設置寫入服務器日誌的文件。默認情況下,這個變量可以被環境變量重載。
  • JACK_VM_COMMAND=${JACK_VM_COMMAND:=java}設置用於在主機上啟動 JVM 的默認命令。默認情況下,這個變量可以被環境變量重載。

Jack 編譯故障排除

問題行動
您的計算機在編譯期間變得無響應,或者您遇到 Jack 編譯因內存不足錯誤而失敗通過編輯$HOME/.jack並將SERVER_NB_COMPILE更改為較低的值來減少同時進行 Jack 編譯的數量。
編譯失敗無法啟動後台服務器最可能的原因是您的計算機上已使用 TCP 端口。通過編輯$HOME/.jackSERVER_PORT_SERVICESERVER_PORT_ADMIN變量)更改端口。要解除阻塞,請通過編輯$HOME/.jack並將SERVER更改為false來禁用 Jack 編譯服務器。不幸的是,這會顯著減慢您的編譯速度,並可能迫使您使用負載控制啟動make -j (選項-lmake )。
編譯卡住沒有任何進展要解除阻塞,請使用jack-admin kill-server殺死 Jack 後台服務器,然後刪除臨時目錄的jack-$USER中包含的臨時目錄( /tmp$TMPDIR )。

尋找傑克日誌

如果您使用 dist 目標運行make命令,則 Jack 日誌位於$ANDROID_BUILD_TOP/out/dist/logs/jack-server.log 。否則,您可以通過運行jack-admin server-log找到日誌。如果出現可重現的 Jack 故障,您可以通過設置以下變量來獲取更詳細的日誌:

export ANDROID_JACK_EXTRA_ARGS="--verbose debug --sanity-checks on -D sched.runner=single-threaded"

使用標準 makefile 命令編譯樹(或您的項目)並附加標準輸出和錯誤。要刪除詳細的構建日誌,請運行:

unset ANDROID_JACK_EXTRA_ARGS

插孔限制

  • 默認情況下,Jack 服務器只能由計算機上的一個用戶使用。要支持其他用戶,請為每個用戶選擇不同的端口號並相應地調整SERVER_NB_COMPILE 。您還可以通過在$HOME/.jack中設置SERVER=false來禁用 Jack 服務器。
  • 由於當前vm-tests-tf集成,CTS 編譯速度很慢。
  • 不支持字節碼操作工具(例如 JaCoCo)。

使用傑克

Jack 支持 Java 編程語言 1.7 並集成了以下描述的附加功能。

預索引

生成 Jack 庫文件時,會生成庫的.dex並將其作為 pre-dex 存儲在.jack庫文件中。編譯時,Jack 重用每個庫中的 pre-dex。所有庫都是預先索引的。

帶有 pre-dex 的 Jack 庫
圖 4.帶有 pre-dex 的 Jack 庫

如果在編譯中使用了壓縮、混淆或重新打包,Jack 不會重用庫 pre-dex。

增量編譯

增量編譯意味著僅重新編譯自上次編譯以來涉及的組件(及其依賴項)。當更改僅限於一組組件時,增量編譯可能比完整編譯快得多。

默認情況下禁用增量編譯(啟用收縮、混淆、重新打包或多 dex 遺留時會自動停用)。要啟用增量構建,請將以下行添加到要增量構建的項目的Android.mk文件中:

LOCAL_JACK_ENABLED := incremental

收縮和混淆

Jack 使用 ProGuard 配置文件來啟用收縮和混淆。

常見的選項包括:

  • @
  • -include
  • -basedirectory
  • -injars
  • -outjars (僅支持 1 個輸出 jar)
  • -libraryjars
  • -keep
  • -keepclassmembers
  • -keepclasseswithmembers
  • -keepnames
  • -keepclassmembernames
  • -keepclasseswithmembernames
  • -printseeds

收縮選項包括:

  • -dontshrink

混淆選項包括以下內容:

  • -dontobfuscate
  • -printmapping
  • -applymapping
  • -obfuscationdictionary
  • -classobfuscationdictionary
  • -packageobfuscationdictionary
  • -useuniqueclassmembernames
  • -dontusemixedcaseclassnames
  • -keeppackagenames
  • -flattenpackagehierarchy
  • -repackageclasses
  • -keepattributes
  • -adaptclassstrings

忽略的選項包括:

  • -dontoptimize (Jack 不優化)
  • -dontpreverify (傑克不預先驗證)
  • -skipnonpubliclibraryclasses
  • -dontskipnonpubliclibraryclasses
  • -dontskipnonpubliclibraryclassmembers
  • -keepdirectories
  • -target
  • -forceprocessing
  • -printusage
  • -whyareyoukeeping
  • -optimizations
  • -optimizationpasses
  • -assumenosideeffects
  • -allowaccessmodification
  • -mergeinterfacesaggressively
  • -overloadaggressively
  • -microedition
  • -verbose
  • -dontnote
  • -dontwarn
  • -ignorewarnings
  • -printconfiguration
  • -dump

重新包裝

Jack 使用 jarjar 配置文件進行重新打包。雖然 Jack 與“rule”規則類型兼容,但它與“zap”或“keep”規則類型不兼容。

多索引支持

Jack 提供原生和傳統的 multidex 支持。由於 dex 文件限制為 65K 方法,因此方法超過 65K 的應用必須拆分為多個 dex 文件。有關更多詳細信息,請參閱為具有超過 64K 方法的應用啟用 multidex