linwoain的个人blog

知我者谓我心忧,不知我者谓我何求

0%

android插件后开发获取未安装apk的资源

原理:根据activity获取资源的方法getResources(),通过查找其源码,根据其原理,通过生成一个AssetManager并添加一个APK文件的 ,最终生成一个包含所有资源的Resource对象。由于 AssetManager无法直接实例化,所以通过反射方法获取其实例,并调用其添加apk包的addAssetPath()方法。使用DexClassLoader加载目标apk中的资源R类获取需要的资源id的值。使用Resource的get方法(getString(int id)、getDrawable(int id))即可获取到相应的资源。
源码如下:
a.生成一个包含apk路径的AssetManager实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static AssetManager getAssetManager(String filePath) throws            
ClassNotFoundException {
AssetManager assetManager = null;
Class<?> aClass = Class.forName("android.content.res.AssetManager");
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals("addAssetPath")) {
try {
assetManager = (AssetManager) aClass.newInstance();
method.invoke(assetManager, filePath);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
return assetManager;
}

b.生成对应的Resource对象:

1
2
3
4
5
6
7
8
private static PluginResource resource;
public static PluginResource getInstance(String filePath) throws ClassNotFoundException {
if (resource == null) {
resource = new PluginResource(getAssetManager(filePath), new DisplayMetrics(),
new Configuration());
}
return resource;
}

c.获取需要对象的id并根据资源Id获取资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
try {
PluginResource resource = PluginResource.getInstance(filePath);
DexClassLoader dexClassLoader =
new DexClassLoader(filePath, this.getDir("demo",MODE_PRIVATE).getPath(), null, this.getClassLoader());
Class<?> aClass =dexClassLoader.loadClass("com.linwoain.demo.R$string");
for (Field field : aClass.getDeclaredFields()) {
if (field.getName().equals("test")) {
try {
int targetId = field.getInt(R.string.class);
String string = resource.getString(targetId);
Log.i(TAG, "onCreate: "+string);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}