Stark Wong 的個人開發網站
 


 此頁面:更新於 2019 年 5 月 2 日 12 時 04 分 09 秒,頁面處理需時 0.0008 秒
 網站內容版權所有(C)Stark Wong。頁面(不包括檔案)可自由連結。網站系統版本 1.90-AngularJSBase (2015/9/27)
 
網站地圖

Notice: Undefined variable: row in /var/www/html/blog.inc.php on line 22
有關 APK 使用 Apktool 重建後無法在 Android 11 或以上的裝置

我在之前修改 APK 用 Apktool 重建後曾經試過安裝在 Android 11 或以上裝置會失敗,但由於再重建後問題又消失了,讓我以為是由於我用的 Apktool 版本問題所導致,誰知道今天又再次遇到同一個問題。

症狀

APK 在重建時不會遇到任何問題,但當使用 adb install 安裝時則會顯示如下的錯誤:

Performing Streamed Install
adb: failed to install xxx.apk: Failure [-124: Failed parse during installPackageLI: Targeting R+ (version 30 and above) requires the resources.arsc of installed APKs to be stored uncompressed and aligned on a 4-byte boundary]

其實這個問題在官方 issue tracker 裡也有報告 (https://github.com/iBotPeaches/Apktool/issues/2421),然而問題直到最新的 Apktool 2.6.0 仍然沒有解決。

原因及解決方法

從錯誤訊息中看到,目標為 Android 11 的 APK 中的 resources.arsc 檔案必須符合 2 個條件:

  1. 檔案必須沒有進行壓縮
  2. 檔案必須對齊到4位元組的邊界

將重建後的 APK 用壓縮程式開啟,可以看到 resources.arsc 的壓縮前後大小是相同的,也就是沒有進行過壓縮。至於要驗證4位元組邊界,我們可以使用 zipalign 工具,輸入 zipalign.exe -c -v 4 xxx.apk | find "resources.arsc" 的結果如下:

25786697 resources.arsc (BAD - 1)

果然 Apktool 並沒有正確地將 resources.arsc 對齊到 4 位元組的邊界。要解決這個問題,我們也可以使用 zipalign 工具 (zipalign.exe -p -f -v 4 input.apk output.apk) 將 APK 裡的檔案重新對齊一次,然後對輸出檔案再次驗證後的結果如下:

25787768 resources.arsc (OK)

確認過後,再將 APK 重新進行數位簽名後就再不會安裝失敗了 (注意數位簽名必須使用 Android Build Tools 裡的 apksigner,不能再使用 jarsigner)。

為什麼要對齊邊界?

大部份作業系統都支援將檔案直接對應成虛擬的記憶體區域 (*nix / Android 稱為 mmap,Windows 稱為 File Mapping),這樣的話就可以直接將檔案的區域指定到 C Struct、陣列等直接使用而不需要先分配記憶體,再將檔案中所需部份複製到記憶體後才能使用。然而系統本身的記憶體管理會有邊界要求,以進行優化及允許偵測問題,所以進行記憶體影射時也有同樣要求。

為什麼不能壓縮?

由於 resources.arsc 本身是一個二進制檔案,你可以把它看成是一個封裝檔或壓縮檔,檔案裡面除了有各被封裝檔案的內容外,也有列出封裝檔案的索引,而這索引有特定格式及位置,當使用 mmap 時就可以像記憶體般直接進行存取。如果將這個檔案壓縮過,索引就會成為被壓縮內容的一部份,也就是說除非先將索引解壓縮,否則無法直接進行存取。


撰寫於:2021/11/26 22:08:01 / 回應已關閉
正在讀取回響內容...
其他內容請回到主頁