xamarin / AndroidSupportComponents

Xamarin bindings for Android Support libraries - For AndroidX see https://github.com/xamarin/AndroidX
MIT License
146 stars 56 forks source link

28.0.0 Issues with Proguard #141

Closed leonluc-dev closed 5 years ago

leonluc-dev commented 5 years ago

Xamarin.Android Version (eg: 6.0):

9.1.4.2

Operating System & Version (eg: Mac OSX 10.11):

Windows 10 (1809)

Support Libraries Version (eg: 23.3.0):

28.0.0

Describe your Issue:

This is a followup to issue #96 After updating to version 28.0.0 a few new issues started popping up.

Among others android.support.v7.widget.FitWindowsFrameLayout and android.support.v7.preference.PreferenceCategory are giving issues during inflation. I've adjusted my proguard configuration file to explicitly include (the packages of) these classes, but these rules are supposed to be included with the support library itself (at least they are in Android Studio).

Steps to Reproduce (with link to sample solution if possible):

Build a project with Proguard enabled and use the (for example) PreferenceCategory class in a xml file. Then inflate said xml file in code.

Temporary workaround

Add the following to the ProGuard configuration file:

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

-keep public class android.support.v7.widget.** { *; }
-keep public class android.support.v7.internal.widget.** { *; }
-keep public class android.support.v7.internal.view.menu.** { *; }
-keep public class android.support.v7.preference.** { *; }

-keep public class android.support.percent.PercentRelativeLayout { *; }

-keep public class * extends android.support.v4.view.ActionProvider {
    public <init>(android.content.Context);
}

Example stack trace

01-04 12:29:49.059  3653  3653 I MonoDroid: Java.Lang.RuntimeException: Binary XML file line #1: Error inflating class (not found)android.support.v7.preference.PreferenceCategory ---> Java.Lang.ClassNotFoundException: Didn't find class "android.support.v7.preference.PreferenceCategory" on path: DexPathList[[zip file "[REDACTED]/base.apk!/lib/armeabi-v7a, /system/lib]]
01-04 12:29:49.059  3653  3653 I MonoDroid:    --- End of inner exception stack trace ---
01-04 12:29:49.059  3653  3653 I MonoDroid:   at Java.Interop.JniEnvironment+InstanceMethods.CallNonvirtualVoidMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00089] in <5b1a0346b3f444fd9fdc7d9f5b436ed8>:0 
01-04 12:29:49.059  3653  3653 I MonoDroid:   at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualVoidMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x0005d] in <5b1a0346b3f444fd9fdc7d9f5b436ed8>:0 
01-04 12:29:49.059  3653  3653 I MonoDroid:   at Android.Support.V7.Preferences.PreferenceFragmentCompat.AddPreferencesFromResource (System.Int32 preferencesResId) [0x00022] in <56f32f0261e045a3aaa63e0a5eaa36d0>:0 
01-04 12:29:49.059  3653  3653 I MonoDroid:   at Example.AndroidApp.ApplicationScreens.Settings.TTProfileDetailsActivity+ProfileDetailsFragment.OnCreatePreferences (Android.OS.Bundle savedInstanceState, System.String rootKey) [0x000cb] in <20ee224b7abe4914bc8d5cea9c57fe4a>:0 
01-04 12:29:49.059  3653  3653 I MonoDroid:   at Android.Support.V7.Preferences.PreferenceFragmentCompat.n_OnCreatePreferences_Landroid_os_Bundle_Ljava_lang_String_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState, System.IntPtr native_rootKey) [0x00017] in <56f32f0261e045a3aaa63e0a5eaa36d0>:0 
01-04 12:29:49.059  3653  3653 I MonoDroid:   at (wrapper dynamic-method) System.Object.56(intptr,intptr,intptr,intptr)
01-04 12:29:49.059  3653  3653 I MonoDroid:   --- End of managed Java.Lang.RuntimeException stack trace ---
01-04 12:29:49.059  3653  3653 I MonoDroid: android.view.InflateException: Binary XML file line #1: Error inflating class (not found)android.support.v7.preference.PreferenceCategory
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v7.preference.PreferenceInflater.createItemFromTag(PreferenceInflater.java:305)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v7.preference.PreferenceInflater.rInflate(PreferenceInflater.java:362)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v7.preference.PreferenceInflater.inflate(PreferenceInflater.java:170)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v7.preference.PreferenceInflater.inflate(PreferenceInflater.java:120)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v7.preference.PreferenceManager.inflateFromResource(PreferenceManager.java:138)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v7.preference.PreferenceFragmentCompat.addPreferencesFromResource(PreferenceFragmentCompat.java:429)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at com.example.ExampleApp8.TTProfileDetailsActivity_ProfileDetailsFragment.n_onCreatePreferences(Native Method)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at com.example.ExampleApp8.TTProfileDetailsActivity_ProfileDetailsFragment.onCreatePreferences(TTProfileDetailsActivity_ProfileDetailsFragment.java:36)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v7.preference.PreferenceFragmentCompat.onCreate(PreferenceFragmentCompat.java:228)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.Fragment.performCreate(Fragment.java:2414)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1418)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1195)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.FragmentTransition.calculateFragments(FragmentTransition.java:1078)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.FragmentTransition.startTransitions(FragmentTransition.java:117)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2408)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3273)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3229)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:201)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:620)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1392)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.app.Activity.performStart(Activity.java:7157)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.app.ActivityThread.handleStartActivity(ActivityThread.java:2952)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1823)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.os.Handler.dispatchMessage(Handler.java:107)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.os.Looper.loop(Looper.java:198)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.app.ActivityThread.main(ActivityThread.java:6729)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at java.lang.reflect.Method.invoke(Native Method)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
01-04 12:29:49.059  3653  3653 I MonoDroid: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v7.preference.PreferenceCategory" on path: DexPathList[[zip file "[REDACTED]/base.apk!/lib/armeabi-v7a, /system/lib]]
01-04 12:29:49.059  3653  3653 I MonoDroid:     at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v7.preference.PreferenceInflater.createItem(PreferenceInflater.java:231)
01-04 12:29:49.059  3653  3653 I MonoDroid:     at android.support.v7.preference.PreferenceInflater.createItemFromTag(PreferenceInflater.java:295)
01-04 12:29:49.059  3653  3653 I MonoDroid:     ... 35 more
01-04 12:29:49.059  3653  3653 I MonoDroid: 

VS bug #762062

Redth commented 5 years ago

So, we do include the proguard.txt file that is in the original .aar:

# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Preference objects are inflated via reflection
-keep public class android.support.v7.preference.Preference {
    public <init>(android.content.Context, android.util.AttributeSet);
}
-keep public class * extends android.support.v7.preference.Preference {
    public <init>(android.content.Context, android.util.AttributeSet);
}

This doesn't look obviously the same as your rule set. Would you be able to share a diagnostic build log (or better yet a binlog) of your project? I'd like to see / ensure that the .aar file we do ship is being considered in the proguard call.

leonluc-dev commented 5 years ago

@Redth While I'm still waiting for approval to publish the binlog. I have noticed something interesting about the nuget packages. I have my project target set to <TargetFrameworkVersion>v9.0</TargetFrameworkVersion> (monoandroid90), and it seems that most of the packages that require proguard rules do not include them for that particular platform (while the lib folders do contain the dlls).

Directory of <redacted>\.nuget\packages\xamarin.android.support.v7.preference\28.0.0\proguard

18 Dec 2018  11:38    <DIR>          .
18 Dec 2018  11:38    <DIR>          ..
18 Dec 2018  11:38    <DIR>          monoandroid71
18 Dec 2018  11:38    <DIR>          monoandroid80
18 Dec 2018  11:38    <DIR>          monoandroid81
               0 File(s)              0 bytes
               5 Dir(s)  130.333.097.984 bytes free
Directory of <redacted>\.nuget\packages\xamarin.android.support.v7.preference\28.0.0\lib

18 Dec 2018  11:38    <DIR>          .
18 Dec 2018  11:38    <DIR>          ..
18 Dec 2018  11:38    <DIR>          monoandroid60
18 Dec 2018  11:38    <DIR>          monoandroid70
18 Dec 2018  11:38    <DIR>          monoandroid71
18 Dec 2018  11:38    <DIR>          monoandroid80
18 Dec 2018  11:38    <DIR>          monoandroid81
18 Dec 2018  11:38    <DIR>          monoandroid90
               0 File(s)              0 bytes
               8 Dir(s)  130.333.208.576 bytes free

This is not only the case for the preference library but for all xamarin.android.support packages. Could this have anything to do with the cause of this issue?

leonluc-dev commented 5 years ago

I have attached the binlog for a recent build. Binlog-2019-01-14.zip

luryus commented 5 years ago

Any updates on this? The issue seems to indeed be that the proguard configs are missing for monoandroid90.

Take for example the latest version of Xamarin.Android.Support.v7.RecyclerView: in the nupkg, build/monoandroid81/Xamarin.Android.Support.v7.RecyclerView.targets contains this:

  <ItemGroup>
    <ProguardConfiguration Include="$(MSBuildThisFileDirectory)..\..\proguard\monoandroid81\proguard.txt" />
  </ItemGroup>

while build/monoandroid90/Xamarin.Android.Support.v7.RecyclerView.targets does not:

  <ItemGroup>
  </ItemGroup>
  <ItemGroup>
  </ItemGroup>

And like @gameleon-dev noticed, under the proguard/ folder there's no subfolder for monoandroid90.

I created a minimal project (attached) which just creates a RecyclerView and specifies the layout manager in xml. When building with 8.1 everything works, but after switching to 9.0 the app crashes on launch, as LinearLayoutManager is removed by Proguard.

ProguardRepro.zip

luryus commented 5 years ago

I built the fat Nuget packages from current master branch locally and they contain the correct Proguard config files even for monoandroid90.

Is there going to be a public 28.0.0.2 release? It seems that just releasing the current version could fix this issue. The missing proguard config is currently preventing us from upgrading to Support Library 28 or Google Play Services 71. Having a working release before the AndroidX migration would be very helpful.

Redth commented 5 years ago

This is fixed in 28.0.0.3

yaliashkevich commented 5 years ago

I built the fat Nuget packages from current master branch locally and they contain the correct Proguard config files even for monoandroid90.

Is there going to be a public 28.0.0.2 release? It seems that just releasing the current version could fix this issue. The missing proguard config is currently preventing us from upgrading to Support Library 28 or Google Play Services 71. Having a working release before the AndroidX migration would be very helpful.

@luryus, most likely you will need custom proguard rules anyway due to LinkerSafe attribute for monoadroid90, see https://github.com/xamarin/AndroidSupportComponents/issues/219

luryus commented 5 years ago

@yaliashkevich We actually ran into issues with java.lang.ClassNotFoundException: Didn't find class "android.support.v7.widget.FitWindowsFrameLayout", but I think the reason for that is not related to linking. We fixed it with the workaround here: https://github.com/xamarin/xamarin-android/issues/3636

Basically, Xamarin.Android does not use the proguard configuration generated by AAPT, and classes referenced via XML are stripped out by proguard or something like that.

I don't know if this is actually related to the linker changes. It could be, but our app works fine with linker enabled and the proguard configuration generated by the workaround.

moljac commented 5 years ago

@yaliashkevich FWIK there should be 28.0.0.3 released.

For example

https://www.nuget.org/packages/Xamarin.Android.Support.Design/

https://www.nuget.org/packages/Xamarin.Android.Support.Design/28.0.0.3

yaliashkevich commented 5 years ago

@luryus, LinkerSafe attribute for monodroid90 is exact reason. Isn’t it ridiculous to have it on a library so tied with reflection and inflation from xml.

Thank you for pointing to https://github.com/xamarin/xamarin-android/issues/3636, that gonna save me from running million build-run-catch exception-update proguard rules iterations made by hand.