我怎样才能正确排除一些库,使它们不在 Xamarin.Android 中链接?

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

我有一个运行良好的应用程序,但由于我无法 link 库(因为它会导致 异常行为 )它变得更大(多 20 MiB ).主要问题发生在我自己的图书馆之一:

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

我“排除”了包及其依赖项:

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

但是“linking”选项的行为很奇怪,因为它们在 linking all 或仅 linking SDK 中都没有被排除。动画不知何故变得疯狂,它们以一种“特殊”的方式工作,汉堡包菜单在不应该的时候变成箭头,反之亦然,如果我点击 X,它只会永远删除 X 而不会'不干净。下图可以让您了解异常行为

这是预期的行为,当我什么都不link时是正常的:

应用程序只有在我使用时才能正常运行,不要Link。但是,我想了解我必须排除什么(或如何正确执行)或更改以避免此问题。此时,我尝试在 ProGuard 文件、“排除”部分等中排除它,但没有任何效果。

在我的 ProGuard 文件中,我有这些组合:

-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.** { *; }

我也尝试添加:

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

但结果完全一样。老实说,我不知道我能排除什么。有什么想法吗?

P.S.:

我可以创建要发布的包,这不是我的问题。

我的库是开源的,如果你想给我任何关于如何改变这个逻辑和解决这个问题的建议:

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

重要的是要强调我是用 C# 和 Xamarin 编写这个库的。这不是另一个的绑定。

在我看来,问题发生在这个部分:

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

更新一:

我已经添加到我的图书馆:

[Preserve(AllMembers = true)]

[assembly: LinkerSafe]

这是我的项目:

--linkskip=tk.supernovaic.MaterialSearchBar

错误仍然存​​在;因此,它应该与动画库或类似的东西有关。

更新二:

我也试过:

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

和:

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

两者仍然失败,但似乎与动画有关:

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

此外,我添加了 --linkskip=android.animation --linkskip=tk.supernovaicMaterialSearchBar 没有任何结果。

更新 3:

我将文件从我的库复制到我的项目,并保留了所有以前的规则,但没有任何积极的结果。

更新四:

我更新了我的资料库和应用程序,并在 资源 中添加了一个名为 raw 的新文件夹,其中包含一个 keep.xml 使用以下代码:

<?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" />

并添加到我的 ProGuard:

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

这一切都没有任何积极的结果。该错误仍然存​​在。

更新5:

我已经向 Microsoft 提出了问题,因为我几乎确信这是与 linker 本身相关的错误:

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

我的结论是基于这三点:

  1. 我将原始文件(动画)添加到项目中。
  2. 我添加了一条规则以将 XML 保留在项目和库中。
  3. 我添加了规则以保留 R 类 和 ProGuard 文件中的所有内容(资源)。

在我看来,前 3 点没有保留动画是没有意义的。如果您有任何其他想法,请随时分享,我愿意倾听。

更新 6:

我也在 GitHub 中开了一个工单,因为我认为这是一个错误:

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

在 Whosebug、GitHub、Visual Studio 和 Microsoft 论坛之间进行了大量更新和 运行 之后,我找到了问题所在:

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

 #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://docs.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.

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

我更新了我的库并添加了推荐的解决方法。我仍然认为这是一个错误,但我的库作为我的应用程序正常工作。

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