Linker preventing MvvmCross MvxApplication Initialize being called

72 Views Asked by At

I have updated my Target Android Api to Android 12 (API 31) so our app can be accepted in the PlayStore. This meant that the Android X packages had to be updated as well.

However, our MvxApplication Intialize override is no longer called, meaning we can not call RegisterCustomAppStart, so the app gets stuck on the splash screen.

This only happens when Linker (Link SDK assemblies only) is enabled. When it is disabled, everything works fine.

I find it impossible to determine what is happening under the hood with MvvmCross startup process, and therefore determine what may be linked out. I have included as many classes and methods as I can think of in our "LinkerPleaseInclude" file, but that is really stabbing in the dark.

1

There are 1 best solutions below

0
Trevor Balcom On

ADB will output the missing method at runtime. It is indeed stabbing in the dark. It's more of a Xamarin issue than an MvvmCross issue.

The Custom Linker Configuration is a superior alternative to LinkerPleaseInclude.cs. I use this XML to prevent linking out key MvvmCross bits with an Android MvvmCross 8.x app:

<assembly fullname="MvvmCross">
    <type fullname="MvvmCross.IoC.MvxPropertyInjector" />
    <type fullname="MvvmCross.Core.MvxSettings" />
    <type fullname="MvvmCross.Core.MvxStringToTypeParser" />
    <type fullname="MvvmCross.ViewModels.MvxViewModelLoader" />
    <type fullname="MvvmCross.Platforms.Android.Views.MvxSavedStateConverter" />
    <type fullname="MvvmCross.ViewModels.MvxAppStart`1" />
</assembly>

Here is a full example from an Android app built with MvvmCross 8.0.2. The idea is to keep only what is needed. For example, remove the NumberPicker parts if you don't use that widget in your app.

<?xml version="1.0" encoding="utf-8" ?>
<!--
  This file prevents the Xamarin.Android Linker from removing code from the final executable.

  C# Properties are implemented as two methods: get_PropertyName + put_PropertyName
  C# Events are implemented as two methods: add_EventName + remove_EventName
  C# Constructors are implemented as such:
      default: .ctor
      string parameter: System.Void .ctor(System.String)
      
  See https://docs.microsoft.com/en-us/xamarin/cross-platform/deploy-test/linker for more information.
  -->
<linker>

    <!-- Mono.Android -->
    <assembly fullname="Mono.Android">
        <type fullname="Android.Views.View">
            <method name="get_Text" />
            <method name="put_Text" />
            <method name="get_ContentDescription" />
            <method name="put_ContentDescription" />
            <method name="add_Click" />
            <method name="remove_Click" />
            <method name="add_LongClick" />
            <method name="remove_LongClick" />
            <method name="Invalidate" />
        </type>
        <type fullname="Android.Views.View.LongClickEventArgs">
            <method name="System.Void .ctor(System.Boolean)" />
            <method name="get_Handled" />
            <method name="put_Handled" />
        </type>
        <type fullname="Android.Widget.TextView">
            <method name="add_AfterTextChanged" />
            <method name="remove_AfterTextChanged" />
        </type>
        <type fullname="Android.Widget.NumberPicker">
            <method name="get_Value" />
            <method name="put_Value" />
            <method name="add_ValueChanged" />
            <method name="remove_ValueChanged" />
        </type>
        <type fullname="Android.Widget.NumberPicker.ValueChangeEventArgs">
            <method name="get_Picker" />
            <method name="put_Picker" />
            <method name="get_OldVal" />
            <method name="put_OldVal" />
            <method name="get_NewVal" />
            <method name="put_NewVal" />
        </type>
    </assembly>

    <!-- netstandard -->
    <assembly fullname="netstandard">
        <type fullname="System.TimeSpan" >
            <method name="get_Hours" />
            <method name="get_Minutes" />
            <method name="get_Seconds" />
        </type>
    </assembly>

    <!-- Google Material Design Components -->
    <assembly fullname="Xamarin.Google.Android.Material">
        <type fullname="Google.Android.Material.TextField.TextInputLayout">
            <method name="get_Hint" />
            <method name="set_Hint" />
            <method name="get_Error" />
            <method name="set_Error" />
        </type>
        <type fullname="Google.Android.Material.TextField.TextInputEditText">
            <method name="get_Text" />
            <method name="set_Text" />
        </type>
    </assembly>

    <!-- MvvmCross -->
    <assembly fullname="MvvmCross">
        <type fullname="MvvmCross.IoC.MvxPropertyInjector" />
        <type fullname="MvvmCross.Core.MvxSettings" />
        <type fullname="MvvmCross.Core.MvxStringToTypeParser" />
        <type fullname="MvvmCross.ViewModels.MvxViewModelLoader" />
        <type fullname="MvvmCross.Platforms.Android.Views.MvxSavedStateConverter" />
        <type fullname="MvvmCross.ViewModels.MvxAppStart`1" />
    </assembly>
    
    <!-- Xamarin.AndroidX.Core -->
    <assembly fullname="Xamarin.AndroidX.Core">
        <type fullname="AndroidX.Core.App.CoreComponentFactory" />
    </assembly>

</linker>