如何使用导航架构组件修复动态功能模块中片段的发布版本中的 ClassNotFoundException?
How to fix ClassNotFoundException in release build for a fragment in a Dynamic Feature Module using Navigation Architecture Component?
我正在尝试使用动态功能模块构建应用程序,没有 按需支持。
我的应用程序结构如下所示:
-app
---MainActivity
-base
---SharedFile
-comments
---CommentsFragment
-posts
---PostsFragment
当然,每个模块中还有其他文件。
应用程序的调试构建工作正常,发布构建编译成功。但是,在发布版本中,我遇到了 CommentsFragment 和 PostsFragment 都出现 ClassNotFound Exception
的运行时崩溃。
即使在我的发布版本 (minifyEnabled false
) 上没有启用混淆器,也会发生此错误。当我启用 Proguard 时,结果是一样的。我尝试将以下混淆器规则添加到应用程序模块混淆器文件(取自 here):
-keep public class * extends android.app.Activity
-keep public class * extends androidx.fragment.app.Fragment
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.content.Context {
public void *(android.view.View);
public void *(android.view.MenuItem);
}
-keepclassmembers class * implements android.os.Parcelable {
static ** CREATOR;
}
-keepclassmembers class **.R$* {
public static <fields>;
}
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
结果还是一样:运行时崩溃。
这是我的应用程序模块 build.gradle
文件:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'androidx.navigation.safeargs.kotlin'
android {
compileSdkVersion ProjectProps.compileSdk
defaultConfig {
applicationId ProjectProps.applicationId
minSdkVersion ProjectProps.minSdk
targetSdkVersion ProjectProps.targetSdk
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
dynamicFeatures = [":users", ":posts"]
packagingOptions {
exclude 'META-INF/atomicfu.kotlin_module'
}
dataBinding {
enabled = true
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(path: ':base')
api project(path: ':json-placeholder-repository')
...
}
这是我得到的完整错误:
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.app.usersmodule.UsersFragment" on path: DexPathList[[zip file "/data/app/com.app-r8BPSasOKhil086vurQf4g==/base.apk"],nativeLibraryDirectories=[/data/app/com.app-r8BPSasOKhil086vurQf4g==/lib/arm64, /system/lib64, /vendor/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at androidx.fragment.app.FragmentFactory.loadClass(FragmentFactory.java:50)
at androidx.fragment.app.FragmentFactory.loadFragmentClass(FragmentFactory.java:91)
我不确定我做错了什么,因为调试构建工作正常。
这似乎是 Nav AAC 的局限性,因为它会在图表 inflation 期间检查所有 classes 在运行时是否存在。我不确定为什么 class 不存在。我在项目中禁用了 Proguard,因此 none 的代码被删除了。
问题出在将签名的 APK 部署到设备上,而不是使用 Android App Bundle 格式生成签名的 APK。
创建签名的 AAB,然后使用来自 Google 的 bundletool
将其转换为签名的 APK,创建一个包含所有片段和 类 的 APK。这在我的设备上运行得很好。
如果您的项目有动态功能模块,请使用 AAB。
我正在尝试使用动态功能模块构建应用程序,没有 按需支持。
我的应用程序结构如下所示:
-app
---MainActivity
-base
---SharedFile
-comments
---CommentsFragment
-posts
---PostsFragment
当然,每个模块中还有其他文件。
应用程序的调试构建工作正常,发布构建编译成功。但是,在发布版本中,我遇到了 CommentsFragment 和 PostsFragment 都出现 ClassNotFound Exception
的运行时崩溃。
即使在我的发布版本 (minifyEnabled false
) 上没有启用混淆器,也会发生此错误。当我启用 Proguard 时,结果是一样的。我尝试将以下混淆器规则添加到应用程序模块混淆器文件(取自 here):
-keep public class * extends android.app.Activity
-keep public class * extends androidx.fragment.app.Fragment
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.content.Context {
public void *(android.view.View);
public void *(android.view.MenuItem);
}
-keepclassmembers class * implements android.os.Parcelable {
static ** CREATOR;
}
-keepclassmembers class **.R$* {
public static <fields>;
}
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
结果还是一样:运行时崩溃。
这是我的应用程序模块 build.gradle
文件:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'androidx.navigation.safeargs.kotlin'
android {
compileSdkVersion ProjectProps.compileSdk
defaultConfig {
applicationId ProjectProps.applicationId
minSdkVersion ProjectProps.minSdk
targetSdkVersion ProjectProps.targetSdk
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
dynamicFeatures = [":users", ":posts"]
packagingOptions {
exclude 'META-INF/atomicfu.kotlin_module'
}
dataBinding {
enabled = true
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(path: ':base')
api project(path: ':json-placeholder-repository')
...
}
这是我得到的完整错误:
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.app.usersmodule.UsersFragment" on path: DexPathList[[zip file "/data/app/com.app-r8BPSasOKhil086vurQf4g==/base.apk"],nativeLibraryDirectories=[/data/app/com.app-r8BPSasOKhil086vurQf4g==/lib/arm64, /system/lib64, /vendor/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at androidx.fragment.app.FragmentFactory.loadClass(FragmentFactory.java:50)
at androidx.fragment.app.FragmentFactory.loadFragmentClass(FragmentFactory.java:91)
我不确定我做错了什么,因为调试构建工作正常。
这似乎是 Nav AAC 的局限性,因为它会在图表 inflation 期间检查所有 classes 在运行时是否存在。我不确定为什么 class 不存在。我在项目中禁用了 Proguard,因此 none 的代码被删除了。
问题出在将签名的 APK 部署到设备上,而不是使用 Android App Bundle 格式生成签名的 APK。
创建签名的 AAB,然后使用来自 Google 的 bundletool
将其转换为签名的 APK,创建一个包含所有片段和 类 的 APK。这在我的设备上运行得很好。
如果您的项目有动态功能模块,请使用 AAB。