业务场景:在插件A 里面,我们想嵌入插件B 的视图。
1,先把插件B 的 Fragment 改造成 View,这样拿到 View 可以直接放到插件A 里面。
2,宿主里面依赖 support 包,其他插件全部不依赖 support 包(provided)。这样各个插件的 Fragment 可以通过反射相互填充了。
3,在插件A 反射调用插件B 的 Fragment 生命周期。
第一种方案,是最直接的,也是问题最少的。
第二种方案,也比较简单,不过需要注意 support 包的版本要统一,还有注意主题 Theme。
第三种方案,需要适配。
很多时候,我们碰到的业务场景是把一个插件的 Activity 内嵌到另一个插件的 Tab。正常我们把 Activity 改造成 View ,这样问题最少。但是有时候我们 Activity 用的是 MVVM,使用了 ViewModel,这样改造了,肯定会报错的。因为宿主和插件的 FragmentActivity 不是一个类的。这时候要么大改代码。要么考虑2,3两种方案了。
而如果这时候,我们不想发主版本,宿主和插件 support 包版本又不一致。
如果宿主的版本是比较大的,还可以直接升级下插件的 support 包就行了。
而如果宿主的比较小,或者不全,这样可以考虑第三种方案了。
单纯的 Fragment 代理,挺简单的。主要就是把插件 Fragment onCreateView 创建的 View 作为返回值就好了,其他生命周期再代理一下。
以下 v4 包源码,都是基于 28.0.0 版本。
public class Fragment {
FragmentHostCallback mHost;
public final FragmentActivity getActivity() {
// 看到 getActivity(),注意 mHost 不能为空。
return this.mHost == null ? null : (FragmentActivity)this.mHost.getActivity();
}
}
public class FragmentActivity extends SupportActivity {
// 注意到 FragmentActivity 初始化就会创建 FragmentController,里面就有一个 mHost
final FragmentController mFragments = FragmentController.createController(new FragmentActivity.HostCallbacks());
}
public class FragmentController {
private final FragmentHostCallback<?> mHost;
}
从源码,我们可以考虑把 FragmentActivity 的 mFragments.mHost 赋值给 Fragment 就行了。(最后会附带实现源码)
本身要用到 ViewModel 就得适配 getActivity(),不能返回空。
// 我们正常利用 ViewModelProviders 创建 VM
mViewModel = ViewModelProviders.of(this).get(UserInfoBarViewModel.class);
public class ViewModelProviders {
public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
// 注意 checkActivity checkApplication,会检查
Application application = checkApplication(checkActivity(fragment));
if (factory == null) {
factory = AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(ViewModelStores.of(fragment), (Factory)factory);
}
private static Activity checkActivity(Fragment fragment) {
// 这里会判断 getActivity() 不能为空,否则报错。
Activity activity = fragment.getActivity();
if (activity == null) {
throw new IllegalStateException("Can't create ViewModelProvider for detached fragment");
} else {
return activity;
}
}
}
VM 生命周期的实现就是注册监听,相关类主要就是 LiveData,Lifecycle,LifecycleRegistry。
// 正常我们监听某个属性变化,都是 LiveData.observe。
public abstract class LiveData<T> {
// LifecycleOwner 就是 FragmentActivity 或者 Fragment。
public void observe(LifecycleOwner owner, Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() != State.DESTROYED) {
LiveData<T>.LifecycleBoundObserver wrapper = new LiveData.LifecycleBoundObserver(owner, observer);
LiveData<T>.ObserverWrapper existing = (LiveData.ObserverWrapper)this.mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
} else if (existing == null) {
owner.getLifecycle().addObserver(wrapper);
}
}
}
}
public class Fragment implements LifecycleOwner {
LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
public Lifecycle getLifecycle() {
return this.mLifecycleRegistry;
}
}
public class FragmentActivity extends SupportActivity implements LifecycleOwner {
private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
public Lifecycle getLifecycle() {
return this.mLifecycleRegistry;
}
}
不管是 Fragment 还是 FragmentActivity,getLifecycle() 都是 LifecycleRegistry。
// 接着来看怎么调用 LifecycleRegistry 的。
public class Fragment {
void performCreate(Bundle savedInstanceState) {
this.onCreate(savedInstanceState);
......
// 都是通过调用 LifecycleRegistry.handleLifecycleEvent 方法来通知生命周期变化的
this.mLifecycleRegistry.handleLifecycleEvent(Event.ON_CREATE);
}
void performResume() {
this.onResume();
......
this.mLifecycleRegistry.handleLifecycleEvent(Event.ON_RESUME);
}
}
从源码,可以看出我们自己代理调用 mLifecycleRegistry.handleLifecycleEvent(Event) 就可以切换生命周期了。
1,自己创建一个 FragmentActivity。(因为2个插件的 ClassLoader 不一样,导致插件之间 FragmentActivity 就不一样了。)
2,把 FragmentActivity 的 mFragments.mHost 赋值给 Fragment.mHost。这样使得 getActivity() 不为空了。
3,把 Fragment 的 mLifecycleRegistry 赋值给 FragmentActivity,mLifecycleRegistry。
4,手动代理 Fragment 的生命周期,并手动调用 mLifecycleRegistry.handleLifecycleEvent(Event) ,使得 VM 正常。
插件 A 要使用 插件 B 的 XXXFragment,来展示。
再次强调 插件B v4 包源码,都是 28.0.0 版本。
插件 B 里面的代码:
// 要展示的 XXXFragment 继承 ExportFragment
public class ExportFragment extends Fragment {
protected FragmentActivityEx mActivityEx;
public FragmentActivityEx getActivityEx(Activity activity) {
if (mActivityEx == null) {
mActivityEx = FragmentActivityEx.buildActivityEx(activity, this);
}
return mActivityEx;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mActivityEx != null) {
mActivityEx.release();
}
}
}
// ContextUtils.getPluginAppContext() 就是当前插件(插件B)的 AppContext。
public class FragmentActivityEx extends FragmentActivity {
public Fragment mTargetFrag;
public static FragmentActivity buildActivityEx(Activity activity, Fragment fragment) {
FragmentActivityEx obj = new FragmentActivityEx();//通过反射创建对象
try {
Class clazz = Class.forName("android.content.ContextWrapper");
Field f = clazz.getDeclaredField("mBase");
f.setAccessible(true);
f.set(obj, activity);
} catch (Exception e) {
}
try {
// 4.4.4 空指针
Class clazz = Class.forName("android.view.ContextThemeWrapper");
Field f = clazz.getDeclaredField("mBase");
f.setAccessible(true);
f.set(obj, activity);
} catch (Exception e) {
}
try {
Class clazz = Class.forName("android.app.Activity");
Field f = clazz.getDeclaredField("mApplication");
f.setAccessible(true);
f.set(obj, ContextUtils.getPluginAppContext());
} catch (Exception e) {
}
try {
Field field = null;
Class csl = null;
// 步骤2,设置 Fragment 的 mHost。
csl = Class.forName("android.support.v4.app.FragmentActivity");
field = csl.getDeclaredField("mFragments");
field.setAccessible(true);
Object fControl = field.get(obj);
csl = Class.forName("android.support.v4.app.FragmentController");
field = csl.getDeclaredField("mHost");
field.setAccessible(true);
Object host = field.get(fControl);
csl = Class.forName("android.support.v4.app.Fragment");
field = csl.getDeclaredField("mHost");
field.setAccessible(true);
field.set(fragment, host);
// 步骤3,设置 ActivityEx 的 mLifecycleRegistry。
csl = Class.forName("android.support.v4.app.SupportActivity");
field = csl.getDeclaredField("mLifecycleRegistry");
field.setAccessible(true);
field.set(obj, fragment.getLifecycle());
} catch (Exception e) {
if (LogUtils.isDebug()) {
throw new RuntimeException(e);
}
}
return obj;
}
private Activity getSrcActivity() {
if (getBaseContext() instanceof Activity) {
return (Activity) getBaseContext();
}
if ((getBaseContext() instanceof ContextWrapper)
&& ((ContextWrapper) getBaseContext()).getBaseContext() instanceof Activity) {
return ((Activity) ((ContextWrapper) getBaseContext()).getBaseContext());
}
return null;
}
@Override
public boolean equals(Object obj) {
Activity activity = getSrcActivity();
if (activity != null) {
return activity.equals(obj);
}
return super.equals(obj);
}
@Override
public FragmentManager getSupportFragmentManager() {
// 为解决 glide 内存泄漏
return mTargetFrag.getChildFragmentManager();
}
public void release() {
try {
Field field = null;
Class csl = null;
// 设置 ActivityEx 的 LifecycleOwner
csl = Class.forName("android.support.v4.app.SupportActivity");
field = csl.getDeclaredField("mLifecycleRegistry");
field.setAccessible(true);
field.set(this, null);
} catch (Exception e) {
}
mTargetFrag = null;
}
@Override
public Intent getIntent() {
Activity activity = getSrcActivity();
if (activity != null) {
return activity.getIntent();
}
return super.getIntent();
}
@Override
public void finish() {
Activity activity = getSrcActivity();
if (activity != null) {
activity.finish();
}
super.finish();
}
@Override
public Window getWindow() {
Activity activity = getSrcActivity();
if (activity != null) {
return activity.getWindow();
}
return super.getWindow();
}
@Override
public WindowManager getWindowManager() {
Activity activity = getSrcActivity();
if (activity != null) {
return activity.getWindowManager();
}
return super.getWindowManager();
}
@Override
public Context getApplicationContext() {
return ContextUtils.getPluginAppContext();
}
@Override
public Resources getResources() {
return ContextUtils.getPluginAppContext().getResources();
}
@Override
public AssetManager getAssets() {
return ContextUtils.getPluginAppContext().getAssets();
}
@Override
public LayoutInflater getLayoutInflater() {
return LayoutInflater.from(ContextUtils.getPluginAppContext()).cloneInContext(ContextUtils.getPluginAppContext());
}
@Override
public Object getSystemService(String name) {
// Dialog WindowManager$BadTokenException
if (LAYOUT_INFLATER_SERVICE.equals(name)) {
return getLayoutInflater();
}
Activity activity = getSrcActivity();
if (activity != null) {
return activity.getSystemService(name);
}
return super.getSystemService(name);
}
@Override
public Resources.Theme getTheme() {
return ContextUtils.getPluginAppContext().getTheme();
}
@Override
public ComponentName getComponentName() {
// 4.4.4闪退
// NullPointerException
// ApplicationPackageManager.getActivityInfo
// ContentViewCore.hasHardwareAcceleration android.webkit.WebView.init
// com.baidu.mobads.container.ae.
Activity activity = getSrcActivity();
if (activity != null) {
return activity.getComponentName();
}
return super.getComponentName();
}
@Override
public void startActivity(Intent intent) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ContextUtils.getPluginAppContext().startActivity(intent);
}
@Override
public void startActivity(Intent intent, Bundle options) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ContextUtils.getPluginAppContext().startActivity(intent, options);
}
}
插件 A 里面的代码:
// 步骤4,手动调用生命周期。
// 直接调用 FragmentProxy.create 方法,就创建了一个代理 Fragment。
public class FragmentProxy extends Fragment {
private static final String TAG = "FragmentProxy";
private static final String ARGS_KEY_CLS = "cls";
private static final String PLUGIN_NAME = "插件B包名";
public static final String FRAGMENT_CLASS_NAME = "插件B.XXXFragment";
public static Fragment create(String className) {
AnswerFragmentProxy proxy = new AnswerFragmentProxy();
Bundle args = new Bundle();
args.putString(ARGS_KEY_CLS, className);
proxy.setArguments(args);
return proxy;
}
private Object target;
private Object targetAtyEx;
public void createTarget(String className) {
try {
Field field = null;
Class csl = null;
Context tContext = RePlugin.fetchContext(PLUGIN_NAME);
csl = Class.forName(className, false, tContext.getClassLoader());
target = csl.newInstance();
Object atyEx = ReflectUtils.invokeMethod(target, "getActivityEx", new Class[]{Activity.class}, new Object[]{getActivity()});
} catch (Exception e) {
}
}
public View getTargetView() {
try {
Field field = null;
Class csl = null;
Context tContext = RePlugin.fetchContext(PLUGIN_NAME);
csl = Class.forName("android.support.v4.app.Fragment", false, tContext.getClassLoader());
field = csl.getDeclaredField("mView");
field.setAccessible(true);
return (View) field.get(target);
} catch (Exception e) {
}
return null;
}
public void release() {
try {
Field field = null;
Class csl = null;
Context tContext = RePlugin.fetchContext(PLUGIN_NAME);
csl = Class.forName("android.support.v4.app.Fragment", false, tContext.getClassLoader());
field = csl.getDeclaredField("mHost");
field.setAccessible(true);
field.set(target, null);
} catch (Exception e) {
}
target = null;
targetAtyEx = null;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
createTarget(getArguments().getString(ARGS_KEY_CLS));
if (target != null) {
ReflectUtils.invokeMethod(target, "performCreate", new Class[]{Bundle.class}, new Object[]{savedInstanceState});
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (target != null) {
// 拿到 插件B 的 inflate。
Object inflaterObj = ReflectUtils.invokeMethod(targetAtyEx, "getLayoutInflater", null);
ReflectUtils.invokeMethod(target, "performCreateView", new Class[]{LayoutInflater.class, ViewGroup.class, Bundle.class}, new Object[]{inflaterObj, container, savedInstanceState});
return getTargetView();
}
return null;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
if (target != null) {
ReflectUtils.invokeMethod(target, "onViewCreated", new Class[]{View.class, Bundle.class}, new Object[]{view, savedInstanceState});
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (target != null) {
ReflectUtils.invokeMethod(target, "performActivityCreated", new Class[]{Bundle.class}, new Object[]{savedInstanceState});
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (target != null) {
ReflectUtils.invokeMethod(target, "onAttach", new Class[]{Context.class}, new Object[]{context});
}
}
@Override
public void onResume() {
super.onResume();
if (target != null) {
ReflectUtils.invokeMethod(target, "performResume", null);
}
}
@Override
public void onStart() {
super.onStart();
if (target != null) {
ReflectUtils.invokeMethod(target, "performStart", null);
}
}
@Override
public void onPause() {
super.onPause();
if (target != null) {
ReflectUtils.invokeMethod(target, "performPause", null);
}
}
@Override
public void onStop() {
super.onStop();
if (target != null) {
ReflectUtils.invokeMethod(target, "performStop", null);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (target != null) {
ReflectUtils.invokeMethod(target, "performDestroy", null);
release();
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (target != null) {
ReflectUtils.invokeMethod(target, "performDestroyView", null);
}
}
@Override
public void onDetach() {
super.onDetach();
if (target != null) {
ReflectUtils.invokeMethod(target, "performDetach", null);
}
}
}
-keep class android.support.v4.app.FragmentActivity { android.support.v4.app.FragmentController mFragments;}
-keep class android.support.v4.app.Fragment {*;}
-keep class android.support.v4.app.FragmentController {android.support.v4.app.FragmentHostCallback mHost;}
-keep class android.support.v4.app.SupportActivity {android.arch.lifecycle.LifecycleRegistry mLifecycleRegistry;}
-keep class android.arch.lifecycle.LifecycleRegistry {<methods>;}
-keep class com.xxx.ExportFragment {*;}
-keep class * extends com.xxx.ExportFragment {<methods>;}