How can I correctly exclude some libraries so that they are not linked in Xamarin.Android?

Federico Navarrete 616 Reputation points
2021-07-26T08:07:42.147+00:00

I have an app that is working fine but since I cannot link the libraries (because it causes an abnormal behavior) it becomes significantly bigger (20 MiB more). The main issue happens with one of my own libraries:

https://www.nuget.org/packages/Xamarin-MaterialSearchBar

I “excluded” the package and its dependencies:

Xamarin.AndroidX.AppCompat;Xamarin.AndroidX.ConstraintLayout;Xamarin.AndroidX.RecyclerView;Xamarin.AndroidX.CardView

But the “linking” options behave quite odd because they are not excluded neither in linking all or only linking SDK only. The animations got somehow mad and they are working in a "particular" way, the hamburger menu transforms into an arrow when it shouldn’t and vice-versa and if I do click on the X, it just removes the X forever and doesn’t clean. The following image can give you an idea of the abnormal behavior.

117840-z54bs.gif

This is the expected and normal behavior when I don't link anything:

118271-cg0ut.gif

The app only works properly when I use Don’t Link. However, I want to understand what I must exclude (or how to do it properly) or change to avoid this issue. At this point, I tried excluding it in the guard file, in the “exclusion” section, etc. but nothing works.

In my guard file, I have these combinations:

-keep class androidx.work.** { *; }  
-keep class androidx.concurrent.** { *; }  
-keep class androidx.tracing.** { *; }  
-keep class androidx.paging.** { *; }  
-keep class com.google.android.gms.** { *; }  
-keep class androidx.appcompat.widget.** { *; }  
-keep class com.google.android.material.** { *; }  

And I also tried to add:

-keep class tk.supernovaic.MaterialSearchBar.** { *; }  

But the results were exactly the same. I don't know what I can exclude being honest. Any idea?

P.S.:

I can create the package to be published that is not my problem.

My library is open-source if you want to give me any advice on how to change this logic and fix this problem:

https://github.com/FANMixco/Xamarin-SearchBar

It's important to highlight that I wrote this library in C# and Xamarin. This is not the binding of another one.

In my opinion, the issue happens in this section:

public void OnClick(View v)  
{  
 int id = v.Id;  
 if (id == Id)  
 {  
 if (!IsSearchEnabled)  
 {  
 EnableSearch();  
 }  
 }  
 else if (id == Resource.Id.mt_arrow)  
 {  
 DisableSearch();  
 }  
 else if (id == Resource.Id.mt_search)  
 {  
 if (ListenerExists())  
 {  
 OnSearchActionListener.OnButtonClicked(BUTTON_SPEECH);  
 }  
 }  
 else if (id == Resource.Id.mt_clear)  
 {  
 SearchEdit.Text = "";  
 }  
 else if (id == Resource.Id.mt_menu)  
 {  
 PopupMenu.Show();  
 }  
 else if (id == Resource.Id.mt_nav)  
 {  
 int button = IsSearchEnabled ? BUTTON_BACK : BUTTON_NAVIGATION;  
 if (IsSearchEnabled)  
 {  
 DisableSearch();  
 }  
 if (ListenerExists())  
 {  
 OnSearchActionListener.OnButtonClicked(button);  
 }  
 }  
}  

Update 1:

I have added to my library:

[Preserve(AllMembers = true)]

[assembly: LinkerSafe]

And this to my project:

--linkskip=tk.supernovaic.MaterialSearchBar

And the bug persists; therefore, it should be related to the animations library or something like that.

Update 2:

I have tried also:

-keep class android.animation.ObjectAnimator.** { *; } \-keep class **.R$* { public static <fields>; }

and:

-keep class android.animation.** { *; }

Both still fails but it seems it´s related to the animations:

https://github.com/FANMixco/Xamarin-SearchBar/blob/master/tk.supernovaic.MaterialSearchBar/Resources/animator/menu_to_back_rotation.xml

Also, I added --linkskip=android.animation --linkskip=tk.supernovaicMaterialSearchBar without any result.

Update 3:

I copied the files from my lib to my project and kept all previous rules without any positive result.

Update 4:

I updated my library and app and added a new folder in the Resources called raw that contains a keep.xml with the following code:

<?xml version="1.0" encoding="UTF-8" ?>  
<resources xmlns:tools="http://schemas.android.com/tools"  
    tools:keep="@anim/fade_in_left,@anim/fade_in_right,@anim/fade_out,@anim/fade_out_left,@animator/back_to_menu_morph,@animator/back_to_menu_rotation,@animator/menu_to_back_morph,@animator/menu_to_back_rotation" />  

And added to my ProGuard:

-keep class **.R  
-keepclassmembers class tk.supernovaic.MaterialSearchBar.* {  
    <fields>;  
    <init>();  
    <methods>;  
}  

All this without any positive result. The bug persists.

Update 5:

I have raised a ticket to Microsoft because I'm almost convinced this is a bug related to the linker itself:

https://developercommunity.visualstudio.com/t/xamarinandroid-linking-libs-not-working-as-expecte/1482147?from=email

My conclusions are based on these three points:

  1. I added the original files (animations) to the project.
  2. I added a rule to keep the XMLs in the project and library.
  3. I added rules to preserve the R classes and everything (resources) in the ProGuard file.

It makes no sense that with the previous 3 points the animations are not preserved, in my opinion. If you have any other thoughts feel free to share them, I'm open to listening to them.

Update 6:

I also opened a ticket in GitHub because I believe it's a bug:

https://github.com/xamarin/xamarin-android/issues/6156

Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,325 questions
0 comments No comments
{count} votes

Accepted answer
  1. Federico Navarrete 616 Reputation points
    2021-08-06T08:14:06.147+00:00

    After a lot of updates and running between StackOverflow, GitHub, Visual Studio and the Microsoft Forums, I was able to find the problem:

    dellis1972
    Changing this line
    https://github.com/FANMixco/Xamarin-SearchBar/blob/master/tk.supernovaic.MaterialSearchBar/MaterialSearchBar.cs#L633
    to be.

    if (NavIcon.Drawable is AnimatedVectorDrawable a) Fixes the issue. For
    some reason the IAnimatable interface is not supported after the
    linker is run.

    fanmixco
    Hi @dellis1972, I'm going to check it. Thanks. However, is it still a bug to be reported, isn't it? Because it allows the icons to be shown properly but the animation doesn't happen.

    dellis1972
    It is still a bug, but you have a work around for now.
    We'll need to look at see why the interface is removed as part of the link step.

    ok. so its not a linker bug, but I understand what is happening in
    this case.

    So the code in the MaterialSearchBar library is relying on the
    AnimatedVectorDrawable class deal with its animations. However these
    is no code in the library which actually uses it directly. So the type
    is linked out as part of the SdkOnly/Full linker step. The java side
    of the code will still exist , but all the glue on the C# side which
    will react to events being raised from the java side is all gone. So
    when you access the NavIcon.Drawable property you just get a
    Android.Graphics.Drawable type back which does not support
    IAnimatable, because the actual type which the java type is , doesn't
    exist on the C# side.

    The reason why my workaround works is that is stops the type from
    being linked away. So you can either use the work around I provided or
    add something like this to the MaterialSearchBar class

       // Linker stuff  
        #pragma warning disable 0219, 0649  
            static bool falseflag = false;  
            static MaterialSearchBar ()  
            {  
                if (falseflag) {  
                    var ignore = new AnimatedVectorDrawable ();  
                }  
            }  
    

    pragma warning restore 0219, 0649 as described in https://learn.microsoft.com/en-us/xamarin/android/deploy-test/linker#falseflag.

    So its not a bug, its how the linker works. There isn't anything we
    can really fix on this side. If the code is not directly using a type,
    it will be removed. The code above fools the linker into thinking the
    type is used.

    Source: https://github.com/xamarin/xamarin-android/issues/6156

    I updated my library and added the recommended workaround. I still believe it's a bug but my library is working properly as my app.

    https://www.nuget.org/packages/Xamarin-MaterialSearchBar/

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Leon Lu (Shanghai Wicresoft Co,.Ltd.) 71,681 Reputation points Microsoft Vendor
    2021-07-27T07:34:54.347+00:00

    Hello,​

    Welcome to our Microsoft Q&A platform!

    I used this nuget package, then I set the linker to SDK Assemblies only, then I release the application, it could generate apk correctly.

    118176-image.png

    When you release the apk, you find the package is significantly bigger and Linker just be setted to Don’t Link? If so, you can try to generate AAB.

    You can try to use native Search Widget in android, if it worked.

    Best Regards,

    Leon Lu


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.