Aly Elhaddad
Aly Elhaddad

Reputation: 1943

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:

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);
        }
    }
}

Upvotes: 4

Views: 2517

Answers (3)

Bill.F
Bill.F

Reputation: 41

I had to set the following

<AndroidUseAapt2>true</AndroidUseAapt2>

in the Android.csproj file to get this to work. (it was set to false and appears multiple times in the csproj file).

Upvotes: 2

Aly Elhaddad
Aly Elhaddad

Reputation: 1943

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.

Upvotes: 2

Dimitris
Dimitris

Reputation: 755

I had the same problem but only for the first XML that you mentioned (<id name="view_tree_lifecycle_owner"/>)

I found an answer that worked for me (Release configuration with linking set to Sdk Assemblies Only)

In the Android project properties, I enabled the "use incremental Android packaging system" checkbox under "Android Options." and that solved the issue.

I found the solution in this thread.

Upvotes: 6

Related Questions