一、结构介绍
Shadow是19年腾讯开源的自研Android插件化结构,经过线上亿级用户量检验。 Shadow不只开源共享了插件技术的要害代码,还完整的共享了上线部署所需求的一切规划。
项目地址:github.com/Tencent/Sha…
长处: 1)复用独立安装app源码。 2)少反射、0hook。侵入性低,体系兼容性好; 3)全动态结构规划(runtime的动态化有1处hook)。结构自身迭代也支撑动态化,宿主增量极小(15K左右); 4)插件支撑运转在独立进程。与宿主运转环境阻隔,稳定性高。
缺点: 1)接入本钱高。没有完善的接入文档,demo也过于杂乱;没有官方maven依靠,需求开发者自行发布维护; 2)现在结构现已没有迭代维护,虽然现在功用现已比较完整稳定性也很高,可是特定事务场景下还是会遇到功用不完善的状况,需求自行迭代; 3)全动态化规划版本操控更杂乱了; 4)宿主环境阻隔带来的插件多进程约束。
二、Shadow结构全体规划
宿主
- host: 加载manager插件;
- manager: 跨进程完成插件包全体的加载;
插件
- runtime: activity署理转发全体完成计划;
- loader: 负责加载插件;
- plugin: 事务插件(支撑多个);
全体流程:宿主负责下载manager和插件,先动态加载manager,经过它再ipc动态加载插件中的runtime和loader,再经过loader加载插件。其间插件全体打包为一个zip包,zip包结构:
三、结构加载插件流程
#####3.1 宿主经过host加载manager:
中心办法:
final class ManagerImplLoader extends ImplLoader {
PluginManagerImpl load() {
ApkClassLoader apkClassLoader = new ApkClassLoader(
installedApk,
getClass().getClassLoader(),
loadWhiteList(installedApk),
1
);
Context pluginManagerContext = new ChangeApkContextWrapper(
applicationContext,
installedApk.apkFilePath,
apkClassLoader
);
try {
ManagerFactory managerFactory = apkClassLoader.getInterface(
ManagerFactory.class,
MANAGER_FACTORY_CLASS_NAME
);
return managerFactory.buildManager(pluginManagerContext);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
这儿首要功用是加载manager插件,中心完成首要3块:
- 1)manager专用插件加载器ApkClassLoader的类加载完成;
- 2)上下文封装
- 3)加载插件进口类完成.
1)manager专用插件加载器ApkClassLoader的类加载完成;
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
String packageName;
int dot = className.lastIndexOf('.');
if (dot != -1) {
packageName = className.substring(0, dot);
} else {
packageName = "";
}
boolean isInterface = false;
for (String interfacePackageName : mInterfacePackageNames) {
if (packageName.equals(interfacePackageName)) {
isInterface = true;
break;
}
}
if (isInterface) {
// 白名单,则经过父类(即:宿主ClassLoader加载)
return super.loadClass(className, resolve);
} else {
// 查询是否被插件ClassLoader现已加载,已加载则直接获取回来
Class<?> clazz = findLoadedClass(className);
if (clazz == null) {
ClassNotFoundException suppressed = null;
try {
// 插件ClassLoader从自己类途径中查找
clazz = findClass(className);
} catch (ClassNotFoundException e) {
suppressed = e;
}
if (clazz == null) {
try {
// 从parent的parent ClassLoader中查找
clazz = mGrandParent.loadClass(className);
} catch (ClassNotFoundException e) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
e.addSuppressed(suppressed);
}
throw e;
}
}
}
return clazz;
}
}
这儿插件加载规划首要处理两个问题:
-
插件怎么拜访宿主类? 插件怎么拜访宿主的类,首要遵循类加载双亲派遣准则,这儿把宿主ClassLoader设置为ApkClassLoader的父类来完成。
-
插件假如有类和宿主同名,假如处理类抵触,坚持插件加载自己的类? 引进白名单,在白名单中走正常双亲派遣(即:宿主优先),不在白名单,则从宿主classLoader的父classLoader中查找,查找不到再从自己中查找(即:插件优先)。
2)上下文封装
其间Resource获取是经过:
private Resources createResources(String apkPath, Context base) {
PackageManager packageManager = base.getPackageManager();
PackageInfo packageArchiveInfo = packageManager.getPackageArchiveInfo(apkPath, GET_META_DATA);
packageArchiveInfo.applicationInfo.publicSourceDir = apkPath;
packageArchiveInfo.applicationInfo.sourceDir = apkPath;
try {
return packageManager.getResourcesForApplication(packageArchiveInfo.applicationInfo);
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
}
3)加载插件进口类完成
private static final String MANAGER_FACTORY_CLASS_NAME = "com.tencent.shadow.dynamic.impl.ManagerFactoryImpl";
try {
ManagerFactory managerFactory = apkClassLoader.getInterface(
ManagerFactory.class,
MANAGER_FACTORY_CLASS_NAME
);
return managerFactory.buildManager(pluginManagerContext);
} catch (Exception e) {
throw new RuntimeException(e);
}
// 从插件manager apk中读取进口类接口完成
public <T> T getInterface(Class<T> clazz, String className) throws Exception {
try {
Class<?> interfaceImplementClass = loadClass(className);
Object interfaceImplement = interfaceImplementClass.newInstance();
return clazz.cast(interfaceImplement);
} catch (ClassNotFoundException | InstantiationException
| ClassCastException | IllegalAccessException e) {
throw new Exception(e);
}
}
其间:ManagerFactory是宿主中的类,它的完成类ManagerFactoryImpl在插件manager中,他们的完成别离是:
// host
public interface ManagerFactory {
PluginManagerImpl buildManager(Context context);
}
// manager插件
public final class ManagerFactoryImpl implements ManagerFactory {
@Override
public PluginManagerImpl buildManager(Context context) {
return new SamplePluginManager(context);
}
}
至此,经过host的DynamicPluginManager enter 加载了manager插件进口类SamplePluginManager,然后以它作为署理完成类,真实履行enter。
public final class DynamicPluginManager implements PluginManager {
private PluginManagerImpl mManagerImpl;
@Override
public void enter(Context context, long fromId, Bundle bundle, EnterCallback callback) {
if (mLogger.isInfoEnabled()) {
mLogger.info("enter fromId:" + fromId + " callback:" + callback);
}
updateManagerImpl(context);
mManagerImpl.enter(context, fromId, bundle, callback);
mUpdater.update();
}
3.2 manager解析插件包
SamplePluginManager enter办法进入后中心完成流程如下:
private void onStartActivity(final Context context, Bundle bundle, final EnterCallback callback) {
final String pluginZipPath = bundle.getString(Constant.KEY_PLUGIN_ZIP_PATH);
final String partKey = bundle.getString(Constant.KEY_PLUGIN_PART_KEY);
final String className = bundle.getString(Constant.KEY_ACTIVITY_CLASSNAME);
if (className == null) {
throw new NullPointerException("className == null");
}
final Bundle extras = bundle.getBundle(Constant.KEY_EXTRAS);
if (callback != null) {
final View view = LayoutInflater.from(mCurrentContext).inflate(R.layout.activity_load_plugin, null);
callback.onShowLoadingView(view);
}
executorService.execute(new Runnable() {
@Override
public void run() {
try {
// 1解析插件包
InstalledPlugin installedPlugin = installPlugin(pluginZipPath, null, true);
// 2加载插件
loadPlugin(installedPlugin.UUID, PART_KEY_PLUGIN_BASE);
// 3拉起插件application及进口activity
callApplicationOnCreate(PART_KEY_PLUGIN_BASE);
Intent pluginIntent = new Intent();
pluginIntent.setClassName(
context.getPackageName(),
className
);
if (extras != null) {
pluginIntent.replaceExtras(extras);
}
Intent intent = mPluginLoader.convertActivityIntent(pluginIntent);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mPluginLoader.startActivityInPluginProcess(intent);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (callback != null) {
callback.onCloseLoadingView();
}
}
});
}
这儿先看installPlugin办法完成的插件包解析,首要有3块:
- 1)解析插件zip包
- 2)尝试对插件dex进行预编译
- 3)解压apk中so
1)解析插件zip包
这儿首要是解析config.json装备文件,封装PluginConfig
2)尝试对插件dex进行odex预编译 编译的apk包括:runtime、loader、plugin(可能有多个) 触发编译条件:< android 8.1 预编译完成:
com.tencent.shadow.core.manager.installplugin.ODexBloc#oDexPlugin
public static void oDexPlugin(File apkFile, File oDexDir, File copiedTagFile) throws InstallPluginException {
...
new DexClassLoader(apkFile.getAbsolutePath(), oDexDir.getAbsolutePath(), null, ODexBloc.class.getClassLoader());
...
}
编译完成流程参考:
DexClassLoader初始化会触发Dex加载,Dex加载在android 10以下版本会强行走odex预编译。
3)解压apk中so 中心办法: com.tencent.shadow.core.manager.installplugin.CopySoBloc#copySo 将so解压到如下目录: /data/user/0/com.tencent.shadow.sample.host/files/ShadowPluginManager/UnpackedPlugin/test-dynamic-manager
这儿dex编译和so提取均经过Feature来做异步处理,一切成果都回来后才进行后续流程。
经过插件包解析,终究构建InstalledPlugin数据结构保存插件相关信息,这儿别离经过pluginLoaderFile、plugins、runtimeFile别离保存loader、plugin、runtime插件信息详情
3.3 manager跨进程加载插件规划
在正式加载插件之前,会拉起一个插件环境的服务,该服务装备在宿主androidManifest.xml中
<service
android:name="com.tencent.shadow.sample.host.PluginProcessPPS"
android:process=":plugin" />
manager插件经过getPluginProcessServiceName装备匹配的插件环境服务,然后经过bindPluginProcessService绑定服务。
if (mPpsController == null) {
bindPluginProcessService(getPluginProcessServiceName(partKey));
// 服务绑定超时处理
waitServiceConnected(10, TimeUnit.SECONDS);
}
PluginProcessPPS承继自PluginProgressService,中心功用完成在PluginProgressService,首要跨进程加载插件的runtime和loader两个部分。
这儿跨进程规划计划如下: 1)宿主binder call触发插件进程建议runtime、loader插件加载,而插件加载需求binder call到宿首要解析后的插件信息; 2)宿主binder call触发插件进程建议经由loader的plugin加载;
中心类介绍: PpsController: 宿主进程持有的插件进程中插件环境服务PluginProcessService的署理; BinderUuidManager: 插件进程中持有的宿主进程中UuidManagerImpl署理; PluginLoader:宿主进程持有的插件进程DynamicPluginLoader署理;
对端完成类中心才能:
3.4 manager加载runtime
这儿首要要知道runtime是什么,它的规划处理什么问题? shadow是经过预埋壳activity,经过署理分发的方式来拉起并办理插件生命周期,runtime做的其实便是把这套Container组件署理完成计划从host剥离出来,原因是由于Activity组件有很多的办法需求署理完成,直接由宿主集成会造成宿主的办法数增量较多。这儿动态化的目的首要是寻求极致办法数增量。
接下来看看代码完成:
com.tencent.shadow.dynamic.host.PluginProcessService#loadRuntime
void loadRuntime(String uuid) throws FailedException {
...
// 从宿主拿包信息
installedApk = mUuidManager.getRuntime(uuid);
...
// 加载runtime插件
boolean loaded = DynamicRuntime.loadRuntime(installedRuntimeApk);
}
这儿先思考一个问题: 壳activity注册在宿主的AndroidManifest.xml,而对应的类文件却在插件里。当动态加载runtime插件后,直接调用体系的startActivity来发动一个署理组件,是否可行呢?答案是否定的,履行办法后,体系直接就抛出了ClassNotFundException。为什么咱们分明现已加载了Container署理组件,体系却找不到呢?原因是体系在找一个Activity组件时,总是从加载宿主的classLoader中开端查找(通用是PathClassLoader),假如查找不到,则抛反常。
host:
<activity
android:name="com.tencent.shadow.sample.plugin.runtime.PluginDefaultProxyActivity"
android:launchMode="standard"
android:screenOrientation="portrait"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
android:hardwareAccelerated="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
android:multiprocess="true" />
plugin:
@SuppressLint("Registered")//无需注册在这个模块的Manifest中,要注册在宿主的Manifest中。
public class PluginDefaultProxyActivity extends PluginContainerActivity {
@Override
protected String getDelegateProviderKey() {
return "SAMPLE";
}
}
shadow给出的处理计划是:
将RuntimeClassLoader刺进到PathClassLoader和BootClassLoader之间,根据双亲派遣准则,宿主能够拿到Runtime容器相关类。
接下来看loadRuntime的详细完成:
private static void hackParentToRuntime(InstalledApk installedRuntimeApk, ClassLoader contextClassLoader) throws Exception {
RuntimeClassLoader runtimeClassLoader = new RuntimeClassLoader(installedRuntimeApk.apkFilePath, installedRuntimeApk.oDexPath,
installedRuntimeApk.libraryPath, contextClassLoader.getParent());
hackParentClassLoader(contextClassLoader, runtimeClassLoader);
}
/**
* 修正ClassLoader的parent
*
* @param classLoader 需求修正的ClassLoader
* @param newParentClassLoader classLoader的新的parent
* @throws Exception 失利时抛出
*/
static void hackParentClassLoader(ClassLoader classLoader,
ClassLoader newParentClassLoader) throws Exception {
Field field = getParentField();
if (field == null) {
throw new RuntimeException("在ClassLoader.class中没找到类型为ClassLoader的parent域");
}
field.setAccessible(true);
field.set(classLoader, newParentClassLoader);
}
/**
* 安全地获取到ClassLoader类的parent域
*
* @return ClassLoader类的parent域.或不能经过反射拜访该域时回来null.
*/
private static Field getParentField() {
ClassLoader classLoader = DynamicRuntime.class.getClassLoader();
ClassLoader parent = classLoader.getParent();
Field field = null;
for (Field f : ClassLoader.class.getDeclaredFields()) {
try {
boolean accessible = f.isAccessible();
f.setAccessible(true);
Object o = f.get(classLoader);
f.setAccessible(accessible);
if (o == parent) {
field = f;
break;
}
} catch (IllegalAccessException ignore) {
}
}
return field;
}
分析ClassLoader类,发现ClassLoader的双亲派遣联系是由ClassLoader的一个私有属性parent来决议的,所以咱们只要反射的修正这个属性,就能构成上述的ClassLoader结构。可能有同学会关怀,这个修正是否安全。ClassLoader这个类不在Android P的约束名单中,并且是归于JDK的类,后续出现在约束名单中的概率也不大,并且这部分动态化是可选的,所以咱们评价这一处修正是安全的。
3.5 manager加载loader
com.tencent.shadow.dynamic.host.LoaderImplLoader#load
PluginLoaderImpl load(InstalledApk installedApk, String uuid, Context appContext) throws Exception {
ApkClassLoader pluginLoaderClassLoader = new ApkClassLoader(
installedApk,
LoaderImplLoader.class.getClassLoader(),
loadWhiteList(installedApk),
1
);
LoaderFactory loaderFactory = pluginLoaderClassLoader.getInterface(
LoaderFactory.class,
sLoaderFactoryImplClassName
);
return loaderFactory.buildLoader(uuid, appContext);
}
open class LoaderFactoryImpl : LoaderFactory {
override fun buildLoader(p0: String, p2: Context): PluginLoaderImpl {
return PluginLoaderBinder(DynamicPluginLoader(p2, p0))
}
}
相似于manager插件加载,这儿相同是经过工厂接口去加载loader进口完成类。可是这儿回来的是一个binder,宿主持有这个binder的署理来触发插件的加载。
这儿PluginLoaderBinder在插件端经过DynamicPluginLoader来履行详细插件操作,而它的详细操作又是经过ShadowPluginLoader署理来完成的, 而ShadowPluginLoader的初始化又是经过factory接口的方式加载的。
internal class DynamicPluginLoader(hostContext: Context, uuid: String) {
private val mPluginLoader: ShadowPluginLoader
init {
try {
val coreLoaderFactory = mDynamicLoaderClassLoader.getInterface(
CoreLoaderFactory::class.java,
CORE_LOADER_FACTORY_IMPL_NAME
)
mPluginLoader = coreLoaderFactory.build(hostContext)
DelegateProviderHolder.setDelegateProvider(
mPluginLoader.delegateProviderKey,
mPluginLoader
)
ContentProviderDelegateProviderHolder.setContentProviderDelegateProvider(mPluginLoader)
mPluginLoader.onCreate()
} catch (e: Exception) {
throw RuntimeException("当前的classLoader找不到PluginLoader的完成", e)
}
mContext = hostContext
mUuid = uuid
}
}
所以宿主经过PluginLoader履行的插件操作,终究插件端经过ShadowPluginLoader来完成的。
3.6 loader加载plugin
回到manager的loadPlugin,这儿loadPluginLoaderAndRuntime加载完runtime和loader后,开端经过PluginLoader建议插件加载
com.tencent.shadow.sample.manager.FastPluginManager#loadPlugin
protected void loadPlugin(String uuid, String partKey) throws RemoteException, TimeoutException, FailedException {
loadPluginLoaderAndRuntime(uuid, partKey);
Map map = mPluginLoader.getLoadedPlugin();
if (!map.containsKey(partKey)) {
mPluginLoader.loadPlugin(partKey);
}
}
loadPlugin终究是经过LoadPluginBloc完成插件加载:
com.tencent.shadow.core.loader.blocs.LoadPluginBloc#loadPlugin
fun loadPlugin(
executorService: ExecutorService,
componentManager: ComponentManager,
lock: ReentrantLock,
pluginPartsMap: MutableMap<String, PluginParts>,
hostAppContext: Context,
installedApk: InstalledApk,
loadParameters: LoadParameters
): Future<*> {
if (installedApk.apkFilePath == null) {
throw LoadPluginException("apkFilePath==null")
} else {
// 加载插件
val buildClassLoader = executorService.submit(Callable {
lock.withLock {
LoadApkBloc.loadPlugin(installedApk, loadParameters, pluginPartsMap)
}
})
val buildPluginManifest = executorService.submit(Callable {
val pluginClassLoader = buildClassLoader.get()
// 解析插件manifest
val pluginManifest = pluginClassLoader.loadPluginManifest()
// 查看插件和宿主包名共同
CheckPackageNameBloc.check(pluginManifest, hostAppContext)
pluginManifest
})
val buildPluginApplicationInfo = executorService.submit(Callable {
val pluginManifest = buildPluginManifest.get()
// 初始化ApplicationInfo
val pluginApplicationInfo = CreatePluginApplicationInfoBloc.create(
installedApk,
loadParameters,
pluginManifest,
hostAppContext
)
pluginApplicationInfo
})
val buildPackageManager = executorService.submit(Callable {
val pluginApplicationInfo = buildPluginApplicationInfo.get()
val hostPackageManager = hostAppContext.packageManager
// 经过宿主context获PackageManager并封装相关信息类
PluginPackageManagerImpl(
pluginApplicationInfo,
installedApk.apkFilePath,
componentManager,
hostPackageManager,
)
})
val buildResources = executorService.submit(Callable {
// 创立插件Resource
CreateResourceBloc.create(installedApk.apkFilePath, hostAppContext)
})
// 封装组件信息
val buildAppComponentFactory = executorService.submit(Callable {
val pluginClassLoader = buildClassLoader.get()
val pluginManifest = buildPluginManifest.get()
val appComponentFactory = pluginManifest.appComponentFactory
if (appComponentFactory != null) {
val clazz = pluginClassLoader.loadClass(appComponentFactory)
ShadowAppComponentFactory::class.java.cast(clazz.newInstance())
} else ShadowAppComponentFactory()
})
// 初始化插件ShadowApplication,它是插件Application替换的一般父类
val buildApplication = executorService.submit(Callable {
val pluginClassLoader = buildClassLoader.get()
val resources = buildResources.get()
val appComponentFactory = buildAppComponentFactory.get()
val pluginManifest = buildPluginManifest.get()
val pluginApplicationInfo = buildPluginApplicationInfo.get()
CreateApplicationBloc.createShadowApplication(
pluginClassLoader,
loadParameters,
pluginManifest,
resources,
hostAppContext,
componentManager,
pluginApplicationInfo,
appComponentFactory
)
})
val buildRunningPlugin = executorService.submit {
if (File(installedApk.apkFilePath).exists().not()) {
throw LoadPluginException("插件文件不存在.pluginFile==" + installedApk.apkFilePath)
}
val pluginPackageManager = buildPackageManager.get()
val pluginClassLoader = buildClassLoader.get()
val resources = buildResources.get()
val shadowApplication = buildApplication.get()
val appComponentFactory = buildAppComponentFactory.get()
val pluginManifest = buildPluginManifest.get()
lock.withLock {
componentManager.addPluginApkInfo(
pluginManifest,
loadParameters,
installedApk.apkFilePath,
)
pluginPartsMap[loadParameters.partKey] = PluginParts(
appComponentFactory,
shadowApplication,
pluginClassLoader,
resources,
pluginPackageManager
)
PluginPartInfoManager.addPluginInfo(
pluginClassLoader, PluginPartInfo(
shadowApplication, resources,
pluginClassLoader, pluginPackageManager
)
)
}
}
return buildRunningPlugin
}
}
解析完终究的产出:
3.7 manager拉起插件application onCreate
com.tencent.shadow.sample.manager.FastPluginManager#callApplicationOnCreate
protected void callApplicationOnCreate(String partKey) throws RemoteException {
Map map = mPluginLoader.getLoadedPlugin();
Boolean isCall = (Boolean) map.get(partKey);
if (isCall == null || !isCall) {
mPluginLoader.callApplicationOnCreate(partKey);
}
}
com.tencent.shadow.core.loader.ShadowPluginLoader#callApplicationOnCreate
fun callApplicationOnCreate(partKey: String) {
fun realAction() {
val pluginParts = getPluginParts(partKey)
pluginParts?.let {
val application = pluginParts.application
application.attachBaseContext(mHostAppContext)
mPluginContentProviderManager.createContentProviderAndCallOnCreate(
application, partKey, pluginParts
)
// 获取ShadowApplication,调用它的onCreate办法
application.onCreate()
}
}
if (isUiThread()) {
realAction()
} else {
val waitUiLock = CountDownLatch(1)
mUiHandler.post {
realAction()
waitUiLock.countDown()
}
waitUiLock.await();
}
}
直接获取插件对应的Application替换的父类:ShadowApplication,调用它的onCreate办法
3.8 manager拉起插件的进口activity
经过convertActivityIntent建议插件进口activity的发动,这儿方针activity是插件内的SplashActivity,可是咱们知道在AndroidManifest.xml里注册的壳Activity是PluginDefaultProxyActivity。 另外,在看下壳Activity和插件进口Activity的署理规划: 那这儿加载插件Activity终究流程会拆成2步走: 1)拉起SplashActivity的intent转换为拉起PluginDefaultProxyActivity; 2)由PluginDefaultProxyActivity署理转发,履行SplashActivity对应的生命周期,从而直接完成拉起插件进口Activity。
1)拉起SplashActivity的intent转换为拉起PluginDefaultProxyActivity;
com.tencent.shadow.dynamic.loader.impl.DynamicPluginLoader#convertActivityIntent
fun convertActivityIntent(pluginActivityIntent: Intent): Intent? {
return mPluginLoader.mComponentManager.convertPluginActivityIntent(pluginActivityIntent)
}
终究在ComponentManager中转换为发动PluginDefaultProxyActivity,并将插件进口activity装备在intent bundle中。 其间插件Activity和壳Activity的映射联系装备在:
com.tencent.shadow.sample.plugin.loader.SampleComponentManager#onBindContainerActivity
private static final String DEFAULT_ACTIVITY = "com.tencent.shadow.sample.plugin.runtime.PluginDefaultProxyActivity";
public ComponentName onBindContainerActivity(ComponentName pluginActivity) {
switch (pluginActivity.getClassName()) {
/**
* 这儿装备对应的对应联系
*/
}
return new ComponentName(context, DEFAULT_ACTIVITY);
}
2)由PluginDefaultProxyActivity署理转发,履行SplashActivity对应的生命周期,从而直接完成拉起插件进口Activity 以onCreate分发为例:
public class PluginContainerActivity extends GeneratedPluginContainerActivity implements HostActivity, HostActivityDelegator {
HostActivityDelegate hostActivityDelegate;
public PluginContainerActivity() {
HostActivityDelegate delegate;
DelegateProvider delegateProvider = DelegateProviderHolder.getDelegateProvider(getDelegateProviderKey());
if (delegateProvider != null) {
delegate = delegateProvider.getHostActivityDelegate(this.getClass());
delegate.setDelegator(this);
} else {
Log.e(TAG, "PluginContainerActivity: DelegateProviderHolder没有初始化");
delegate = null;
}
super.hostActivityDelegate = delegate;
hostActivityDelegate = delegate;
}
@Override
final protected void onCreate(Bundle savedInstanceState) {
isBeforeOnCreate = false;
mHostTheme = null;//释放资源
boolean illegalIntent = isIllegalIntent(savedInstanceState);
if (illegalIntent) {
super.hostActivityDelegate = null;
hostActivityDelegate = null;
Log.e(TAG, "illegalIntent savedInstanceState==" + savedInstanceState + " getIntent().getExtras()==" + getIntent().getExtras());
}
if (hostActivityDelegate != null) {
hostActivityDelegate.onCreate(savedInstanceState);
} else {
//这儿是进程被杀后重启后走到,当需求康复fragment状况的时候,由于体系保留了TAG,会由于找不到fragment引起crash
super.onCreate(null);
Log.e(TAG, "onCreate: hostActivityDelegate==null finish activity");
finish();
System.exit(0);
}
}
}
之前插件加载把ShadowPluginLoader存到了DelegateProviderHolder中,这儿delegateProvider.getHostActivityDelegate终究取出的是:
com.tencent.shadow.core.loader.ShadowPluginLoader#getHostActivityDelegate
override fun getHostActivityDelegate(aClass: Class<out HostActivityDelegator>): HostActivityDelegate {
return if (HostNativeActivityDelegator::class.java.isAssignableFrom(aClass)) {
ShadowNativeActivityDelegate(this)
} else {
ShadowActivityDelegate(this)
}
}
终究PluginContainerActivity.onCreate是调用的ShadowActivityDelegate.onCreate,这儿看下详细完成:
override fun onCreate(savedInstanceState: Bundle?) {
...
// 向插件注入上下文相关信息
mDI.inject(this, partKey)
...
// 加载插件父类ShadowActivity
val pluginActivity = mAppComponentFactory.instantiateActivity(
mPluginClassLoader,
pluginActivityClassName,
mHostActivityDelegator.intent
)
// 初始化ShadowActivity
initPluginActivity(pluginActivity, pluginActivityInfo)
...
// 履行对应生命周期回调
pluginActivity.onCreate(pluginSavedInstanceState)
...
}
总结宿主拉起插件activity署理流程:
3.9 gradle transform 编译期替换基础组件
对应gradle插件为ShadowPlugin
gradlePlugin {
plugins {
shadow {
id = "com.tencent.shadow.plugin"
implementationClass = "com.tencent.shadow.core.gradle.ShadowPlugin"
}
}
}
com.tencent.shadow.core.gradle.ShadowPlugin#apply
val shadowExtension = project.extensions.create("shadow", ShadowExtension::class.java)
if (!project.hasProperty("disable_shadow_transform")) {
baseExtension.registerTransform(ShadowTransform(
project,
lateInitBuilder,
{ shadowExtension.transformConfig.useHostContext },
{ shadowExtension.transformConfig.keepClassNames }
))
}
com.tencent.shadow.core.transform.ShadowTransform
_mTransformManager = TransformManager(mCtClassInputMap, classPool, useHostContext, keepClassNames)
这儿首要看看TransformManager详细完成:
class TransformManager(
ctClassInputMap: Map<CtClass, InputClass>,
classPool: ClassPool,
useHostContext: () -> Array<String>,
keepClassNames: () -> List<String>
) : AbstractTransformManager(ctClassInputMap, classPool) {
/**
* 按这个列表的顺序使用各子Transform逻辑。
*
* 注意这个列表的顺序是有联系的,
* 比如在ActivityTransform之前的Transform能够看到本来的Activity类型,
* 在其之后的Transform在插件中就看不到Activity类型了,
* 一切有些Transform在获取办法时要将本来的Activity类型改为ShadowActivity类型,
* 由于ActivityTransform在它之前现已收效了。
*/
override val mTransformList: List<SpecificTransform> = listOf(
ApplicationTransform(keepClassNames()),
ActivityTransform(keepClassNames()),
ServiceTransform(),
IntentServiceTransform(),
InstrumentationTransform(),
FragmentSupportTransform(),
DialogSupportTransform(),
WebViewTransform(),
ContentProviderTransform(),
PackageManagerTransform(),
PackageItemInfoTransform(),
AppComponentFactoryTransform(),
LayoutInflaterTransform(),
KeepHostContextTransform(useHostContext()),
ActivityOptionsSupportTransform(),
)
}
以ActivityTransform为例:
class ActivityTransform(
keepClassNames: List<String> = emptyList()
) : SimpleRenameTransform(
mapOf(
"android.app.Activity"
to "com.tencent.shadow.core.runtime.ShadowActivity",
"android.app.NativeActivity"
to "com.tencent.shadow.core.runtime.ShadowNativeActivity"
),
keepClassNames
)
open class SimpleRenameTransform(
private val fromToMap: Map<String, String>,
private val keepClassNames: List<String> = emptyList()
) : SpecificTransform() {
final override fun setup(allInputClass: Set<CtClass>) {
newStep(object : TransformStep {
override fun filter(allInputClass: Set<CtClass>) =
allInputClass.filterNot { keepClassNames.contains(it.name) }.toSet()
override fun transform(ctClass: CtClass) {
if (keepClassNames.contains(ctClass.name)) {
System.err.println("${ctClass.name} is in keepClassNames, which should not be transformed.")
}
fromToMap.forEach {
ReplaceClassName.replaceClassName(ctClass, it.key, it.value)
}
}
})
}
}
大局扫描,将原生Activity替换为一般类。
3.10 插件四大组件之Service的完成
插件Service父类会被替换为ShadowService一般类,与Activity相似, 相同承继于ShadowContext,这儿跟Activity完成的区别是:Activity是依靠于真实注册在manifest中的壳activity署理转发生命周期,而Service并不是,这儿Shadow只是代码简单模仿了生命周期的调用。
com.tencent.shadow.core.loader.ShadowPluginLoader#loadPlugin
// 在这儿初始化PluginServiceManager
mPluginServiceManagerLock.withLock {
if (!::mPluginServiceManager.isInitialized) {
mPluginServiceManager = PluginServiceManager(this, mHostAppContext)
}
mComponentManager.setPluginServiceManager(mPluginServiceManager)
}
在加载插件环境初始化了一个PluginServiceManager类,由他作为组件Service的署理完成
com.tencent.shadow.core.loader.managers.ComponentManager#startService
override fun startService(
context: ShadowContext,
service: Intent
): Pair<Boolean, ComponentName?> {
if (service.isPluginComponent()) {
// 插件service intent不需求转换成container service intent,直接使用intent
val component = mPluginServiceManager!!.startPluginService(service)
if (component != null) {
return Pair(true, component)
}
}
return Pair(false, service.component)
}
override fun bindService(
context: ShadowContext,
intent: Intent,
conn: ServiceConnection,
flags: Int
): Pair<Boolean, Boolean> {
return if (intent.isPluginComponent()) {
// 插件service intent不需求转换成container service intent,直接使用intent
mPluginServiceManager!!.bindPluginService(intent, conn, flags)
Pair(true, true)
} else {
Pair(false, false)
}
}
这儿并没有经过delegate分发真实体系Service的生命周期,而是PluginServiceManager模仿Service自己完成了一套 1)startPluginService完成
// 中心办法
private fun createServiceAndCallOnCreate(intent: Intent): ShadowService {
val service = newServiceInstance(intent)
service.onCreate()
return service
}
createServiceAndCallOnCreate首要便是加载对应的插件Service类并初始化,然后调用其onStart办法。 2)bindPluginService
fun bindPluginService(intent: Intent, conn: ServiceConnection, flags: Int): Boolean {
// todo #25 现在完成未处理flags,后续完成补上
val componentName = intent.component!!
// 1. 看要bind的service是否创立并在运转了
if (!mAliveServicesMap.containsKey(componentName)) {
// 假如还没创立,则创立,并坚持
val service = createServiceAndCallOnCreate(intent)
mAliveServicesMap[componentName] = service
}
val service = mAliveServicesMap[componentName]!!
// 2. 查看是否该Service之前是否被绑定过了
if (!mServiceBinderMap.containsKey(componentName)) {
// 还没调用过onBinder,在这儿调用
mServiceBinderMap[componentName] = service.onBind(intent)
}
// 3. 假如binder不为空,则要回调onServiceConnected
mServiceBinderMap[componentName]?.let {
// 查看该connections是否存在了
if (mServiceConnectionMap.containsKey(componentName)) {
if (!mServiceConnectionMap[componentName]!!.contains(conn)) {
// 假如service的bind connection集合中不包含该connection,则加入
mServiceConnectionMap[componentName]!!.add(conn)
mConnectionIntentMap[conn] = intent
// 回调onServiceConnected
conn.onServiceConnected(componentName, it)
} else {
// 现已包含该connection了,说明onServiceConnected现已回调过了,所以这儿什么也不必干
}
} else {
// 该connection是第一个bind connection
val connectionSet = HashSet<ServiceConnection>()
connectionSet.add(conn)
mServiceConnectionMap[componentName] = connectionSet
mConnectionIntentMap[conn] = intent
// 回调onServiceConnected
conn.onServiceConnected(componentName, it)
}
}
return true
}
3.11 插件四大组件之ContentProvider完成
与Activity相似,由注册在宿主manifest中的ContentProvider来署理回调。
这儿宿主中对应的是PluginContainerContentProvider,它直接承继自ContentProvider,插件经过Delegate署理回调,现类:PluginContentProviderManager
3.12 插件四大组件之BroadcastReceiver完成
只支撑动态广播,静态广播不支撑。动态广播不需求在宿主manifest中注册,只需求处理onReceive()回调的context类型为ShadowContext,这儿只需求包一层即可:
public class BroadcastReceiverWrapper extends BroadcastReceiver {
final private BroadcastReceiver mRealBroadcastReceiver;
final private ShadowContext mShadowContext;
public BroadcastReceiverWrapper(BroadcastReceiver broadcastReceiver, ShadowContext shadowContext) {
mRealBroadcastReceiver = broadcastReceiver;
mShadowContext = shadowContext;
}
@Override
public void onReceive(Context context, Intent intent) {
intent.setExtrasClassLoader(mShadowContext.mPluginClassLoader);
mRealBroadcastReceiver.onReceive(mShadowContext, intent);
}
}
最后总结一张结构加载插件流程中心类UML图: