最近看了下Shadow,别人写的博客,都是比较旧,几年前的,没基于最新的代码分析,于是我写了这篇文章分享下! 前面还有几篇Shadow实战的,太多,先跳过,后面再补上
引言
在 Android 开发中,插件化技术是实现应用模块化、动态更新与体积优化的重要手段。Shadow 是腾讯开源的一款高性能、零反射、零 Hook 的插件化框架,其核心设计目标是在不破坏 Android 系统机制的前提下,安全、稳定地运行插件代码。
本文将结合源码和官方文档,系统梳理 Shadow 启动插件 Activity 的完整流程,帮助开发者深入理解其底层原理。
一、Shadow 整体架构概览
1.1 整体架构分层设计
Shadow 的整体架构清晰分层,主要包含以下组件:
graph TB
subgraph "宿主应用 (Host App)"
A1[宿主AndroidManifest<br/>预注册代理Activity]
A2[宿主Application]
A3[入口Activity]
end
subgraph "管理器层 (Manager Layer)"
B1[PluginManager<br/>插件管理器]
B2[UuidManager<br/>插件实例管理]
B3[ComponentManager<br/>组件管理]
end
subgraph "加载器层 (Loader Layer)"
C1[DynamicPluginLoader<br/>动态加载器]
C2[FixedPluginLoader<br/>固定加载器]
C3[PluginClassLoader<br/>插件类加载器]
end
subgraph "运行时层 (Runtime Layer)"
D1[ShadowActivity<br/>代理基类]
D2[PluginContainerActivity<br/>容器Activity]
D3[ShadowContext<br/>上下文代理]
end
subgraph "插件层 (Plugin Layer)"
E1[插件APK<br/>业务模块]
E2[插件Activity<br/>业务逻辑]
E3[插件资源<br/>独立资源]
end
A3 --> B1
B1 --> C1
C1 --> D1
D1 --> D2
D2 --> E2
E2 --> E3
D3 -.-> C3
D3 -.-> E3
1.2 核心模块说明
| 模块 | 职责 |
|---|---|
| Host App | 集成 Shadow SDK,提供代理容器 Activity |
| PluginManager | 插件入口管理,负责路由与调度 |
| PluginLoader | 加载插件 APK,创建 ClassLoader 和 Resources |
| Runtime | 提供插件运行所需的基础能力(Context 代理、生命周期转发等) |
| Plugin APK | 独立业务模块,编译为标准 APK |
核心思想:"宿主壳 + 插件实现" —— 插件 Activity 实际由宿主中预注册的代理 Activity 承载。
二、Shadow启动Activity示例代码
public void startPlugin() {
PluginHelper.getInstance().singlePool.execute(new Runnable() {
@Override
public void run() {
HostApplication.getApp().loadPluginManager(PluginHelper.getInstance().pluginManagerFile);
Bundle bundle = new Bundle();
bundle.putString(TaoDuoduoConstant.KEY_PLUGIN_ZIP_PATH, PluginHelper.getInstance().pluginZipFile.getAbsolutePath());
bundle.putString(TaoDuoduoConstant.KEY_PLUGIN_PART_KEY, getIntent().getStringExtra(TaoDuoduoConstant.KEY_PLUGIN_PART_KEY));
bundle.putString(TaoDuoduoConstant.KEY_ACTIVITY_CLASSNAME, getIntent().getStringExtra(TaoDuoduoConstant.KEY_ACTIVITY_CLASSNAME));
HostApplication.getApp().getPluginManager()
.enter(PluginLoadActivity.this, TaoDuoduoConstant.FROM_ID_START_ACTIVITY, bundle, new EnterCallback() {
@Override
public void onShowLoadingView(final View view) {
mHandler.post(new Runnable() {
@Override
public void run() {
mViewGroup.addView(view);
}
});
}
@Override
public void onCloseLoadingView() {
finish();
}
@Override
public void onEnterComplete() {
}
});
}
});
}
三、架构图与流程图解析
3.1 Shadow插件化整体架构图
graph LR
subgraph "宿主环境"
A[宿主Application] --> B[PluginManager]
B --> C[Runtime环境]
D[代理Activity容器] --> C
end
subgraph "插件环境"
E[插件APK] --> F[插件ClassLoader]
E --> G[插件Resources]
F --> H[插件Activity]
G --> H
end
subgraph "桥梁层"
I[ShadowContext代理] --> J[ActivityContainer]
J --> K[生命周期同步器]
end
C --> I
I --> F
I --> G
D --> J
J --> H
K --> H
3.2 启动插件Activity的核心流程图
sequenceDiagram
participant 开发者
participant PluginManager
participant 系统AMS
participant 代理Activity
participant PluginLoader
participant 插件APK
participant 插件Activity
开发者->>PluginManager: 1.调用enter()方法
PluginManager->>PluginManager: 2.构造代理Intent<br/>包装插件信息
PluginManager->>系统AMS: 3.启动代理Activity<br/>PluginDefaultProxyActivity
系统AMS->>代理Activity: 4.创建实例,调用onCreate()
代理Activity->>PluginLoader: 5.请求加载插件
PluginLoader->>插件APK: 6.创建插件ClassLoader
PluginLoader->>插件APK: 7.加载插件资源
PluginLoader->>插件APK: 8.创建插件Activity实例
插件APK-->>PluginLoader: 9.返回插件Activity对象
PluginLoader-->>代理Activity: 10.返回插件Activity
代理Activity->>代理Activity: 11.创建ShadowContext
代理Activity->>代理Activity: 12.替换插件Activity的Context
代理Activity->>代理Activity: 13.建立生命周期同步
代理Activity->>插件Activity: 14.调用onCreate()
代理Activity->>插件Activity: 15.调用onStart()
代理Activity->>插件Activity: 16.调用onResume()
代理Activity-->>开发者: 17.显示插件界面
3.3 核心组件交互图
graph TD
subgraph "启动阶段"
A[PluginManager.enter] --> B[创建ShadowIntent]
B --> C[启动代理Activity]
end
subgraph "初始化阶段"
C --> D[代理Activity.onCreate]
D --> E[解析插件信息]
E --> F[调用PluginLoader.loadPlugin]
F --> G[创建插件ClassLoader]
G --> H[加载插件资源]
H --> I[创建插件Activity实例]
end
subgraph "绑定阶段"
I --> J[创建ShadowContext]
J --> K[注入插件Activity]
K --> L[建立ActivityContainer]
L --> M[转发生命周期]
M --> N[显示插件UI]
end
subgraph "运行阶段"
N --> O[用户交互]
O --> P[代理Activity接收]
P --> Q[转发到插件Activity]
Q --> R[插件处理业务逻辑]
R --> S[更新UI]
end
3.4 关键类关系图
classDiagram
class PluginManager {
+enter(Context, String, String, Bundle, Callback)
+startPluginActivity(Intent, int, Bundle)
-Map<String, PluginInfo> mPlugins
+loadPlugin(String apkPath)
}
class PluginContainerActivity {
-Activity mPluginActivity
-ActivityContainer mContainer
+onCreate(Bundle)
+onStart()
+onResume()
-attachPluginActivity(Activity)
}
class DynamicPluginLoader {
-Map<String, LoadedPlugin> mLoadedPlugins
+loadPlugin(String) LoadedPlugin
+createActivity(String) Activity
+createAssetManager(String) AssetManager
}
class LoadedPlugin {
-ClassLoader mClassLoader
-Resources mResources
-AssetManager mAssetManager
-PluginInfo mPluginInfo
+getClassLoader()
+getResources()
}
class ShadowContext {
-Context mHostContext
-LoadedPlugin mPlugin
+getResources()
+getClassLoader()
+getApplicationContext()
}
class ActivityContainer {
-Activity mHostActivity
-Activity mPluginActivity
+setPluginActivity(Activity)
+forwardLifecycle()
}
class PluginActivity {
<<插件Activity>>
-Context mBase
-Application mApplication
+onCreate(Bundle)
+onResume()
}
PluginManager --> DynamicPluginLoader : 使用
PluginContainerActivity --> DynamicPluginLoader : 调用
DynamicPluginLoader --> LoadedPlugin : 创建
PluginContainerActivity --> ActivityContainer : 包含
ActivityContainer --> PluginActivity : 包装
ShadowContext --> LoadedPlugin : 引用
PluginActivity --> ShadowContext : 被注入
四、关键组件位置与部署结构
4.1 具体代码位置证明
在 Shadow 源码项目中:
shadow-sample/
├── host/ # 宿主模块
│ ├── src/main/
│ │ ├── AndroidManifest.xml # 包含代理Activity声明
│ │ └── java/com/tencent/shadow/sample/host/
│ │ └── SamplePluginManager.java # 管理代理Activity
│ └── build.gradle # 依赖 shadow-core-loader
│
├── plugin-manager/ # PluginManager 实现
│
└── core/
└── loader/ # 核心加载器模块
└── src/main/java/com/tencent/shadow/core/loader/delegates/
├── PluginDefaultProxyActivity.java # 代理Activity实现
├── PluginSingleTaskProxyActivity.java
└── PluginContainerActivity.java # 代理基类
4.2 实际部署时的位置
在 APK 文件结构中:
宿主 APK (host.apk):
├── AndroidManifest.xml
├── classes.dex
│ └── com/tencent/shadow/core/loader/delegates/
│ └── PluginDefaultProxyActivity.class ✅ 代理Activity在这里
└── assets/plugins/
└── plugin.apk # 插件APK
插件 APK (plugin.apk):
├── AndroidManifest.xml (仅编译期使用,不安装)
├── classes.dex
│ └── com/example/plugin/
│ └── PluginActivity.class # 真正的业务Activity
└── res/ # 插件资源
五、启动流程详解(附关键源码)
5.1 第一步:PluginManager.enter() → 构造代理 Intent
启动插件 Activity 的典型调用方式如下:
PluginManager.getInstance().enter(
context,
"plugin-part-key", // 插件标识(partKey)
"com.example.PluginActivity", // 插件 Activity 全类名
null, // Bundle 参数
null // 回调
);
enter() 是启动流程的入口方法,但其背后涉及多层转发与代理机制。PluginManager 是一个接口,通常由 SamplePluginManager 实现。其内部会调用:
PendingIntent pendingIntent = mPluginLoader.getLaunchIntent(...);
context.startActivity(pendingIntent.getIntent());
关键点:
Shadow 不会直接启动插件中的 Activity,而是构造一个指向宿主中预注册的占位 Activity(如 PluginDefaultProxyActivity)的 Intent,并将插件信息(类名、partKey 等)作为 extra 传入。
为什么需要占位 Activity? Android 系统要求所有 Activity 必须在
AndroidManifest.xml中声明,否则会抛出ActivityNotFoundException。Shadow 通过预注册一组通用代理 Activity 来绕过此限制。
5.2 第二步:宿主中启动代理 Activity(PluginDefaultProxyActivity)
宿主 Manifest 中预先声明了多个代理 Activity,用于支持不同 launchMode:
<activity android:name="com.tencent.shadow.core.loader.delegates.PluginDefaultProxyActivity" />
<activity android:name="com.tencent.shadow.core.loader.delegates.PluginSingleTaskProxyActivity"
android:launchMode="singleTask" />
<!-- ... -->
PluginDefaultProxyActivity 是 Shadow 框架在宿主应用中预先注册的代理容器
以 PluginDefaultProxyActivity 为例,它继承自 PluginContainerActivity,而后者又继承自 ShadowActivity。
当系统启动该代理 Activity 时,会执行其 onCreate() 方法。
5.3 代理Activity的onCreate流程
当系统启动PluginDefaultProxyActivity后,其onCreate方法开始执行:
// PluginContainerActivity.java (基类)
@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);
}
}
5.4 ShadowActivityDelegate
override fun onCreate(savedInstanceState: Bundle?) {
val pluginInitBundle = savedInstanceState ?: mHostActivityDelegator.intent.extras!!
mCallingActivity = pluginInitBundle.getParcelable(CM_CALLING_ACTIVITY_KEY)
mBusinessName = pluginInitBundle.getString(CM_BUSINESS_NAME_KEY, "")
val partKey = pluginInitBundle.getString(CM_PART_KEY)!!
mPartKey = partKey
mDI.inject(this, partKey)
mDependenciesInjected = true
val bundleForPluginLoader = pluginInitBundle.getBundle(CM_LOADER_BUNDLE_KEY)!!
mBundleForPluginLoader = bundleForPluginLoader
bundleForPluginLoader.classLoader = this.javaClass.classLoader
val pluginActivityClassName = bundleForPluginLoader.getString(CM_CLASS_NAME_KEY)!!
val pluginActivityInfo: PluginManifest.ActivityInfo =
bundleForPluginLoader.getParcelable(CM_ACTIVITY_INFO_KEY)!!
mPluginActivityInfo = pluginActivityInfo
mCurrentConfiguration = Configuration(resources.configuration)
mPluginHandleConfigurationChange =
(pluginActivityInfo.configChanges
or ActivityInfo.CONFIG_SCREEN_SIZE//系统本身就会单独对待这个属性,不声明也不会重启Activity。
or ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE//系统本身就会单独对待这个属性,不声明也不会重启Activity。
or 0x20000000 //见ActivityInfo.CONFIG_WINDOW_CONFIGURATION 系统处理属性
)
if (savedInstanceState == null) {
mRawIntentExtraBundle = pluginInitBundle.getBundle(CM_EXTRAS_BUNDLE_KEY)
mHostActivityDelegator.intent.replaceExtras(mRawIntentExtraBundle)
}
mHostActivityDelegator.intent.setExtrasClassLoader(mPluginClassLoader)
try {
val pluginActivity = mAppComponentFactory.instantiateActivity(
mPluginClassLoader,
pluginActivityClassName,
mHostActivityDelegator.intent
)
initPluginActivity(pluginActivity, pluginActivityInfo)
super.pluginActivity = pluginActivity
if (mLogger.isDebugEnabled) {
mLogger.debug(
"{} mPluginHandleConfigurationChange=={}",
mPluginActivity.javaClass.canonicalName,
mPluginHandleConfigurationChange
)
}
//使PluginActivity替代ContainerActivity接收Window的Callback
mHostActivityDelegator.window.callback = pluginActivity
//设置插件AndroidManifest.xml 中注册的WindowSoftInputMode
mHostActivityDelegator.window.setSoftInputMode(pluginActivityInfo.softInputMode)
//Activity.onCreate调用之前应该先收到onWindowAttributesChanged。
if (mCallOnWindowAttributesChanged) {
pluginActivity.onWindowAttributesChanged(
mBeforeOnCreateOnWindowAttributesChangedCalledParams
)
mBeforeOnCreateOnWindowAttributesChangedCalledParams = null
}
val pluginSavedInstanceState: Bundle? =
savedInstanceState?.getBundle(PLUGIN_OUT_STATE_KEY)
pluginSavedInstanceState?.classLoader = mPluginClassLoader
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
notifyPluginActivityPreCreated(pluginActivity, pluginSavedInstanceState)
}
pluginActivity.onCreate(pluginSavedInstanceState)
mPluginActivityCreated = true
} catch (e: Exception) {
throw RuntimeException(e)
}
}
5.5 插件Activity实例化与赋值流程
插件Activity (pluginActivity) 的赋值过程可以概括为:
- 获取类名:从启动参数中提取插件 Activity 的完整类名
- 加载类:使用插件的
ClassLoader加载指定的类 - 创建实例:通过反射调用
newInstance()创建对象 - 类型转换:将实例转换为
ShadowActivity类型 - 初始化:通过
initPluginActivity()设置上下文、资源等 - 赋值:将初始化后的实例赋值给
super.pluginActivity
完整的赋值时序图:
sequenceDiagram
participant 宿主Activity
participant ShadowActivityDelegate
participant AppComponentFactory
participant PluginClassLoader
participant 插件Activity类
participant 插件Activity实例
宿主Activity->>ShadowActivityDelegate: onCreate()
ShadowActivityDelegate->>ShadowActivityDelegate: 解析插件信息
ShadowActivityDelegate->>AppComponentFactory: instantiateActivity()
AppComponentFactory->>PluginClassLoader: loadClass(className)
PluginClassLoader->>插件Activity类: 加载类
插件Activity类-->>PluginClassLoader: 返回Class对象
AppComponentFactory->>插件Activity类: newInstance()
插件Activity类->>插件Activity实例: 创建实例
插件Activity实例-->>AppComponentFactory: 返回实例
AppComponentFactory-->>ShadowActivityDelegate: 返回插件Activity实例
ShadowActivityDelegate->>ShadowActivityDelegate: initPluginActivity()
ShadowActivityDelegate->>ShadowActivityDelegate: 设置Context、Application等
ShadowActivityDelegate->>ShadowActivityDelegate: super.pluginActivity = pluginActivity
ShadowActivityDelegate->>插件Activity实例: onCreate()
插件Activity实例-->>宿主Activity: 完成初始化
第一步:通过 AppComponentFactory 创建实例
// 1. 获取插件 Activity 的类名
val pluginActivityClassName = bundleForPluginLoader.getString(CM_CLASS_NAME_KEY)!!
// 2. 使用 AppComponentFactory 创建插件 Activity 实例
val pluginActivity = mAppComponentFactory.instantiateActivity(
mPluginClassLoader, // 插件 ClassLoader
pluginActivityClassName, // 插件 Activity 完整类名
mHostActivityDelegator.intent // Intent 参数
)
第二步:调用 initPluginActivity() 进行初始化
// 3. 初始化插件 Activity
initPluginActivity(pluginActivity, pluginActivityInfo)
initPluginActivity() 方法会:
- 设置插件 Activity 的 Context(ShadowContext)
- 设置插件 Application
- 设置 Window 和 WindowManager
- 设置主题等
第三步:赋值给父类属性
// 4. 赋值给父类的 pluginActivity 字段
super.pluginActivity = pluginActivity
这里 super 指的是 PluginContainerActivity 或类似基类。
AppComponentFactory 的来源
// 1. 从插件 Manifest 中获取 AppComponentFactory 配置
val appComponentFactory = pluginManifest.appComponentFactory
// 2. 创建 AppComponentFactory 实例
val clazz = pluginClassLoader.loadClass(appComponentFactory)
ShadowAppComponentFactory::class.java.cast(clazz.newInstance())
ShadowAppComponentFactory.instantiateActivity 方法
public class ShadowAppComponentFactory {
public ShadowActivity instantiateActivity(ClassLoader cl, String className, Intent intent)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
// 使用插件 ClassLoader 加载类并创建实例
return (ShadowActivity) cl.loadClass(className).newInstance();
}
}
插件 Activity 的类型转换
注意实例化后的类型转换:
// ShadowAppComponentFactory 返回的是 ShadowActivity 类型
return (ShadowActivity) cl.loadClass(className).newInstance();
// 但插件中的 Activity 实际上继承自 ShadowActivity(编译期插桩修改)
// 编译前的插件 Activity:
public class PluginMainActivity extends Activity { ... }
// 编译后(经过 Shadow Transform 插桩):
public class PluginMainActivity extends ShadowActivity { ... }
关键类的继承关系
// 宿主中的代理 Activity
public class PluginDefaultProxyActivity
extends PluginContainerActivity
implements ComponentManager
// 插件中的 Activity(编译后)
public class PluginMainActivity
extends ShadowActivity // 编译期插桩修改的父类
// ShadowActivity 是框架提供的基类
public abstract class ShadowActivity extends Activity {
// 提供插件化所需的各种代理方法
}
5.6 生命周期同步(手动转发)
由于插件 Activity 不是系统管理的组件,其生命周期需由宿主代理 Activity 手动转发:
// ShadowActivity.java
@Override
protected void onResume() {
super.onResume();
if (mPluginActivity != null) {
mPluginActivity.onResume(); // 手动调用
}
}
@Override
protected void onPause() {
if (mPluginActivity != null) {
mPluginActivity.onPause();
}
super.onPause();
}
public class ShadowActivity extends PluginActivity {
@Override
public void setContentView(int layoutResID) {
if ("merge".equals(XmlPullParserUtil.getLayoutStartTagName(getResources(), layoutResID))) {
//如果传进来的xml文件的根tag是merge时,需要特殊处理
View decorView = hostActivityDelegator.getWindow().getDecorView();
ViewGroup viewGroup = decorView.findViewById(android.R.id.content);
LayoutInflater.from(this).inflate(layoutResID, viewGroup);
} else {
View inflate = LayoutInflater.from(this).inflate(layoutResID, null);
hostActivityDelegator.setContentView(inflate);
}
}
@Override
public final ShadowApplication getApplication() {
return mPluginApplication;
}
@Override
public final ShadowActivity getParent() {
return null;
}
@Override
public void overridePendingTransition(int enterAnim, int exitAnim) {
//如果使用的资源不是系统资源,我们无法支持这个特性。
if ((enterAnim & 0xFF000000) != 0x01000000) {
enterAnim = 0;
}
if ((exitAnim & 0xFF000000) != 0x01000000) {
exitAnim = 0;
}
hostActivityDelegator.overridePendingTransition(enterAnim, exitAnim);
}
@Override
public void startActivityForResult(Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
@Override
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
final Intent pluginIntent = new Intent(intent);
pluginIntent.setExtrasClassLoader(mPluginClassLoader);
ComponentName callingActivity = new ComponentName(getPackageName(), getClass().getName());
final boolean success = mPluginComponentLauncher.startActivityForResult(hostActivityDelegator, pluginIntent, requestCode, options, callingActivity);
if (!success) {
hostActivityDelegator.startActivityForResult(intent, requestCode, options);
}
}
@Override
public SharedPreferences getPreferences(int mode) {
return super.getSharedPreferences(getLocalClassName(), mode);
}
@Override
public String getLocalClassName() {
return this.getClass().getName();
}
@Override
public boolean shouldUpRecreateTask(Intent targetIntent) {
Intent intent = mPluginComponentLauncher.convertPluginActivityIntent(targetIntent);
return hostActivityDelegator.shouldUpRecreateTask(intent);
}
@Override
public boolean navigateUpTo(Intent upIntent) {
Intent intent = mPluginComponentLauncher.convertPluginActivityIntent(upIntent);
return hostActivityDelegator.navigateUpTo(intent);
}
此外,onBackPressed()、onActivityResult() 等回调也会被代理转发。
5.7 Context 替换与资源隔离
为了使插件 Activity 能正确访问资源、主题、ClassLoader 等,Shadow 会:
- 创建
ShadowContext,封装插件的Resources、AssetManager、ClassLoader - 通过 编译期字节码插桩(Transform)将插件中所有
this(作为 Context)替换为getShadowDelegate().getPluginContext() - 在运行时通过
ReflectUtil.setField(activity, "mBase", shadowContext)注入上下文(部分版本使用 delegate 机制避免反射)
"零反射"实现:Shadow 尽量在编译期完成适配,仅在必要时使用少量反射(如设置
mBase),相比其他框架大幅降低兼容性风险。
5.8 插件资源与类加载隔离
每个插件拥有独立的:
DexClassLoader:加载插件 DEXAssetManager:加载插件资源(通过addAssetPath())Resources:基于插件 AssetManager 构建
在 DynamicPluginLoader.loadPlugin() 中:
DexClassLoader classLoader = new DexClassLoader(
apkPath,
optDir.getAbsolutePath(),
libDir.getAbsolutePath(),
getHostClassLoader()
);
AssetManager assetManager = createAssetManager(apkPath);
Resources resources = new Resources(assetManager, ..., ...);
这样确保插件资源与宿主完全隔离,同时支持跨插件或访问宿主资源(通过配置)。
六、关键设计思想总结
| 技术挑战 | Shadow 解决方案 |
|---|---|
| Manifest 限制 | 宿主预注册通用代理 Activity(Placeholder) |
| Activity 生命周期 | 容器 Activity 手动转发所有生命周期回调 |
| Context 正确性 | 编译期插桩 + ShadowContext 代理 |
| 资源隔离 | 每个插件独立 AssetManager 和 Resources |
| 无反射 / 无 Hook | 基于接口 + 代码生成 + 字节码修改,规避系统限制 |
七、结语
Shadow 通过 "代理容器 + 编译期插桩 + 运行时隔离" 的组合策略,实现了高度兼容、稳定可靠的插件化方案。其启动插件 Activity 的流程虽涉及多层抽象,但逻辑清晰、职责分明,是 Android 插件化技术中的优秀实践。
对于希望构建大型模块化 App 或实现热更新能力的团队,Shadow 值得深入研究与集成。