shadow插件中使用 EventBus产生的问题
在shadow插件中使用Eventbus。代码如下: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ... EventBus.getDefault().register(this); }
启动后会报如下错误:
Process: com.tencent.shadow.sample.host:plugin, PID: 29900 java.lang.NoClassDefFoundError: android.app.PictureInPictureParams at libcore.reflect.InternalNames.getClass(InternalNames.java:55) at java.lang.Class.getDexCacheType(Class.java:2551) at java.lang.reflect.AbstractMethod.getParameterTypes(AbstractMethod.java:169) at java.lang.reflect.Method.getParameterTypes(Method.java:193) at java.lang.reflect.Method$1.compare(Method.java:72) at java.lang.reflect.Method$1.compare(Method.java:66) at libcore.util.CollectionUtils.removeDuplicates(CollectionUtils.java:89) at java.lang.Class.getMethods(Class.java:1423) at org.greenrobot.eventbus.SubscriberMethodFinder.findUsingReflectionInSingleClass(SubscriberMethodFinder.java:157) at org.greenrobot.eventbus.SubscriberMethodFinder.findUsingInfo(SubscriberMethodFinder.java:88) at org.greenrobot.eventbus.SubscriberMethodFinder.findSubscriberMethods(SubscriberMethodFinder.java:64) at org.greenrobot.eventbus.EventBus.register(EventBus.java:140) at com.gykj.commontool.locationservicetest.LocationServiceTestActivity.onCreate(LocationServiceTestActivity.java:36) at com.tencent.shadow.core.loader.delegates.ShadowActivityDelegate.onCreate(Unknown Source) at com.tencent.shadow.core.runtime.container.PluginContainerActivity.onCreate(PluginContainerActivity.java:84) at android.app.Activity.performCreate(Activity.java:6910) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2757) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2875) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1578) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:156) at android.app.ActivityThread.main(ActivityThread.java:6618) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832) Caused by: java.lang.ClassNotFoundException: Didn't find class "android.app.PictureInPictureParams" on path: DexPathList[[zip file "/data/user/0/com.tencent.shadow.sample.host/files/ShadowPluginManager/UnpackedPlugin/sample-manager/7ebf44f2867797786e2f30966c82c6cb/plugin-debug.zip/sample-runtime-debug.apk"],nativeLibraryDirectories=[/data/user/0/com.tencent.shadow.sample.host/files/ShadowPluginManager/UnpackedPlugin/sample-manager/lib/E442EB4E-D377-4F4B-AC7A-57050F7820D7_lib, /system/lib64, /vendor/lib64, /system/vendor/lib64, /product/lib64]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56) at java.lang.ClassLoader.loadClass(ClassLoader.java:380) at java.lang.ClassLoader.loadClass(ClassLoader.java:312) at com.tencent.shadow.dynamic.apk.ApkClassLoader.loadClass(ApkClassLoader.java:86) at java.lang.ClassLoader.loadClass(ClassLoader.java:312) at libcore.reflect.InternalNames.getClass(InternalNames.java:53) at java.lang.Class.getDexCacheType(Class.java:2551) at java.lang.reflect.AbstractMethod.getParameterTypes(AbstractMethod.java:169) at java.lang.reflect.Method.getParameterTypes(Method.java:193) at java.lang.reflect.Method$1.compare(Method.java:72) at java.lang.reflect.Method$1.compare(Method.java:66) at libcore.util.CollectionUtils.removeDuplicates(CollectionUtils.java:89) at java.lang.Class.getMethods(Class.java:1423) at org.greenrobot.eventbus.SubscriberMethodFinder.findUsingReflectionInSingleClass(SubscriberMethodFinder.java:157) at org.greenrobot.eventbus.SubscriberMethodFinder.findUsingInfo(SubscriberMethodFinder.java:88) at org.greenrobot.eventbus.SubscriberMethodFinder.findSubscriberMethods(SubscriberMethodFinder.java:64) at org.greenrobot.eventbus.EventBus.register(EventBus.java:140) at com.gykj.commontool.locationservicetest.LocationServiceTestActivity.onCreate(LocationServiceTestActivity.java:36) at com.tencent.shadow.core.loader.delegates.ShadowActivityDelegate.onCreate(Unknown Source) at com.tencent.shadow.core.runtime.container.PluginContainerActivity.onCreate(PluginContainerActivity.java:84) at android.app.Activity.performCreate(Activity.java:6910) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2757) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2875) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1578) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:156) at android.app.ActivityThread.main(ActivityThread.java:6618) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832) Suppressed: java.lang.ClassNotFoundException: Didn't find class "android.app.PictureInPictureParams" on path: DexPathList[[zip file "/data/user/0/com.tencent.shadow.sample.host/files/ShadowPluginManager/UnpackedPlugin/sample-manager/7ebf44f2867797786e2f30966c82c6cb/plugin-debug.zip/sample-loader-debug.apk"],nativeLibraryDirectories=[/data/user/0/com.tencent.shadow.sample.host/files/ShadowPluginManager/UnpackedPlugin/sample-manager/lib/E442EB4E-D377-4F4B-AC7A-57050F7820D7_lib, /system/lib64, /vendor/lib64, /system/vendor/lib64, /product/lib64]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56) at com.tencent.shadow.dynamic.apk.ApkClassLoader.loadClass(ApkClassLoader.java:79) ... 28 more
看起来是EventBus的代码写了一些不安全的反射逻辑。找不到android.app.PictureInPictureParams这种系统类的情况,你可以在插件里自己定义一个这个名字的类来解决。
这是因为EventBus会去寻遍历所有register的类(包括其父类),用来查找被@Subscribe注解标记的类,但是系统SDK的类将被忽略(看这里) 所以,最好的办法是忽略Shadow中代替Activity的类(ShadowActivity及其父类) 可以这么改: ` void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
// Skip system classes, this degrades performance.
// Also we might avoid some ClassNotFoundException (see FAQ for background).
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") ||
clazzName.startsWith("android.") || clazzName.startsWith("androidx.")
|| clazzName.startsWith("com.tencent.shadow.core")) {
clazz = null;
}
}
}`
有能力的也可以通过插件用javassist来改这里
这是因为EventBus会去寻遍历所有类(包括其父类),用来查找被@subscribe注解标记的类,但是系统SDK的类将被忽略(看这里) 所以,最好的办法是忽略Shadow中代替Activity的类(ShadowActivity及其父类) 可以这么改: ` void moveToSuperclass() {
if (skipSuperClasses) { clazz = null; } else { clazz = clazz.getSuperclass(); String clazzName = clazz.getName(); // Skip system classes, this degrades performance. // Also we might avoid some ClassNotFoundException (see FAQ for background). if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.") || clazzName.startsWith("androidx.") || clazzName.startsWith("com.tencent.shadow.core")) { clazz = null; } } }`有能力的也可以通过插件用javassist来改这里
这段代码是不是也可以通过判断clazz的ClassLoader来区分是否是系统类呀?
这是因为EventBus会去寻遍历所有类(包括其父类),用来查找被@subscribe注解标记的类,但是系统SDK的类将被忽略(看这里) 所以,最好的办法是忽略Shadow中代替Activity的类(ShadowActivity及其父类) 可以这么改: ` void moveToSuperclass() {
if (skipSuperClasses) { clazz = null; } else { clazz = clazz.getSuperclass(); String clazzName = clazz.getName(); // Skip system classes, this degrades performance. // Also we might avoid some ClassNotFoundException (see FAQ for background). if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.") || clazzName.startsWith("androidx.") || clazzName.startsWith("com.tencent.shadow.core")) { clazz = null; } } }`有能力的也可以通过插件用javassist来改这里
这段代码是不是也可以通过判断
clazz的ClassLoader来区分是否是系统类呀?
我简单看了下框架代码 loader runtime 下的类由apkClassLoader加载 插件中的类由pluginClassLoader加载 一般只有业务代码中会用到eventBus 也就是说只要是eventbus只去检测pluginClassLoader加载的类就可以了
但是如果单独运行apk呢 这时候所有的类都是系统的ClassLoader加载啊 那是不是就要弄两套eventBus库啊
或者说忽略由apkClassLoader加载的类就可以
但是如果单独运行apk呢 这时候所有的类都是系统的ClassLoader加载啊 那是不是就要弄两套eventBus库啊
单独运行的时候,系统类也跟app的类不在一个ClassLoader。app的类正常在PathClassLoader里。插件运行时换成了PluginClassLoader。EventBus自己所在的ClassLoader就是app的ClassLoader。
但是如果单独运行apk呢 这时候所有的类都是系统的ClassLoader加载啊 那是不是就要弄两套eventBus库啊
单独运行的时候,系统类也跟app的类不在一个ClassLoader。app的类正常在PathClassLoader里。插件运行时换成了PluginClassLoader。EventBus自己所在的ClassLoader就是app的ClassLoader。
那这么改应该更好一点
` void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
//String clazzName = clazz.getName();
// Skip system classes, this degrades performance.
// Also we might avoid some ClassNotFoundException (see FAQ for background).
if (getClass().getClassLoader().getClass() != clazz.getClassLoader().getClass()) {
clazz = null;
}
}
}
`
但是如果单独运行apk呢 这时候所有的类都是系统的ClassLoader加载啊 那是不是就要弄两套eventBus库啊
单独运行的时候,系统类也跟app的类不在一个ClassLoader。app的类正常在PathClassLoader里。插件运行时换成了PluginClassLoader。EventBus自己所在的ClassLoader就是app的ClassLoader。
那这么改应该更好一点
` void moveToSuperclass() {
if (skipSuperClasses) { clazz = null; } else { clazz = clazz.getSuperclass(); //String clazzName = clazz.getName(); // Skip system classes, this degrades performance. // Also we might avoid some ClassNotFoundException (see FAQ for background). if (getClass().getClassLoader().getClass() != clazz.getClassLoader().getClass()) { clazz = null; } } }`
Hi,这个问题您最后是怎么解决的啊,通过javassist修改SubscriberMethodFinder 这个类嘛?
是的,我就是自定了了一个transform专门用于修改这个类,问题解决了
是的,我就是自定了了一个transform专门用于修改这个类,问题解决了
请问有没有放到远程的插件直接使用的,不会写这个transform。。