androidx dependency issues: Didn't find class "android.support.v4.app.SupportActivity" on path

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:



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]]


Using AndroidStudio to inspec the Dex files in the generated APK does not help because SupportActivity is listed.

UPL.xml:


<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>

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:


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>.

I tried the solution here How to force the Unreal Engine Android project to use AndroidX? | by Taras Leskiv | nineva | Medium 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:


> 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: