宿主程序提供一个代理Activity:
public class ProxyActivity extends AppCompatActivity {
private static final String TAG = "ProxyActivity";
public static final String FROM = "extra.from";
public static final int FROM_EXTERNAL = 0;
public static final int FROM_INTERNAL = 1;
public static final String EXTRA_DEX_PATH = "extra.dex.path";
public static final String EXTRA_CLASS = "extra.class";
private String mClass;
private String mDexPath;
//远程Activity
private Activity remoteActivity;
//生命周期相关的方法
private Map<String, Method> mActivityLifecircleMethods = new HashMap<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDexPath = getIntent().getStringExtra(EXTRA_DEX_PATH);
mClass = getIntent().getStringExtra(EXTRA_CLASS);
if (mClass != null) {
launchTargetActivity(mClass);
}
}
//activity的命名规则是:全包名+类名,例如 com.example.client.MainActivity
protected void launchTargetActivity(final String className) {
File dexOutputDir = this.getDir("dex", 0);
final String dexOutputPath = dexOutputDir.getAbsolutePath();
ClassLoader localClassLoader = ClassLoader.getSystemClassLoader();
DexClassLoader dexClassLoader = new DexClassLoader(mDexPath,
dexOutputPath, null, localClassLoader);
try {
Class<?> remoteClass = dexClassLoader.loadClass(className);
Constructor<?> remoteConstructor = localClass.getConstructor(new Class[]{});
//创建远程Activity
Object instance = remoteConstructor.newInstance(new Object[]{});
remoteActivity = (Activity) instance;
//设置远程Activity的代理,即ProxyActivity
Method setProxy = remoteClass.getMethod("setProxy", new Class[]{Activity.class});
setProxy.setAccessible(true);
setProxy.invoke(instance, new Object[]{this});
//手动执行远程Activity的onCreate方法
Method onCreate = remoteClass.getDeclaredMethod("onCreate", new Class[]{Bundle.class});
onCreate.setAccessible(true);
Bundle bundle = new Bundle();
bundle.putInt(FROM, FROM_EXTERNAL);
onCreate.invoke(instance, new Object[]{bundle});
} catch (Exception e) {
e.printStackTrace();
}
}
//localClass就是从APK中解析出的Activity的Class对象
//这个方法将这个Activity中的生命周期相关的方法都取出来放进一个Map;
protected void bindLifecircleMethods(Class<?> localClass) {
String[] methodNames = new String[]{
"onRestart",
"onStart",
"onResume",
"onPause",
"onStop",
"onDestory"
};
for (String methodName : methodNames) {
Method method = null;
try {
method = localClass.getDeclaredMethod(methodName, new Class[]{});
method.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
mActivityLifecircleMethods.put(methodName, method);
}
Method onCreate = null;
try {
onCreate = localClass.getDeclaredMethod("onCreate", new Class[]{Bundle.class});
onCreate.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
mActivityLifecircleMethods.put("onCreate", onCreate);
Method onActivityResult = null;
try {
onActivityResult = localClass.getDeclaredMethod("onActivityResult",
new Class[]{int.class, int.class, Intent.class});
onActivityResult.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
mActivityLifecircleMethods.put("onActivityResult", onActivityResult);
}
@Override
//这里在Proxy执行生命周期相关的方法时调用远程Activity的生命周期方法就可以了
protected void onResume() {
super.onResume();
Method onResume = mActivityLifecircleMethods.get("onResume");
if (onResume != null) {
try {
onResume.invoke(mRemoteActivity, new Object[]{});
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void launch(Activity activity, String url, String clazz) {
Intent intent = new Intent(activity, ProxyActivity.class);
intent.putExtra(EXTRA_DEX_PATH, url);
intent.putExtra(EXTRA_CLASS, clazz);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
}
}
远程Activity在宿主程序看来就是一个普通的类,并不具有生命周期,所以需要在ProxyActivity中生命周期方法中手动调用远程Activity的生命周期方法;
另外可以考虑使用Fragment来实现页面,因为ProxyActivity会自动管理Fragment的生命周期,不用手动通过反射去调用;
插件程序实现:
首先创建一个BaseActivity:
public class BaseActivity extends Activity {
public static final String FROM = "extra.from";
public static final int FROM_INTERNAL = 1;
protected Activity mProxyActivity;
protected int mFrom = FROM_INTERNAL;
public void setProxy(Activity proxyActivity) {
mProxyActivity = proxyActivity;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
mFrom = savedInstanceState.getInt(FROM, FROM_INTERNAL);
}
if (mFrom == FROM_INTERNAL) {
super.onCreate(savedInstanceState);
mProxyActivity = this;
}
}
@Override
public void setContentView(View view) {
if (mProxyActivity == this) {
super.setContentView(view);
} else {
mProxyActivity.setContentView(view);
}
}
@Override
public void setContentView(View view, LayoutParams params) {
if (mProxyActivity == this) {
super.setContentView(view, params);
} else {
mProxyActivity.setContentView(view, params);
}
}
@Override
public void addContentView(View view, LayoutParams params) {
if (mProxyActivity == this) {
super.addContentView(view, params);
} else {
mProxyActivity.addContentView(view, params);
}
}
}
创建入口Activity:
public class MainActivity extends BaseActivity {
private static final String TAG = "Client-MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mProxyActivity.setContentView(new LinearLayout(context));
}
@Override
protected void onResume() {
super.onResume(savedInstanceState);
Log.e("ClientMainActivity","onResumeTest");
}
}
然后记得在宿主程序动态申请sd卡权限否则调用不会成功
将这个程序打包成APK放在sd卡根目录下,在宿主程序中执行打开ProxyActivity,发现程序跳转到了插件程序页面
参考:
https://blog.csdn.net/singwhatiwanna/article/details/22597587