TobiasBuchholz / Plugin.Firebase

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

Notification Tapped event not working in IOS #232

Closed AmanGoyal009 closed 9 months ago

AmanGoyal009 commented 10 months ago

Package : Plugin.Firebase Device : iPhone Package Version : 2.0.6 Framework : .Net 7 using MAUI Development Tool : Visual Studio

I have registered the event : CrossFirebaseCloudMessaging.Current.NotificationTapped

Above event is working fine in case of android but it's not working fine in IOS. When we click on the notification then we are not receiving any event in IOS.

I initialised the methods also : Plugin.Firebase.Core.Platforms.iOS.CrossFirebase.Initialize(); FirebaseCloudMessagingImplementation.Initialize();

Can you guys please help me on this. So, that we redirect user to particular page when user clicks on the notification.

TobiasBuchholz commented 10 months ago

Hi @AmanGoyal009, could you please provide a sample project that demonstrates this issue?

AmanGoyal009 commented 10 months ago

Hi @TobiasBuchholz Sorry due to some company restrictions I can't share and upload the code from my system.

But I can share the links which I followed for implementing the push notification :

  1. https://github.com/leowagnersouza/fcmmaui/blob/main/MauiDemo/MauiProgram.cs

CrossFirebaseCloudMessaging.Current.NotificationTapped += (sender, e) => { // Handle the code of open the specific page when user clicks on the notification. // For Android this event is getting called. But for IOS it's not calling. };

I registered this event inside the RegisterFirebaseServices method which is available in the above link inside MAUI PROGRAM file.

  1. In the App Delegate File I override the Finished Launching Method and write the below code : var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound; UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => { if (granted && error == null) { this.InvokeOnMainThread(() => { UIApplication.SharedApplication.RegisterForRemoteNotifications(); }); } });

  2. Added some properties inside the Info.Plist file and Entitlements.Plist file for receiving the notification.

  3. Add the GoogleService-Info.plist file and make the Build Property as Bundle Resource and set the property as Copy to Output Directory if newer.

  4. So, I am receiving the notification in IOS and Android both.

  5. Even the event which is registered in 2nd step is getting called for Android. BUT FOR IOS ITS NOT GETTING CALLED.

  6. Link for Notification Tap : https://cedricgabrang.medium.com/handle-firebase-push-notifications-tap-in-net-maui-9bdb7f3c1de1

AmanGoyal009 commented 10 months ago

Hi @TobiasBuchholz

Any update on this issue. Currently I am stuck as notification tap event is not working in IOS.

TobiasBuchholz commented 10 months ago
  1. In the App Delegate File I override the Finished Launching Method and write the below code : var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound; UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => { if (granted && error == null) { this.InvokeOnMainThread(() => { UIApplication.SharedApplication.RegisterForRemoteNotifications(); }); } });

You don't need to do that, this code is called already due to the FirebaseCloudMessagingImplementation.Initialize() method, so maybe that's the problem. Additionally you can try to register the NotifcationTapped event at a later point in your app instead of inside the RegisterFirebaseServices method.

AmanGoyal009 commented 10 months ago

Hi @TobiasBuchholz ,

I checked without FirebaseCloudMessagingImplementation.Initialize() also but nothing happened. And also checked by registering the NotificationTapped event at later point also but nothing happened.

TobiasBuchholz commented 10 months ago

No, I meant you should remove the code from 2. since it's called internally by FirebaseCloudMessagingImplementation.Initialize() already, see here.

So to be clear, keep calling FirebaseCloudMessagingImplementation.Initialize() after CrossFirebase.Initialize() and from your AppDelegate remove this code:

var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound; UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => { if (granted && error == null) { this.InvokeOnMainThread(() => { UIApplication.SharedApplication.RegisterForRemoteNotifications(); }); } });

AmanGoyal009 commented 10 months ago

Hi @TobiasBuchholz ,

As per your suggestion I removed the below code :

var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound; UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => { if (granted && error == null) { this.InvokeOnMainThread(() => { UIApplication.SharedApplication.RegisterForRemoteNotifications(); }); } });

But still Notification Tapped event is not fired in IOS.

By looking at the code which you shared in the previous comment may be this event is creating problem : _missedTappedNotification Or why _notificationTapped event is null even after registration.

Please give your guidance to resolve the issue.

AmanGoyal009 commented 10 months ago

Hi @TobiasBuchholz ,

As per your suggestion I removed the below code :

var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound; UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => { if (granted && error == null) { this.InvokeOnMainThread(() => { UIApplication.SharedApplication.RegisterForRemoteNotifications(); }); } });

But still Notification Tapped event is not fired in IOS.

By looking at the code which you shared in the previous comment may be this event is creating problem : _missedTappedNotification

Please give your guidance to resolve the issue.

Hello @TobiasBuchholz

Please help me on this. For IOS we are stuck now. As per your suggestion I did the same steps which you shared but still facing the same problem.

TobiasBuchholz commented 10 months ago

By looking at the code which you shared in the previous comment may be this event is creating problem : _missedTappedNotification Or why _notificationTapped event is null even after registration.

_notificationTapped might be null if the app gets started by tapping the notification, so that's why there is _missedTappedNotification to circumvent this issue.

Please create a demo project that demonstrates the issue, otherwise I can't help you, sorry.

AmanGoyal009 commented 10 months ago

Hi @TobiasBuchholz ,

I go through the code of IOS using the link which you shared.

And I believe DidReceiveNotificationResponse this method should called when user clicked on the notification. Because here only we are calling the _notificationTapped.Invoke method for informing user that user has clicked on the notification.

It might be possible that this method is not getting called. And that's why I am not receiving any information when user tapped on the notification.

I found one link : https://stackoverflow.com/questions/44700445/center-didreceivenotificationresponse-not-getting-called

Can you please check on this.

AmanGoyal009 commented 10 months ago

Hi @TobiasBuchholz ,

Due to some restriction I can't share the sample project also here. But I am sure that in this package this DidReceiveNotificationResponse method is not getting called and that's why Notification Tapped event is not firing.

I hope you also tested the code before launching this package. So, can you please check and confirm on that if possible ?

TobiasBuchholz commented 10 months ago

Hi @AmanGoyal009,

yes, when the project is setup correctly, the DidReceiveNotificationResponse method is getting called and thereforeNotificationTapped is firing, take a look at the sample project as a working example.

I understand that you can't share details of your company's project. However, if you suspect the problem is with the library, consider creating a separate, simple project just to demonstrate the issue. This approach not only isolates the problem but might also help you identify the solution yourself.

AmanGoyal009 commented 10 months ago

Hi @TobiasBuchholz

Is there any difference between the package :

  1. Plugin.Firebase.Core.Platform.iOS.Crossfirebase.Initialize();
  2. Plugin.Firebase.Bundled.Platform.iOS.Crossfirebase.Initialize();

And below line also need to add as a mandatory :

  1. builder.Services.AddSingleton(_ => CrossFirebaseAuth.Current); ---> Currently only this line is added.
  2. builder.Services.AddSingleton(_ => CrossFirebaseCloudMessaging.Current); ---> Is it mandatory to add this line also.
TobiasBuchholz commented 10 months ago

Plugin.Firebase.Bundled.Platform.iOS.Crossfirebase.Initialize() is the initialization method of the Plugin.Firebase package which bundles all features into a single nuget package for people who were using prior versions of the plugin before the features were separated into single packages. You should call it with CrossFirebaseSettings as parameter to let the library know which features should be enabled:

#if IOS
using Plugin.Firebase.Bundled.Platforms.iOS;
#elif ANDROID
using Plugin.Firebase.Bundled.Platforms.Android;
#endif

  var settings = new CrossFirebaseSettings(
        isAnalyticsEnabled: true,
        isAuthEnabled: true,
        isCloudMessagingEnabled: true,
        isDynamicLinksEnabled: true,
        isFirestoreEnabled: true,
        isFunctionsEnabled: true,
        isRemoteConfigEnabled: true,
        isStorageEnabled: true,
        googleRequestIdToken: "537235599720-723cgj10dtm47b4ilvuodtp206g0q0fg.apps.googleusercontent.com")

#if IOS
  CrossFirebase.Initialize(settings);
#elif ANDROID
  CrossFirebase.Initialize(activity, settings);
#endif

Plugin.Firebase.Core.Platform.iOS.Crossfirebase.Initialize() is basically the same method but should only be used when only a separated package like Plugin.Firebase.CloudMessaging is added instead of using the bundled version of the library.

AmanGoyal009 commented 10 months ago

Hi @AmanGoyal009,

yes, when the project is setup correctly, the DidReceiveNotificationResponse method is getting called and thereforeNotificationTapped is firing, take a look at the sample project as a working example.

I understand that you can't share details of your company's project. However, if you suspect the problem is with the library, consider creating a separate, simple project just to demonstrate the issue. This approach not only isolates the problem but might also help you identify the solution yourself.

Hi @TobiasBuchholz

In the sample project I didn't found any place where you registered the Notification Tapped event.

TobiasBuchholz commented 10 months ago

You can find it in the PushNotificationService:

private IObservable<FCMNotification> GetNotificationTappedTicks()
{
    return Observable
        .FromEventPattern<FCMNotificationTappedEventArgs>(_firebaseCloudMessaging, nameof(_firebaseCloudMessaging.NotificationTapped))
        .Select(x => x.EventArgs.Notification);
}

Observable.FromEventPattern converts a .NET event, conforming to the standard .NET event pattern, to an observable sequence, so it's basically the same as writing NotificationTapped += (sender, args) => { ... }.

AmanGoyal009 commented 10 months ago

Hi @TobiasBuchholz My code which I am using for the notification for IOS :

  1. MAUIPROGRAM.CS FILE : `using CommunityToolkit.Maui; using Microsoft.Extensions.Logging; using Mopups.Hosting; using Microsoft.Maui.LifecycleEvents; using Plugin.Firebase.Auth; using Plugin.Firebase.Bundled.Shared; using Plugin.Firebase.Crashlytics; using Plugin.LocalNotification; using Plugin.Firebase.CloudMessaging; using Newtonsoft.Json;

    if IOS

    using Plugin.Firebase.Bundled.Platforms.iOS;

    else

    using Plugin.Firebase.Bundled.Platforms.Android;

    endif

    namespace SampleApp;

public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp() .UseMauiCommunityToolkit() .ConfigureMopups() .RegisterFirebaseServices() .UseLocalNotification() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); });

if DEBUG

    builder.Logging.AddDebug();

endif

    return builder.Build();
}

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

if IOS

        events.AddiOS(iOS => iOS.WillFinishLaunching((app, launchOptions) => {
            Plugin.Firebase.Bundled.Platforms.iOS.CrossFirebase.Initialize(CreateCrossFirebaseSettings());
            FirebaseCloudMessagingImplementation.Initialize();
            return false;
        }));

else

        events.AddAndroid(android => android.OnCreate((activity, _) =>
            CrossFirebase.Initialize(activity, CreateCrossFirebaseSettings())));
        CrossFirebaseCrashlytics.Current.SetCrashlyticsCollectionEnabled(true);

endif

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

    CrossFirebaseCloudMessaging.Current.NotificationTapped += (sender, e) =>
    {
        var responseData = e.Notification.Data;
        // Redirect to different page.
    };

    return builder;
}

private static CrossFirebaseSettings CreateCrossFirebaseSettings()
{
    return new CrossFirebaseSettings(isAuthEnabled: true,
        isCloudMessagingEnabled: true,
        isAnalyticsEnabled: true);
}

} `

  1. Install the below two packages and added in the csproj file : PackageReference Include="Plugin.Firebase" Version="2.0.6" PackageReference Include="Plugin.Firebase.Crashlytics" Version="2.0.1"

  2. added the Entitlement.plist file and added below line : ` aps-environment

    production`
  3. Added below line inside the Info.plist file : ` UIBackgroundModes

    remote-notification `
  4. Added the GoogleService-Info.plist file in the root folder and make the build action as bundle resource and set quick property to copy to output directory

Now please tell where I doing mistake. This is the exact code I am using for the notification in IOS.

TobiasBuchholz commented 9 months ago

Sorry, but it doesn't work this way. I can't tell you what's wrong based on these code snippets. For instance, what does Plugin.LocalNotification do? Maybe that's the problem, I can't say...as I told you before already, please consider creating a separate, simple project just to demonstrate the issue.

Furthermore please keep in mind that I've created this library as well as I'm providing support for you and the others in my free time, so showing at least a bit of gratitude would be appreciated, thanks.

AmanGoyal009 commented 9 months ago

Hi @TobiasBuchholz ,

I am really thankful to you that you are replying and helping me to resolve the weird issue.

I tried to register the event inside the App.xaml.cs file in the OnStart override method. But still event is not firing. And I am not doing anything with Plugin.LocalNotification package. I tried by removing this package also. but still same issue.

And due to restriction on my machine I can't select and share the sample solution also :(

What I understood by trying different scenarios - There are code changes for receiving the notification in both android and iOS. And by implementing those changes I am able to receive the notification. There is no issue in that part.

But for registering the event there is nothing we have to do extra / different for both android and iOS.

And we are invoking the notification tapped event inside DidReceiveNotificationResponse . So, for sure this method is not called and that's why event is not firing in the case of iOS. It's not about where we are registering the event. Because that thing I tried and issue still same.

May be in your sample project you are not installing the (Plugin.Firebase) library. You directly included the code which you written to make this library and that's why it is working there.

What's your opinion on this and please help me by looking at the above code snippets only.

TobiasBuchholz commented 9 months ago

Hey @AmanGoyal009 by looking at your code I don't know why DidReceiveNotificationResponse wouldn't be called. The code snippet basically looks fine to me, although calling FirebaseCloudMessagingImplementation.Initialize() in this case isn't necessary because it already gets initialized through the CrossFirebaseSettings, but that shouldn't be a problem. You also don't need to add <key>UIBackgroundModes</key> <array> <string>remote-notification</string></array> to the Info.plist, but I don't think that's the problem either.

I have now creatd the most basic sample project NotificationTappedSample.zip I could come up with. The resulting iOS app just receives push notifications and displays an alert view after tapping on it. You can find the code responsible for that in MauiProgram.cs and MainPage.xaml.cs. Please take it as reference and go from there.

To build it yourself you just need to put your GoogleService-Info.plist into the root folder, next to the csproj file. Furthermore in the .csproj file replace <ApplicationId>com.tobishiba.playground</ApplicationId> with the bundle identifier that is defined in GoogleService-Info.plist.

Under the circumstances I don't think I can provide any more help than this, so good luck and please let us know if you find out what caused your issue.

AmanGoyal009 commented 9 months ago

Hi @TobiasBuchholz My code which I am using for the notification for IOS :

  1. MAUIPROGRAM.CS FILE : `using CommunityToolkit.Maui; using Microsoft.Extensions.Logging; using Mopups.Hosting; using Microsoft.Maui.LifecycleEvents; using Plugin.Firebase.Auth; using Plugin.Firebase.Bundled.Shared; using Plugin.Firebase.Crashlytics; using Plugin.LocalNotification; using Plugin.Firebase.CloudMessaging; using Newtonsoft.Json;

    if IOS

    using Plugin.Firebase.Bundled.Platforms.iOS;

    else

    using Plugin.Firebase.Bundled.Platforms.Android;

    endif

    namespace SampleApp;

public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp() .UseMauiCommunityToolkit() .ConfigureMopups() .RegisterFirebaseServices() .UseLocalNotification() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); });

if DEBUG builder.Logging.AddDebug(); #endif

  return builder.Build();
}

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

if IOS events.AddiOS(iOS => iOS.WillFinishLaunching((app, launchOptions) => { Plugin.Firebase.Bundled.Platforms.iOS.CrossFirebase.Initialize(CreateCrossFirebaseSettings()); FirebaseCloudMessagingImplementation.Initialize(); return false; })); #else events.AddAndroid(android => android.OnCreate((activity, ) => CrossFirebase.Initialize(activity, CreateCrossFirebaseSettings()))); CrossFirebaseCrashlytics.Current.SetCrashlyticsCollectionEnabled(true); #endif }); builder.Services.AddSingleton( => CrossFirebaseAuth.Current);

    CrossFirebaseCloudMessaging.Current.NotificationTapped += (sender, e) =>
    {
        var responseData = e.Notification.Data;
        // Redirect to different page.
    };

    return builder;
}

private static CrossFirebaseSettings CreateCrossFirebaseSettings()
{
    return new CrossFirebaseSettings(isAuthEnabled: true,
        isCloudMessagingEnabled: true,
        isAnalyticsEnabled: true);
}

} 2. Install the below two packages and added in the csproj file :PackageReference Include="Plugin.Firebase" Version="2.0.6" PackageReference Include="Plugin.Firebase.Crashlytics" Version="2.0.1"`

  1. added the Entitlement.plist file and added below line : <key>aps-environment</key> <string>production</string>
  2. Added below line inside the Info.plist file : <key>UIBackgroundModes</key> <array> <string>remote-notification</string> </array>
  3. Added the GoogleService-Info.plist file in the root folder and make the build action as bundle resource and set quick property to copy to output directory

Now please tell where I doing mistake. This is the exact code I am using for the notification in IOS.

Hi @TobiasBuchholz ,

Issue is resolved finally. Below are the modification I did in the above code.

  1. I removed the below line from the info.plist file. UIBackgroundModes remote-notification
  2. Added below line before registering the notification tapped event in the MAUIProgram.cs file : await CrossFirebaseCloudMessaging.Current.CheckIfValidAsync();
  3. Removed the below line also from the WillFinishLaunching method of iOS : FirebaseCloudMessagingImplementation.Initialize();

Thank you so much for giving your time and helping me in resolving the issue :).

TobiasBuchholz commented 9 months ago

Alright nice, I'm glad your issue could finally be resolved and thanks for letting us now what changes you made :)