Closed axylophon closed 1 year ago
Hey axylophon,
for iOS you need to set the regular iOS permissions to Entitlements.plist:
<key>aps-environment</key>
<string>development</string>
Info.plist:
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>
At least I have the following configuration in Info.plist ;-). Configuratioin of Entitlements.plist is described here. Please ensure that you do NOT startup the application with an attached debugger as this might cause issues (at the very least with Android and more specifically: stopping the application with the debugger, not attaching a debugger in itself). I would recommend sending data manually via a backend to do your testing (see my comment https://github.com/TobiasBuchholz/Plugin.Firebase/issues/145 for a test notification).
For reference my solution for Android 13: https://github.com/TobiasBuchholz/Plugin.Firebase/issues/145#issuecomment-1455182588. However I like yours better. I think I might integrate this into my application. Can you tell me where you are calling var status = await Microsoft.Maui.ApplicationModel.Permissions.CheckStatusAsync<Notification>();
from?
Hey thanks for your reply!
Thank you for your insights. Its a shame that there is still no support from Microsoft in such a vital feature for mobile apps.
I have a prototype ready for Android but I am still struggling with the details. Foreground/Background/Icon etc. I also had some struggles with missing notifications which i cannot explain. No changes to the app, tried with or without debugging. Sometimes it works sometimes not.
Am I right that this package always displays a push notification even when the app is in foreground?
Next week I am looking to do the same for iOS but my dev Mac is right now in repair 😅
Do you maybe have an idea how i can implement the iOS permission handling manually? It would maybe be possible to inhert also from BasePlatformPermission/BasePermission. But i would need some guidance how to request/check the status.
Here my use case that you understand it better:
I have a Blazor MAUI Hybrid App. Maui is just a wrapper for the Blazor Application.
During the app login I have a specific page in the Blazor application which explains the user the notifications and asks if the user wants them. If accepted I trigger the permission request for Android. For this i inject an Interface that abstracts the Maui Permission API. The implementation of this Interface is done in the maui project. If the user denies it I show a warning and an additional explanation.
I want the same behaviour also for iOS to trigger the system permission dialog and react to the response as in Android 13+.
Thank you for your comment to my Android Permission handling. I think its a rather nice solution that could easily integrated directly into Maui.
Yeah, there is a lot of features lacking in MAUI. It gets really bad if you use a Microsoft MAUI component (such as the Bottom Tab Bar), you want a feature but it is not there (like: I want four tabs at the most). In this case you are lost and have to to a lot of changes to your source code (in my case: removing Shell, replacing the Bottom Tab Bar with a custom tab bar etc. pp.). Actually at the moment I would recommend to use as few Microsoft components as possible if you want to do customization (layout, font style, font colors) than whatever is the default. But using MAUI Hybrid seems to indicate this is not a problem on your side.
Notifcation behaviour: The notification will always be displayed whether the App is in foreground, in background or closed. I THINK there are event hooks which let you either handle the message yourself (app is active) or not (app is active with special behaviour, app is inactive or closed) however at the moment I am satisfied with the default behaviour.
iOS: I tried to check my iOS app however at the moment I cannot build iOS because I have fcm related build copy errors due to long file names. Don't know when they appeared :-/. There is always a problem with MAUI. Especially with iOS.
I think the iOS app behaves the following: when configured to use the Notification Permission the system will ask the user at the moment he is launching the app. I don't think you can override this. Might be a "good" decision on MAUI part or it could be a limitation of iOS.
Yeah with Blazor we have more freedom regarding the UI but it has also issues like the interaction between MAUI and Blazor and Webview issues in general.
Thanks i will take a look when my Mac is ready again.
Regarding the build error:
I also had a file copy build error when adding the FCM Nuget package although the file was clearly there. I currently removed the iOS target framework as i hoped that it is a windows issue...
Could you maybe post the error message?
We should try to find a workaround/fix for it or start an issue at microsoft to get this fixed...
For your information even though it is off topic: I tried to create a bug report regarding their .NET 8 MAUI "build script" for an iOS build (.NET 8, so Visual Studio Beta) a couple of weeks ago which I had an workaround and spend 1 hour of collecting data for the report I had to supply something event more (don't remember what it was) which would have cost me hours of work most likely. Which is were I quit my attempt of reporting the bug.
When enabling iOS as Target Framework I get the following error (when building Android OR iOS):
Error MSB3027 Could not copy "C:\nuget\xamarin.firebase.ios.core\8.10.0.3\lib\net6.0-ios15.4\Firebase.Core.resources\GoogleAPIClientForREST.xcframework\ios-arm64_x86_64-simulator\GoogleAPIClientForREST.framework\Headers\GoogleAPIClientForREST-umbrella.h" to "bin\Debug\net7.0-ios16.2\iossimulator-x64\Firebase.Core.resources\GoogleAPIClientForREST.xcframework\ios-arm64_x86_64-simulator\GoogleAPIClientForREST.framework\Headers\GoogleAPIClientForREST-umbrella.h". Exceeded retry count of 10. Failed.
Error MSB3027 Could not copy "C:\nuget\xamarin.firebase.ios.installations\8.10.0.3\lib\net6.0-ios15.4\Firebase.Installations.resources\FirebaseInstallations.xcframework\ios-arm64_x86_64-simulator\FirebaseInstallations.framework\Headers\FirebaseInstallations-umbrella.h" to "bin\Debug\net7.0-ios16.2\iossimulator-x64\Firebase.Installations.resources\FirebaseInstallations.xcframework\ios-arm64_x86_64-simulator\FirebaseInstallations.framework\Headers\FirebaseInstallations-umbrella.h". Exceeded retry count of 10. Failed.
...
iOS enabled as Target Framework:
<TargetFrameworks>net7.0-android33.0;net7.0-ios16.2</TargetFrameworks>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">28.0</SupportedOSPlatformVersion>
I think its related to the file path length which exceeds 255 characters. But don't you worry. I think (and strongly hope) it was introduced with the current Visual Studio v17.6.4 and possibly it will be resolved with the next. My friend has the same issue (but don't know if this happened for him before the VS update ...). Truth is: the MAUI iOS build / deploy keeps on breaking like every second Visual Studio update.
Thanks!
I got my Mac back from repair - the push notifications are working at the first glance on the latest iOS 🙂 🎉- I forgot an Initialize call that was mentioned in the readme but not in the sample as there is the whole Plugin.Firebase nuget package used and not only the Plugin.Firebase.CloudMessaging one 😂
I have the latest SDK, XCode, VS installed on MacOS. It is working and building for me in VS. But i cannot start it via Rider... 🙄
I also had the same issue with copying the file. It occured only on Windows when the iOS target framework was in the project file as soon as i installed the FCM nuget package. I adapted the csproj file that on Windows only Android and on MacOS only iOS is built.
Maybe that issue is helping? https://github.com/xamarin/xamarin-macios/issues/18445
I still got two open tasks on my side:
It occured only on Windows when the iOS target framework was in the project file as soon as i installed the FCM nuget package. I adapted the csproj file that on Windows only Android and on MacOS only iOS is built.
That's just so sad but yeah ... I guess the way to go.
Regarding you Icon issue: can you provide an example? I can compare it to our icon. Actually I have to ask my friend, he has a Pixel and I don't think we tested it with Material You Design activated.
Yeah i will provide an icon example next week 👍🏻 I tested it with the Android emulator. But i have also a personal pixel which i will test before sending you the example 🙂
Then i will also have feedback regarding the permissions.
This is my current solution to request the permission manually on iOS:
CheckIfValid
method on Android to avoid the permission popupBasePlatformPermission
class and just specify the name of the Android permission. For iOS I extend the BasePermission
class and implement the methods manually by calling the iOS APIs.With this implementation i can use the MAUI API for requesting permissions and control the behaviour as i like.
#if ANDROID
await CrossFirebaseCloudMessaging.Current.CheckIfValidAsync();
#endif
This is the content of my Notification.cs file:
#if ANDROID
public class Notification : Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission
{
public override (string androidPermission, bool isRuntime)[] RequiredPermissions =>
new List<(string androidPermission, bool isRuntime)>
{
(Android.Manifest.Permission.PostNotifications, true),
}.ToArray();
}
#elif IOS
public class Notification : Microsoft.Maui.ApplicationModel.Permissions.BasePermission
{
public override Task<PermissionStatus> CheckStatusAsync()
{
var taskCompletionSource = new TaskCompletionSource<PermissionStatus>();
UNUserNotificationCenter.Current.GetNotificationSettings((settings) =>
{
var status = settings.AuthorizationStatus switch
{
UNAuthorizationStatus.Authorized => PermissionStatus.Granted,
UNAuthorizationStatus.Denied => PermissionStatus.Denied,
UNAuthorizationStatus.Ephemeral => PermissionStatus.Granted,
UNAuthorizationStatus.NotDetermined => PermissionStatus.Unknown,
UNAuthorizationStatus.Provisional => PermissionStatus.Granted,
_ => PermissionStatus.Unknown
};
taskCompletionSource.SetResult(status);
});
return taskCompletionSource.Task;
}
public override Task<PermissionStatus> RequestAsync()
{
var taskCompletionSource = new TaskCompletionSource<PermissionStatus>();
UNUserNotificationCenter.Current.RequestAuthorization(
UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
(granted, error) => {
if(!granted) {
taskCompletionSource.SetResult(PermissionStatus.Denied);
}
else
{
taskCompletionSource.SetResult(PermissionStatus.Granted);
}
});
return taskCompletionSource.Task;
}
public override void EnsureDeclared()
{
}
public override bool ShouldShowRationale()
{
return false;
}
}
#endif
@andyzukunft: regarding the icon issue:
I have put the svg icon under \Resources\Images\notify.svg. It is also the same file that i use for the app icon itself. It is this file:
Images are included in the csproj file:
<!-- Images -->
<MauiImage Include="Resources\Images\*" />
I added it to the AndroidManifest.xml:
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notify" />
And when creating the channel in MainActivity.cs
:
FirebaseCloudMessagingImplementation.SmallIconRef = Resource.Drawable.notify;
Here are the results (Android 13):
Samsung: Icon looks good:
I think the white circle around the icon is too large here:
Pixel:
Icon not visible (color issue?):
Icon not visible (color issue?):
@andyzukunft: con respecto al problema del icono:
He puesto el ícono svg en \Resources\Images\notify.svg . También es el mismo archivo que uso para el ícono de la aplicación. Es este archivo:
Las imágenes están incluidas en el archivo csproj:
<!-- Images --> <MauiImage Include="Resources\Images\*" />
Lo agregué a la
AndroidManifest.xml:
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notify" />
Y al crear el canal en
MainActivity.cs
:FirebaseCloudMessagingImplementation.SmallIconRef = Resource.Drawable.notify;
Aquí están los resultados (Android 13):
Samsung: El icono se ve bien:
Creo que el círculo blanco alrededor del icono es demasiado grande aquí:
Píxel:
Icono no visible (¿problema de color?):
Icono no visible (¿problema de color?):
In android it is recommended to have an icon with a white background and the rest of the icon in black, within the resources of the Android project.
I created a new Android icon which is working fine now :) We are now in a test phase before going live - so far it looks good. But i observered another problem - i will create a new issue for it.
It occured only on Windows when the iOS target framework was in the project file as soon as i installed the FCM nuget package. I adapted the csproj file that on Windows only Android and on MacOS only iOS is built.
That's just so sad but yeah ... I guess the way to go.
Any chance you can share sample code ?
Any chance you can share sample code ?
This is how I have done it right now in the csproj file:
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('osx'))">$(TargetFrameworks);net7.0-ios</TargetFrameworks><TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net7.0-android33.0</TargetFrameworks>
@axylophon I want to backtrack some of this topic. You mentioned and provided an example of how you circumvent the permission request for iOS during application startup. Is this still your production code?
Around two months ago Microsoft implement the Post Notification permission into MAUI and I am wondering if any special implementation is required or if we still need special behaviour for iOS.
Hi,
yes it is still my production code. As far as i know the permission was only implemented for Android and not for iOS?
So I believe for iOS the special handling is still necessary if more control is needed when the permission popup should be visible to the user.
It seems you might be correct. I am currently adapting your iOS example to work with my app.
Can you please verify something for me? I am only calling CheckIfValidAsync()
for Android however the iOS dialog "App Would Like to Send You Notifications" still pops up on startup. Can you confirm this does (not) appear for you on a "clean" emulator (e.g. where the app has been deinstalled beforehand)? It seems FirebaseCloudMessagingImplementation.Initialize()
implemented in MauiProgram.cs also checks and requests the permision. How do you handle that?
// Example for MAUI App.xaml.cs OnStart()
protected override void OnStart()
{
#if ANDROID
CrossFirebaseCloudMessaging.Current.CheckIfValidAsync().Wait();
#endif
}
// Example for MAUI MauiProgram.cs Firebase initialization
private static MauiAppBuilder RegisterFirebaseServices(this MauiAppBuilder builder)
{
#if ANDROID
// Init Android components
#elif IOS
builder.ConfigureLifecycleEvents(events =>
{
events.AddiOS(iOS => iOS.WillFinishLaunching((_,__) => {
CrossFirebase.Initialize();
FirebaseCloudMessagingImplementation.Initialize();
return false;
}
#endif
}
Update:
It also happens if I remove FirebaseCloudMessagingImplementation.Initialize()
:
// Example for MAUI MauiProgram.cs Firebase initialization
private static MauiAppBuilder RegisterFirebaseServices(this MauiAppBuilder builder)
{
#if ANDROID
// Init Android components
#elif IOS
builder.ConfigureLifecycleEvents(events =>
{
events.AddiOS(iOS => iOS.WillFinishLaunching((_,__) => {
CrossFirebase.Initialize();
return false;
}
#endif
}
FYI: I am still on version 2.0.4. I only use the Plugin.Firebase.CloudMessaging nuget package.
Yes with my solution I never saw the iOS permission dialog on app start. I could trigger it myself. Last time I tested it was iOS 15. If you cannot get it to run I could test it again on my device if anything changed.
Maybe it has something to do with the 3.0 version and the iOS dependency updates? Have you tried the older version 2.0.4?
Here are my code snippets:
MauiProgram.cs
:
private static MauiAppBuilder RegisterFirebaseServices(this MauiAppBuilder builder)
{
builder.ConfigureLifecycleEvents(events =>
{
#if IOS
events.AddiOS(iOS => iOS.WillFinishLaunching((_, launchOptions) => {
CrossFirebase.Initialize();
FirebaseCloudMessagingImplementation.Initialize();
return false;
}));
#else
events.AddAndroid(android => android.OnCreate((activity, _) =>
CrossFirebase.Initialize(activity)));
#endif
});
return builder;
}
When getting the push token:
#if ANDROID
await CrossFirebaseCloudMessaging.Current.CheckIfValidAsync(); //run check valid only on android as this triggers the permission request on iOS
#endif
var token = await CrossFirebaseCloudMessaging.Current.GetTokenAsync();
@andyzukunft : I just read about all the iOS binding issues and the version 3.0.0. I was not actively developing the app in the last months. If i understand it right i should update ASAP to 3.0.0.
Should i expect any issues with 3.0.0? What is your experience?
I gave my fcm implementation some love within the last week. One part of it was updating the Plugin.Firebase.CloudMessaging to v3.0.0. As far as I can tell the update works with the usual Visual Studio troubles (-> long file names). The running app is working without problems as far as I can tell. Well there might be the permission dialog - but I hope it's not related.
The Visual Studio workaround is the following:
/bin
and /obj
folders in your mobile project development folderPlugin.Firebase.CloudMessaging
to 3.0.0
dotnet restore
dotnet build
Later on, when you want to build a release version I believe you have to use the terminal to create an initial build as well. I am not that impacted by that because I started to use the terminal to publish release builds anyway.
It would be great if you can check on your end if the permission dialog appears for v2.0.4 and later on for 3.0.0. I think I will go with my current solution (based on yours) for the moment. While it does not properly asks for the iOS permission where I want it, it does can check it at the point I want it to and prevent the user going further without having notifications activated.
I have put the 3.0.0 update on my agenda now. Have you already published a new iOS version with 3.0.0? Any problems with the app store?
Do you know if the version 2.0.4 and its dependencies use the legacy FCM API? If yes the push notifications for iOS users are maybe already broken. I have no access to an iOS device right now to test it.
I will give you some feedback once i have updated to 3.0.0.
I don't know what kind of API is being used. But it sounds reasonable that the old FCM API was being used. However I believe it was still working with iOS.
I already pushed my app (MAUI v8.0.71, Plugin.Firebase.CloudMessaging v3.0.0) to the iOS store and it is running in production for a few days. So far I don't see any problems.
That sounds nice thank you!
Yeah maybe I am confused with the APIs. I am not sure if this is even relevant for the client.
Hi,
i have a question regarding the iOS notification permission request. As I understand this is done in the CheckIfValidAsync method:
With Android 13 the permissions must be requested manually - i solved this via a custom permission class as maui does not support it currently:
Usage with the permissions api. This is working great:
How can i achieve the same behaviour for iOS to request the permission manually in the code or check if the permission for notifications is granted or not? I do not want to do it on application start but when the user activates notifications in our app.
Therefore it would be nice to build an async method to do this to block the UI until the permission dialog is closed like in the android example.
Should i skip calling CheckIfValidAsync on iOS if i want to do it on my own?
Is it possible to request the Push Token without the granted permission?