Android有两种类型的API是不能经由SDK访问的。java
第一种是位于com.android.internal包中的API。我将称之为internal API。第二种API类型是一系列被标记为@hide属性的类和方法。从严格意义上来说,这不是一个单一的API,而是一组小的被隐藏的API,但我仍将其假设为一种API,并称之为hidden API。android
Hidden API 例子架构
你能够查看一下android的源码,并能找到一些变量、函数和类等,都被@hide属性标记了。ide
下面的例子就是在WifiManager(API 10源码)中隐藏的变量。wordpress
另外一个例子是在WifiManager(API 10源码)中隐藏了setWifiApEnabled函数。函数
所以,只要你看到@hide属性,那你看到的就是hidden API。工具
Internal和hidden API的区别post
Hidden API之因此被隐藏,是想阻止开发者使用SDK中那些未完成或不稳定的部分(接口或架构)。举个例子,Bluetooth API在API 5(Android 2.0)上才开放;在API 3 和4上都是用@hide属性隐藏了。当这些API被验证和清理后,Google的开发者会移除@hide属性,并让其在API 5官方化。不少地方在API 4 和5之间发生了变化。若是你的程序依赖某些隐藏的API,当其部署到新的平台上时,就有可能陷入困境。优化
对于internal API来讲,历来都没有计划将其开放出来。它就是Android的“内部厨房”,对开发者来讲,应该将其视做黑盒。凡事都会有变化的。若是你依赖某些internal API,也有可能在新的Android release上,这些internal API发生变化,从而令你失望。网站
总结一下区别:
Hidden API = 进行中的工做;
Internal API = 黑盒;
Internal和hidden API的编译时 vs. 运行时
当你使用Android SDK进行开发的时候,你引用了一个很是重要的jar文件——android.jar。它位于Android SDK平台的文件夹中(SDK_DIR/platforms/platform-X/android.jar,其中,X表示API等级)。这个android.jar移掉了com.android.internal包中全部的类,也移掉了全部标记有@hide的类,枚举,字段和方法。
但当你在设备上启动应用程序时,它将加载framework.jar(简单来讲,它和android.jar等同),而其未移掉internal API和hidden API。(但它对开发者来讲,并不能友好地访问,所以,我将向你们展现不经过反射如何使用这些API)。
关于internal API,还有一件事须要说明。Eclipse的ADT插件增长了一个额外的规则,那就是禁止使用com.android.internal包中的任何东西。因此,即使是咱们能够拿到最原始的android.jar(未删减版),也没有轻松的办法经过Eclipse使用这些internal API。
你能够亲自检查一下。建立一个新的Android工程(或者使用已有的)。查看一下它引用的类库(右击project Properties –> Java Build Path –> Libraries)。
重要的总结:internal和hidden API在SDK中是按照同样的方式处理的(都从android.jar中移除了),但internal API更惨的是,还被Eclipse的ADT插件显式禁止了。
不经过反射使用internal和hidden API
这些文章的终极目标是让开发者可以不经过反射使用Internal和Hidden API。若是你完成了接下来部分中描述的步骤,你将能使用这些Internal和Hidden API,如同公开的API。你再也不须要使用反射。
注:若是你正在使用这些非公开的API,你必须知道,你的程序有着极大的风险。基本上,没法保证在下一次的Android OS更新时,这些API不被破坏,也没法保证不一样的运营商有着一致的行为。你本身决定吧。
接下来有三个场景:
1. Internal 和hidden API均可用(场景A)
2. 只Hidden API可用(场景B)
3. 只Internal API可用(场景C)
场景A是B、C的总和。场景B是最简单的一个(不须要对Eclipse的ADT修改)。
场景A:阅读Part1, 2, 3, 4, 5
场景B:阅读Part1, 2, 3, 5
场景C:阅读Part1, 2, 3, 4, 5
我解释了为何咱们不经过反射就会很难使用internal和hidden API。这是由于android.jar中就没包含这些API,所以,没人可以在编译时引用这些类。
这篇文章将描述如何还原最初的android.jar。这将容许咱们像使用公开的API那样使用internal和hidden API。
如何获得原版android.jar?
咱们须要修改android.jar,这样它才能包含全部的*.class文件(包括internal和hidden API类)。有两种办法:
1) Android是一个开源工程。咱们能够下载源码并搭建编译环境,这样它就不能移除那些internal和hidden的类了。这个办法比较困难;
2) 每一个模拟器或真机在运行时都会有一个等同android.jar的东西。咱们能够从这里拿到jar文件,提取出原始的.class文件,并拷贝到Android SDK的android.jar中。
我将采用方案2。它易于开始,还不须要搭建Linux环境及编译环境等。
从设备上获取framework.jar
你可使用命令行(adb pull)从模拟器或设备上下载文件,或者使用DDMS(借助Eclipse或SDK中的应用)。
注意:模拟器一般在.dex文件中包含代码,而真机通常在优化版的dex文件中包含代码——odex文件。操做odex文件比较困难,这也是为何我选择模拟器的缘由。
与Android SDK中的android.jar等同的文件是framework.jar。这个文件位于设备的:/system/framework/framework.jar
adb pull /system/framework/framework.jar
当framework.jar从设备上下下来以后,重命名为framework.zip并解压到独立的文件夹中,看起来是这个样子的:
classes.dex正是咱们须要的。
建立framework-classes.zip
首先,咱们须要把.dex文件转换成.jar格式。你可使用通用的工具dex2jar。只须要运行:
dev2jar classes.dex
当转换结束时,你应该获得了classes.dex.dex2jar.jar文件。重命名为framework-classes.zip。使用zip查看器,进入到framework-classes.zip/com/android/internal/:
恭喜你,你已经拥有了全部的.class文件,包括internal和hidden API(尽管截图只确认了internal部分)。
建立original-android.jar
Android SDK的android.jar位于ANDROID_SDK/platforms/android-X/android.jar(X表示API等级)。
拷贝android.jar成custom-android.jar。解压至custom-android文件夹。将framework-classes.zip中全部的.class文件拷贝到custom-android文件夹中(你须要覆盖全部已经存在的.class文件)。
而后,压缩custom-android文件成original-android.zip。重命名为original-android.jar。
步骤总结
1. 选择你的目标平台X
2. 建立目标平台X的模拟器
3. 启动模拟器,下载/system/framework/framework.jar
4. 重命名framework.jar -> framework.zip
5. 从framework.zip中抽取classes.dex
6. 使用dex2jar工具,将其转换成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
打完收功。
总结
咱们还原了android.jar,使其包含全部的internal和hidden API的.class文件。这只是第一步。下一步将建立定制的android平台,使其使用未删节版的android.jar,并将其添加到Android SDK platforms文件夹中。
我已经展现了如何建立一个包含全部internal和hidden API的original-android.jar。
接下来的工做就是要修改已经存在的Android平台(SDK_DIR/platforms/platform-X/android.jar,X表示API等级)。你能够直接使用Part2中建立的original-android.jar替换android.jar。但这样的话,你的全部工程都将直接使用internal和hidden API而没有任何限制。这不够方便,由于在多数的工程中你不但愿这样。甚至,你可能更但愿禁止这些API(ADT/android.jar的默认行为)。但对于一些特定的工程,你但愿可以使用这些internal和hidden API。
为了达到这样的灵活性,你须要建立一个新的自定义的Android平台。当不须要访问internal和hidden API时,你只需使用原有的Android平台。当你使用这些API时,你使用自定义的Android平台。
Android SDK文件夹结构
让咱们看一下Android SDK树是如何组织的:
咱们须要“platforms”文件夹。看一下里面:
这里列出了支持的Android平台。
如今,咱们看一下它是如何与Eclipse设定关联的。选择你的工程,右击–> Properties –> Android。你将会看到一组支持的Android平台(与…/platforms/folder类似)。下面是截图:
建立新的平台
为了建立一个新的平台,咱们须要拷贝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。并确认你能看到新的平台。下面是我所看到的:
为何我选择API等级为-9?这是由于它必须是一个数字,并且它不能是9(或者其它已经存在的API等级)。不然,你自定义的平台将不能被使用(它在列表里可见,但选中后也不能正常工做,编译时仍然使用相应API等级的原始平台)。
下面是引用类库的截图(当前工程选中了自定义的平台):
总结
在上一篇中,我已经告诉你如何建立一个未删节版的android.jar。在这一篇中,我向你展现了如何建立一个自定义的Android平台,并在其中使用original-android.jar。这对于hidden API来讲已经足够了。但对于internal API来讲,还须要另外一步。这是由于ADT仍然不容许使用com.android.internal包中的类(参见上图中的“forbidden”访问规则)。下一节我将向你展现如何定制ADT来容许使用internal包中的类。
============华丽的分割线=============
在实际的操做过程当中,我建立的自定义的android.jar(API 10)不能被Eclipse成功加载,会出现如下的错误框,如同网站上其它人操做的结果同样,期待解决方案。
不过,做者提供了可用的自定义的android.jar,若是不想本身尝试的话,能够直接从网站下载,地址将在Part5中给出,稍等。
为了可以使用Internal和Hidden API,你须要:
1. 建立自定义的original-android.jar,包含全部的.class文件
2. 建立自定义的Android平台来使用original-android.jar
3. 修改ADT插件,容许使用com.android.internal包(只为Internal API)
4. 建立新的工程,引用自定义的Android平台(本文中的例子)
在本文中,我将向大家展现如何使用那些Internal和Hidden API。
此外,在本文的结尾,我列出了一些自定义的Android平台,它们都包含Internal和Hidden API。我附带了它们,是为了可能你不想花太多时间在这方面,但又想快速的尝试什么。
例子
建立一个新工程,选择2.3.extender平台:
下面是代码:
这个代码使用了Internal API(PowerProfile)和Hidden API(isWifiApEnabled)。我不用使用反射就能编译并运行这些代码。
自定义平台
下面有些平台,是我为本身建立的。只用拷贝它们到SDK_DIR\platforms文件夹下。这只是让Hidden API可用。对于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
==============华丽的分割线=============
我尝试了其中的几个自定义平台,发现,internal 和hidden API真的是可用了,但也有一些意外的问题,如AlertDialog.Builder(Context context)竟然说Context参数是多余的。。
没花时间去研究为何会这样,若是哪位童鞋知道缘由,告诉我哈~~
来源:http://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-1-introduction/