1、APK 的組成
我們都知道,APK 其實是一個 zip 類型的壓縮包,而一個典型的 APK 通常都會包含了以下七部分的內(nèi)容:
我們都知道,APK 其實是一個 zip 類型的壓縮包,而一個典型的 APK 通常都會包含了以下七部分的內(nèi)容:
1、AndroidManifest.xml:如果 App 是一本書,那么這個文件就是它的 “封面” 和 “目錄” 。它記載了 App 的名稱、權(quán)限聲明、所包含的組件等一系列信息。
2、classes.dex:它是由項目源碼生成的 .class 文件經(jīng)過進一步地轉(zhuǎn)換而生成的 Android 系統(tǒng)可識別的 Dalvik Byte Code。并且,由于 Android 系統(tǒng)中的字節(jié)碼和標(biāo)準(zhǔn) JVM 中的字節(jié)碼是有區(qū)別的,所以如果 App 中引用了第三方 jar 包的話,那么通常情況下它也會被包含在 classes.dex 中。
3、resources.arsc:資源索引表,包含編譯后的二進制資源文件。每當(dāng)在 res 文件夾下放一個文件時,aapt 就會自動生成對應(yīng)的 id 并保存在 .R 文件中,但 .R 文件僅僅只是保證編譯程序不會報錯,實際上在應(yīng)用運行時,系統(tǒng)會根據(jù) ID 尋找對應(yīng)的資源路徑,而 resources.arsc 文件就是用來記錄這些 ID 和 資源文件位置對應(yīng)關(guān)系 的文件。
4、res 目錄:未編譯的資源文件。
5、asserts:額外建立的資源文件夾。res 和 assets 的不同在于 res 目錄下的文件會在 .R 文件中生成對應(yīng)的資源 ID,而 assets 不會自動生成對應(yīng)的 ID,而是通過 AssetManager 類的接口來獲取。
6、libs 目錄:如果存在的話,存放的是 ndk 編出來的 so 庫 。
-
7、META-INF 目錄:用于保存 App 的簽名和校驗信息,以保證程序的完整性。當(dāng)生成 APK 包時,系統(tǒng)會對包中的所有內(nèi)容做一次校驗,然后將結(jié)果保存在這里。而手機在安裝這一 App 時還會對內(nèi)容再做一次校驗,并和 META-INF 中的值進行比較,以避免 APK 被惡意篡改。其中包含如下 三個文件,如下所示:
- 1)、MANIFEST.MF:其中每一個資源文件都有一個對應(yīng)的 SHA-256-Digest(SHA1) 簽名,MANIFEST.MF 文件的 SHA256(SHA1) 經(jīng)過 base64 編碼的結(jié)果即為 CERT.SF 中的 SHA256(SHA1)-Digest-Manifest 值。
- 2)、CERT.SF:除了開頭處定義的 SHA256(SHA1)-Digest-Manifest 值,后面幾項的值是對 MANIFEST.MF 文件中的每項再次 SHA256(SHA1) 經(jīng)過 base64 編碼后的值。
- 3)、CERT.RSA:其中包含了公鑰、加密算法等信息。首先,對前一步生成的 CERT.SF 使用了 SHA256(SHA1)生成了數(shù)字摘要并使用了 RSA 加密,接著,利用了開發(fā)者私鑰進行簽名。然后,在安裝時使用公鑰解密。最后,將其與未加密的摘要信息(MANIFEST.MF文件)進行對比,如果相符,則表明內(nèi)容沒有被修改。
Gradle Task
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:compileDebugAidl NO-SOURCE
> Task :app:compileDebugRenderscript NO-SOURCE
> Task :app:generateDebugBuildConfig UP-TO-DATE
> Task :app:javaPreCompileDebug UP-TO-DATE
> Task :app:checkDebugAarMetadata UP-TO-DATE
> Task :app:generateDebugResValues UP-TO-DATE
> Task :app:generateDebugResources UP-TO-DATE
> Task :app:mergeDebugResources UP-TO-DATE
> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
> Task :app:extractDeepLinksDebug UP-TO-DATE
> Task :app:processDebugMainManifest UP-TO-DATE
> Task :app:processDebugManifest UP-TO-DATE
> Task :app:processDebugManifestForPackage UP-TO-DATE
> Task :app:processDebugResources UP-TO-DATE
> Task :app:compileDebugJavaWithJavac UP-TO-DATE
> Task :app:mergeDebugShaders UP-TO-DATE
> Task :app:compileDebugShaders NO-SOURCE
> Task :app:generateDebugAssets UP-TO-DATE
> Task :app:mergeDebugAssets UP-TO-DATE
> Task :app:compressDebugAssets UP-TO-DATE
> Task :app:processDebugJavaRes NO-SOURCE
> Task :app:mergeDebugJavaResource UP-TO-DATE
> Task :app:checkDebugDuplicateClasses UP-TO-DATE
> Task :app:desugarDebugFileDependencies UP-TO-DATE
> Task :app:mergeExtDexDebug UP-TO-DATE
> Task :app:mergeLibDexDebug UP-TO-DATE
> Task :app:dexBuilderDebug UP-TO-DATE
> Task :app:mergeProjectDexDebug UP-TO-DATE
> Task :app:mergeDebugJniLibFolders UP-TO-DATE
> Task :app:mergeDebugNativeLibs UP-TO-DATE
> Task :app:stripDebugDebugSymbols NO-SOURCE
> Task :app:validateSigningDebug UP-TO-DATE
> Task :app:packageDebug UP-TO-DATE
> Task :app:installDebug
//aidl 轉(zhuǎn)換aidl文件為java文件
> Task :app:compileDebugAidl
//生成BuildConfig文件
> Task :app:generateDebugBuildConfig
//獲取gradle中配置的資源文件
> Task :app:generateDebugResValues
// merge資源文件
> Task :app:mergeDebugResources
// merge assets文件
> Task :app:mergeDebugAssets
> Task :app:compressDebugAssets
// merge所有的manifest文件
> Task :app:processDebugManifest
//AAPT 生成R文件
> Task :app:processDebugResources
//編譯kotlin文件
> Task :app:compileDebugKotlin
//javac 編譯java文件
> Task :app:compileDebugJavaWithJavac
//轉(zhuǎn)換class文件為dex文件
> Task :app:dexBuilderDebug
//打包成apk并簽名
> Task :app:packageDebug
生成BuildConfig文件,資源文件
在引入Gradle編譯工具之后,Apk的打包流程就多了這么一步,生成BuildConfig文件和資源文件。
也就是會根據(jù)build.gradle里面配置的內(nèi)容生成相應(yīng)的java代碼或者res代碼。簡單舉個例子:
//build.gradle
buildTypes {
debug{
buildConfigField("boolean", "ISDEBUG", "true")
resValue "string", "TestName", "love1"
}
release {
buildConfigField("boolean", "ISDEBUG", "false")
resValue "string", "TestName", "love2"
}
}
//BuildConfig.java
public final class BuildConfig {
// Field from build type: debug
public static final boolean ISDEBUG = true;
}
R.string.TestName
merge 資源文件
這一步就是合并res資源文件,assets文件,manifest文件。
因為在項目中會依賴不同的庫、組件,也會有多渠道的需求,所以merge這一步操作就是將不同地方的資源文件進行整合。
多個manifest文件需要整理成一個完整的文件,所以如果有屬性沖突這一步就會報錯。資源文件也會整理分類到不同的分辨率目錄中。
AAPT/AAPT2(打包資源文件)
2、APK 的編譯打包流程

打包流程可簡述為如下 八個步驟:
處理.aidl file
1、首先,.aidl(Android Interface Description Language)文件需要通過 aidl 工具轉(zhuǎn)換成編譯器能夠處理的 Java 接口文件。
打包資源文件AAPT
AAPT,全稱Android Asset Packaging Tool,所以這個構(gòu)建工具就是用來打包資源文件的。
資源文件包括:圖片,res目錄下的xml文件,AndroidManifest.xml文件;
處理資源文件主要包括兩步
1、編譯:將資源文件編譯為二進制格式。
把所有的Android資源文件進行解析,生成擴展名為.flat的二進制文件。比如是png圖片,那么就會被壓縮處理,采用.png.flat的擴展名。2、鏈接:合并所有已編譯的文件并打包到一個軟件包中。
首先,這一步會生成輔助文件,比如R.java(R文件),R文件大家應(yīng)該都比較熟悉,就是一個資源索引文件,我們平時引用也都是通過R.的方式引用資源id。
最后,會將R文件和之前的二進制文件進行打包,打包到一個APK壓縮包(沒有dex文件、沒有簽名)。
2、同時,資源文件(包括 AndroidManifest.xml、布局文件、各種 xml 資源等等)將被 AAPT(Asset Packaging Tool)(Android Gradle Plugin 3.0.0 及之后使用 AAPT2 替代了 AAPT)處理為最終的 resources.arsc,并生成 R.java 文件以保證源碼編寫時可以方便地訪問到這些資源。
Android Gradle插件 3.0.0 及更高版本默認(rèn)情況下會啟用 AAPT2,而老版本的AAPT已經(jīng)被棄用,那么AAPT2到底優(yōu)化改進了什么呢?
- 1、鏈接過程優(yōu)化
在AAPT中是沒有鏈接功能的,會將所有的資源進行編譯生成壓縮包。這樣處理方式有個缺點就是每次編譯都要全量編譯。
所以在AAPT2中用到鏈接的功能,當(dāng)修改了某個資源文件之后,只需要重新編譯這個改變的文件,然后與其他資源進行鏈接即可,支持了增量更新,大大提升了效率。
- 2、行為變化
對一些行為進行了優(yōu)化,一些錯誤的元素以前不會報錯,只會警告或者忽略,現(xiàn)在會直接報錯,保證程序正確運行。比如
1)、在以前的AAPT版本,Android 清單文件中出現(xiàn)錯誤的節(jié)點元素只會被忽略或警告,而AAPT2開始會對這些節(jié)點進行報錯,比如:
<activity android:name=".MainActivity">
<action android:name="android.intent.action.TEST" />
</activity>
AndroidManifest.xml:15: error: unknown element <action> found.
2)、在AAPT2中,無法通過name屬性指明資源類型了,需要單獨使用type屬性:
<item name="attr/my_attr">@color/pink</item>
// 修改為
<item type="attr" name="my_attr">@color/pink</item>
3)、ForegroundLinearLayout(前景色相關(guān))屬性限制嚴(yán)格
foregroundInsidePadding屬性,不屬于android命名空間,所以AAPT2的改進就是對于這個屬性使用更加嚴(yán)格了,原來使用android:foregroundInsidePadding的時候會被忽略,現(xiàn)在會報錯,需要改為foregroundInsidePadding。
4)、@ 資源引用符號使用嚴(yán)格
對于遺漏或者錯誤引用@(資源引用符號)時候,AAPT2會報錯。
5)、庫配置不正確
當(dāng)某些庫創(chuàng)建過程中R文件字段聲明為final會導(dǎo)致報錯,AAPT2就會對這種情況進行優(yōu)化。
編譯Compiler javac(編譯java文件)
3、然后,通過 Java Compiler 編譯 R.java、Java 接口文件、Java 源文件,最終它們會統(tǒng)一被編譯成 .class 文件。
接下來就是編譯java文件了,用到的工具就是大家熟知的javac,通過它將java文件編譯成.class文件。
注解代碼也是在這個階段生成的。當(dāng)注解的生命周期被設(shè)置為CLASS的時候,就代表該注解會在編譯class文件的時候生效,并且存在與java源文件和Class字節(jié)碼文件。
javac的基礎(chǔ)命令還是可以了解下:
javac -d destdir(class文件存放目錄) srcFile(java文件)
生成dex文件 dx/r8/d8 (編譯class文件)
4、因為 .class 并不是 Android 系統(tǒng)所能識別的格式,所以還需要通過 dex 工具將它們轉(zhuǎn)化為相應(yīng)的 Dalvik 字節(jié)碼(包含壓縮常量池以及清除冗余信息等工作)。這個過程中還會加入應(yīng)用所依賴的所有 “第三方庫”
再談?wù)勥@三個工具(dx/r8/d8)的區(qū)別:
- dx是最早的轉(zhuǎn)換工具,用于轉(zhuǎn)換class文件為dex文件。
- Android Studio 3.1之后,引入了D8編譯器和 R8 工具。
注意這里的措辭:D8 編譯器和 R8 工具。
所以D8就是用來代替dx用來進行轉(zhuǎn)換class文件的,它的優(yōu)勢在于:編譯更快、更小的dex文件、更好的性能。
而R8工具是用來替代ProGuard的,用于代碼的壓縮和混淆。
編譯class文件過程也常用于編譯插樁,比如ASM,通過直接操作字節(jié)碼文件完成代碼修改或生成。
apkbuilder/zipflinger(生成APK包)
5、這一步就是生成APK文件,將manifest文件、resources文件、dex文件、assets文件等等打包成一個壓縮包,也就是apk文件。
在老版本使用的工具是apkbuilder,但是在最新的版本我發(fā)現(xiàn)沒有這個工具了,sdk目錄下也找不到了。
所以我想到從打包的task——packageDebug中找找答案,果然,讓我找到了新的打包工具——zipflinger。
//PackageAndroidArtifact.java (packageDebug相關(guān)代碼)
for (File arch : archives) {
mApkCreator.writeZip(arch, pathNameMap::get, name -> !names.contains(name));
}
mApkCreator =new ApkFlinger(mCreationData, compressionLevel, !mIsDebuggableBuild);
/** An implementation of [ApkCreator] using the zipflinger library */
class ApkFlinger
jarsigner/apksigner(簽名)
在生成APK文件之后,必須對該apk文件進行簽名,否則無法被安裝。
之前大家比較熟知的簽名工具是JDK提供的jarsigner,而apksigner是Google專門為Android提供的簽名和簽證工具。
其區(qū)別就在于jarsigner只能進行v1簽名,而apksigner可以進行v2、v3、v4簽名。
7、然后,通過簽名工具 Jarsigner 或者其它簽名工具對 APK 進行簽名得到簽名后的 APK。如果是在 Debug 模式下,簽名所用的 keystore 是系統(tǒng)自帶的默認(rèn)值,否則我們需要提供自己的私鑰以完成簽名過程。
-
v1簽名
v1簽名方式主要是利用META-INFO文件夾中的三個文件。
首先,將apk中除了META-INFO文件夾中的所有文件進行進行摘要寫到 META-INFO/MANIFEST.MF;然后計算MANIFEST.MF文件的摘要寫到CERT.SF;最后計算CERT.SF的摘要,使用私鑰計算簽名,將簽名和開發(fā)者證書寫到CERT.RSA。
所以META-INFO文件夾中這三個文件就能保證apk不會被修改。
但是缺點也很明顯,META-INFO文件夾不會被簽名,所以美團針對這種簽名方式設(shè)計了一種多渠道打包方案:
利用pythone在META-INFO文件夾中創(chuàng)建一個文件,其名稱就是渠道名,然后用java去讀取文件名獲取渠道。
-
v2簽名
Android7.0之后,推出了v2簽名,為了解決v1簽名速度慢以及簽名不完整的問題。
apk本質(zhì)上是一個壓縮包,而壓縮包文件格式一般分為三塊:
文件數(shù)據(jù)區(qū),中央目錄結(jié)果,中央目錄結(jié)束節(jié)。
而v2要做的就是,在文件中插入一個APK簽名分塊,位于中央目錄部分之前,如下圖:

這樣處理之后,文件就完成無法修改了。
- v3簽名
Android 9 推出了v3簽名方案,和v2簽名方式基本相同,不同的是在v3簽名分塊中添加了有關(guān)受支持的sdk版本和新舊簽名信息,可以用作簽名替換升級。
-
v4簽名
Android 11 推出了v4簽名方案。
v4 簽名基于根據(jù) APK 的所有字節(jié)計算得出的 Merkle 哈希樹。它完全遵循 fs-verity 哈希樹的結(jié)構(gòu),將簽名存儲在單獨的.apk.idsig 文件中。
ZipAlign對齊
zipalign 是一種歸檔對齊工具,可對 Android 應(yīng)用 (APK) 文件提供重要的優(yōu)化
它會使 APK 中的所有未壓縮數(shù)據(jù)(例如圖片或原始文件)在 4 字節(jié)邊界上對齊。
這里涉及到一個Data structurealignment(數(shù)據(jù)對齊)的知識點,其大概意思就是如果數(shù)據(jù)是自然對齊的,CPU讀寫就會更高效。
簽名工具的不同帶來的對齊處理的順序不同:
如果使用的是 apksigner,只能在為 APK 文件簽名之前執(zhí)行 zipalign。
如果使用的是 jarsigner,只能在為 APK 文件簽名之后執(zhí)行 zipalign。
8、最后,如果是正式版的 APK,還會利用 ZipAlign 工具進行對齊處理,以提高程序的加載和運行速度。而對齊的過程就是將 APK 文件中所有的資源文件距離文件的起始位置都偏移4字節(jié)的整數(shù)倍,這樣通過 mmap 訪問 APK 文件的速度會更快,并且會減少其在設(shè)備上運行時的內(nèi)存占用。
為什么 XML 資源文件要從文本格式編譯成二進制格式?
主要基于以下 兩點原因:
- 1、空間占用更小:因為所有 XML 元素的標(biāo)簽、屬性名稱、屬性值和內(nèi)容所涉及到的字符串都會被統(tǒng)一收集到一個字符串資源池中,并且會去重。有了這個字符串資源池,原來使用字符串的地方就會被替換成一個索引到字符串資源池的整數(shù)值,從而可以減少文件的大小。
- 2、解析效率更高:二進制格式的 XML 文件解析速度更快。這是由于二進制格式的 XML 元素里面不再包含有字符串值,因此就避免了進行字符串解析,從而提高了解析效率。
Android 資源管理框架又是如何快速定位到最匹配資源的?
主要基于兩個文件,如下所示:
- 1、資源 ID 文件 R.java:賦予每一個非 assets 資源一個 ID 值,這些 ID 值以常量的形式定義在 R.java 文件中。
- 2、資源索引表 resources.arsc:用來描述那些具有 ID 值的資源的配置信息。
3、簽名算法的原理
什么是簽名?
在 Apk 中寫入一個 “指紋”。指紋寫入以后,Apk 中有任何修改,都會導(dǎo)致這個指紋無效,Android 系統(tǒng)在安裝 Apk 進行簽名校驗時就會不通過,從而保證了安全性。
那么,為什么要簽名?
主要有 兩點原因,如下所示:
- 1、確保 Apk 來源的真實性。
- 2、確保 Apk 沒有被第三方篡改。
數(shù)字摘要
對一個任意長度的數(shù)據(jù),通過一個 Hash 算法計算后,都可以得到一個固定長度的二進制數(shù)據(jù),這個數(shù)據(jù)就稱為 “摘要”。
在簽名和校驗的流程之中,應(yīng)用了許多密碼學(xué)的知識,這里我們需要先大致了解一下。
Hash(散列算法)的基礎(chǔ)原理
Hash 算法就是 將數(shù)據(jù)(如一段文字)運算變?yōu)榱硪还潭ㄩL度值。它的特點主要有如下 三點:
- 1、唯一性。
- 2、固定長度:比較常用的 Hash 算法有 MD5 和 SHA1,MD5 的長度是128位,SHA1 的長度是160位。
- 3、不可逆性。
而常用的 Hash 算法有如下 三種: - 1、SHA-1:在密碼學(xué)中,SHA-1(安全散列算法1)是一種加密散列函數(shù),它接受輸入并產(chǎn)生一個160 位(20 字節(jié))散列值,稱為消息摘要。
- 2、MD5:MD5 消息摘要算法(英語:MD5 Message-Digest Algorithm),一種被廣泛使用的密碼散列函數(shù),可以產(chǎn)生出一個128位(16字節(jié))的散列值(hash value),用于確保信息傳輸完整一致。
- 3、SHA-2:名稱來自于安全散列算法2(Secure Hash Algorithm 2)的縮寫,一種密碼散列函數(shù)算法標(biāo)準(zhǔn),其下又可再分為六個不同的算法標(biāo)準(zhǔn),包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。
簽名和校驗的主要過程
簽名就是 在摘要的基礎(chǔ)上再進行一次加密,對摘要加密后的數(shù)據(jù)就可以當(dāng)作數(shù)字簽名。
簽名過程:
簽名過程可以細分為 三步,如下所示:
- 1、計算摘要:通過 Hash 算法提取出原始數(shù)據(jù)的摘要。
- 2、計算簽名:再通過基于密鑰(私鑰)的非對稱加密算法對提取出的摘要進行加密,加密后的數(shù)據(jù)就是簽名信息。
- 3、寫入簽名:將簽名信息寫入原始數(shù)據(jù)的簽名區(qū)塊內(nèi)。
校驗過程:
校驗過程同樣也可以分為 三步,如下: - 1、提取摘要:首先用同樣的 Hash 算法從接收到的數(shù)據(jù)中提取出摘要。
- 2、解密簽名:使用發(fā)送方的公鑰對數(shù)字簽名進行解密,解密出原始摘要。
- 3、比較摘要:如果解密后的數(shù)據(jù)和提取的摘要一致,則校驗通過;如果數(shù)據(jù)被第三方篡改過,解密后的數(shù)據(jù)和摘要將會不一致,則校驗不通過。
那么,我們該如何保證公鑰的可靠性呢?答案是 數(shù)字證書。
數(shù)字證書
數(shù)字證書是 身份認(rèn)證機構(gòu)(Certificate Authority)頒發(fā)的,主要包含了以下 六類信息:
- 1、證書頒發(fā)機構(gòu)
- 2、證書頒發(fā)機構(gòu)簽名
- 3、證書綁定的服務(wù)器域名
- 4、證書版本、有效期
- 5、簽名使用的加密算法(非對稱算法,如 RSA)
- 6、公鑰等
接收方收到消息后,需要先向 CA 驗證證書的合法性,再進行簽名校驗。
需要注意的是,Apk 的證書通常是自簽名的,也就是由開發(fā)者自己制作,沒有向 CA 機構(gòu)申請。Android 在安裝 Apk 時并沒有校驗證書本身的合法性,只是從證書中提取公鑰和加密算法,這也正是對第三方 Apk 重新簽名后,還能夠繼續(xù)在沒有安裝這個 Apk 的系統(tǒng)中繼續(xù)安裝的原因。
keystore 和證書格式
keystore 文件中包含了 私鑰、公鑰和數(shù)字證書。根據(jù)編碼不同,keystore 文件分為很多種,Android 使用的是 Java 標(biāo)準(zhǔn) keystore 格式 JKS(Java Key Storage),所以通過 Android Studio 導(dǎo)出的 keystore 文件是以 .jks 結(jié)尾的。
keystore 使用的 證書標(biāo)準(zhǔn)是 X.509,X.509 標(biāo)準(zhǔn)也有多種 編碼格式,常用的有兩種:pem(Privacy Enhanced Mail)和 der(Distinguished Encoding Rules)。jks 使用的是 der 格式,但是,Android 也支持直接使用 pem 格式的證書進行簽名。
下面,我們了解下兩種證書編碼格式的區(qū)別,如下所示:
- DER(Distinguished Encoding Rules):二進制格式,所有類型的證書和私鑰都可以存儲為 der 格式。
- PEM(Privacy Enhanced Mail):base64 編碼,內(nèi)容以-----BEGIN xxx----- 開頭,以-----END xxx----- 結(jié)尾。
jarsigner 和 apksigner 的區(qū)別
Android 提供了 兩種對 Apk 的簽名方式,一種是基于 JAR 的簽名方式,另一種是基于 Apk 的簽名方式,它們的 主要區(qū)別在于使用的簽名文件不一樣:jarsigner 使用 keystore 文件進行簽名;而 apksigner 除了支持使用 keystore 文件進行簽名外,還支持直接指定 pem 證書文件和私鑰進行簽名。
在我們簽名時,除了要指定 keystore 文件和密碼外,也要指定 alias 和 key 的密碼,這是為什么呢?
keystore 是一個密鑰庫,也就是說它可以存儲多對密鑰和證書,keystore 的密碼是用于保護 keystore 本身的,每一對密鑰和證書是通過 alias 來區(qū)分的。所以 jarsigner 是支持使用多個證書對 Apk 進行簽名的,apksigner 也同樣支持。
Android Apk V1 驗證簽名的原理
Android Apk V1 驗證簽名的過程主要可以分為如下 四步:
- 1、解析出 CERT.RSA 文件中的證書、公鑰,解密 CERT.RSA 中的加密數(shù)據(jù)。
- 2、解密結(jié)果和 CERT.SF 的指紋進行對比,保證 CERT.SF 沒有被篡改。
- 3、接著,將 CERT.SF 中的內(nèi)容再和 MANIFEST.MF 中的指紋對比,保證 MANIFEST.MF 文件沒有被篡改。
- 4、MANIFEST.MF 中的內(nèi)容和 APK 所有文件指紋逐一對比,保證 APK 沒有被篡改。
附1、查看 Gradle 源碼
這里提供一種Gradle源碼的查看方式,就是導(dǎo)入Gradle庫,然后在External Libraries中查看:
implementation 'com.android.tools.build:gradle:4.1.1'
先以依賴的方式導(dǎo)入gradle庫,然后編譯,就能在左側(cè)External Libraries欄中看到源碼了:
