作为
Android
应用的开发者,在
Android
平台上开发,最熟悉的莫过于
Android SDK
。
SDK
给开发者带来的巨大的便利,使得
Android
平台的应用开发效率大大提高。不过遗憾的是,
Android
的功能远不止
SDK
暴露的那么多,还有很多隐藏的东西
Google
都没有通过
SDK
暴露给用户开发者。查看
Android
源代码时就会发现,这些隐藏的
API
都有一个共同的特点:类或者方法前都有
@hide
。如图:
一、 如何隐藏API 的?
1)
在正常情况下,即不加 @hide 的时候,所有的public 的类或者方法,在编译时都会编译生成到stub library 的jar 文件中。这个stub library 其实是个空实现,但是它包含了所有的public 方法。所以用这个stub library ,应用开发者就可以在eclipse 中进行开发了。
2)
但一旦加了 @hide ,那么在编译生成stublibrary 时,凡是被 @hide 标记的类或者方法都被移除了。所以应用开发者就无法通过这个stub library “直接”调用被隐藏的类或者方法。如果强行在eclipse 里调用隐藏的类或者方法,则eclipse 会报错。典型的例子就是Android SDK 中的android.jar ,这个stub library 所包含的就是已经被移除的的API 。上图中,ActivityManager 的forceStopPackage() 方法在Android SDK 中是无法找到的。
二、 隐藏的API 可以调用吗?
1)
那么应用开发者可以使用这些隐藏的API 吗? 答案是肯定的。在真实的运行环境中,所有的API 都是存在的并且是被实现的。那么很容易就会想到用“反射”。如果我们已经知道目标类的类名和方法名,以及参数列表,那么这样的方法即使被 @hide 了,我们依然可以通过反射来调用它。对于Java 反射,这里我们不准备展开,不是很了解的同学请自行学习研究。下面是一个反射的例子。
IActivitManageram = ActivityManagerNative.getDefault();
Method forceStopPackage = am.getClass().getDeclaredMethod("forceStopPackage", String.class); forceStopPackage.setAccessible(true);
forceStopPackage.invoke(am, yourpkgname);
2)
反射虽好,不过写起来真麻烦,本来一个调用代码,一行就可以搞定,但是现在用发射写的话,需要好多行。有没有其他更加方便的办法呢,其实是有的。上面我们提到在Android SDK 中的android.jar 是一个阉割版,如果我们能生成一个完整版,这个问题就迎刃而解了。方法是现在整套Android 源代码,然后做一次完整的编译。在out/target/common/obj/JAVA_LIBRARIES/ 目录下可以根据需要提取自己所要的stublibrary 。以framework 为例: 将out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar 复制到eclipse 开发环境中,用userlibrary 的方式挂载,使其的优先级比android.jar 要高即可。
以下是在 eclipse 中的设置步骤:
一、 需要注意的一些问题
1)
无论是反射还是使用自编译的stublibrary ,只能解决调用隐藏API 的问题,而无法越过权限检查。
2)
Google 之所以将有些API 隐藏,有些原因可能是因为这些API 属于内部逻辑,不想对外暴露,也有可能是API 接口还未最终确定下来。所以在低版本Android 上的隐藏API 不一定能在高版本的Android 上使用。这点是一定要注意的。也就说隐藏API 的兼容性比较差。因此利用反射调用隐藏API 时,一定要注意根据Android 的版本采用不同的方式去反射。
一、 如何隐藏API 的?
1)
在正常情况下,即不加 @hide 的时候,所有的public 的类或者方法,在编译时都会编译生成到stub library 的jar 文件中。这个stub library 其实是个空实现,但是它包含了所有的public 方法。所以用这个stub library ,应用开发者就可以在eclipse 中进行开发了。
2)
但一旦加了 @hide ,那么在编译生成stublibrary 时,凡是被 @hide 标记的类或者方法都被移除了。所以应用开发者就无法通过这个stub library “直接”调用被隐藏的类或者方法。如果强行在eclipse 里调用隐藏的类或者方法,则eclipse 会报错。典型的例子就是Android SDK 中的android.jar ,这个stub library 所包含的就是已经被移除的的API 。上图中,ActivityManager 的forceStopPackage() 方法在Android SDK 中是无法找到的。
二、 隐藏的API 可以调用吗?
1)
那么应用开发者可以使用这些隐藏的API 吗? 答案是肯定的。在真实的运行环境中,所有的API 都是存在的并且是被实现的。那么很容易就会想到用“反射”。如果我们已经知道目标类的类名和方法名,以及参数列表,那么这样的方法即使被 @hide 了,我们依然可以通过反射来调用它。对于Java 反射,这里我们不准备展开,不是很了解的同学请自行学习研究。下面是一个反射的例子。
IActivitManageram = ActivityManagerNative.getDefault();
Method forceStopPackage = am.getClass().getDeclaredMethod("forceStopPackage", String.class); forceStopPackage.setAccessible(true);
forceStopPackage.invoke(am, yourpkgname);
2)
反射虽好,不过写起来真麻烦,本来一个调用代码,一行就可以搞定,但是现在用发射写的话,需要好多行。有没有其他更加方便的办法呢,其实是有的。上面我们提到在Android SDK 中的android.jar 是一个阉割版,如果我们能生成一个完整版,这个问题就迎刃而解了。方法是现在整套Android 源代码,然后做一次完整的编译。在out/target/common/obj/JAVA_LIBRARIES/ 目录下可以根据需要提取自己所要的stublibrary 。以framework 为例: 将out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar 复制到eclipse 开发环境中,用userlibrary 的方式挂载,使其的优先级比android.jar 要高即可。
以下是在 eclipse 中的设置步骤:
一、 需要注意的一些问题
1)
无论是反射还是使用自编译的stublibrary ,只能解决调用隐藏API 的问题,而无法越过权限检查。
2)
Google 之所以将有些API 隐藏,有些原因可能是因为这些API 属于内部逻辑,不想对外暴露,也有可能是API 接口还未最终确定下来。所以在低版本Android 上的隐藏API 不一定能在高版本的Android 上使用。这点是一定要注意的。也就说隐藏API 的兼容性比较差。因此利用反射调用隐藏API 时,一定要注意根据Android 的版本采用不同的方式去反射。