sensorsdata / sa-sdk-android

神策数据官方 Android 埋点 SDK,是一款轻量级用于 Android 端的数据采集埋点 SDK,包含代码埋点、全埋点、点击图和可视化全埋点功能。全埋点通过配合神策官方 Android 埋点插件来实现,神策数据官方 Android 埋点插件使用字节码插桩(ASM)的技术实现 Android 端的全埋点(无埋点、无码埋点、无痕埋点、自动埋点)。
http://opensource.sensorsdata.cn
Other
1.31k stars 434 forks source link

与Realm数据库冲突 #68

Closed AwakenDragon closed 4 years ago

AwakenDragon commented 4 years ago

主module apply plugin: 'com.sensorsdata.analytics.android' apply plugin: 'realm-android' 其它module apply plugin: 'realm-android'

同时引入神策和Realm数据库,编译无法通过。 报错信息: Type io.realm.DefaultRealmModule is defined multiple times: /Users/zhou/workspace/android/JDXL/app/build/intermediates/project_dex_archive/AliyunDebug/out/io/realm/DefaultRealmModule.dex, /Users/zhou/workspace/android/JDXL/app/build/intermediates/mixed_scope_dex_archive/AliyunDebug/out/82421774901896ca028ce13eb6b35e68091364770fddf70cce4d0eb3fc6efcbe_1.jar:classes.dex

dengshiwei commented 4 years ago

@AwakenDragon 感谢反馈,明天工作日研发同学验证下。

GvcZhang commented 4 years ago

@AwakenDragon 本地验证,使用如下版本

classpath "io.realm:realm-gradle-plugin:6.0.2"

以及同时使用 Realm PluginSA Plugin 测试,可以正常通过编译。可能是还有其他因素导致的,你可以将 io.realm包加入到插件处理的黑名单中 再尝试编译一次。 如果还是无法解决,请发一个能复现的 Demo 给我们,我们好排查问题。

AwakenDragon commented 4 years ago

冲突出现的具体操作: 1.项目中包含多个module 2.主module和其它module同时引入Realm Plugin,并且每个module中新建几个继承RealmObject的Model。编译,每个module都会自动生成一个DefaultRealmModuleMediator类。此时主module未引入SA Plugin,可以运行,可以打包,没有问题 3.在2条件的基础上引入SA Plugin,无法编译通过,报Type io.realm.DefaultRealmModule is defined multiple times错误 解决方案:子module中,注解@RealmModule的属性library必须设置为true

GvcZhang commented 4 years ago

根据 @RealmModule上的注释来看,在 library moduleapp module同时引入Realm的时候确实需要给这个注解加上 library=true这个属性,这是一个正确的做法:

RealmModules and libraries Realms default behavior is to automatically create a RealmModule called DefaultRealmModule which contains all classes extending RealmObject in a project. This module is automatically known by Realm. This behavior is problematic when combining a library project and an app project that both uses Realm. This is because the DefaultRealmModule will be created for both the library project and the app project, which will cause the project to fail with duplicate class definition errors. Library authors are responsible for avoiding this conflict by using explicit modules where library = true is set. This disables the generation of the DefaultRealmModule for the library project and allows the library to be included in the app project that also uses Realm. This means that library projects that uses Realm internally are required to specify a specific module using RealmConfiguration.modules(). App developers are not required to specify any modules, as they implicitly use the DefaultRealmModule, but they now has the option of adding the library project classes to their schema using RealmConfiguration.addModule().

至于项目中为啥会在引入 SA Plugin 后出错,从提供的错误日志上看并非插件导致的,插件只会处理字节码,相反在没有引入插件的情况下能够编译通过似乎反而说不通,不知道是否是因为缓存的原因导致的?

GvcZhang commented 4 years ago

本地集成 Realm 验证,在不使用 SA Plugin 以及设置 Library 中 @RealmModule(library=false) 的情况下总是会报如下错误:

java.lang.RuntimeException: java.lang.RuntimeException: com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: 
Learn how to resolve the issue at https://developer.android.com/studio/build/dependencies#duplicate_classes.
Program type already present: io.realm.DefaultRealmModuleMediator
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:593)
        at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
        at java.util.concurrent.ForkJoinTask.join(ForkJoinTask.java:720)
        at com.google.common.collect.ImmutableList.forEach(ImmutableList.java:407)

跟题主反馈的问题相近。另外设置 Library 中 @RealmModule(library=true) 的情况下,加或者不加 SA Plugin 都不会报错。项目使用的 Realm 版本如下:

 classpath "io.realm:realm-gradle-plugin:6.0.2"

暂定此问题与插件关系不大。