Part One
原文路徑:http://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-1-introduction/
Android有兩種類型的API是不能經(jīng)由SDK訪問的。
第一種是位于com.android.internal包中的API。我將稱之為internal API。第二種API類型是一系列被標(biāo)記為@hide屬性的類和方法。從嚴(yán)格意義上來講,這不是一個(gè)單一的API,而是一組小的被隱藏的API,但我仍將其假設(shè)為一種API,并稱之為hidden API。
Hidden API 例子
你可以查看一下android的源碼,并能找到一些變量、函數(shù)和類等,都被@hide屬性標(biāo)記了。
下面的例子就是在WifiManager(API 10源碼)中隱藏的變量。

另一個(gè)例子是在WifiManager(API 10源碼)中隱藏了setWifiApEnabled函數(shù)。

因此,只要你看到@hide屬性,那你看到的就是hidden API。
Internal和hidden API的區(qū)別
Hidden API之所以被隱藏,是想阻止開發(fā)者使用SDK中那些未完成或不穩(wěn)定的部分(接口或架構(gòu))。舉個(gè)例子,Bluetooth API在API 5(Android
2.0)上才開放;在API 3 和4上都是用@hide屬性隱藏了。當(dāng)這些API被驗(yàn)證和清理后,Google的開發(fā)者會(huì)移除@hide屬性,并讓其在API 5官方化。很多地方在API 4 和5之間發(fā)生了變化。如果你的程序依賴某些隱藏的API,當(dāng)其部署到新的平臺(tái)上時(shí),就有可能陷入困境。
對(duì)于internal API來說,從來都沒有計(jì)劃將其開放出來。它就是Android的“內(nèi)部廚房”,對(duì)開發(fā)者來說,應(yīng)該將其視作黑盒。凡事都會(huì)有變化的。如果你依賴某些internal
API,也有可能在新的Android release上,這些internal API發(fā)生變化,從而令你失望。
總結(jié)一下區(qū)別:
Hidden API = 進(jìn)行中的工作;
Internal API = 黑盒;
Internal和hidden API的編譯時(shí) vs. 運(yùn)行時(shí)
當(dāng)你使用Android SDK進(jìn)行開發(fā)的時(shí)候,你引用了一個(gè)非常重要的jar文件——android.jar。它位于Android
SDK平臺(tái)的文件夾中(SDK_DIR/platforms/platform-X/android.jar,其中,X表示API等級(jí))。這個(gè)android.jar移掉了com.android.internal包中所有的類,也移掉了所有標(biāo)記有@hide的類,枚舉,字段和方法。
但當(dāng)你在設(shè)備上啟動(dòng)應(yīng)用程序時(shí),它將加載framework.jar(簡(jiǎn)單來說,它和android.jar等同),而其未移掉internal
API和hidden API。(但它對(duì)開發(fā)者來說,并不能友好地訪問,因此,我將向大家展示不通過反射如何使用這些API)。
關(guān)于internal API,還有一件事需要說明。Eclipse的ADT插件增加了一個(gè)額外的規(guī)則,那就是禁止使用com.android.internal包中的任何東西。所以,即便是我們可以拿到最原始的android.jar(未刪減版),也沒有輕松的辦法通過Eclipse使用這些internal API。
你可以親自檢查一下。創(chuàng)建一個(gè)新的Android工程(或者使用已有的)。查看一下它引用的類庫(右擊project Properties
–> Java Build Path –> Libraries)。


重要的總結(jié):internal和hidden API在SDK中是按照一樣的方式處理的(都從android.jar中移除了),但internal API更慘的是,還被Eclipse的ADT插件顯式禁止了。
不通過反射使用internal和hidden API
這些文章的終極目標(biāo)是讓開發(fā)者能夠不通過反射使用Internal和Hidden API。如果你完成了接下來部分中描述的步驟,你將能使用這些Internal和Hidden API,如同公開的API。你不再需要使用反射。
注:如果你正在使用這些非公開的API,你必須知道,你的程序有著極大的風(fēng)險(xiǎn)。基本上,無法保證在下一次的Android OS更新時(shí),這些API不被破壞,也無法保證不同的運(yùn)營商有著一致的行為。你自己決定吧。
接下來有三個(gè)場(chǎng)景:
1. Internal 和hidden
API都可用(場(chǎng)景A)
2. 只Hidden
API可用(場(chǎng)景B)
3. 只Internal
API可用(場(chǎng)景C)
場(chǎng)景A是B、C的總和。場(chǎng)景B是最簡(jiǎn)單的一個(gè)(不需要對(duì)Eclipse的ADT修改)。
場(chǎng)景A:閱讀Part1, 2, 3, 4, 5
場(chǎng)景B:閱讀Part1, 2, 3, 5
場(chǎng)景C:閱讀Part1, 2, 3, 4, 5
Part 2
原文路徑:http://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-2-hacking-around/
在上一篇中,我解釋了為什么我們不通過反射就會(huì)很難使用internal和hidden API。這是因?yàn)閍ndroid.jar中就沒包含這些API,因此,沒人能夠在編譯時(shí)引用這些類。
這篇文章將描述如何還原最初的android.jar。這將允許我們像使用公開的API那樣使用internal和hidden API。
如何得到原版android.jar?
我們需要修改android.jar,這樣它才能包含所有的*.class文件(包括internal和hidden API類)。有兩種辦法:
1) Android是一個(gè)開源工程。我們可以下載源碼并搭建編譯環(huán)境,這樣它就不能移除那些internal和hidden的類了。這個(gè)辦法比較困難;
2) 每個(gè)模擬器或真機(jī)在運(yùn)行時(shí)都會(huì)有一個(gè)等同android.jar的東西。我們可以從這里拿到j(luò)ar文件,提取出原始的.class文件,并拷貝到Android SDK的android.jar中。
我將采用方案2。它易于開始,還不需要搭建Linux環(huán)境及編譯環(huán)境等。
從設(shè)備上獲取framework.jar
你可以使用命令行(adb pull)從模擬器或設(shè)備上下載文件,或者使用DDMS(借助Eclipse或SDK中的應(yīng)用)。
注意:模擬器通常在.dex文件中包含代碼,而真機(jī)一般在優(yōu)化版的dex文件中包含代碼——odex文件。操作odex文件比較困難,這也是為什么我選擇模擬器的原因。
與Android SDK中的android.jar等同的文件是framework.jar。這個(gè)文件位于設(shè)備的:/system/framework/framework.jar
adb pull /system/framework/framework.jar
當(dāng)framework.jar從設(shè)備上下下來之后,重命名為framework.zip并解壓到獨(dú)立的文件夾中,看起來是這個(gè)樣子的:
classes.dex正是我們需要的。
創(chuàng)建framework-classes.zip
首先,我們需要把.dex文件轉(zhuǎn)換成.jar格式。你可以使用通用的工具dex2jar。只需要運(yùn)行:
dev2jar classes.dex
當(dāng)轉(zhuǎn)換結(jié)束時(shí),你應(yīng)該得到了classes.dex.dex2jar.jar文件。重命名為framework-classes.zip。使用zip查看器,進(jìn)入到framework-classes.zip/com/android/internal/:

恭喜你,你已經(jīng)擁有了所有的.class文件,包括internal和hidden
API(盡管截圖只確認(rèn)了internal部分)。
創(chuàng)建original-android.jar
Android SDK的android.jar位于ANDROID_SDK/platforms/android-X/android.jar(X表示API等級(jí))。
拷貝android.jar成custom-android.jar。解壓至custom-android文件夾。將framework-classes.zip中所有的.class文件拷貝到custom-android文件夾中(你需要覆蓋所有已經(jīng)存在的.class文件)。
然后,壓縮custom-android文件成original-android.zip。重命名為original-android.jar。
步驟總結(jié)
1. 選擇你的目標(biāo)平臺(tái)X
2. 創(chuàng)建目標(biāo)平臺(tái)X的模擬器
3. 啟動(dòng)模擬器,下載/system/framework/framework.jar
4. 重命名framework.jar
-> framework.zip
5. 從framework.zip中抽取classes.dex
6. 使用dex2jar工具,將其轉(zhuǎn)換成classes.jar
7. 重命名classes.jar
-> framework-classes.zip
8. 拷貝android.jar –> custom-android.zip
9. 解壓custom-android.zip至custom-android文件夾
10. 將framework-classes.zip中所有文件拷貝至custom-android文件夾(覆蓋存在的文件)
11. 壓縮custom-android文件夾成original-android.zip
12. 重命名original-android.zip
-> original-android.jar
打完收功。
總結(jié)
我們還原了android.jar,使其包含所有的internal和hidden
API的.class文件。這只是第一步。下一步將創(chuàng)建定制的android平臺(tái),使其使用未刪節(jié)版的android.jar,并將其添加到Android SDK platforms文件夾中。
Part 3
原文路徑:http://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-3-custom-android-platform/
在上一篇中,我已經(jīng)展示了如何創(chuàng)建一個(gè)包含所有internal和hidden API的original-android.jar。
接下來的工作就是要修改已經(jīng)存在的Android平臺(tái)(SDK_DIR/platforms/platform-X/android.jar,X表示API等級(jí))。你可以直接使用Part2中創(chuàng)建的original-android.jar替換android.jar。但這樣的話,你的所有工程都將直接使用internal和hidden API而沒有任何限制。這不夠方便,因?yàn)樵诙鄶?shù)的工程中你不希望這樣。甚至,你可能更希望禁止這些API(ADT/android.jar的默認(rèn)行為)。但對(duì)于一些特定的工程,你希望能夠使用這些internal和hidden API。
為了達(dá)到這樣的靈活性,你需要?jiǎng)?chuàng)建一個(gè)新的自定義的Android平臺(tái)。當(dāng)不需要訪問internal和hidden
API時(shí),你只需使用原有的Android平臺(tái)。當(dāng)你使用這些API時(shí),你使用自定義的Android平臺(tái)。
Android SDK文件夾結(jié)構(gòu)
讓我們看一下Android
SDK樹是如何組織的:

我們需要“platforms”文件夾。看一下里面:

這里列出了支持的Android平臺(tái)。
現(xiàn)在,我們看一下它是如何與Eclipse設(shè)定關(guān)聯(lián)的。選擇你的工程,右擊–> Properties –> Android。你將會(huì)看到一組支持的Android平臺(tái)(與…/platforms/folder相似)。下面是截圖:

創(chuàng)建新的平臺(tái)
為了創(chuàng)建一個(gè)新的平臺(tái),我們需要拷貝android-9文件夾 -> android-9-internals。讓我們做一些修正:
1. 刪除其中的android.jar
2. 拷貝original-android.jar,并改名為android.jar
3. 修改build.prop文件:
…
ro.build.version.sdk=9 -> ro.build.version.sdk=-9
…
ro.build.version.release=2.3 ->
ro.build.version.release=2.3.extended
…
重啟Eclipse。并確認(rèn)你能看到新的平臺(tái)。下面是我所看到的:

為什么我選擇API等級(jí)為-9?這是因?yàn)樗仨毷且粋€(gè)數(shù)字,而且它不能是9(或者其它已經(jīng)存在的API等級(jí))。否則,你自定義的平臺(tái)將不能被使用(它在列表里可見,但選中后也不能正常工作,編譯時(shí)仍然使用相應(yīng)API等級(jí)的原始平臺(tái))。
下面是引用類庫的截圖(當(dāng)前工程選中了自定義的平臺(tái)):

總結(jié)
在上一篇中,我已經(jīng)告訴你如何創(chuàng)建一個(gè)未刪節(jié)版的android.jar。在這一篇中,我向你展示了如何創(chuàng)建一個(gè)自定義的Android平臺(tái),并在其中使用original-android.jar。這對(duì)于hidden API來說已經(jīng)足夠了。但對(duì)于internal
API來說,還需要另一步。這是因?yàn)锳DT仍然不允許使用com.android.internal包中的類(參見上圖中的“forbidden”訪問規(guī)則)。下一節(jié)我將向你展示如何定制ADT來允許使用internal包中的類。
============華麗的分割線=============
在實(shí)際的操作過程中,我創(chuàng)建的自定義的android.jar(API 10)不能被Eclipse成功加載,會(huì)出現(xiàn)以下的錯(cuò)誤框,如同網(wǎng)站上其它人操作的結(jié)果一樣,期待解決方案。

不過,作者提供了可用的自定義的android.jar,如果不想自己嘗試的話,可以直接從網(wǎng)站下載,地址將在Part5中給出,稍等。
Part 4
原文路徑:http://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-4-customizing-adt/
在上一篇文章里,我描述了如何創(chuàng)建一個(gè)自定義的original-android.jar,以及如何創(chuàng)建一個(gè)自定義的Android平臺(tái)來使用這個(gè)original-android.jar。這對(duì)Hidden API來說足夠了。但對(duì)Internal
API來說,仍然還有一個(gè)包袱:Eclipse的ADT插件。它限制使用com.android.internal包中的任何類。

有幾種方法可以解決這個(gè)訪問限制。
1) ADT源碼可以下載。因此,刪除/修改代碼中的某些代碼,從而編譯出一個(gè)新的ADT是可以的。麻煩的是你需要搭建64位Linux系統(tǒng),下載源碼,編譯等。它需要花費(fèi)一些時(shí)間。當(dāng)有新的ADT版本時(shí),你需要重來一遍。
2) 另外的方法就是修改ADT的字節(jié)碼。用一個(gè)類似于“com/android/internax/**”的字符串替換“com/android/internal/**”。
第二種方法可以用腳本實(shí)現(xiàn)。并且不需要訪問源碼以及可在Windows上操作。這也是為什么我在這篇中選用第二種解決方案的原因。
修改ADT的字節(jié)碼
進(jìn)入Eclipse的plugins文件夾。找到文件名看起來像“com.android.ide.eclipse.adt_*.jar”的文件。備份一下這個(gè)文件(以防中間有錯(cuò)誤發(fā)生)。并拷貝這個(gè)文件到一個(gè)“experimental”文件夾,在這里,我們要完成對(duì)其字節(jié)碼的修改。
重命名*.jar為*.zip。解壓這個(gè)文件到單獨(dú)的文件夾。參看以下圖片:

現(xiàn)在,進(jìn)入到com/android/ide/eclipse/adt/internal/project子文件夾。
找到AndroidClasspathContainerInitializer.class文件。

這個(gè)文件包含“com/android/internal/**”字符串。接下來就是要替換這個(gè)字符串,例如“com/android/internax/**”。改變字符串的長度理論上是安全的,但最好還是替換其中的一個(gè)字母,并保持長度一致。
我使用notepad++修改的,它支持非可印刷字符,因此在對(duì)其修改時(shí),不要觸碰修改非可印刷字符。

當(dāng)做完這個(gè),保存文件。壓縮這個(gè)文件夾,保證文件名與原始文件一模一樣。在我這里,文件名是:com.android.ide.eclipse.adt_8.0.1.v201012062107-82219.zip。
注意:確保壓縮文件的正確性。比較原始文件和修改文件的根文件結(jié)構(gòu)。
現(xiàn)在,用修改后的版本替換原來的ADT的*.jar文件。然后,啟動(dòng)Eclipse。
在使用庫窗口,你應(yīng)該看到下面的樣子,一切都變得那么的美好:

步驟總結(jié)
1. 關(guān)閉Eclipse
2. 從Eclipse的plugin文件夾中拷貝出ADT插件的jar文件
3. 重命名.jar
-> .zip,然后解壓至獨(dú)立的文件夾
4. 找到com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerInitializer.class文件
5. 用“com/android/internax/**”替換“com/android/internal/**”
6. 壓縮這個(gè)文件夾
7. 重命名 .zip
-> .jar
8. 用修改后的jar替換原始的ADT jar文件
9. 啟動(dòng)Eclipse
結(jié)論
這是不使用反射也能使用Internal
API的最后一步。
Part 5
原文路徑:https://devmaze.wordpress.com/2011/01/19/using-com-android-internal-part-5-summary-and-example/
為了能夠使用Internal和Hidden API,你需要:
1. 創(chuàng)建自定義的original-android.jar,包含所有的.class文件
2. 創(chuàng)建自定義的Android平臺(tái)來使用original-android.jar
3. 修改ADT插件,允許使用com.android.internal包(只為Internal API)
4. 創(chuàng)建新的工程,引用自定義的Android平臺(tái)(本文中的例子)
在本文中,我將向你們展示如何使用那些Internal和Hidden API。
此外,在本文的結(jié)尾,我列出了一些自定義的Android平臺(tái),它們都包含Internal和Hidden
API。我附帶了它們,是為了可能你不想花太多時(shí)間在這方面,但又想快速的嘗試什么。
例子
創(chuàng)建一個(gè)新工程,選擇2.3.extender平臺(tái):

下面是代碼:

這個(gè)代碼使用了Internal
API(PowerProfile)和Hidden API(isWifiApEnabled)。我不用使用反射就能編譯并運(yùn)行這些代碼。
自定義平臺(tái)
下面有些平臺(tái),是我為自己創(chuàng)建的。只用拷貝它們到SDK_DIR\platforms文件夾下。這只是讓Hidden API可用。對(duì)于Internal
API,你需要修改你的ADT插件。
API 3:http://www.megaupload.com/?d=S1F2MKYZ
API 4:http://www.megaupload.com/?d=VUCTRI3Y
API 7:http://www.megaupload.com/?d=7ITNILBK
API 8:http://www.megaupload.com/?d=EXT5FKKT
API 9:http://www.megaupload.com/?d=EXT5FKKT
API 10:http://www.megaupload.com/?d=FCV78A9M
==============華麗的分割線=============
我嘗試了其中的幾個(gè)自定義平臺(tái),發(fā)現(xiàn),internal 和hidden API真的是可用了,但也有一些意外的問題,如AlertDialog.Builder(Context
context)居然說Context參數(shù)是多余的。。
沒花時(shí)間去研究為什么會(huì)這樣,如果哪位童鞋知道原因,告訴我哈~~
@import url(http://www.shnenglu.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
posted on 2011-09-26 17:52
frank.sunny 閱讀(3282)
評(píng)論(3) 編輯 收藏 引用 所屬分類:
Android開發(fā)