不同uuid的插件A和B(具有各自的loader和runtime),通过框架启动时,点击插件A,然后在点击插件B,插件B启动不起来并报错,再次点击插件B有可能才启动起来
报错日志: 2020-10-28 17:23:49.328 29602-30188/com.slp.apkhost E/com.tencent.shadow.dynamic.manager.BaseDynamicPluginManager: getPlugin exception: java.lang.NullPointerException: Attempt to read from field 'java.io.File com.tencent.shadow.core.manager.installplugin.InstalledPlugin$Part.pluginFile' on a null object reference at com.tencent.shadow.dynamic.manager.BaseDynamicPluginManager.getPlugin(BaseDynamicPluginManager.java:192) at com.tencent.shadow.dynamic.manager.UuidManagerBinder.onTransact(UuidManagerBinder.java:50) at android.os.Binder.execTransactInternal(Binder.java:1021) at android.os.Binder.execTransact(Binder.java:994) at android.os.BinderProxy.transactNative(Native Method) at android.os.BinderProxy.transact(BinderProxy.java:518) at com.tencent.shadow.dynamic.manager.BinderPluginLoader.loadPlugin(BinderPluginLoader.java:46) at com.tencent.shadow.sample.manager.FastPluginManager.loadPlugin(FastPluginManager.java:146) at com.tencent.shadow.sample.manager.FastPluginManager.convertActivityIntent(FastPluginManager.java:124) at com.tencent.shadow.sample.manager.FastPluginManager.startPluginActivity(FastPluginManager.java:117) at com.tencent.shadow.sample.manager.SamplePluginManager$1.run(SamplePluginManager.java:117) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:919) 2020-10-28 17:23:49.329 30053-30070/com.slp.apkhost E/JavaBinder: *** Uncaught remote exception! (Exceptions are not yet supported across processes.) com.tencent.shadow.dynamic.host.FailedException at com.tencent.shadow.dynamic.host.BinderUuidManager.checkException(BinderUuidManager.java:36) at com.tencent.shadow.dynamic.host.BinderUuidManager.getPlugin(BinderUuidManager.java:54) at com.tencent.shadow.dynamic.loader.impl.DynamicPluginLoader.loadPlugin(DynamicPluginLoader.kt:80) at com.tencent.shadow.dynamic.loader.impl.PluginLoaderBinder.onTransact(PluginLoaderBinder.kt:43) at android.os.Binder.execTransactInternal(Binder.java:1021) at android.os.Binder.execTransact(Binder.java:994) 2020-10-28 17:23:49.334 30053-30053/com.slp.apkhost E/AndroidRuntime: FATAL EXCEPTION: main Process: com.slp.apkhost:plugin, PID: 30053 android.content.ActivityNotFoundException: Unable to find explicit activity class {com.slp.apkhost/com.example.wakeupdemo.MainActivity}; have you declared this activity in your AndroidManifest.xml? at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2064) at android.app.Instrumentation.execStartActivity(Instrumentation.java:1720) at android.app.ContextImpl.startActivity(ContextImpl.java:967) at android.app.ContextImpl.startActivity(ContextImpl.java:938) at android.content.ContextWrapper.startActivity(ContextWrapper.java:393) at com.tencent.shadow.dynamic.loader.impl.DynamicPluginLoader$startActivityInPluginProcess$1.run(DynamicPluginLoader.kt:190) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:227) at android.app.ActivityThread.main(ActivityThread.java:7582) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:953)
有没有什么解决方案呢?大佬
没有可复现问题的代码,就自己Debug看看UuidManager和BaseDynamicPluginManager的执行情况吧。
没有可复现问题的代码,就自己Debug看看UuidManager和BaseDynamicPluginManager的执行情况吧。
好的,谢啦,有一个问题麻烦请教一下您,2个不同uuid的插件能运行在同一个进程吗? private void loadPluginLoaderAndRuntime(String uuid, String partKey) throws RemoteException, TimeoutException, FailedException { if (mPpsController == null) { bindPluginProcessService(getPluginProcessServiceName(partKey)); waitServiceConnected(10, TimeUnit.SECONDS); } loadRunTime(uuid); loadPluginLoader(uuid); }
private void loadPlugin(String uuid, String partKey) throws RemoteException, TimeoutException, FailedException { loadPluginLoaderAndRuntime(uuid, partKey); Map map = mPluginLoader.getLoadedPlugin(); if (!map.containsKey(partKey)) { mPluginLoader.loadPlugin(partKey); } } 运行在同一个进程loader、runtime不会重新加载,loadPlugin()方法会执行,但启动另一个插件失败,再次点击才能正常启动,有什么办法能处理这种情况吗?
2个不同uuid的插件能运行在同一个进程吗?
现有代码不允许。这是因为我们主要用uuid来区分同一组可以共同工作的插件、loader、runtime的不同版本。uuid不同就表示它们是不同的版本。这个设计主要用来支持插件版本升级的需求的。
但是从实现原理上,这个限制修改起来不难,可以自己试试。
同一个进程运行不同的loader实现,可以自行开发多个ClassLoader并行的实现,原理上是可行的。
@vinaiso 你好 请问这个问题最终的解决方案可以分享下吗 我也有跟你相同的业务场景,也是找不到插件里面对应的组件,做法也是差不多 插件a 插件b分别都有自己的loader和runtime, uuid也不相同
@shifujun 请问下你们插件都是直接可独立运行的单元么?像demo里面那种没有相关性的
@shifujun 请问下你们插件都是直接可独立运行的单元么?像demo里面那种没有相关性的
很多业务在密集开发后是会导致独立编译运行不了。但因为正式场景都是插件环境运行,也就没精力修复了。从技术角度上,应该是可以保持始终独立运行的。对宿主的依赖需要额外的工作使其在独立编译运行时也能满足。
@shifujun 请问下你们插件都是直接可独立运行的单元么?像demo里面那种没有相关性的
很多业务在密集开发后是会导致独立编译运行不了。但因为正式场景都是插件环境运行,也就没精力修复了。从技术角度上,应该是可以保持始终独立运行的。对宿主的依赖需要额外的工作使其在独立编译运行时也能满足。
嗯,那请问你们相关业务都是使用MultiLoaderPluginProcessService 这个进程加载的么?这样所有插件就可以互通数据了?还是说你们是采用其他的数据互通方案? 还有请问下PluginPart 是指什么? 就是一个loader runtime 下面能有多个PluginApp么
请问你们相关业务都是使用MultiLoaderPluginProcessService 这个进程加载的么?
只有个别场景用了。就是一个进程里有多个不相关的业务都使用Shadow时,它们想各自维护一套完整的插件框架不受其他业务影响。但这里不受影响主要指的是Java层面的影响。
这样所有插件就可以互通数据了?还是说你们是采用其他的数据互通方案?
插件之间的数据交换总是可以通过bindPluginService得到的Binder来交换数据。插件的Binder是能够正常跨进程通信的。
还有请问下PluginPart 是指什么? 就是一个loader runtime 下面能有多个PluginApp么
可以有多个插件app的,sample工程就是多个插件app的。这些插件在动态更新过程中apk文件肯定变化了,总要有一个不变的东西来表示它是同一个app吧,这就是PluginPart了。
@shifujun 能否在maven中增加一个插件呢?实现一个宿主调用多个插件的功能?
@shifujun 能否在maven中增加一个插件呢?实现一个宿主调用多个插件的功能?
没能理解你的意思。宿主本来就能调用多个插件。建议用fork代码后在sample中做简要修改来表达你的场景,然后另外提个issue说明。
@shifujun 能否在maven中增加一个插件呢?实现一个宿主调用多个插件的功能?
没能理解你的意思。宿主本来就能调用多个插件。建议用fork代码后在sample中做简要修改来表达你的场景,然后另外提个issue说明。
我用sample下maven作为我的开发源码, 一、将plugin-project复制了一份,作为另外一个插件,然后将里面的partKey 改为 'sample-plugin2'。将包名改为“com.tencent.shadow.sample.plugin2”。打包成zip后再重命名为"plugin2-debug.zip" 二、将manager-project 里面的 samplePluginManager.java中enter函数中复制了一个代码如下: public void enter(final Context context, long fromId, Bundle bundle, final EnterCallback callback) { if (fromId == Constant.FROM_ID_START_ACTIVITY) { bundle.putString(Constant.KEY_PLUGIN_ZIP_PATH, "/data/local/tmp/plugin-debug.zip"); bundle.putString(Constant.KEY_PLUGIN_PART_KEY, "sample-plugin"); bundle.putString(Constant.KEY_ACTIVITY_CLASSNAME, "com.tencent.shadow.sample.plugin.MainActivity"); onStartActivity(context, bundle, callback); }else if (fromId == Constant.FROM_ID_START_ACTIVITY2) { bundle.putString(Constant.KEY_PLUGIN_ZIP_PATH, "/data/local/tmp/plugin2-debug.zip"); bundle.putString(Constant.KEY_PLUGIN_PART_KEY, "sample-plugin2"); bundle.putString(Constant.KEY_ACTIVITY_CLASSNAME, "com.tencent.shadow.sample.plugin2.MainActivity"); onStartActivity(context, bundle, callback); }else if (fromId == Constant.FROM_ID_CALL_SERVICE) { callPluginService(context); } else { throw new IllegalArgumentException("不认识的fromId==" + fromId); } } 三、将宿主增加了一个按钮2,用于启动插件2.代码如下 Button button2 = new Button(this); button2.setText("启动插件2"); button2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { v.setEnabled(false);//防止点击重入
PluginManager pluginManager = InitApplication.getPluginManager();
pluginManager.enter(SecondActivity.this, FROM_ID_START_ACTIVITY2, new Bundle(), new EnterCallback() {
@Override
public void onShowLoadingView(View view) {
SecondActivity.this.setContentView(view);//显示Manager传来的Loading页面
}
@Override
public void onCloseLoadingView() {
SecondActivity.this.setContentView(linearLayout);
}
@Override
public void onEnterComplete() {
v.setEnabled(true);
}
});
}
});
linearLayout.addView(button2);
//==================================
四、将plugin-debug.zip,plugin2-debug.zip,sample-manager-debug.apk上传到 data/local/tmp下面。 五、运行sample-host ,现象是点击启动插件1按钮,插件1能起来,再点启动插件2按钮,程序崩溃。 重新安装sample-host,先点击启动插件2按钮,插件2可以起来,再点启动插件1按钮,程序崩溃。 六、错误信息如下:java.lang.RuntimeException: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.tencent.shadow.sample.host/com.tencent.shadow.sample.plugin2.MainActivity}; have you declared this activity in your AndroidManifest.xml? at com.tencent.shadow.sample.manager.SamplePluginManager$1.run(SamplePluginManager.java:102) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:919) Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.tencent.shadow.sample.host/com.tencent.shadow.sample.plugin2.MainActivity}; have you declared this activity in your AndroidManifest.xml? 七、我想知道哪里出现了问题,宿主,manager,插件1,还是插件2,我这么做的过程有没有问题呢?