Custom iOS notifications sound local notifications package Flutter - ios

I'm using Firebase Cloud Messaging to send notifications to my flutter app, and I'm using the flutter_local_notifications package to handle them, but when I tried to change the default notification sound it worked for android but didn't work for iOS, keep in mind that I add the "sound.aiff" to the root of the native iOS project, can anyone show me what I'm missing here, and thanks in advance
class FCMFunctions {
static final FCMFunctions _singleton = new FCMFunctions._internal();
FCMFunctions._internal();
factory FCMFunctions() {
return _singleton;
}
late FirebaseMessaging messaging;
//************************************************************************************************************ */
/// Create a [AndroidNotificationChannel] for heads up notifications
late AndroidNotificationChannel channel;
/// Initialize the [FlutterLocalNotificationsPlugin] package.
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
//************************************************************************************************************ */
Future initApp() async {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
messaging = FirebaseMessaging.instance;
if (!kIsWeb) {
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
importance: Importance.high,
sound: RawResourceAndroidNotificationSound('sound'),
playSound: true,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
/// Create an Android Notification Channel.
///
/// We use this channel in the `AndroidManifest.xml` file to override the
/// default FCM channel to enable heads up notifications.
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
//for IOS Foreground Notification
await messaging.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void initializeNotifications() async {
var initializationSettingsAndroid =
const AndroidInitializationSettings('icon');
var initializationSettingsIOS = const IOSInitializationSettings();
//var initializationSettings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
var initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onSelectNotification: onSelectNotification,
);
}
Future onSelectNotification(String? payload) async {
if (payload != null) {
debugPrint('notification payload: $payload');
}
navigatorKey.currentState!.pushNamed(Routes.blackCurrency,
arguments: false); //message.data['category']
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Future subscripeToTopics(String topic) async {
await messaging.subscribeToTopic(topic);
}
///Expire : https://firebase.google.com/docs/cloud-messaging/manage-tokens
Future<String?> getFCMToken() async {
final fcmToken = await messaging.getToken();
return fcmToken;
}
void tokenListener() {
messaging.onTokenRefresh.listen((fcmToken) {
print("FCM Token dinlemede");
// TODO: If necessary send token to application server.
}).onError((err) {
print(err);
});
}
/// IOS
Future iosWebPermission() async {
if (Platform.isIOS || kIsWeb) {
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
}
}
///Foreground messages
///
///To handle messages while your application is in the foreground, listen to the onMessage stream.
void foreGroundMessageListener() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print(
'///////////////////////////// NOTIFICATIONS ARE COMMING /////////////////////////////');
print('${message.notification!.body} ');
print("Message data type : ${message.data.runtimeType}");
var bodyRaw = message.data['body'];
var body = List<dynamic>.from(jsonDecode(bodyRaw ?? '[]'));
print("body : $body");
String bodyMessage = '';
if (body.first['sale'] == null) {
bodyMessage = body.first['name'];
} else if (body.first['name'] == null) {
bodyMessage = body.first['sale'];
} else {
bodyMessage =
body.map((e) => e['name'] + '-' + e['sale']).join(', ').toString();
}
RemoteNotification? notification = RemoteNotification(
android: const AndroidNotification(
smallIcon: 'assets/imgs/logo.png',
priority: AndroidNotificationPriority.highPriority,
visibility: AndroidNotificationVisibility.public,
),
apple: const AppleNotification(
sound: AppleNotificationSound(
name: 'sound',
volume: 1.0,
),
),
title: message.data['title'],
body: bodyMessage,
);
// message.notification;
AndroidNotification? android =
notification.android; //message.notification?.android;
if (notification != null && android != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
importance: Importance.max,
priority: Priority.max,
ticker: 'ticker',
sound: const RawResourceAndroidNotificationSound('sound'),
// icon: "#mipmap/icon",
playSound: true,
styleInformation: const DefaultStyleInformation(true, true),
),
iOS: const IOSNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
sound: 'sound',
),
),
);
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('A new onMessageOpenedApp event was published!');
navigatorKey.currentState!.pushNamed(Routes.blackCurrency,
arguments: false); //message.data['category']
// Navigator.pushNamed(
// context,
// '/message',
// arguments: MessageArguments(message, true),
// );
});
}
}
final fcmFunctions = FCMFunctions();

Your server administrator will send you the sound name in notification payload which you added in iOS folder. Payload will look like this
{
aps =
{
alert = "notification message";
sound = "example.caf";
};
}
more information check this reference link
49
49
custom sound file for your app, follow this apple documentation.

Related

How to get flutter local notification on iOS using only FCM data message?

I have an app that send notifications if someone commented or published a new post. I use FCM and flutter local notification. It works well on Android, but on iOS it does not. I realized if I add a 'notification' message block to the firebase function then finally I get the data message BUT I get the notification message too at the same time. That is not what I want. If I remove Notification message then data message not triggered and I do not get any notification.
The app should works only from iOS 10+. I tried this on iOS 15.
This is my firebase function:
exports.myFunction = functions.firestore
.document("animal/{message}")
.onCreate((snapshot, context) => {
return admin.messaging().sendToTopic("animal", {
data: {
latitude: snapshot.data()["latitude"].toString(),
longitude: snapshot.data()["longitude"].toString(),
title: snapshot.data().username,
body: snapshot.data().description,
uid: snapshot.data().userId,
animalId: snapshot.id,
},
//I do not want to use this, but if I remove this I do not get any push notification. Data notification neither.
//On Android it does not matter if I delete notification block or no. I will get the data notification.
notification: {
title: "title",
body: "new post",
},
});
});
In main.dart there is the flutter local notification initializing
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final AndroidInitializationSettings _initialzationSettingsAndriod =
AndroidInitializationSettings('noticon');
final IOSInitializationSettings _initialzationSettingsIOS =
IOSInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false,
);
final InitializationSettings _initializationSettings = InitializationSettings(
android: _initialzationSettingsAndriod, iOS: _initialzationSettingsIOS);
_flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await _flutterLocalNotificationsPlugin.initialize(
_initializationSettings,
onSelectNotification: (payload) async {
if (payload != null) {
debugPrint('notification payload: ' + payload);
}
initPayload = payload!;
await navigatorKey.currentState!.push(CupertinoPageRoute<void>(
builder: (BuildContext context) => AnimalDetailScreen(payload, true),
));
},
);
....
#override
void initState() {
super.initState();
_requestPermissions();
final messaging = FirebaseMessaging.instance;
messaging.subscribeToTopic('animal');
messaging.subscribeToTopic('notifications');
messaging.requestPermission(
alert: true,
sound: true,
badge: true,
provisional: false,
);
And this is the showing notification. If I remove the notification message from firebase function then onMessage cannot be called on iOS but on only Android.
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
print("onMessage called");
....
if (isValid && currentUser != message.data['uid']) {
showNotification(message);
notifierCounter.value = notifierCounter.value + 1;
}
}
...
showNotification(RemoteMessage message) async {
Map<String, dynamic> data = message.data;
await flutterLocalNotificationsPlugin.show(
data.hashCode,
data['title'],
data['body'],
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
priority: Priority.high,
),
iOS: IOSNotificationDetails(),
),
payload: data['animalId'],
);
}
I found a solution.
I changed this:
notification: {
title: "title",
body: "new post",
},
to:
notification: {
sound: "default",
},
In this way I wont get automatic push notification and I can handle data message on iOS.

How to make a flutter app recieve push notifications from firebase for IOS

I am currently trying to set up push notifications for my flutter app (on IOS, it works on android). I have tried both the Flutter Local Notifications and Awesome Notifications but neither are yielding any notifications. I am testing on a physical device and I have gone through the process of setting up my APNs with firebase.
import 'dart:io';
import 'package:awesome_notifications/awesome_notifications.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
const AndroidNotificationChannel channel = AndroidNotificationChannel(
"general_notifications", " General Notifications",
description: "This channel is used for ALL notification",
importance: Importance.max);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
AwesomeNotifications().createNotificationFromJsonData(message.data);
}
class FirebaseNotifications {
initialize() async {
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
var initalizationSettingsAndroid =
AndroidInitializationSettings("#mipmap/ic_launcher");
var initializationSettingsIOS = IOSInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true);
var initializationSettings = InitializationSettings(
android: initalizationSettingsAndroid, iOS: initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings);
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
if (Platform.isAndroid) {
RemoteNotification? notification = message.notification;
AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails(channel.id, channel.name,
channelDescription: channel.description,
importance: Importance.max,
priority: Priority.high,
groupKey: channel.groupId);
NotificationDetails notificationDetails =
NotificationDetails(android: androidNotificationDetails);
flutterLocalNotificationsPlugin.show(notification.hashCode,
notification!.title, notification.body, notificationDetails);
List<ActiveNotification>? activeNotifications =
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.getActiveNotifications();
if (activeNotifications!.length > 0) {
List<String> lines =
activeNotifications.map((e) => e.title.toString()).toList();
InboxStyleInformation inboxStyleInformation = InboxStyleInformation(
lines,
contentTitle: "${activeNotifications.length - 1} messages",
summaryText: "${activeNotifications.length - 1} messages");
AndroidNotificationDetails groupNotificationDetails =
AndroidNotificationDetails(channel.id, channel.name,
channelDescription: channel.description,
styleInformation: inboxStyleInformation,
setAsGroupSummary: true);
NotificationDetails groupNotificationDetailsPlatformSpefics =
NotificationDetails(android: groupNotificationDetails);
await flutterLocalNotificationsPlugin.show(
0, '', '', groupNotificationDetailsPlatformSpefics);
}
} else if (Platform.isIOS) {
// FirebaseMessaging.instance.setF
RemoteNotification? notification = message.notification;
IOSNotificationDetails iOSNotificationDetails = IOSNotificationDetails(
presentAlert: true, presentBadge: true, presentSound: true);
NotificationDetails notificationDetails =
NotificationDetails(iOS: iOSNotificationDetails);
flutterLocalNotificationsPlugin.show(notification.hashCode,
notification!.title, notification.body, notificationDetails);
}
AwesomeNotifications().initialize(null, [
NotificationChannel(
channelKey: 'basic_channel',
channelName: 'Basic notifications',
channelDescription: 'Notification channel for basic tests',
defaultColor: const Color(0xFF9D50DD),
ledColor: Colors.white,
playSound: true,
)
]);
});
}
Future<String?> getToken() async {
String? token = await FirebaseMessaging.instance.getToken();
print(token);
return token;
}
subscribeToTopic(String topic) async {
await FirebaseMessaging.instance.subscribeToTopic(topic);
}
}
Not sure where the issue is (client side, or inside my apple settings)...

flutter_local_notifications does not show the notification(IOS only)

i am beginner in flutter. I try to make an app which should notify users on scheduled time. I decided to use flutter_local_notification.
(I am trying to implement this only IOS as first step so that is why code blocks related with android commented in.)
class NotificationHelper {
FlutterLocalNotificationsPlugin
flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
initializeNotification() async {
//tz.initializeTimeZones();
final IOSInitializationSettings initializationSettingsIOS =
IOSInitializationSettings(
requestSoundPermission: false,
requestBadgePermission: false,
requestAlertPermission: false,
onDidReceiveLocalNotification: onDidReceiveLocalNotification
);
// final Android InitializationSettings initializationSettingsAndroid =
// Android InitializationSettings("appicon");
final InitializationSettings initializationSettings =
InitializationSettings(
iOS: initializationSettingsIOS,
);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onSelectNotification: selectNotification);
}
onDidReceiveLocalNotification(
int id, String? title, String? body, String? payload) async {
// display a dialog with the notification details, tap ok to go to another page
// showDialog(
// //context: context,
// builder: (BuildContext context) => CupertinoAlertDialog(
// title: Text(title),
// content: Text(body),
// actions: [
// CupertinoDialogAction(
// isDefaultAction: true,
// child: Text('Ok'),
// onPressed: () async {
// Navigator.of(context, rootNavigator: true).pop();
// await Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => SecondScreen(payload),
// ),
// );
// },
// )
// ],
// ),
// );
}
Future selectNotification(String? payload) async {
if (payload != null) {
print('notification payload: $payload');
} else {
print("Notification Done");
}
}
void requestIOSPermissions() {
flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
}
displayNotification({required String title, required String body}) async {
print("doing test");
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails('your channel id', 'your channel name',
channelDescription: 'your channel description',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker');
const NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics);
flutterLocalNotificationsPlugin.show(
12345,
"A Notification From My Application",
"This notification was sent using Flutter Local Notifcations Package",
platformChannelSpecifics,
payload: 'data');
}
}
and i call the initializeNotification() function on my main.dart like this:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
NotificationHelper().requestIOSPermissions();
NotificationHelper().initializeNotification();
runApp(const MyApp());
}
and after user logged in,
I just try to see my notification so i call displayNotification() on a button like this:
IconButton(
icon: const Icon(Icons.settings),
onPressed: () {
NotificationHelper().displayNotification(title: 'title', body: 'hede');
},
color: Colors.white,
iconSize: 25,
),
and also i call this code in AppDelegate.swift
import UIKit
import Flutter
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
when application opens it successfully asks permissions for send notifications. After it allowed i just try to call displayNotification() but it doesn't work. I cannot see any notification on my simulator.
environment:
sdk: ">=2.15.1 <3.0.0"
flutter_local_notifications: ^9.3.3
What should i do ? Thank you for you all your answers.
I think notifications doesn't work currently on İOS simulator. You should try real ios device

Background message handler on iOS is not called via FCM when the app is in background

Can anyone tell me why can't I receive the trigger for onBackgroundMessage in iOS but I can receive the notification via FCM hence if I click the notification onMessageOpenedApp is triggered. What will I do to trigger onBackgroundMessage? Compared to Android everything is working fine.
Here is me code
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
if (Firebase.apps.isEmpty) await Firebase.initializeApp();
print('Handling a background message ${message.data['id']}');
}
handleNotifications() async {
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
NotificationSettings settings = await _firebaseMessaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
print('User granted permission: ${settings.authorizationStatus}');
_firebaseMessaging.getToken().then((String token) async {
assert(token != null);
print(token);
final sessionPrefs = await SharedPreferences.getInstance();
if (Platform.isAndroid) {
sessionPrefs.setString('token', token);
sessionPrefs.setString('platform', 'android');
} else if (Platform.isIOS) {
sessionPrefs.setString('token', token);
sessionPrefs.setString('platform', 'ios');
}
});
FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(badge: false, alert: false, sound: true); //presentation options for Apple notifications when received in the foreground.
FirebaseMessaging.onMessage.listen((message) async {
print('Got a message whilst in the FOREGROUND!');
return;
}).onData((data) async {
print('Got a DATA message whilst in the FOREGROUND!');
print('data from stream: ${data.data['id']}');
});
FirebaseMessaging.onMessageOpenedApp.listen((message) async {
print('NOTIFICATION MESSAGE TAPPED');
return;
}).onData((data) async {
print('NOTIFICATION MESSAGE TAPPED');
print('data from streamOpen: ${data.data}');
});
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
FirebaseMessaging.instance.getInitialMessage().then((value) => value != null ? _firebaseMessagingBackgroundHandler : false);
return;
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
handleNotifications();
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: '/',
home: session //Menu if the user has not loged out the app else Home
? Menu()
: HomePage(), // CONDITION FOR CHECKING IF THE SESSION IS TRUE OR FALSE
),
);
}

Flutter ios device doesn't trigger onMessage from FCM notification. Sendtodevice fails when implementing APNs

In my fcm cloud function to send notifications to other players, it fails to send when I add the apns layer. When the apns layer is removed, notifications appear on android but for iOS the notifications are received in the front end but fail to trigger the onMessage function to display an alert dialog.
var payload = {
data: {
click_action: "FLUTTER_NOTIFICATION_CLICK",
notificationType: "friendsRequest",
fromUsername: fromUsername,
fromProfilePic: fromProfilePic,
fromColorIndex: fromColorIndex,
type: type
},
};
This payload returns a server response of "crash"
To enable notification for iOS you need to set up FCM for iOS first:
As you said you have generated APNs. just confirm have you linked apn with firebase project or not. after that open your project ios module in Xcode and make following changes in AppDelegate
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as?
UNUserNotificationCenterDelegate
}
Make changes in flutter side (I'm using this code in splash screen):
Initialization
FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
Code in initState()
var initializationSettingsAndroid =
new AndroidInitializationSettings('#mipmap/ic_launcher'); //replace with your app icon file
var initializationSettingsIOS = new IOSInitializationSettings();
var initializationSettings = new InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: onSelectNotification);
FirebaseNotifications().setUpFirebase(_firebaseMessaging);
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
showNotification(
message['notification']['title'], message['notification']['body']);
print("onMessage: $message");
},
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
},
);
Methods for notification:
void showNotification(String title, String body) async {
await _demoNotification(title, body);
}
Future<void> _demoNotification(String title, String body) async {
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
'channel_ID', 'channel name', 'channel description',
importance: Importance.Max,
playSound: true,
sound: 'sound',
showProgress: true,
icon: 'notification_icon',
color: AppTheme.secondaryaccent,
priority: Priority.High,
ticker: 'test ticker');
var iOSChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSChannelSpecifics);
await flutterLocalNotificationsPlugin
.show(0, title, body, platformChannelSpecifics, payload: 'test');
}

Resources