原文链接地址:http://www.eoeandroid.com/thread-83194-1-1.html
1.
Android有两种类型的API是不能经由SDK访问的。
第一种是位于com.android.internal包中的API。 我将称之为internal API。第二种API类型是一系列被标记为@hide属性的类和方法。从严格意义上来讲,这不是一个单一的API,而是一组小的被隐藏的API,但我仍将 其假设为一种API,并称之为hidden API。
Hidden API 例子
你可以查看一下android的源码,并能找到一些变量、函数和类等,都被@hide属性标记了。下面的例子就是在WifiManager中隐藏的变量。
另一个例子是在WifiManager中隐藏了setWifiApEnabled函数。
Hidden API之所以被隐藏,是想阻止开发者使用SDK中那些未完成或不稳定的部分(接口或架构)。举个例子,Bluetooth API在API 5上才开放;在API 3 和4上都是用@hide属性隐藏了。当这些API被验证和清理后,Google的开发者会移除@hide属性,并让其在API 5官方化。很多地方在API 4 和5之间发生了变化。如果你的程序依赖某些隐藏的API,当其部署到新的平台上时,就有可能陷入困境。
当你使用Android SDK进行开发的时候,你引用了一个非常重要的jar文件——android.jar。它位于Android SDK平台的文件夹中(SDK_DIR/platforms/platform-X/android.jar,其中,X表示API等级)。这个 android.jar移掉了com.android.internal包中所有的类,也移掉了所有标记有@hide的类,枚举,字段和方法。
2
在上一篇中,我解释了为什么我们不通过反射就会很难使用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并解压到独立的文件夹中,看起来是这个样子的:
步骤总结
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
3.
在上一篇中,我已经展示了如何创建一个包含所有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”文件夹。看一下里面:
创建新的平台
为什么我选择API等级为9?这是因为它必须是一个数字,而且它不能是9(或者其它已经存在的API等级)。否则,你自定义的平台将不能被使用(它在列表里可见,但选中后也不能正常工作,编译时仍然使用相应API等级的原始平台)。
下面是引用类库的截图(当前工程选中了自定义的平台):
4.
在上一篇文章里,我描述了如何创建一个自定义的original-android.jar,以及如何创建一个自定义的Android平台来使用这个 original-android.jar。这对Hidden API来说足够了。但对Internal API来说,仍然还有一个包袱:Eclipse的ADT插件。它限制使用com.android.internal包中的任何类。
进入Eclipse的plugins文件夹。找到文件名看起来像“com.android.ide.eclipse.adt_*.jar”的文件。备份一下 这个文件(以防中间有错误发生)。并拷贝这个文件到一个“experimental”文件夹,在这里,我们要完成对其字节码的修改。
现在,进入到com/android/ide/eclipse/adt/internal/project子文件夹。
找到AndroidClasspathContainerInitializer.class文件。
1. 关闭Eclipse
注意: 关于第4条,即修改android.jar 的Access Rules问题,可以不修改Eclipse中的插件adt相关的jar,而是通过在修改java的编译方式,即Windows-------->Preferences------->Java----------->Compiler------------->Errors/Warnings---------->Deprecated and restricted Api--------->Forbidden references(access rules)将其改成Ignore 或者 Warning。而且在按第四条进行的时候,Android工程中的System Library都出问题了,即不能找到android.jar。所以感觉还是修改编译选项比较好。