Tencent / Shadow

零反射全动态Android插件框架
BSD 3-Clause "New" or "Revised" License
7.45k stars 1.3k forks source link

每个插件都需要导入loader、runtime吗? #1340

Closed hehe2015 closed 2 months ago

hehe2015 commented 3 months ago

每个插件都需要导入loader、runtime吗?

hehe2015 commented 3 months ago

我调试使用的是projects/sample/maven/host-project ,projects/sample/maven/manager-project ,projects/sample/maven/plugin-project这三个目录。

hehe2015 commented 3 months ago

我的需求是把公司的4个app合并到一个新的app里。我需要做个宿主app,和4个插件,刚开始研究这个shadow,这个4个插件都引入了loader和runtime,./gradlew packageDebugPlugin命令生成的.zip文件包含了loader、runtime.apk,但我在运行宿主时,打开的其中任意一个插件,其他3个都报错: 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:1157) at android.os.Binder.execTransact(Binder.java:1126) at android.os.BinderProxy.transactNative(Native Method) at android.os.BinderProxy.transact(BinderProxy.java:593) at com.tencent.shadow.dynamic.manager.BinderPluginLoader.loadPlugin(BinderPluginLoader.java:46) at com.tencent.shadow.sample.manager.FastPluginManager.loadPlugin(FastPluginManager.java:124) at com.tencent.shadow.sample.manager.FastPluginManager.convertActivityIntent(FastPluginManager.java:107) at com.tencent.shadow.sample.manager.FastPluginManager.startPluginActivity(FastPluginManager.java:99) at com.tencent.shadow.sample.manager.SamplePluginManager$1.run(SamplePluginManager.java:109) 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:923) *** 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:1157) at android.os.Binder.execTransact(Binder.java:1126) Timeline: Activity_launch_request time:80556348 FATAL EXCEPTION: pool-3-thread-1 Process: com.tencent.shadow.sample.host, PID: 17251 java.lang.RuntimeException: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.tencent.shadow.sample.host/com.example.testplugin.MainActivity}; have you declared this activity in your AndroidManifest.xml? at com.tencent.shadow.sample.manager.SamplePluginManager$1.run(SamplePluginManager.java:111) 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:923) Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.tencent.shadow.sample.host/com.example.testplugin.MainActivity}; have you declared this activity in your AndroidManifest.xml? at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2079) at android.app.Instrumentation.execStartActivity(Instrumentation.java:1737) at android.app.Activity.startActivityForResult(Activity.java:5436) at android.app.Activity.startActivityForResult(Activity.java:5394) at android.app.Activity.startActivity(Activity.java:5780) at android.app.Activity.startActivity(Activity.java:5733) at com.tencent.shadow.sample.manager.FastPluginManager.startPluginActivity(FastPluginManager.java:103) at com.tencent.shadow.sample.manager.SamplePluginManager$1.run(SamplePluginManager.java:109) 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:923) 重启宿主app后任一个插件都无法打开了: FATAL EXCEPTION: main Process: com.tencent.shadow.sample.host:plugin, PID: 17351 java.lang.RuntimeException: Unable to create service com.tencent.shadow.sample.introduce_shadow_lib.MainPluginProcessService: java.lang.IllegalStateException: PPS出现多实例 at android.app.ActivityThread.handleCreateService(ActivityThread.java:4308) at android.app.ActivityThread.access$1700(ActivityThread.java:258) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2002) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:236) at android.app.ActivityThread.main(ActivityThread.java:8060) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967) Caused by: java.lang.IllegalStateException: PPS出现多实例 at com.tencent.shadow.dynamic.host.BasePluginProcessService.onCreate(BasePluginProcessService.java:32) at android.app.ActivityThread.handleCreateService(ActivityThread.java:4296) at android.app.ActivityThread.access$1700(ActivityThread.java:258) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2002) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:236) at android.app.ActivityThread.main(ActivityThread.java:8060) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967) Sending signal. PID: 17351 SIG: 9 FATAL EXCEPTION: pool-3-thread-1 Process: com.tencent.shadow.sample.host, PID: 22682 java.lang.RuntimeException: java.util.concurrent.TimeoutException: 连接Service超时 ,等待了:10001 at com.tencent.shadow.sample.manager.SamplePluginManager$1.run(SamplePluginManager.java:111) 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:923) Caused by: java.util.concurrent.TimeoutException: 连接Service超时 ,等待了:10001 at com.tencent.shadow.dynamic.manager.BaseDynamicPluginManager.waitServiceConnected(BaseDynamicPluginManager.java:127) at com.tencent.shadow.sample.manager.FastPluginManager.loadPluginLoaderAndRuntime(FastPluginManager.java:114) at com.tencent.shadow.sample.manager.FastPluginManager.loadPlugin(FastPluginManager.java:121) at com.tencent.shadow.sample.manager.FastPluginManager.convertActivityIntent(FastPluginManager.java:107) at com.tencent.shadow.sample.manager.FastPluginManager.startPluginActivity(FastPluginManager.java:99) at com.tencent.shadow.sample.manager.SamplePluginManager$1.run(SamplePluginManager.java:109) 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:923) 请问这个怎么处理?🙏

shifujun commented 3 months ago

将原本4个独立app作为一个宿主app的4个插件运行,这个需求是适合基于shadow实现的。

目前source sample中已有多插件的示例。sample-app和sample-base就是两个插件,只是额外的它们有依赖关系。

注意shadow的manager管理插件版本的设计,可以多搜下issue。

多插件更复杂一点,更需要你先厘清shadow的工作原理和流程。不要试图拿开源项目当商业软件使用。绝大部分情况下,都需要根据你的业务二次开发。

hehe2015 commented 2 months ago

@shifujun 你好,我使用sample-plugin-host调试。 1.自己新建了一个plugin:添加loader、runtime,配置shadow{}

shadow {
    packagePlugin {
        pluginTypes {
            debug {
                loaderApkConfig = new Tuple2('sample-loader-debug.apk', ':sample-loader:assembleDebug')
                runtimeApkConfig = new Tuple2('sample-runtime-debug.apk', ':sample-runtime:assembleDebug')
                pluginApks {
                    pluginApk1 {
                        businessName = 'traffic-plugin'//businessName相同的插件,context获取的Dir是相同的。businessName留空,表示和宿主相同业务,直接使用宿主的Dir。
                        partKey = 'traffic-plugin'
                        buildTask = 'assemblePluginDebug'
                        apkPath = '../build/app/outputs/apk/plugin/debug/app-plugin-debug.apk'
                    }
                }
            }

            release {
                ......
            }
        }

        loaderApkProjectPath = 'sample-loader'

        runtimeApkProjectPath = 'sample-runtime'

        version = 4
        compactVersion = [1, 2, 3]
        uuidNickName = "1.1.5"
        uuid = "FBE0DBFA-A3B1-4785-838F-79636F65F00F"
    }
}

2.在sample-host的MainActivity中增加:

Button traffic = new Button(this);
        traffic.setText("###启动traffic插件");
        traffic.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, PluginLoadActivity.class);

                intent.putExtra("zipPath","/data/user/0/com.tencent.shadow.sample.host/files/traffic-plugin-debug.zip");

                intent.putExtra(Constant.KEY_PLUGIN_PART_KEY, "traffic-plugin");
                intent.putExtra(Constant.KEY_ACTIVITY_CLASSNAME, "xxx.MainActivity");
                startActivity(intent);
            }
        });
        rootView.addView(traffic);

3.manager -> amplePluginManager -> onStartActivity 修改:

executorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    InstalledPlugin installedPlugin = installPlugin(pluginZipPath, null, true);
                    System.out.println("##Bundle uuid: " + installedPlugin.UUID);

                    /*loadPlugin(installedPlugin.UUID, PART_KEY_PLUGIN_BASE);
                    loadPlugin(installedPlugin.UUID, PART_KEY_PLUGIN_MAIN_APP);
                    callApplicationOnCreate(PART_KEY_PLUGIN_BASE);
                    callApplicationOnCreate(PART_KEY_PLUGIN_MAIN_APP);*/

                    ///此处增加
                    loadPlugin(installedPlugin.UUID, partKey);
                    callApplicationOnCreate(partKey);

                    Intent pluginIntent = new Intent();
                    pluginIntent.setClassName(
                            context.getPackageName(),
                            className
                    );

4.复制traffic-plugin-debug.zip到设备。

5.打开host应用,直接启动我的traffic插件,报错:

Shutting down VM
FATAL EXCEPTION: main
Process: com.tencent.shadow.sample.host:plugin, PID: 11161
android.content.ActivityNotFoundException: Unable to find explicit activity class {com.tencent.shadow.sample.host/com.tencent.shadow.sample.runtime.PluginDefaultProxyActivity}; have you declared this activity in your AndroidManifest.xml?
    at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2079)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1737)
    at android.app.ContextImpl.startActivity(ContextImpl.java:1033)
    at android.app.ContextImpl.startActivity(ContextImpl.java:1004)
    at android.content.ContextWrapper.startActivity(ContextWrapper.java:414)
    at com.tencent.shadow.dynamic.loader.impl.DynamicPluginLoader$startActivityInPluginProcess$1.run(DynamicPluginLoader.kt:190)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:236)
    at android.app.ActivityThread.main(ActivityThread.java:8060)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)

*但是我如果先启动插件“sample-plugin-app” ,返回,再启动我创建的插件,有能打开了,请问是哪里配置错了吗?