減少Android APK的大小99.99%
我們將這一原則應用於Android。建立可以安裝在執行Oreo的裝置上的最小的應用程式。
測量基線
我們將開始使用Android Studio生成的預設應用。我們,簽署應用程式,並使用位元組來測量檔案大小stat -f%z $filename
。
我們還將在執行Oreo的Nexus 5x上安裝APK,以確保一切正常。
美麗。我們的APK重量約為1.5Mb。
APK分析儀
1.5Mb似乎很多考慮到我們的應用程式,所以讓我們探索這個專案,並尋找任何快速的勝利。Android Studio已經生成:
A
MainActivity
,延伸AppCompatActivity
。具有
ConstraintLayout
根檢視的佈局檔案。包含三種顏色的值檔案,一個字串資源和一個主題。
該
AppCompat
和ConstraintLayout
支援庫。一
AndroidManifest.xml
方形,圓形和前景啟動器圖示PNG。
圖示看起來像最簡單的目標,因為總共有15張圖片,下面有2個XML檔案mipmap-anydpi-v26
。我們來量化使用Android Studio的。
與我們的初始假設相反,似乎我們的Dex檔案是最大的,資源僅佔APK大小的20%。
檔案 | 尺寸 |
---|---|
classes.dex |
74% |
res |
20% |
resources.arsc |
4% |
META-INF |
2% |
AndroidManifest.xml |
我們來分析一下每個檔案的作用。
Dex檔案
classes.dex
是73%的最大罪魁禍首,因此是我們的第一個目標。此檔案包含所有編譯程式碼,並且還引用了Android框架和支援庫中的外部方法。
該android.support
軟體包引用了超過13,000種方法,對於Hello World應用程式來說,這似乎過多了。
資源
我們的res目錄有大量的佈局檔案,可繪製和動畫,在Android Studio的UI中不會立即顯示。再次,這些已經從支援庫中拉入,並且佔據了APK大小的大約20%。
該resources.arsc
檔案還包含對這些資源中的每一個的引用。
簽名
該META-INF
資料夾包含CERT.SF
,,MANIFEST.MF
和CERT.RSA
檔案,這是所必需的。如果攻擊者修改了我們的APK中的程式碼,則簽名將不匹配,這意味著使用者將被儲存以執行第三方惡意軟體。
MANIFEST.MF
列出APK中的檔案,而CERT.SF
包含清單的摘要,以及每個檔案的單個摘要。CERT.RSA
包含用於驗證其完整性的公鑰CERT.SF
。
這裡沒有明顯的目標。
AndroidManifest
AndroidManifest看起來與我們原始的輸入檔案非常相似。唯一的例外是字串和可繪製的資源已經被替換為整數資源ID,從頭開始0x7F
。
啟用分類
我們還沒有嘗試在我們的應用程式build.gradle
檔案中實現小型化和資源縮減。讓我們一起去吧
android { buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile( 'proguard-android.txt'), 'proguard-rules.pro' } }}
-keep class com.fractalwrench.** { *; }
設定minifyEnabled
為true可以使從我們的應用程式中未使用的程式碼。它也模糊符號名稱,使得更難以逆向工程的應用程式。
shrinkResources
將從我們的APK中刪除任何不直接引用的資源。如果您使用反射來間接訪問資源,這可能會導致問題,但這不適用於我們的應用程式。
786 Kb(減少50%)
我們將APK大小減少一半,對我們的應用程式沒有明顯的影響。如果您還沒有啟用minifyEnabled
和shrinkResources
在您的應用程式中,這是您應該從這篇文章中刪除的最重要的一件事。您可以輕鬆地節省幾兆位元組的空間,只需幾個小時的配置和測試。
AppCompat,我們幾乎不知道你們
classes.dex
現在佔用了APK的57%。我們的Dex檔案中的大多數方法引用屬於該android.support
包,因此我們將刪除該支援庫。為此,我們將:
從我們
build.gradle
完全刪除依賴關係塊
dependencies { implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.0.2'}
更新MainActivity擴充套件
android.app.Activity
public class MainActivity extends Activity
更新我們的佈局使用一個
TextView
。
從元素中刪除
styles.xml
並刪除該android:theme
屬性,這是API 15及更高版本支援的更有效的檔案格式。
幸運的是,Google已經最佳化了我們的繪圖,儘管如果不是這樣,也可以最佳化並從PNG中刪除不必要的後設資料。
讓我們成為一個不好的公民,並用一個1畫素的黑點替換所有的發射圖示,放在不合格的
res/drawable
資料夾中。該影像重67頁。6808位元組(減少94%)
我們已經擺脫了我們幾乎所有的資源,所以我們看到我們的APK大小減少了95%,這並不奇怪。以下專案仍然參考
resources.arsc
:1個佈局檔案
1字串資源
1啟動器圖示
我們從頂部開始吧。
佈局檔案(6262位元組,減少9%)
Android框架將,並自動建立一個
TextView
物件設定為contentView
的Activity
。我們可以嘗試透過刪除XML檔案來跳過中間人,並以程式設計方式設定contentView。我們的資源大小會減少,因為XML檔案少一些,但是我們的Dex檔案會增加,因為我們將引用其他
TextView
方法。TextView textView = new TextView(this);textView.setText("Hello World!");setContentView(textView);
看起來我們的權衡已經有效了,我們下降到5710位元組。
應用名稱(6034位元組,減少4%)
我們刪除
strings.xml
,並android:label
在AndroidManifest 替換為“A”。這可能看起來像是一個小小的變化,但刪除一個條目resources.arsc
,減少清單中的字元數,並從res目錄中刪除一個檔案。每一點幫助 - 我們剛剛儲存了228個位元組。啟動器圖示(5300位元組,減少13%)
該在Android平臺庫告訴我們,在APK每個資源被引用的
resources.arsc
一個整數ID。這些ID有兩個名稱空間:0x01:系統資源(預安裝在framework-res.apk中)
0x7f:應用程式資源(捆綁在應用程式中.apk)
那麼如果我們引用0x01名稱空間中的資源,我們的APK會發生什麼?我們應該能夠獲得更好的圖示,同時減少我們的檔案大小。
android:icon="@android:drawable/btn_star"
不用說,但是您不應該在生產應用程式中相信系統資源。這一步將失敗Google Play驗證,並且考慮到某些製造商已經知道重新定義,請謹慎行事。
清單(5252位元組,減少1%)
我們還沒有觸及清單。
android:allowBackup="true"android:supportsRtl="true"
刪除這些屬性可以節省48個位元組。
保衛駭客(4984位元組,減少5%)
它看起來像
BuildConfig
和R
仍然包括在塞米松檔案。-keep class com.fractalwrench.MainActivity { *; }
最佳化我們的Proguard規則將剝離這些類。
混淆(4936位元組,減少1%)
讓我們的Activity成為一個混淆的名字。Proguard自動為常規類執行此操作,但是由於可以透過Intents呼叫Activity類名稱,因此預設情況下不會進行混淆。
MainActivity - > c.java
com.fractalwrench.apkgolf - > cc
META-INF(3307位元組,減少33%)
目前,我們正在使用v1和v2簽名簽署我們的應用程式。這似乎是浪費的,特別是透過雜湊整個APK,v2提供。
我們的v2簽名在APK分析器中不可見,因為它在APK檔案本身中被包含為二進位制塊。我們的v1簽名是可見的,
CERT.RSA
以及CERT.SF
檔案的形式。讓我們取消選中Android Studio介面中的v1簽名核取方塊,並生成一個已簽名的APK。我們也會嘗試相反的做法。
簽名 尺寸 V1 3511 V2 3307 看來我們現在將使用v2。
我們要去哪裡,我們不需要IDE
現在是手動編輯我們的APK了。我們將使用以下命令:
# 1. Create an unsigned apk./gradlew assembleRelease# 2. Unzip archiveunzip app-release-unsigned.apk -d app# Do any edits# 3. Zip archivezip -r app app.zip# 4. Run zipalignzipalign -v -p 4 app-release-unsigned.apk app-release-aligned.apk# 5. Run apksigner with v2 signatureapksigner sign --v1-signing-enabled false --ks $HOME/fake.jks --out signed-release.apk app-release-unsigned.apk# 6. Verify signatureapksigner verify signed-release.apk
可以在找到APK簽名的詳細概述。總而言之,gradle生成一個無符號歸檔,zipalign更改未壓縮資源的位元組對齊方式,以便在APK載入時提高RAM使用率,最後,APK被加密地簽名。
我們的未簽名和未對齊的APK重量在1902位元組,這表明這個過程增加了大約1Kb。
檔案大小差異(2608位元組,減少21%)
奇怪的!解壓縮未對齊的APK並手動刪除
META-INF/MANIFEST.MF
,儲存我們543位元組。如果有人知道為什麼會這樣,請聯絡!我們現在已經在我們簽名的APK中下載了3個檔案。但是,我們也可以擺脫
resources.arsc
,因為我們沒有定義任何資源!這使我們有清單和
classes.dex
檔案,每個檔案大小相同。壓縮駭客(2599位元組,減少0.5%)
我們將所有剩餘的字串更改為“c”,將我們的版本更新為26,然後生成一個已簽名的APK。
compileSdkVersion 26 buildToolsVersion "26.0.1" defaultConfig { applicationId "c.c" minSdkVersion 26 targetSdkVersion 26 versionCode 26 versionName "26" }
進行此最佳化,因為諸如校驗和和偏移之類的各種機制使人工編輯變得更加困難。 然而,為了縮短長篇小說,事實證明,APK安裝的唯一要求是
classes.dex
檔案必須存在。因此,我們只需刪除原始檔案,touch classes.dex
在終端中執行,並使用空檔案減少10%。有時最愚蠢的解決方案是最好的。
瞭解清單(1961位元組,減少0%)
我們的未簽名APK的清單是二進位制XML格式,似乎沒有正式記錄。我們可以使用編輯器來操作檔案內容。
我們可以猜到檔案頭中的幾個有趣的專案 - 前四個位元組的編碼
38
,這是與Dex檔案相同的版本號。接下來的兩個位元組編碼660
,這是檔案大小的方便。我們嘗試透過將targetSdkVersion設定為
1
,並將檔案大小標題更新為一個位元組659
。不幸的是,Android系統拒絕將其視為無效的APK,所以看起來這裡有一些額外的複雜性。不瞭解清單(1777位元組,減少9%)
我們在整個檔案中輸入啞字元,然後嘗試安裝APK,而不更改檔案大小。這將確定是否存在校驗和,或者如果我們的更改使檔案頭中的偏移值無效。
令人驚訝的是,以下清單被解釋為執行Oreo的Nexus 5X上的有效APK:我想我可以聽到Android框架工程師負責保持
BinaryXMLParser.java
尖叫聲大聲地進入枕頭。為了最大化我們的收益,我們將用空位元組替換這些虛擬字元。這將使您可以更輕鬆地檢視HexFiend中檔案的重要部分,並從先前的壓縮駭客中獲取位元組數。
UTF-8清單
這些是清單的基本元件,沒有這些元件,APK無法安裝。一些事情很明顯 - 比如清單和包標籤。versionCode和包名也可以在字串池中找到。
十六進位制顯示
以十六進位制檢視檔案顯示檔案頭中描述字串池和其他值(如檔案大小)的值
0x9402
。字串也有一個有趣的編碼 - 如果它們超過8個位元組,它們的總長度在前面的2個位元組中指定。然而,這看起來並不像在這裡有更多的收穫。
完成了嗎?(1757位元組,減少1%)
我們來檢查一下最終的APK。畢竟這一次,我透過v2簽名將我的名字留在了APK中。讓我們建立一個利用壓縮駭客的新金鑰庫。
這節省了我們20個位元組。
階段5:驗收
1757
位元組很小,據我所知,這是存在的最小的APK。不過,我有信心在Android社群的某個人進行進一步的最佳化,這將會打敗我的分數。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1343/viewspace-2813428/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 減小APK大小APK
- [譯] Android效能最佳實踐:減少您的APK大小看這一篇就夠了AndroidAPK
- [譯] 怎樣減少 Android 應用包 60% 的大小?Android
- 【譯】如何使用webpack減少vuejs打包的大小WebVueJS
- MySQL 減少InnoDB系統表空間的大小MySql
- 如何在Mac上減少PDF檔案大小Mac
- Docker的`COPY --chmod`可將映象檔案大小減少35%Docker
- 10 個最佳化技巧,減少 Docker 映象大小【轉】Docker
- 【Android APK】解析SD卡上的APK檔案AndroidAPKSD卡
- [譯]Web 效能優化: 圖片優化讓網站大小減少 62%Web優化網站
- Android APK打包流程AndroidAPK
- Android之Apk加殼AndroidAPK
- Android空包Apk簽名AndroidAPK
- Flutter 打包 android端 apkFlutterAndroidAPK
- Flutter Notes|Flutter-Apk 大小優化探索FlutterAPK優化
- Android Apk反編譯系列教程(二)APK重打包AndroidAPK編譯
- 減少該死的 if else 巢狀巢狀
- Android低版本上APP首次啟動時間減少80%(二)AndroidAPP
- Android之重新簽名APKAndroidAPK
- Android Studio打包專案:APKAndroidAPK
- Gluon 編譯 JavaFx -> android apk編譯JavaAndroidAPK
- 簽名打包Android版apkAndroidAPK
- APK瘦身屬性——android:extractNativeLibsAPKAndroid
- 如何減少攻擊面
- laravel欄位減少增加Laravel
- Android studio 自動複製生成的 apkAndroidAPK
- [譯] 減少 Python 中迴圈的使用Python
- tcp減少2msl的時間TCP
- python爬蟲如何減少ip的限制Python爬蟲
- Android Apk反編譯系列教程(一)如何反編譯APKAndroidAPK編譯
- Android解決The APK file app-debug.apk does not exist on disk.AndroidAPKAPP
- Android Studio打包apk,aar,jar包AndroidAPKJAR
- Android studio匯出apk檔案AndroidAPK
- face 31減少http請求HTTP
- 如何減少 Hyperf 框架的掃描時間框架
- 前端頁面優化,減少 reflow 的方法前端優化
- CTR:2021年1月廣告市場花費同比減少2.0%,環比減少9.5%
- android 反編譯APK取原始碼。Android編譯APK原始碼