Search code examples
c#xamarinxamarin.formsxamarin.androidandroidx

Xamarin Android getting Didn't find class "androidx.lifecycle.ProcessLifecycleOwnerInitializer" after migrating to AndroidX


After migrating to AndroidX and updating all AndriodX packages to latest, builds would fail showing me three similar errors in build-generated XML files in obj folder:

  1. \obj\Debug\100\lp\117\jl\res\values\values.xml: Found tag id where item is expected

The XML file content is:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <id name="view_tree_lifecycle_owner"/>
</resources>
  1. \obj\Debug\100\lp\121\jl\res\values\values.xml: Found tag id where item is expected

The XML file content is:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <id name="view_tree_saved_state_registry_owner"/>
</resources>
  1. \obj\Debug\100\lp\123\jl\res\values\values.xml: Found tag id where item is expected

The XML file content is:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <id name="view_tree_view_model_store_owner"/>
</resources>

After looking for solutions online, I just changed <id name="... to <item type="id" name="... in each of the generated files and the build succeeded (even though I have to re-do this every time I clean/rebuild).

However, right after the app's splash screen, it app crashes showing the following exception:

Java.Lang.RuntimeException: 'Unable to get provider androidx.lifecycle.ProcessLifecycleOwnerInitializer: java.lang.ClassNotFoundException: Didn't find class "androidx.lifecycle.ProcessLifecycleOwnerInitializer" on path: DexPathList...

I looked that up and found many solutions suggesting enabling and/or configuring multi-dex, none of which ever worked.

The problem occurs only when linking is set to Sdk Assemblies Only or Sdk and User Assemblies.

Here's some of the configuration that didn't work with me:

  • I have tried enabling/disabling Enable Multi-Dex in Android Options tab in project properties.

  • I have tried setting android:name attribute in application tag in AndroidManifest.xml to androidx.multidex.MultiDexApplication.

  • I have tried to make MainApplication class inherit from Android.Support.MultiDex.MultiDexApplication (defined in XamarinLibrary.Xamarin.Android.Support.Multidex) instead of Android.App.Application.

  • I have tried to make MainApplication class inherit from manually created binding for AndroidX MultiDexApplication like this:

MultiDex.cs:

using Android.Content;
using Android.Runtime;

using Java.Interop;

using System;

namespace OnePoint
{
    [Register("androidx/multidex/MultiDex", DoNotGenerateAcw = true)]
    public sealed class MultiDex : Java.Lang.Object
    {
        private static readonly JniPeerMembers _members = new XAPeerMembers("androidx/multidex/MultiDex", typeof(MultiDex));

        internal static IntPtr class_ref => _members.JniPeerType.PeerReference.Handle;

        public override JniPeerMembers JniPeerMembers => _members;

        protected override IntPtr ThresholdClass => _members.JniPeerType.PeerReference.Handle;

        protected override Type ThresholdType => _members.ManagedPeerType;

        internal MultiDex(IntPtr javaReference, JniHandleOwnership transfer)
            : base(javaReference, transfer)
        {
        }

        [Register("install", "(Landroid/content/Context;)V", "")]
        public static unsafe void Install(Context context)
        {
            try
            {
                JniArgumentValue* ptr = stackalloc JniArgumentValue[1];
                *ptr = new JniArgumentValue(context?.Handle ?? IntPtr.Zero);
                _members.StaticMethods.InvokeVoidMethod("install.(Landroid/content/Context;)V", ptr);
            }
            finally
            {
            }
        }

        [Register("installInstrumentation", "(Landroid/content/Context;Landroid/content/Context;)V", "")]
        public static unsafe void InstallInstrumentation(Context instrumentationContext, Context targetContext)
        {
            try
            {
                JniArgumentValue* ptr = stackalloc JniArgumentValue[2];
                *ptr = new JniArgumentValue(instrumentationContext?.Handle ?? IntPtr.Zero);
                ptr[1] = new JniArgumentValue(targetContext?.Handle ?? IntPtr.Zero);
                _members.StaticMethods.InvokeVoidMethod("installInstrumentation.(Landroid/content/Context;Landroid/content/Context;)V", ptr);
            }
            finally
            {
            }
        }
    }
}

MultiDexApplication.cs:

using Android.App;
using Android.Runtime;

using Java.Interop;

using System;

namespace MyNamespace
{
    [Register("androidx/multidex/MultiDexApplication", DoNotGenerateAcw = true)]
    public class MultiDexApplication : Application
    {
        internal static readonly JniPeerMembers _members =
            new XAPeerMembers("androidx/multidex/MultiDexApplication", typeof(MultiDexApplication));

        internal static IntPtr java_class_handle;

        private static IntPtr id_ctor;

        [Register(".ctor", "()V", "", DoNotGenerateAcw = true)]
        public MultiDexApplication()
            : base(IntPtr.Zero, JniHandleOwnership.DoNotTransfer)
        {
            if (Handle != IntPtr.Zero)
                return;

            try
            {
                if (GetType() != typeof(MultiDexApplication))
                {
                    SetHandle(
                        JNIEnv.StartCreateInstance(GetType(), "()V"),
                        JniHandleOwnership.TransferLocalRef);
                    JNIEnv.FinishCreateInstance(Handle, "()V");
                    return;
                }

                if (id_ctor == IntPtr.Zero)
                    id_ctor = JNIEnv.GetMethodID(class_ref, "<init>", "()V");
                SetHandle(
                    JNIEnv.StartCreateInstance(class_ref, id_ctor),
                    JniHandleOwnership.TransferLocalRef);
                JNIEnv.FinishCreateInstance(Handle, class_ref, id_ctor);
            }
            finally
            {
            }
        }

        protected MultiDexApplication(IntPtr javaReference, JniHandleOwnership transfer)
            : base(javaReference, transfer)
        {
        }

        internal static IntPtr class_ref => JNIEnv.FindClass("androidx/multidex/MultiDexApplication", ref java_class_handle);

        protected override IntPtr ThresholdClass => class_ref;

        protected override Type ThresholdType => typeof(MultiDexApplication);

        public override void OnCreate()
        {
            base.OnCreate();
            MultiDex.Install(this);
        }
    }
}
  • I have tried cleaning/rebuilding the solution.
  • I have tried restarting Visual Studio.
  • I have tried executing update-package -reinstall in Visual Studio's package manager console.

Solution

  • It turns out this problem was misleadingly reported by r8 dex compiler. When I changed the dex compiler to dx, it reported a different compilation error: invalid opcode ba - invokedynamic requires --min-sdk-version >= 26 (currently 13) even though the min-sdk-version was not 13. After looking up the latter error, thanks to this thread, I was able to resolve the problem by downgrading Xamarin.AndroidX.Browser to version 1.0.0.1 (the latest version before 1.2.0 where the problem was introduced). After downgrading the mentioned package, I could successfully compile and run with either dx or d8.