package com.tws.plugin.core;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import tws.component.log.TwsLog;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Application;
import android.app.Fragment;
import android.app.Instrumentation;
import android.app.Service;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.UserHandle;
import android.text.TextUtils;
import com.tws.plugin.bridge.TwsPluginBridgeActivity;
import com.tws.plugin.content.ComponentInfo;
import com.tws.plugin.content.PluginDescriptor;
import com.tws.plugin.core.android.HackContextImpl;
import com.tws.plugin.core.android.HackInstrumentation;
import com.tws.plugin.core.annotation.PluginContainer;
import com.tws.plugin.core.localservice.LocalServiceManager;
import com.tws.plugin.core.viewfactory.PluginViewFactory;
import com.tws.plugin.manager.PluginActivityMonitor;
import com.tws.plugin.manager.PluginManagerHelper;
import com.tws.plugin.util.ProcessUtil;
/**
* 插件Activity免注册的主要实现原理。 如有必要,可以增加被代理的方法数量。
*
* @author yongchen
*
*/
public class PluginInstrumentionWrapper extends Instrumentation {
private static final String RELAUNCH_FLAG = "relaunch.category.";
private static final String TAG = "rick_Print:PluginInstrumentionWrapper";
private final HackInstrumentation hackInstrumentation;
private PluginActivityMonitor monitor;
public PluginInstrumentionWrapper(Instrumentation instrumentation) {
this.hackInstrumentation = new HackInstrumentation(instrumentation);
this.monitor = new PluginActivityMonitor();
}
/**
*
* @param app
*/
@Override
public void callApplicationOnCreate(Application app) {
// 此方法在application的attach之后被ActivityThread调用
super.callApplicationOnCreate(app);
if (ProcessUtil.isPluginProcess()) {
Iterator<PluginDescriptor> itr = PluginManagerHelper.getPlugins().iterator();
while (itr.hasNext()) {
PluginDescriptor plugin = itr.next();
LocalServiceManager.registerService(plugin);
}
}
}
@Override
public boolean onException(Object obj, Throwable e) {
if (obj instanceof Activity) {
((Activity) obj).finish();
} else if (obj instanceof Service) {
((Service) obj).stopSelf();
}
TwsLog.e(TAG, "记录错误日志", e);
return super.onException(obj, e);
}
@Override
public Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException,
IllegalAccessException, ClassNotFoundException {
if (ProcessUtil.isPluginProcess()) {
PluginDescriptor pluginDescriptor = PluginManagerHelper.getPluginDescriptorByClassName(className);
if (pluginDescriptor != null) {
return PluginLauncher.instance().getRunningPlugin(pluginDescriptor.getPackageName()).pluginApplication;
}
}
return super.newApplication(cl, className, context);
}
@Override
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException,
IllegalAccessException, ClassNotFoundException {
ClassLoader orignalCl = cl;
String orginalClassName = className;
String orignalIntent = intent.toString();
if (ProcessUtil.isHostProcess() && TwsPluginBridgeActivity.class.getName().equals(className)) {
// 第三方应用启动了TwsPluginBridgeActivity
String packageName = PluginLoader.getPackageName(intent);
ArrayList<ComponentInfo> componentInfos = PluginIntentResolver.matchPlugin(intent, PluginDescriptor.ACTIVITY,
packageName);
String pluginClassName = null;
if (componentInfos != null && componentInfos.size() > 0) {
pluginClassName = componentInfos.get(0).name;
}
if (null == pluginClassName) {
pluginClassName = intent.getStringExtra(PluginIntentResolver.INTENT_EXTRA_BRIDGE_TO_PLUGIN);
}
if (pluginClassName != null) {
PluginDescriptor pluginDescriptor = PluginManagerHelper.getPluginDescriptorByClassName(pluginClassName);
if (pluginDescriptor != null) {
packageName = pluginDescriptor.getPackageName();
Class<?> clazz = PluginLoader.loadPluginClassByName(pluginDescriptor, pluginClassName);
if (clazz != null) {
intent.putExtra(PluginIntentResolver.INTENT_EXTRA_BRIDGE_RAMP, className);
className = pluginClassName;
cl = clazz.getClassLoader();
intent.setExtrasClassLoader(cl);
intent.setAction(null);
// 添加一个标记符
intent.addCategory(RELAUNCH_FLAG + className);
} else {
throw new ClassNotFoundException("pluginClassName : " + pluginClassName, new Throwable());
}
}
}
} else if (ProcessUtil.isPluginProcess()) {
// 将PluginStubActivity替换成插件中的activity
if (PluginManagerHelper.isStub(className)) {
String action = intent.getAction();
TwsLog.d(TAG, "newActivity action=" + action + " className=" + className);
if (action != null && action.contains(PluginIntentResolver.CLASS_SEPARATOR)) {
String[] targetClassName = action.split(PluginIntentResolver.CLASS_SEPARATOR);
String pluginClassName = targetClassName[0];
final String pid = targetClassName.length > 2 ? targetClassName[2] : "";
PluginDescriptor pluginDescriptor = null;
if (!TextUtils.isEmpty(pid)) {
pluginDescriptor = PluginManagerHelper.getPluginDescriptorByPluginId(pid);
}
if (null == pluginDescriptor) {
pluginDescriptor = PluginManagerHelper.getPluginDescriptorByClassName(pluginClassName);
}
Class<?> clazz = PluginLoader.loadPluginClassByName(pluginDescriptor, pluginClassName);
if (clazz != null) {
className = pluginClassName;
cl = clazz.getClassLoader();
intent.setExtrasClassLoader(cl);
if (targetClassName.length > 1) {
// 之前为了传递classNae,intent的action被修改过
// 这里再把Action还原到原始的Action
intent.setAction(targetClassName[1]);
} else {
intent.setAction(null);
}
// 添加一个标记符
intent.addCategory(RELAUNCH_FLAG + className);
} else {
throw new ClassNotFoundException("pluginClassName : " + pluginClassName, new Throwable());
}
} else if (PluginManagerHelper.isExact(className, PluginDescriptor.ACTIVITY)) {
// 这个逻辑是为了支持外部app唤起配置了stub_exact的插件Activity
PluginDescriptor pluginDescriptor = PluginManagerHelper.getPluginDescriptorByClassName(className);
Class<?> clazz = PluginLoader.loadPluginClassByName(pluginDescriptor, className);
if (clazz != null) {
cl = clazz.getClassLoader();
} else {
throw new ClassNotFoundException("className : " + className, new Throwable());
}
} else {
// 进入这个分支可能是因为activity重启了,比如横竖屏切换,由于上面的分支已经把Action还原到原始到Action了
// 这里只能通过之前添加的标记符来查找className
boolean found = false;
Set<String> category = intent.getCategories();
if (category != null) {
Iterator<String> itr = category.iterator();
while (itr.hasNext()) {
String cate = itr.next();
if (cate.startsWith(RELAUNCH_FLAG)) {
className = cate.replace(RELAUNCH_FLAG, "");
PluginDescriptor pluginDescriptor = PluginManagerHelper
.getPluginDescriptorByClassName(className);
Class<?> clazz = PluginLoader.loadPluginClassByName(pluginDescriptor, className);
cl = clazz.getClassLoader();
found = true;
break;
}
}
}
if (!found) {
throw new ClassNotFoundException(
"className : " + className + ", intent : " + intent.toString(), new Throwable());
}
}
} else {
// 到这里有2中种情况
// 1、确实是宿主Activity
// 2、是插件Activity,但是上面的if没有识别出来(这种情况目前只发现在ActivityGroup情况下会出现,因为ActivityGroup不会触发resolveActivity方法,导致Intent没有更换)
// 判断上述两种情况可以通过ClassLoader的类型来判断, 判断出来以后补一个resolveActivity方法
if (cl instanceof PluginClassLoader) {
PluginIntentResolver.resolveActivity(intent);
} else {
// Do Nothing
}
}
}
try {
Activity activity = super.newActivity(cl, className, intent);
if (activity instanceof PluginContainer) {
((PluginContainer) activity).setPluginId(intent.getStringExtra(PluginContainer.FRAGMENT_PLUGIN_ID));
}
return activity;
} catch (ClassNotFoundException e) {
// 收集状态,便于异常分析
throw new ClassNotFoundException(" orignalCl : " + orignalCl.toString() + ", orginalClassName : "
+ orginalClassName + ", orignalIntent : " + orignalIntent + ", currentCl : " + cl.toString()
+ ", currentClassName : " + className + ", currentIntent : " + intent.toString() + ", process : "
+ ProcessUtil.isPluginProcess() + ", isStubActivity : "
+ PluginManagerHelper.isStub(orginalClassName) + ", isExact : "
+ PluginManagerHelper.isExact(orginalClassName, PluginDescriptor.ACTIVITY), e);
}
}
@Override
public void callActivityOnCreate(Activity activity, Bundle icicle) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
PluginInjector.injectActivityContext(activity);
Intent intent = activity.getIntent();
if (intent != null) {
intent.setExtrasClassLoader(activity.getClassLoader());
}
if (icicle != null) {
icicle.setClassLoader(activity.getClassLoader());
}
if (ProcessUtil.isPluginProcess()) {
installPluginViewFactory(activity);
if (activity.isChild()) {
// 修正TabActivity中的Activity的ContextImpl的packageName
Context base = activity.getBaseContext();
while (base instanceof ContextWrapper) {
base = ((ContextWrapper) base).getBaseContext();
}
if (HackContextImpl.instanceOf(base)) {
HackContextImpl impl = new HackContextImpl(base);
String packageName = PluginLoader.getApplication().getPackageName();
// String packageName1 = activity.getPackageName();
impl.setBasePackageName(packageName);
impl.setOpPackageName(packageName);
}
}
}
super.callActivityOnCreate(activity, icicle);
monitor.onActivityCreate(activity);
}
private void installPluginViewFactory(Activity activity) {
String pluginId = null;
if (activity instanceof PluginContainer) {
pluginId = ((PluginContainer) activity).getPluginId();
}
// 如果配置了插件容器注解而且指定了插件Id, 框架会自动更换activity的context,无需安装PluginViewFactory
if (TextUtils.isEmpty(pluginId)) {
new PluginViewFactory(activity, activity.getWindow(), new PluginViewCreator()).installViewFactory();
}
}
@Override
public void callActivityOnDestroy(Activity activity) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
monitor.onActivityDestory(activity);
super.callActivityOnDestroy(activity);
}
@Override
public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
if (savedInstanceState != null) {
savedInstanceState.setClassLoader(activity.getClassLoader());
}
super.callActivityOnRestoreInstanceState(activity, savedInstanceState);
}
@Override
public void callActivityOnPostCreate(Activity activity, Bundle icicle) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
if (icicle != null) {
icicle.setClassLoader(activity.getClassLoader());
}
super.callActivityOnPostCreate(activity, icicle);
}
@Override
public void callActivityOnNewIntent(Activity activity, Intent intent) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
if (intent != null) {
intent.setExtrasClassLoader(activity.getClassLoader());
}
super.callActivityOnNewIntent(activity, intent);
}
@Override
public void callActivityOnStart(Activity activity) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
super.callActivityOnStart(activity);
}
@Override
public void callActivityOnRestart(Activity activity) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
super.callActivityOnRestart(activity);
}
@Override
public void callActivityOnResume(Activity activity) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
super.callActivityOnResume(activity);
monitor.onActivityResume(activity);
}
@Override
public void callActivityOnStop(Activity activity) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
super.callActivityOnStop(activity);
}
@Override
public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
if (outState != null) {
outState.setClassLoader(activity.getClassLoader());
}
super.callActivityOnSaveInstanceState(activity, outState);
}
@Override
public void callActivityOnPause(Activity activity) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
super.callActivityOnPause(activity);
monitor.onActivityPause(activity);
}
@Override
public void callActivityOnUserLeaving(Activity activity) {
PluginInjector.injectInstrumetionFor360Safe(activity, this);
super.callActivityOnUserLeaving(activity);
}
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
PluginIntentResolver.resolveActivity(intent);
return hackInstrumentation.execStartActivity(who, contextThread, token, target, intent, requestCode, options);
}
public void execStartActivities(Context who, IBinder contextThread, IBinder token, Activity target,
Intent[] intents, Bundle options) {
PluginIntentResolver.resolveActivity(intents);
hackInstrumentation.execStartActivities(who, contextThread, token, target, intents, options);
}
public void execStartActivitiesAsUser(Context who, IBinder contextThread, IBinder token, Activity target,
Intent[] intents, Bundle options, int userId) {
PluginIntentResolver.resolveActivity(intents);
hackInstrumentation.execStartActivitiesAsUser(who, contextThread, token, target, intents, options, userId);
}
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Fragment target,
Intent intent, int requestCode, Bundle options) {
PluginIntentResolver.resolveActivity(intent);
return hackInstrumentation.execStartActivity(who, contextThread, token, target, intent, requestCode, options);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options, UserHandle user) {
PluginIntentResolver.resolveActivity(intent);
return hackInstrumentation.execStartActivity(who, contextThread, token, target, intent, requestCode, options,
user);
}
// /////////// Android 4.0.4及以下 ///////////////
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode) {
PluginIntentResolver.resolveActivity(intent);
return hackInstrumentation.execStartActivity(who, contextThread, token, target, intent, requestCode);
}
public void execStartActivities(Context who, IBinder contextThread, IBinder token, Activity target, Intent[] intents) {
PluginIntentResolver.resolveActivity(intents);
hackInstrumentation.execStartActivities(who, contextThread, token, target, intents);
}
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Fragment target,
Intent intent, int requestCode) {
PluginIntentResolver.resolveActivity(intent);
return hackInstrumentation.execStartActivity(who, contextThread, token, target, intent, requestCode);
}
// ///// For Android 5.1
public ActivityResult execStartActivityAsCaller(Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options, int userId) {
PluginIntentResolver.resolveActivity(intent);
return hackInstrumentation.execStartActivityAsCaller(who, contextThread, token, target, intent, requestCode,
options, userId);
}
public void execStartActivityFromAppTask(Context who, IBinder contextThread, Object appTask, Intent intent,
Bundle options) {
PluginIntentResolver.resolveActivity(intent);
hackInstrumentation.execStartActivityFromAppTask(who, contextThread, appTask, intent, options);
}
}