插件化原理
插桩法实现:使用一个已注册的Activity为壳,加载apk中的Activity
1、定义接口,用于传递上下文和生命周期
public interface PluginAtyInterface {
public void onCreate(Bundle savedInstanceState);
public void onDestroy();
public void onStart();
public void onStop();
public void onResume();
public void onRestart();
public void attch(Activity context);
}
2、插件中的类实现上面接口并在重写关于上下文类引用的方法,使其使用已注册的aty去加载(抽象基类):
public class BaseActivity extends Activity implements PluginAtyInterface {
protected Activity that;
@Override
public void setContentView(int layoutResID) {
if (that == null) {
super.setContentView(layoutResID);
} else {
that.setContentView(layoutResID);
}
}
@Override
public <T extends View> T findViewById(int id) {
if (that == null) {
return super.findViewById(id);
} else {
return that.findViewById(id);
}
}
@Override
public ClassLoader getClassLoader() {
if (that == null) {
return super.getClassLoader();
} else {
return that.getClassLoader();
}
}
@Override
public WindowManager getWindowManager() {
if (that == null) {
return super.getWindowManager();
} else {
return that.getWindowManager();
}
}
@Override
public Window getWindow() {
if (that == null) {
return super.getWindow();
} else {
return that.getWindow();
}
}
@NonNull
@Override
public LayoutInflater getLayoutInflater() {
if (that == null) {
return super.getLayoutInflater();
} else {
return that.getLayoutInflater();
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
if (that == null) {
super.onCreate(savedInstanceState);
}
}
@Override
public void onDestroy() {
if (that == null) {
super.onDestroy();
}
}
@Override
public void onStart() {
if (that == null) {
super.onStart();
}
}
@Override
public void onStop() {
if (that == null) {
super.onStop();
}
}
@Override
public void onResume() {
if (that == null) {
super.onResume();
}
}
@Override
public void onRestart() {
if (that == null) {
super.onRestart();
}
}
public void attch(Activity context) {
this.that = context;
}
@Override
public void startActivity(Intent intent) {
if (that != null) {
Intent intent1 = new Intent();
intent1.putExtra(PluginApkManger.ClassName, intent.getComponent().getClassName());
that.startActivity(intent1);
} else {
super.startActivity(intent);
}
}
}
3、创建工具类用于从插件apk中获取到 包名+入口aty名、Resource、ClassLoder:
public class PluginApkManger {
String TAG = "PluginApkManger";
public static String ClassName="classname";
private static PluginApkManger pluginApkManger;
private String EntryName;
private String apkPath;
private AssetManager assetManager;
private Resources resources;
private ClassLoader classLoader;
private Context context;
public Resources getResources() {
return resources;
}
public static PluginApkManger getInstance() {
if (pluginApkManger == null) {
pluginApkManger = new PluginApkManger();
}
return pluginApkManger;
}
public void setContext(Context context) {
this.context = context;
}
//通过apk存放的路径初始化资源管理和类加载器
public void loadApk(String apkpath) {
this.apkPath = apkpath;
// 初始化Assetmanger和classLoader EntryName
//1
try {
//反射
AssetManager assetManager = AssetManager.class.newInstance();
Method getNameMethod = AssetManager.class.getMethod("addAssetPath", String.class);
Object name = getNameMethod.invoke(assetManager, apkPath);
if (name.toString().equals("0")) {
Log.i(TAG, "loadApk: " + "资源加载失败");
}
resources=new Resources(assetManager,context.getResources().getDisplayMetrics(),context.getResources().getConfiguration());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//2
File file = new File(apkPath);
File optimizedDirectoryFile = new File(file.getParentFile(), "optimizedDirectory");
if (!optimizedDirectoryFile.exists()) {
optimizedDirectoryFile.mkdir();
}
DexClassLoader dexClassLoader = new DexClassLoader(apkPath, optimizedDirectoryFile.getAbsolutePath(), null, context.getClassLoader());
this.classLoader = dexClassLoader;
//3获取入口类名
if(context!=null){
PackageManager packageManager=context.getPackageManager();
PackageInfo packageInfo=packageManager.getPackageArchiveInfo(apkPath,PackageManager.GET_ACTIVITIES);
EntryName=packageInfo.activities[0].name;
Log.i(TAG, "loadApk: "+EntryName);
}else{
Log.e(TAG, "loadApk: 没有注入上下文,请使用setContext方法" );
}
}
public String getEntryName() {
return EntryName;
}
public ClassLoader getClassLoader() {
return classLoader;
}
public AssetManager getAssetManager() {
return assetManager;
}
public void setApkPath(String apkPath) {
this.apkPath = apkPath;
}
public String getApkPath() {
return apkPath;
}
}
4、用于插桩的aty从先使用上面工具传入apkpath获得Resource和classloder、包名+类名
重写自身的getResource和getclassloder方法,通过反射及apk中的classloder和包名加载到apk包的aty,将其与自身通过attch绑定,将其强转为PluginAtyInterface,在生命周期的各个方法中调用aty强转后的PluginAtyInterface的各个对应方法,实现生命周期的绑定,重写StartActivity方法实现Apk中aty跳转(通过重写apk中的startactivity方法将要跳转的aty名字传给壳aty的StartActivity方法)。
public class KeAty extends Activity {
private String TAG="keaty";
private PluginAtyInterface pluginAtyInterface;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String classname=getIntent().getStringExtra(PluginApkManger.ClassName);
try {
//反射加载到类 获取实例
Class aty = getClassLoader().loadClass(classname);
Constructor constructor = aty.getConstructor(new Class[]{});
Object instance = constructor.newInstance(new Object[]{});
pluginAtyInterface = (PluginAtyInterface) instance;
pluginAtyInterface.attch(this);
Bundle bundle = new Bundle();
pluginAtyInterface.onCreate(bundle);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
public ClassLoader getClassLoader() {
return PluginApkManger.getInstance().getClassLoader();
}
@Override
protected void onDestroy() {
super.onDestroy();
pluginAtyInterface.onDestroy();
}
@Override
protected void onRestart() {
super.onRestart();
pluginAtyInterface.onRestart();
}
@Override
protected void onStop() {
super.onStop();
pluginAtyInterface.onStop();
}
@Override
protected void onStart() {
super.onStart();
pluginAtyInterface.onStart();
}
@Override
public Resources getResources() {
return PluginApkManger.getInstance().getResources();
}
@Override
protected void onResume() {
super.onResume();
pluginAtyInterface.onResume();
}
@Override
public void startActivity(Intent intent) {
Intent intent1=new Intent(this,KeAty.class);
Log.i(TAG, "startActivity: "+intent.getStringExtra(PluginApkManger.ClassName));
intent1.putExtra(PluginApkManger.ClassName,intent.getStringExtra(PluginApkManger.ClassName));
super.startActivity(intent1);
}
}