TobiasBuchholz / Plugin.Firebase

Wrapper around the native Android and iOS Firebase Xamarin SDKs
MIT License
211 stars 49 forks source link

`CrossFirebase.Initialize` throws null pointer exception for iOS #211

Closed ksoftllc closed 11 months ago

ksoftllc commented 11 months ago

This code from your plugin crashes with null pointer exception:

namespace Plugin.Firebase.Auth;

public sealed class FirebaseAuthImplementation : DisposableBase, IFirebaseAuth
{
    public static void Initialize()
    {
        var googleServiceDictionary = NSDictionary.FromFile("GoogleService-Info.plist");
        SignIn.SharedInstance.ClientId = googleServiceDictionary["CLIENT_ID"].ToString();
    }

My GoogleService-Info.plist file from FCM console does not have a CLIENT_ID key. Here is the redacted file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>API_KEY</key>
    <string>...</string>
    <key>GCM_SENDER_ID</key>
    <string>...</string>
    <key>PLIST_VERSION</key>
    <string>1</string>
    <key>BUNDLE_ID</key>
    <string>...</string>
    <key>PROJECT_ID</key>
    <string>...</string>
    <key>STORAGE_BUCKET</key>
    <string>...</string>
    <key>IS_ADS_ENABLED</key>
    <false></false>
    <key>IS_ANALYTICS_ENABLED</key>
    <false></false>
    <key>IS_APPINVITE_ENABLED</key>
    <true></true>
    <key>IS_GCM_ENABLED</key>
    <true></true>
    <key>IS_SIGNIN_ENABLED</key>
    <true></true>
    <key>GOOGLE_APP_ID</key>
    <string>...</string>
</dict>
</plist>

I have recreated the file a couple of times and it never comes with a CLIENT_ID key.

Here is my code:

    private static MauiAppBuilder RegisterFirebaseServices(this MauiAppBuilder builder)
    {
        builder.ConfigureLifecycleEvents(events => {

#if IOS
            events.AddiOS(iOS => iOS.FinishedLaunching((app, launchOptions) => {
                CrossFirebase.Initialize(CreateCrossFirebaseSettings());
                return false;
            }));
#endif
#if Android
            events.AddAndroid(android => android.OnCreate((activity, _) =>
                CrossFirebase.Initialize(activity, CreateCrossFirebaseSettings())));
#endif
        });

        builder.Services.AddSingleton(_ => CrossFirebaseAuth.Current);
        return builder;
    }

Here is the stack trace:

Object reference not set to an instance of an object. -    
   at Plugin.Firebase.Auth.FirebaseAuthImplementation.Initialize()
   at Plugin.Firebase.Bundled.Platforms.iOS.CrossFirebase.Initialize(CrossFirebaseSettings settings, Options firebaseOptions, String name)
   at FleetHDMobile.MauiProgram.<>c.<RegisterFirebaseServices>b__5_3(UIApplication app, NSDictionary launchOptions) in .../MauiProgram.cs:line 109

How do I initialize for iOS?

SheikMydeenMuthu commented 11 months ago

same issue happen mine too, could help any one?

ksoftllc commented 11 months ago

Update: I found this link that explained how to get the CLIENT_ID to generate in the plist file: https://stackoverflow.com/a/77235721/1256015.

Now I get a different null pointer exception:

Object reference not set to an instance of an object. -    at Plugin.Firebase.CloudMessaging.FirebaseCloudMessagingImplementation.GetTokenAsync()

This is the code that is throwing:

 public Task<string> GetTokenAsync()
    {
        var token = Messaging.SharedInstance.FcmToken;
        return string.IsNullOrEmpty(token) ? throw new FirebaseException("Couldn't retrieve FCM token") : Task.FromResult(token);
    }

Since I am not getting the FirebaseException, I have to conclude that Messaging.SharedInstance is null. The call to CrossFirebase.Initialize(...) is not throwing, so why is the shared instance null?

ksoftllc commented 11 months ago

I got this working on my Apple device. The issue for me was calling GetTokenAsync() before CrossFirebase.Initialize(...). In my case, I had added the call to GetTokenAsync() to App.xaml.cs which was executing before iOS.FinishedLaunching event. For me, I resolved it by changed to iOS.WillFinishLaunching event. Could also have moved the GetTokenAsync() call site to occur later in the app startup.