使用反射調用隱藏或內部API
原文链接 https://jamling.github.io/2015/12/26/Android-Android-invoke-hide-api/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
內部API定義
供Android内部使用,不向SDK开放的类、接口、方法等
内部API出现的形式
- Hide 在public类,方法,(静态)常量使用了/** @hide */注释的java元素。如android.os.ServiceManager类
- internal 包名中带有internal标记的所有类或包,如com.android.internal.* <!-- more --> ## 使用優缺點
为什么不开放?
- 版本复杂
- 本身不稳定
- 兼容性差
优点:在特定的条件下使用,会产生意想不到的效果
缺点:兼容性差
使用需谨慎
調用方式
- 和源代码一起编译
- 修改eclipse adt规则
- 使用java反射机制
Java反射簡介
- 動態語言:允許程序在運行時改變程序結構及變量類型
- Java反射:加載在運行時才知道的class及獲取/調用此類的所有屬性/方法。
Java反射API
Class Class#forName(String className); Constructor Class#getConstructor(); Object Class#newInstance(); Constructor Class#getConstructor(Class<?>... constructorTypeParameters); Object Constructor#newInstance(Object... constructorParameterValues); Method Class#getDeclaredMethod(String name, Class<?>... parameterTypes); Object Method#invoke(Object target, Object... parameterValues);
示例
獲取apk運行統計信息
// IBinder oRemoteService = ServiceManager.getService("usagestats")
Class<?> cServiceManager = Class.forName("android.os.ServiceManager");
Method mGetService = cServiceManager.getMethod("getService", java.lang.String.class);
Object oRemoteService = mGetService.invoke(null, "usagestats");
// IUsageStats oIUsageStats = IUsageStats.Stub.asInterface(oRemoteService)
Class<?> cStub = Class.forName("com.android.internal.app.IUsageStats$Stub");
Method mUsageStatsService = cStub.getMethod("asInterface", android.os.IBinder.class);
Object oIUsageStats = mUsageStatsService.invoke(null, oRemoteService);
// PkgUsageStats[] oPkgUsageStatsArray = mUsageStatsService.getAllPkgUsageStats();
Class<?> cIUsageStatus = Class.forName("com.android.internal.app.IUsageStats");
Method mGetAllPkgUsageStats = cIUsageStatus.getMethod("getAllPkgUsageStats", (Class[]) null);
Object[] oPkgUsageStatsArray = (Object[]) mGetAllPkgUsageStats.invoke(oIUsageStats, (Object[]) null);
Class<?> cPkgUsageStats = Class.forName("com.android.internal.os.PkgUsageStats");
for (Object pkgUsageStats : oPkgUsageStatsArray) {
// get pkgUsageStats.packageName, pkgUsageStats.launchCount,
// pkgUsageStats.usageTime
String packageName = (String) cPkgUsageStats.getDeclaredField("packageName").get(pkgUsageStats);
int launchCount = cPkgUsageStats.getDeclaredField("launchCount").getInt(pkgUsageStats);
long usageTime = cPkgUsageStats.getDeclaredField("usageTime").getLong(pkgUsageStats);
System.out.println(packageName + ":" + launchCount + ":" + usageTime);
}