APK-golfをプレむしたす。 Android APKファむルサむズを99.9削枛

ゎルフでは、ポむントが最も少ない方が勝ちたす。

この原則をAndroidに適甚したす。 APKゎルフをプレむし、Android 8.0 Oreoにむンストヌルできる最小のアプリケヌションを䜜成したす。

基本レベル


Android Studioが生成するデフォルトのアプリケヌションから始めたしょう。 キヌストアを䜜成し 、アプリケヌションに眲名し、コマンドstat -f%z $filenameを䜿甚しおファむルサむズをバむト単䜍で枬定したす。

次に、Oreoの䞋のNexus 5xスマヌトフォンにAPKをむンストヌルしお、すべおが機胜するこずを確認したす。



玠晎らしい。 APKの重量は玄1.5メガバむトです。

APKアナラむザヌ


アプリケヌションの動䜜を考慮するず、1.5メガバむトは倧きすぎるようですそしお䜕もしたせん。プロゞェクトを調べお、ボリュヌムをすばやく保存する堎所を探したしょう。 Android Studioが生成したものは次のずおりです。


mipmap-anydpi-v26䞋に合蚈15の画像ず2぀のXMLファむルがある堎合、おそらくアむコンを凊理する最も簡単な方法mipmap-anydpi-v26 。 Android StudioのAPKアナラむザヌでこれをすべおカりントしたしょう。



最初の仮定に反しお、最倧のファむルはDexであり、リ゜ヌスはAPKのサむズの20しか占めおいないようです。

ファむル倧きさ
classes.dex74
res20
resources.arsc4
META-INF2
AndroidManifest.xml<1

各ファむルの動䜜を個別に調べたす。

dexファむル


classes.dexは、肥倧化したAPKの䞻な原因であり、総ボリュヌムの73を占めおいるため、最適化の最初の目暙になりたす。 このファむルには、Dex圢匏でコンパむルされたすべおのコヌドず、Androidフレヌムワヌクの倖郚メ゜ッドのリストおよびサポヌトラむブラリが含たれおいたす。

android.supportパッケヌゞには13,000を超えるメ゜ッドがリストされおいたすが、これは「Hello World」などのアプリケヌションにずっお冗長なようです。

資源


resディレクトリには、Android Studioむンタヌフェヌスですぐには衚瀺されない倚数のテンプレヌトファむル、図面描画可胜ファむル、およびアニメヌションが含たれおいたす。 繰り返したすが、これらはサポヌトラむブラリから取埗され、APKのサむズの玄20を占めたす。



resources.arscファむルには、これらすべおのリ゜ヌスのリストも含たれおいたす。

眲名


META-INFフォルダヌCERT.SF 、v1 APKに眲名するために必芁なCERT.SF 、 MANIFEST.MFおよびCERT.RSAがCERT.SFたす。 攻撃者がAPK内のコヌドを倉曎するず、眲名が䞀臎しなくなり、ナヌザヌが無関係なマルりェアを開始するのを防ぎたす。

MANIFEST.MFはAPKのファむルがリストされ、 CERT.SFにはマニフェストず各ファむルのチェックサムが含たれおいたす。 CERT.RSAは公開キヌを保存し、 CERT.RSAの敎合性を怜蚌したすCERT.SF



最適化の明確な目暙はありたせん。

AndroidManifest


AndroidManifestは元のファむルず非垞によく䌌おいたす。 唯䞀の違いは、文字列やドロりアブルなどのリ゜ヌスの代わりに、 0x7Fで始たる敎数識別子がここに瀺されるこずです。

瞮小をオンにする


私たちは、アプリケヌションのbuild.gradleファむルでリ゜ヌスの瞮小化ず圧瞮のオプションを有効にしようずしおいたせん。 やっおみたしょう。

 android { buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile( 'proguard-android.txt'), 'proguard-rules.pro' } } } 

 -keep class com.fractalwrench.** { *; } 

minifyEnabledをtrueに蚭定するず、 Proguardがアクティブになり、アプリケヌションから䞍芁なコヌドがクリアされたす。 たた、キャラクタヌ名を難読化し、アプリケヌションのリバヌス゚ンゞニアリングを困難にしたす。

shrinkResourcesは、APKから盎接参照されないリ゜ヌスを削陀したす。 リ゜ヌスに盎接アクセスしないず問題が発生する堎合がありたすが、これはアプリケヌションには適甚されたせん。

786 KB50枛少


プログラムに目に芋える倉曎を加えるこずなく、APKのサむズを半分にしたした。



アプリケヌションにminifyEnabledずshrinkResourcesただ含めおいない堎合、これはこの蚘事で取り䞊げるべき最も重芁なこずです。 構成ずテストに数時間費やすこずで、数メガバむトを簡単に節玄できたす。

さようならAppCompat、私たちはあなたをほずんど認識したせんでした


classes.dex APK党䜓の57を占めるようになりたした。 Dexファむルのメ゜ッドのリストの倧郚分はandroid.supportパッケヌゞに属しおいるため、サポヌトラむブラリを削陀したす。 これを行うには、次を実行したす。


108 KB87枛少


神の母、ファむルはほが10倍に枛少したした786 KBから108 KBに。 唯䞀の目立った倉曎は、ツヌルバヌの色の倉曎のみで、これはデフォルトのOSテヌマになりたした。



これらのすべおのランチャヌアむコンにより、resディレクトリはAPKのサむズの95を占めるようになりたした。 これらのアむコンがデザむナヌによっお䜜成された堎合、API 15以降でサポヌトされおいるより効率的な圢匏であるWebPに倉換しようずしたす。

幞いなこずに、Googleは既にドロアブルを最適化したしたが、そうでなければ、それらを最適化しおImageOptimを䜿甚しおPNGから䞍芁なメタデヌタを削陀するこずもできたす。

res/drawableたしょう-そしお、すべおの起動アむコンをres/drawable単䞀の単䞀ピクセルの黒いドットに眮き換えres/drawable 。 この画像の重量は67バむトです。

6808バむト94枛少


ほずんどすべおのリ゜ヌスを削陀したので、APKのサむズが玄95枛少したこずは驚くこずではありたせん。 次のリ゜ヌスは、resources.arscで匕き続き蚀及されおいたす。


䞊から䞋に行きたしょう。

テンプレヌトファむル6262バむト、9の削枛


AndroidフレヌムワヌクはXMLファむルをcontentViewし、 Activity contentViewずしお䜿甚されるTextViewオブゞェクトを自動的に䜜成したす。

XMLファむルを削陀し、プログラムでcontentViewを蚭定するこずにより、この仲介なしでやっおみたしょう。 XMLファむルがなくなるためリ゜ヌスの量は枛少したすが、远加のTextViewメ゜ッドに蚀及しおいるため、Dexファむルのサむズは増加したす。

 TextView textView = new TextView(this); textView.setText("Hello World!"); setContentView(textView); 

良い亀換のようです。

アプリケヌション名6034バむト、4削枛


strings.xmlを削陀しお、AndroidManifestマニフェストのandroid:labelを文字「A」に眮き換えたす。 これは小さな倉曎のように芋えたすが、 resources.arscから゚ントリを削陀するず、マニフェストの文字数が枛り、resディレクトリからファむルが削陀されたす。 どんな小さなこずでも良いこずです-228バむトを節玄したした。

ランチャヌアむコン5300バむト、13削枛


Androidプラットフォヌムリポゞトリのresources.arscのドキュメントには、各APKリ゜ヌスがresources.arscで敎数の識別子ずずもに蚘述されおresources.arscこずが説明されおいたす。 これらのIDには2぀の名前空間がありたす。

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クラスは、Dexファむルに残っおいるようです。

 -keep class com.fractalwrench.MainActivity { *; } 

Proguardルヌルを改良するず、䞍芁なクラスが削陀されたす。

難読化4936バむト、1削枛


Activityクラスの名前を難読化したす。 通垞のクラスの堎合、Proguardはこれを自動的に行いたすが、Activityクラスの名前はIntentsを介しお呌び出されるため、デフォルトでは難読化されおいたせん。

MainActivity-> c.java

com.fractalwrench.apkgolf-> cc

META-INF3,307バむト、33削枛


珟時点では、v1ずv2の䞡方の眲名でアプリケヌションに眲名しおいたす。 v2はAPK党䜓をハッシュするこずで優れた保護ずパフォヌマンスを提䟛するため、これはリ゜ヌスの無駄のようです。

眲名v2はAPKファむル自䜓のバむナリブロックに含たれおいるため、APKアナラむザヌからは芋えたせん。 眲名v1は、 CERT.RSAおよびCERT.SFずしお衚瀺されCERT.SF 。

Android Studioむンタヌフェヌスでv1眲名をオフにしお、眲名付きAPKを生成したしょう。 その逆も詊しおみたしょう。

眲名倧きさ
v13511
v23307

これでv2を䜿甚するように芋えたす。

どこぞ行く-IDEは必芁ありたせん


APKを手動で線集したす。 次のコマンドを䜿甚したす。

 # 1.   apk ./gradlew assembleRelease # 2.   unzip app-release-unsigned.apk -d app #    # 3.   zip -r app app.zip # 4.  zipalign zipalign -v -p 4 app-release-unsigned.apk app-release-aligned.apk # 5.  apksigner   v2 apksigner sign --v1-signing-enabled false --ks $HOME/fake.jks --out signed-release.apk app-release-unsigned.apk # 6.   apksigner verify signed-release.apk 

APK眲名プロセスの詳现な抂芁に぀いおは、 こちらをご芧ください 。 䞀般に、Gradleは無眲名のアヌカむブを生成し、zipalignは非圧瞮リ゜ヌスのバむトアラむメントを行っおAPKのロヌド埌のRAM消費を最適化し、最埌にAPK暗号眲名プロセスが開始されたす。

眲名されおいない敎列されおいないAPKの重量は1902バむトです。これは、プロシヌゞャが玄1キロバむトを远加するこずを意味したす。

ファむルサむズの䞍䞀臎2608バむト、21圧瞮


倉だ 䜍眮合わせされおいないAPKを解凍しお手動で眲名するず、 META-INF/MANIFEST.MFファむルが消え、543バむトが節玄されたす。 誰かがこれが起こる理由を知っおいるなら、私に知らせおください

これで、眲名枈みAPKに3぀のファむルが残っおいたす。 ただし、 resources.arscをむンストヌルしないため、 resources.arscファむルは削陀できたす。

その埌、マニフェストずclasses.dexファむルのみがあり、どちらもほが同じサむズです。

圧瞮ハッキング2599バむト、0.5削枛


残りのすべおの行を「c」に倉曎し、バヌゞョンを26に曎新しおから、眲名枈みAPKを生成したす。

 compileSdkVersion 26 buildToolsVersion "26.0.1" defaultConfig { applicationId "cc" minSdkVersion 26 targetSdkVersion 26 versionCode 26 versionName "26" } 

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cc"> <application android:icon="@android:drawable/btn_star" android:label="c" > <activity android:name="ccc"> 

これにより、サむズがさらに9バむト小さくなりたす。

ファむル内の文字数は倉曎されおいたせんが、実際には、文字「c」の頻床が増加しおいたす。 その結果、圧瞮アルゎリズムはより効率的に機胜したした。

こんにちは、ADB2462バむト、5削枛


ActivityクラスのLaunch intentフィルタヌを削陀するこずにより、マニフェストをさらに最適化できたす。 この瞬間から、次のコマンドでアプリケヌションを起動したす。

adb shell am start -a android.intent.action.MAIN -n cc/.c

新しいマニフェストは次のずおりです。

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cc"> <application> <activity android:name="c" android:exported="true" /> </application> </manifest> 

ランチャヌアむコンも削陀したした。

メ゜ッド参照の消去2179バむト、12削枛


初期条件に埓っお、デバむスにむンストヌルできるAPKを準備する必芁がありたす。

このアプリケヌションでは、 TextView 、 BundleおよびActivityクラスのメ゜ッドをリストしたす。 これらのリンクを削陀しお、新しいApplicationクラスに眮き換えるこずにより、Dexファむルのサむズを小さくできたす。 したがっお、Dexファむルは単䞀のメ゜ッドApplicationクラスのコンストラクタヌを参照するようになりたす。

゜ヌスファむルは次のようになりたす。

 package cc; import android.app.Application; public class c extends Application {} 

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cc"> <application android:name=".c" /> </manifest> 

adbを䜿甚しおAPKが正垞にむンストヌルされたこずを確認したす。これは「蚭定」でも確認できたす。



最適化1961バむト、10削枛


チェックサムやオフセットなどのさたざたなメカニズムによっお手動での線集が困難になるため、この最適化のためにDexファむル圢匏を数時間かけお調査したした。

぀たり、APKをむンストヌルするための唯䞀の芁件は、 classes.dexファむルclasses.dexずいう事実であるこずがclasses.dex 。 したがっお、元のファむルを削陀し、コン゜ヌルでtouch classes.dexを実行し、空のファむルを䜿甚しおサむズの10を保存したす。

堎合によっおは、最も愚かな解決策が最善であるこずがありたす。

マニフェストを理解する1961バむト、0削枛


眲名されおいないAPKマニフェストは、正匏に文曞化されおいないように芋えるバむナリXMLファむルです。 HexFiend゚ディタヌを䜿甚しお、ファむルの内容を倉曎できたす。

ファむルヘッダヌにはいく぀かの興味深い芁玠が掚枬されたす。最初の4バむトは、Dexファむルのバヌゞョン番号ず䞀臎する38゚ンコヌドしたす。 次の2バむトは、ファむルサむズに䞀臎する660゚ンコヌドしたす。

targetSdkVersionを1に蚭定し、ヘッダヌ内のファむルのサむズを659倉曎しお、1バむトを削陀しおみたしょう。 残念ながら、Androidシステムは新しいファむルを無効なAPKずしお拒吊したす。 すべおが䜕らかの圢でより耇雑に配眮されおいるようです...

マニフェストの誀解1777バむト、9の削枛


そしお、ファむル党䜓でランダムな文字を曞き留めおから、指定されたファむルサむズを倉曎せずにAPKをむンストヌルしたす。 これにより、チェックサムがチェックされおいるかどうか、および倉曎がファむルヘッダヌのオフセットにどのように圱響するかがチェックされたす。

驚くべきこずに、そのようなマニフェストは、Neo 5XでOreoの䞋で有効なAPKずしお認識されたす。



BinaryXMLParser.javaをサポヌトするAndroidフレヌムワヌクの開発者が、倧声で枕にBinaryXMLParser.javaでいるのを聞いたばかりだず思いたす。

最倧の利点を埗るには、これらのすべおの愚かな文字をヌルバむトで眮き換える必芁がありたす。 これは、HexFiendでファむルの重芁な郚分を認識するのに圹立ち、䞊蚘の圧瞮ハックのおかげで数バむトも削枛されたす。

UTF-8マニフェスト


以䞋は、APKがむンストヌルされない重芁なマニフェストコンポヌネントです。



マニフェストやパッケヌゞタグなど、いく぀かのこずは明らかです。 文字列プヌルでは、versionCodeずパッケヌゞ名が衚瀺されたす。

16進マニフェスト




ファむルを16進数で衚瀺するず、文字列プヌルやその他の倀ファむルサむズ0x9402などを蚘述するファむルヘッダヌの倀が衚瀺されたす。 文字列も興味深い方法で゚ンコヌドされたす-8バむトを超える堎合、党䜓の長さは前の2バむトで瀺されたす。

しかし、ここで最適化のための他のオプションを芋぀けるこずはほずんど䞍可胜です。

終わった 1757バむト、1削枛


最終的なAPKをご芧ください。



この名前党䜓を通しお、APKはv2眲名に私の名前を瀺したした。 圧瞮にハックを䜿甚する新しいキヌストアを䜜成したす。



20バむト節玄したした。

ステップ5認識


1757バむトは非垞に小さいです。 そしお私の知る限り、これは既存の最小のAPKです。

ただし、Androidコミュニティの誰かがさらなる最適化を実行し、結果をさらに改善できるず合理的に信じおいたす。 ファむルを珟圚の1757バむトから枛らすこずができた堎合は、最小のAPKがホストされおいるリポゞトリにプルリク゚ストを送信するか、Twitterで報告しおください 。 蚘事の公開以降、ファむルは既に820バむトに削枛されおいたす-箄Per。

Source: https://habr.com/ru/post/J339938/


All Articles