怎樣查看并且使用 Android 隱藏 API 和內(nèi)部 API

Android 有兩種類型的 API 不能通過 SDK 訪問。一種是在 com.android.internal 包中的 API,稱之為 internal API。另一種是被標(biāo)記為 @hide 屬性的類和方法,這是一組小級別的被隱藏的 API,稱之為 hidden API。

當(dāng)使用 Android SDK 進(jìn)行開發(fā)的時候,應(yīng)用默認(rèn)引用了 android.jar,它位于 SDKDir\platforms\android-X 目錄下(X 代表 API 級別),默認(rèn)移除了所有的被@hide標(biāo)識的方法或者類以及 internal 包下的類。。當(dāng)應(yīng)用在設(shè)備上運(yùn)行時,它會加載 framework.jar。簡單來說,framework.jar 和 android.jar 等同,但是沒有移除 internal API 和 hidden API。Hidden API 之所以被隱藏,是想阻止開發(fā)者使用 SDK 中未完成或不穩(wěn)定的部分。

舉個栗子:這是沒有移除 internal API 的 android.jar,可以看到包里的類是完整的。

internal api

比如 AssetManager 的 addAssetPath 方法被 @hide 標(biāo)記,它屬于 hidden API,我們無法直接調(diào)用該方法。

    /**
     * Add an additional set of assets to the asset manager.  This can be
     * either a directory or ZIP file.  Not for use by applications.  Returns
     * the cookie of the added asset, or 0 on failure.
     * {@hide}
     */
    public final int addAssetPath(String path) {
        synchronized (this) {
            int res = addAssetPathNative(path);
            makeStringBlocks(mStringBlocks);
            return res;
        }
    }

但是,人的需求是無限的。如果我們非要使用不可用的 API 怎么辦呢?最簡單的就是 Java 的反射,反射 @hiden 的方法或類,修改訪問修飾符,然后就可以搞事情了~~還有一種方法是從設(shè)備中提取,簡單說就是把設(shè)備上的 /system/framework/framework.jar 提取出來,經(jīng)過一系列轉(zhuǎn)換,最終得到完整的 android.jar,具體的步驟可以參考這篇文章:android怎樣調(diào)用@hide和internal API。另外一種方式非常簡單,GitHub 上有一個項目:android-hidden-api,里面提供了眾多版本完整的 android.jar 包,下圖所示。

android hidden api

我們把工程 clone 下來,找到對應(yīng)平臺的 android.jar 包,替換掉 Android SDK 下面的 jar,最好先備份一下原始的 jar,重新編譯工程或者重啟 Studio 就行了。

比如 AssetManager 的 addAssetPath 方法,沒有替換之前是這樣,Studio 提示錯誤,編譯失敗~o(>_<)o ~

can't resolve addAssetPath

但是在使用了完整的 android.jar 后,發(fā)現(xiàn)竟然不會報錯了,代碼可以通過編譯,終于可以愉快地使用想要的方法了 O(∩_∩)O~

can resolve addAssetPath

這種方式對于個人開發(fā)來說沒有問題,你把 android.jar 替換掉就好了,但是如果面對團(tuán)隊開發(fā),就非常痛苦了 %>_<%,每個人都要替換 SDK 的 android.jar,代價和風(fēng)險可想而知。那么有沒有好的解決辦法,既可以讓工程編譯通過,又能夠免去多人替換 jar 的成本呢?答案是有的。

Studio 默認(rèn)引用的是 SDK 下面的 android.jar,那我們把它的引用改成完整的 jar 的路徑不就行了么?
我們把完整的 android.jar 放在工程 libs 目錄下,也就是平時依賴 jar 的地方,然后在工程 build.gradle 配置的 dependencies 里,以 provided 的方式引用 android.jar。因為每個工程模塊依賴 android.jar 的類型就是 provided,這樣不會把 android.jar 打包到應(yīng)用中,運(yùn)行環(huán)境中存在 framework.jar,應(yīng)用直接就可以使用。

dependencies {
     // compile fileTree(include: ['*.jar'], dir: 'libs')  這行一定要去掉,當(dāng)然為 android.jar 換個目錄也行
    testCompile 'junit:junit:4.12'
    provided files('libs/hidden_api_23.jar')
}

最后還要在工程根目錄的 build.gradle 里面配置當(dāng)前 project,加上下面的代碼就行了。

project('app') { // app是你工程的名字,配置只對當(dāng)前工程有效
    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            // 注意修改 jar 包的路徑,替換 app/libs/hidden_api_23.jar,其他部分不要改
            // Xbootclasspath/p:是 Java 編譯的尋址優(yōu)先設(shè)置,先找缺省路徑還是全路徑
            options.compilerArgs.add('-Xbootclasspath/p:app/libs/hidden_api_23.jar')
        }
    }
}

現(xiàn)在重新編譯工程,雖然會在代碼中出現(xiàn)錯誤提示,但是編譯打包運(yùn)行都是正常的。_

在開發(fā)中使用隱藏 API 和內(nèi)部 API 是不推薦的做法,但是為了實現(xiàn)一些「黑科技」,這些又是必須的~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,324評論 25 708
  • afinalAfinal是一個android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,898評論 2 45
  • 今天第一次做個人成長團(tuán)輔,真的很感恩,這么好的機(jī)會大家給我了。職場關(guān)系最近幾年一直是我的短板,我想過怎么怎么不被她...
    寧小小白閱讀 431評論 0 2
  • 這個世界所有東西本不是非黑即白的,所以按照這個理論,除了文藝騷和非文藝騷,還有一類人叫偽文藝騷。 文藝騷通??戳艘?..
    安an安an閱讀 163評論 0 0
  • 開發(fā)過程中真是會用到各種各樣的方法,今天記錄一下字符串和數(shù)組的相互轉(zhuǎn)換的方法 1.將string字符串轉(zhuǎn)換為arr...
    尋常_0閱讀 478評論 0 0

友情鏈接更多精彩內(nèi)容