I built a minimal Unreal Engine 4.25.4 plugin with androidx dependencies, put it into a very simple project, and am trying to package the app for Android 29+ (and have configured the Unreal Editor to do so).The root of the issue I am trying to solve is duplicate classes in androidx and legacy dependencies.
There are lots of examples for getting this working out there w/ Android Studio, and only a couple examples for Unreal Engine -> Android...and none of them worked for me. Below is the UPL file and a few other things I have tried to solve the androidx compat issue. Does anybody know how to solve this issue using Gradle?
The app builds successfully with the UPL.xml file further down in this post, but when Unreal deploys the APK file to the phone it crashes immediately with this error:
Using AndroidStudio to inspec the Dex files in the generated APK does not help because `SupportActivity` _is_ listed.
UPL.xml:
In UPL.xml I replace `com.android.support:support-compat` with `androidx.core:core` because _not_ doing that results in a build failure w/ duplicate classes. When I removed the module replacement, I got this error:
I tried the solution here https://medium.com/nineva/how-to-for...x-f7060abd56ac initially, but could not get Jetpack to work out of the box with the `android.useAndroidX=true` and `android.enableJetifier=true` flags. When I enabled those flags, I got this error:
There are lots of examples for getting this working out there w/ Android Studio, and only a couple examples for Unreal Engine -> Android...and none of them worked for me. Below is the UPL file and a few other things I have tried to solve the androidx compat issue. Does anybody know how to solve this issue using Gradle?
The app builds successfully with the UPL.xml file further down in this post, but when Unreal deploys the APK file to the phone it crashes immediately with this error:
Code:
11-05 10:53:41.468 16597 16597 E AndroidRuntime: FATAL EXCEPTION: main 11-05 10:53:41.468 16597 16597 E AndroidRuntime: Process: com.example.myplugin, PID: 16597 11-05 10:53:41.468 16597 16597 E AndroidRuntime: java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/app/BaseFragmentActivityApi16; 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.arch.lifecycle.LifecycleDispatcher.init(LifecycleDispatcher.java:55) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.arch.lifecycle.ProcessLifecycleOwnerInitializer.onCreate(ProcessLifecycleOwnerInitializer.java:35) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.content.ContentProvider.attachInfo(ContentProvider.java:2092) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.content.ContentProvider.attachInfo(ContentProvider.java:2066) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.app.ActivityThread.installProvider(ActivityThread.java:6983) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.app.ActivityThread.installContentProviders(ActivityThread.java:6528) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6445) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.app.ActivityThread.access$1300(ActivityThread.java:219) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1859) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:107) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.os.Looper.loop(Looper.java:214) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7356) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: Caused by: java.lang.ClassNotFoundException: android.support.v4.app.BaseFragmentActivityApi16 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at java.lang.VMClassLoader.findLoadedClass(Native Method) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at java.lang.ClassLoader.findLoadedClass(ClassLoader.java:738) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:363) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:312) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: ... 15 more 11-05 10:53:41.468 16597 16597 E AndroidRuntime: Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/app/BaseFragmentActivityApi14; 11-05 10:53:41.468 16597 16597 E AndroidRuntime: ... 15 more 11-05 10:53:41.468 16597 16597 E AndroidRuntime: Caused by: java.lang.ClassNotFoundException: android.support.v4.app.BaseFragmentActivityApi14 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at java.lang.VMClassLoader.findLoadedClass(Native Method) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at java.lang.ClassLoader.findLoadedClass(ClassLoader.java:738) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:363) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:312) 11-05 10:53:41.468 16597 16597 E AndroidRuntime: ... 15 more 11-05 10:53:41.468 16597 16597 E AndroidRuntime: Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/app/SupportActivity; 11-05 10:53:41.468 16597 16597 E AndroidRuntime: ... 15 more 11-05 10:53:41.468 16597 16597 E AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v4.app.SupportActivity" on path: DexPathList[[zip file "/data/app/com.example.myplugin-qOQ_ANOu4wWHW-5-4RHeeA==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.myplugin-qOQ_ANOu4wWHW-5-4RHeeA==/lib/arm, /data/app/com.example.myplugin-qOQ_ANOu4wWHW-5-4RHeeA==/base.apk!/lib/armeabi-v7a, /system/lib, /product/lib]]
UPL.xml:
Code:
<root xmlns:android="http://schemas.android.com/apk/res/android"> <androidManifestUpdates> <addPermission android:name="android.permission.INTERNET" /> <addPermission android:name="android.permission.READ_PHONE_STATE" /> </androidManifestUpdates> <proguardAdditions> <!-- -keep class android.support.v4.app.SupportActivity.java --> </proguardAdditions> <buildGradleAdditions> <insert> repositories { mavenCentral() } dependencies { implementation 'androidx.core:core:1.3.2' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.appcompat:appcompat:1.1.0' modules { module('com.android.support:support-compat') { replacedBy('androidx.core:core', 'androidx in use') } } } android { defaultConfig { multiDexEnabled true } } </insert> </buildGradleAdditions> <buildscriptGradleAdditions> <insert> </insert> </buildscriptGradleAdditions> <gradleProperties> <insert> <!-- android.useAndroidX=true android.enableJetifier=true --> </insert> </gradleProperties> <baseBuildGradleAdditions> <insert> allprojects { def mappings = [ 'android.support.v4.app.NotificationCompat': 'androidx.core.app.NotificationCompat', 'android.arch.lifecycle.Lifecycle': 'androidx.lifecycle.Lifecycle', 'android.arch.lifecycle.OnLifecycleEvent': 'androidx.lifecycle.OnLifecycleEvent', 'android.arch.lifecycle.ProcessLifecycleOwner': 'androidx.lifecycle.ProcessLifecycleOwner', 'android.support.annotation.NonNull': 'androidx.annotation.NonNull', 'android.support.annotation.NonNull': 'androidx.annotation.NonNull', 'android.support.annotation.Nullable': 'androidx.annotation.Nullable', 'android.support.v4.app.NotificationCompat': 'androidx.core.app.NotificationCompat', 'android.support.v4.app.ActivityCompat': 'androidx.core.app.ActivityCompat', 'android.support.v4.content.ContextCompat': 'androidx.core.content.ContextCompat', 'android.support.v4.app.NotificationManagerCompat': 'androidx.core.app.NotificationManagerCompat', 'android.support.v4.content.FileProvider': 'androidx.core.content.FileProvider', 'android.support.v4.content.ContextCompat': 'androidx.core.content.ContextCompat' ] beforeEvaluate { project -> print(project.toString()) task modifyAppGameActivityForRemovedPermissionsLibrary() { if (project.toString() == "project ':app'") { println 'modifyAppGameActivityForRemovedPermissionsLibrary: ' + "${System.getProperty('user.dir')}/app/src/main/java/com/epicgames/ue4/GameActivity.java" def file = "src/main/java/com/epicgames/ue4/GameActivity.java" ant.replace(file: file, token: 'com.google.vr.sdk.samples.permission.PermissionHelper', value: 'android.Manifest') ant.replace(file: file, token: 'PermissionHelper.checkPermission("android.permission.GET_ACCOUNTS")', value: 'checkCallingOrSelfPermission("android.permission.GET_ACCOUNTS") == PackageManager.PERMISSION_GRANTED') ant.replace(file: file, token: 'PermissionHelper.checkPermission("android.permission.WRITE_EXTERNAL_STORAGE")', value: '(checkCallingOrSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE") == PackageManager.PERMISSION_GRANTED)') } } task modifyAppGradleProjectsForRemovedPermissionsLibrary() { if (project.toString() == "project ':app'") { println 'modifyAppGradleProjectsForRemovedPermissionsLibrary: ' + "${System.getProperty('user.dir')}/app/projects.gradle" ant.replace(file: "projects.gradle", token: "implementation project(':permission_library')", value: '') } } task removePermissionsLibraryFromGradleSettings() { println 'removePermissionsLibraryFromGradleSettings: ' + "${System.getProperty('user.dir')}/settings.gradle" ant.replace(file: "${System.getProperty('user.dir')}/settings.gradle", token: "include ':permission_library'", value: '') } project.rootProject.projectDir.traverse(type: groovy.io.FileType.FILES, nameFilter: ~/.*\.java$/) { f -> mappings.each { entry -> if (f.getText('UTF-8').contains(entry.key)) { println "mapping legacy ${entry.key} to ${entry.value} in file ${f}" ant.replace(file: f, token: entry.key, value: entry.value) } } } } } </insert> </baseBuildGradleAdditions> <gameActivityImportAdditions> <insert> //import androidx.etc; </insert> </gameActivityImportAdditions> <gameActivityClassAdditions> <insert> public void myCustomMethod() { } </insert> </gameActivityClassAdditions> </root>
Code:
Execution failed for task ':app:checkDebugDuplicateClasses'. LogPlayLevel: > 1 exception was raised by workers: LogPlayLevel: java.lang.RuntimeException: Duplicate class android.support.v4.app.INotificationSideChannel found in modules core-1.3.2-runtime.jar (androidx.core:core:1.3.2) and support-compat-27.1.0-runtime.jar (com.android.support:support-compat:27.1.0) LogPlayLevel: Duplicate class android.support.v4.app.INotificationSideChannel$Stub found in modules core-1.3.2-runtime.jar (androidx.core:core:1.3.2) and support-compat-27.1.0-runtime.jar (com.android.support:support-compat:27.1.0) LogPlayLevel: Duplicate class android.support.v4.app.INotificationSideChannel$Stub$Proxy found in modules core-1.3.2-runtime.jar (androidx.core:core:1.3.2) and support-compat-27.1.0-runtime.jar (com.android.support:support-compat:27.1.0) LogPlayLevel: 27 actionable tasks: 6 executed, 21 up-to-date LogPlayLevel: Duplicate class android.support.v4.os.IResultReceiver found in modules core-1.3.2-runtime.jar (androidx.core:core:1.3.2) and support-compat-27.1.0-runtime.jar (com.android.support:support-compat:27.1.0) LogPlayLevel: Duplicate class android.support.v4.os.IResultReceiver$Stub found in modules core-1.3.2-runtime.jar (androidx.core:core:1.3.2) and support-compat-27.1.0-runtime.jar (com.android.support:support-compat:27.1.0) LogPlayLevel: Duplicate class android.support.v4.os.IResultReceiver$Stub$Proxy found in modules core-1.3.2-runtime.jar (androidx.core:core:1.3.2) and support-compat-27.1.0-runtime.jar (com.android.support:support-compat:27.1.0) LogPlayLevel: Duplicate class android.support.v4.os.ResultReceiver found in modules core-1.3.2-runtime.jar (androidx.core:core:1.3.2) and support-compat-27.1.0-runtime.jar (com.android.support:support-compat:27.1.0) LogPlayLevel: Duplicate class android.support.v4.os.ResultReceiver$1 found in modules core-1.3.2-runtime.jar (androidx.core:core:1.3.2) and support-compat-27.1.0-runtime.jar (com.android.support:support-compat:27.1.0) LogPlayLevel: Duplicate class android.support.v4.os.ResultReceiver$MyResultReceiver found in modules core-1.3.2-runtime.jar (androidx.core:core:1.3.2) and support-compat-27.1.0-runtime.jar (com.android.support:support-compat:27.1.0) LogPlayLevel: Duplicate class android.support.v4.os.ResultReceiver$MyRunnable found in modules core-1.3.2-runtime.jar (androidx.core:core:1.3.2) and support-compat-27.1.0-runtime.jar (com.android.support:support-compat:27.1.0) LogPlayLevel: Go to the documentation to learn how to <a href="d.android.com/r/tools/classpath-sync-errors">Fix dependency resolution errors</a>.
Code:
> Failed to apply plugin [id 'com.android.application'] LogPlayLevel: > Cannot parse project property android.useAndroidX='true ' of type 'class java.lang.String' as boolean. Expected 'true' or 'false'. LogPlayLevel: * Try: