xamarin / GooglePlayServicesComponents

Other
315 stars 146 forks source link

[BUG] Firebase Cloud Firestore (from master_based_androidx branch) crashes with Guava 27.1.0.3 #308

Open RedChops opened 4 years ago

RedChops commented 4 years ago

Xamarin.Android Version (eg: 6.0):

Xamarin.Android 10.1.3.7

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

Windows 10, Mac Catalina

Google Play Services Version (eg: 8.4.0):

Build from master_based_androidx branch, re-pulled around an hour ago

Describe your Issue:

Guava libraries seem to be getting stripped out during dex compilation and only the 'dx' compiler gets close to working. With the latest Firestore library and Guava 27.1.0.3, the app will crash on runtime with the stack trace below.

If I create a hard dependency on Guava 27.1.0, my app will run perfectly fine.

Changing the dex compiler to 'd8' seems to strip everything out of the Guava package, so pretty unusable there.

Adding or removing <uses-library android:name="org.apache.http.legacy" android:required="false" /> from AndroidManifest.xml doesn't make any difference on either version of Guava.

N.B: I've bumped the Firestore library version to the latest from Google, as seen in the stack trace, but the error still happens on the version from the branch with a clean pull, no difference. On Guava 27.1.0, both versions work fine.

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

Given that Firebase Firestore needs to be authenticated, I'm not sure how I could make a reproduction. If needed I can make something most likely. The basic steps would be:

  1. Establish Firebase Auth, log in
  2. Using the latest Firestore plugin, attempt to access any document/resource
  3. App crashes

Include any relevant Exception Stack traces, build logs, adb logs:

[0:] Java.Lang.NoClassDefFoundError: Failed resolution of: Lcom/google/common/base/Preconditions; ---> Java.Lang.ClassNotFoundException: Didn't find class "com.google.common.base.Preconditions" on path: DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/data/app/com.contractplanner.contractplanner-yDXJ7ISFZd_ohYwEV2kklQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.contractplanner.contractplanner-yDXJ7ISFZd_ohYwEV2kklQ==/lib/x86, /data/app/com.contractplanner.contractplanner-yDXJ7ISFZd_ohYwEV2kklQ==/base.apk!/lib/x86, /system/lib]]
   --- End of inner exception stack trace ---
  at Java.Interop.JniEnvironment+StaticMethods.CallStaticObjectMethod (Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <e7e2d009b69d4e5f9a00e6ee600b8a8e>:0 
  at Java.Interop.JniPeerMembers+JniStaticMethods.InvokeObjectMethod (System.String encodedMember, Java.Interop.JniArgumentValue* parameters) [0x00018] in <e7e2d009b69d4e5f9a00e6ee600b8a8e>:0 
  at Firebase.Firestore.FirebaseFirestore.get_Instance () [0x00000] in /Users/danoi/workspace/GooglePlayServicesComponents/generated/com.google.firebase.firebase-firestore/obj/Release/monoandroid90/generated/src/Firebase.Firestore.FirebaseFirestore.cs:218 
  at Plugin.CloudFirestore.FirestoreProvider.get_Firestore () [0x00000] in /Users/dano/workspace/Plugin.CloudFirestore/Plugin.CloudFirestore.Android/FirestoreProvider.cs:12 
  at Plugin.CloudFirestore.CloudFirestoreImplementation.get_Instance () [0x00000] in /Users/dano/workspace/Plugin.CloudFirestore/Plugin.CloudFirestore.Android/CloudFirestoreImplementation.cs:10 
  at ContractPlanner.Services.FireStoreDataStore`1[T].GetItemsAsync (System.Boolean forceRefresh) [0x00031] in C:\Users\danor\Source\Repos\ContractPlanner\ContractPlanner\ContractPlanner\Services\FireStoreDataStore.cs:61 
  at ContractPlanner.Core.Repositories.FirestoreContractRepository.GetContractsAsync () [0x0003c] in C:\Users\danor\Source\Repos\ContractPlanner\ContractPlanner\ContractPlanner\Repositories\FirestoreContractRepository.cs:82 
  at ContractPlanner.Core.ViewModels.HomeViewModel.ExecuteLoadItemsCommand () [0x0004f] in C:\Users\danor\Source\Repos\ContractPlanner\ContractPlanner\ContractPlanner\ViewModels\Home\HomeViewModel.cs:66 
  --- End of managed Java.Lang.NoClassDefFoundError stack trace ---
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/common/base/Preconditions;
    at com.google.firebase.firestore.FirebaseFirestore.getInstance(com.google.firebase:firebase-firestore@@21.4.0:102)
    at com.google.firebase.firestore.FirebaseFirestore.getInstance(com.google.firebase:firebase-firestore@@21.4.0:91)
    at crc643f46942d9dd1fff9.ShellSectionRenderer.n_onCreateView(Native Method)
    at crc643f46942d9dd1fff9.ShellSectionRenderer.onCreateView(ShellSectionRenderer.java:44)
    at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
    at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
    at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
    at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:434)
    at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
    at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
    at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
    at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
    at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2663)
    at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2613)
    at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2624)
    at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:904)
    at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
    at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
    at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
    at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
    at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
    at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
    at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
    at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2663)
    at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2613)
    at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:246)
    at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:542)
    at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:201)
    at crc643f46942d9dd1fff9.FormsAppCompatActivity.n_onStart(Native Method)
    at crc643f46942d9dd1fff9.FormsAppCompatActivity.onStart(FormsAppCompatActivity.java:128)
    at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1391)
    at android.app.Activity.performStart(Activity.java:7157)
    at android.app.ActivityThread.handleStartActivity(ActivityThread.java:2937)
    at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
    at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.common.base.Preconditions" on path: DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/data/app/com.contractplanner.contractplanner-yDXJ7ISFZd_ohYwEV2kklQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.contractplanner.contractplanner-yDXJ7ISFZd_ohYwEV2kklQ==/lib/x86, /data/app/com.contractplanner.contractplanner-yDXJ7ISFZd_ohYwEV2kklQ==/base.apk!/lib/x86, /system/lib]]
    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
    ... 44 more
RedChops commented 4 years ago

Trying to figure out the last working version of Guava:

RedChops commented 4 years ago

Actually, I came up with an extremely minimal reproduction, basically just added the Firebase nugets to the bare Xamarin.Android template. Test308.zip The app wont load beyond GetInstance(app) so I'm not sure how much of the play services json or signing keys are needed, but PM me if you need the test ones I used.

RedChops commented 4 years ago

Hm so it looks like with this commit: https://github.com/xamarin/XamarinComponents/commit/14a3ada30e508c0340e5c2144ceb91336481eac8, the Guava nuget package moved to the build target/transitive system. Nice for smaller dll's, but that jar never seems to end up anywhere outside of the package. I tried compiling it both with the target set to ReferenceJar (what it's currently set to) and EmbeddedReferenceJar, both to no effect.

I pulled the Guava jar down from Maven, removed the ListenableFuture class just as the build.cake suggests https://github.com/xamarin/XamarinComponents/blob/master/Android/Guava/build.cake#L77, and added it to my test project as an AndroidJavaLibrary. This allows me to remove the hard Guava dependency and have my app work, but it's definitely not ideal. I tried setting the build target of the nuget package to AndroidJavaLibrary, but that didn't have an effect either. referenceguava.zip

It looks as though the breaking change was made here: https://github.com/xamarin/XamarinComponents/commit/14a3ada30e508c0340e5c2144ceb91336481eac8#diff-de6c324ea8efa9973accbabba02f3f09L64. I don't really know anything about this build target system for jar files, but it seems as though it's not playing nicely with Guava, maybe it's due to Guava not actually providing any managed types at all?

moljac commented 4 years ago

@RedChops Try 27.1.0.4 released few hours ago.

We faced the similar issues with AndroidX updates (and GPS-FB with AndroidX dependencies). Now it is EmbeddedReferenceJar. And there is also 28.2.0.0 I bound in parallel with 27.1.0.4

And please share feedback here. Thanks for the info. I'll take a look.

RedChops commented 4 years ago

@moljac I've added 27.1.0.4 as a hard dependency, removed the jar, and hey, it works! Fantastic!

Thanks a ton. I'll let you close this, since it looks like the config.json is still pulling .0.3 as a dep

moljac commented 4 years ago

@RedChops

I'm glad it worked. Thanks for your analysis.

I'll let it open for few days. I want to publish AndroidX updates (and some older packages), before I prepare GPS-FB.

RedChops commented 4 years ago

Actually shoot, I was wrong. I thought that I had set the build options to none, but I guess that didn't stick. When I finally went to go clean out my project and rebuild, I found that the error unfortunately still persists.

Without that guava.jar file in the project and marked as AndroidJavaLibrary, the project wont run. I tried both 27.1.0.4 and 28.2.0

Not sure what happened with above. I cleared my nuget cache and it seems to work. Sorry about the confusion!

ifecdr commented 4 years ago

@RedChops Hi, can you explain how you were able to resolve this issue.. All the trouble seemed to have started in my recent package update and for some reason reverting the changes seems not to be effective..

RedChops commented 4 years ago

@ifecdr I wish I could tell you more. I had to clear all NuGet caches, and I removed my obj and bin folders, and both 27.1.0.4 and 28.2.0 started building for me. I think you may also need Xamarin.Build.Download >0.8.0, but I've been building packages from this repo by hand for a while now so I don't know if that would be the case with the released versions.

You also have to make sure that you are in no way using R8, neither by specifying it explicitly, or by having it run implicitly by using D8 and having 'EnableMultiDex' enabled (this is a very dumb change, don't know why that became the default). If R8 runs, the build will almost certainly fail in some way or another. I intend on filing a bug about this once the AndroidX versions are published.