加载插件class类
方式一:
从已安装的apk中读取,必须要有一个activity,且需要配置ACTION。利用这种方式获取插件信息,然后来构建classLoader加载类。
插件APP代码:
- AndroidManifest.xml
<intent-filter>
<action android:name="com.jiangshuai.pluginone"/>
</intent-filter>
- PluginClass
public class PluginClass {
public PluginClass() {
Log.d("JG","初始化PluginClass");
}
public int function(int a, int b){
return a+b;
}
}
宿主APP代码
public void intentFilter(View view) {
useIntentFilterDexClassLoader();
}
private void useIntentFilterDexClassLoader() {
Intent intent = new Intent("com.jiangshuai.pluginone");
PackageManager pm = getPackageManager();
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
if (resolveInfos.size() == 0) {
return;
}
ActivityInfo activityInfo = resolveInfos.get(0).activityInfo;
String packageName = activityInfo.packageName;
String apkPath = activityInfo.applicationInfo.sourceDir;
String dexOutputDir = getApplicationInfo().dataDir;
String libDir = activityInfo.applicationInfo.nativeLibraryDir;
DexClassLoader classLoader =
new DexClassLoader(apkPath, dexOutputDir, libDir, this.getClass().getClassLoader());
try {
Class<?> clazz = classLoader.loadClass(packageName + ".PluginClass");
Object obj = clazz.newInstance();
Class[] param = new Class[2];
param[0] = Integer.TYPE;
param[1] = Integer.TYPE;
Method method = clazz.getMethod("function", param);
Integer result = (Integer) method.invoke(obj, 12, 11);
Log.e(TAG, "result = " + result);
} catch (Exception e) {
}
}
方式二:利用apk path来构建DexClassLoader加载插件目标class
public void appPathLoader(View view) {
if (!hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
requestPermissions(Manifest.permission.READ_EXTERNAL_STORAGE);
return;
}
useApkPathDexClassLoader();
}
public boolean hasPermission(Context context, String permission) {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M
|| (context != null
&& context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED);
}
private void useApkPathDexClassLoader() {
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/app-debug.apk";
File codeDir = getDir("dex", Context.MODE_PRIVATE);
DexClassLoader classLoader =
new DexClassLoader(path, codeDir.getAbsolutePath(),
null, this.getClass().getClassLoader());
try {
Class<?> clazz = classLoader.loadClass("com.jiangshuai.pluginone.PluginClass");
Object object = clazz.newInstance();
Class[] param = new Class[2];
param[0] = Integer.TYPE;
param[1] = Integer.TYPE;
Method method = clazz.getMethod("function", param);
Integer result = (Integer) method.invoke(object, 12, 11);
Log.e(TAG, "result = " + result);
} catch (Exception e) {
}
}
private void requestPermissions(String permission) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
RxPermissions rxPermission = new RxPermissions(this);
rxPermission
.requestEach(permission)
.subscribe(new Consumer<Permission>() {
@Override
public void accept(Permission permission) throws Exception {
}
});
}
}
}
加载插件resource
方式一:通过getResourcesForApplication
PackageManager pm = getPackageManager();
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
if (resolveInfos.size() == 0) {
return;
}
ActivityInfo activityInfo = resolveInfos.get(0).activityInfo;
String packageName = activityInfo.packageName;
try {
Resources res = pm.getResourcesForApplication(packageName);
int id = res.getIdentifier("timg2", "drawable", packageName);
((ImageView)findViewById(R.id.image)).setImageDrawable(res.getDrawable(id));
} catch (Exception e) {
}
方式二:通过AssetManager
public void resourcesLoad(View view) {
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/app-debug.apk";
//获得包管理器
PackageManager pm = getPackageManager();
PackageInfo packageInfo=pm.getPackageArchiveInfo(path,PackageManager.GET_ACTIVITIES);
String packageName=packageInfo.packageName;
loadResources(path);
try {
((ImageView)findViewById(R.id.image)).setImageDrawable(
getResources().getDrawable(getResources().getIdentifier("timg2", "drawable", packageName)));
} catch (Exception e) {
e.printStackTrace();
}
}
private AssetManager mAssetManager;
private Resources mResources;
@Override
public Resources getResources() {
return mResources == null ? super.getResources() : mResources;
}
private void loadResources(String dexPath) {
try {
AssetManager assetManager = AssetManager.class.newInstance();
Method addAssetPath =
assetManager.getClass().getMethod("addAssetPath", String.class);
addAssetPath.invoke(assetManager, dexPath);
mAssetManager = assetManager;
} catch (Exception e) {
}
Resources superRes = super.getResources();
mResources = new Resources(mAssetManager,
superRes.getDisplayMetrics(), superRes.getConfiguration());
}
上述可以通过interface化来动态加载,提高动态加载的灵活性
宿主和插件引用同一目录结构下的interface,宿主为调用方,插件为实现方
一、宿主
public void resourcesLoadByInterface() {
//获取插件路径
String path= Environment.getExternalStorageDirectory().getAbsolutePath()+"/app-debug.apk";
File codeDir=getDir("dex", Context.MODE_PRIVATE);
//创建类加载器,把dex加载到虚拟机中
ClassLoader classLoader = new DexClassLoader(path,codeDir.getAbsolutePath() ,null,
this.getClass().getClassLoader());
loadResources(path);
//获得包管理器
PackageManager pm = getPackageManager();
PackageInfo packageInfo=pm.getPackageArchiveInfo(path,PackageManager.GET_ACTIVITIES);
String packageName=packageInfo.packageName;
try {
Class<?> clazz = classLoader.loadClass(packageName+".PluginClass");
PluginInterface obj = (PluginInterface) clazz.newInstance();
((ImageView)findViewById(R.id.image)).setImageDrawable(obj.getImage(this));
} catch (Exception e) {
e.printStackTrace();
}
}
public void resourcesLoad(View view) {
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/app-debug.apk";
//获得包管理器
PackageManager pm = getPackageManager();
PackageInfo packageInfo=pm.getPackageArchiveInfo(path,PackageManager.GET_ACTIVITIES);
String packageName=packageInfo.packageName;
loadResources(path);
try {
((ImageView)findViewById(R.id.image)).setImageDrawable(
getResources().getDrawable(getResources().getIdentifier("timg2", "drawable", packageName)));
} catch (Exception e) {
e.printStackTrace();
}
}
private AssetManager mAssetManager;
private Resources mResources;
@Override
public Resources getResources() {
return mResources == null ? super.getResources() : mResources;
}
private void loadResources(String dexPath) {
try {
AssetManager assetManager = AssetManager.class.newInstance();
Method addAssetPath =
assetManager.getClass().getMethod("addAssetPath", String.class);
addAssetPath.invoke(assetManager, dexPath);
mAssetManager = assetManager;
} catch (Exception e) {
}
Resources superRes = super.getResources();
mResources = new Resources(mAssetManager,
superRes.getDisplayMetrics(), superRes.getConfiguration());
}
插件:
public class PluginClass implements PluginInterface {
public PluginClass() {
Log.d("JG","初始化PluginClass");
}
public int function(int a, int b){
return a+b;
}
@Override
public Drawable getImage(Context context) {
return context.getResources().getDrawable(R.drawable.timg2);
}
}
interface:
public interface PluginInterface {
Drawable getImage(Context context);
}