flutter_apns fork without any firebase_messaging
dependencies, bringing you APNS push notifications on iOS while allowing you to use (or not) any version of firebase_messaging
.
Original flutter-apns
extends and use firebase_messaging
but is no more compatible with its 8+ version. This plugin doesn't extends it so you're free to use it on iOS without firebase_messaging
or while having your own firebase_messaging
setup.
- On iOS, make sure you have correctly configured your app to support push notifications, and that you have generated certificate/token for sending pushes.
- Add the following lines to the
didFinishLaunchingWithOptions
method in the AppDelegate.m/AppDelegate.swift file of your iOS project
Objective-C:
if (@available(iOS 10.0, *)) {
[UNUserNotificationCenter currentNotificationCenter].delegate = (id<UNUserNotificationCenterDelegate>) self;
}
Swift:
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
- Add
flutter_apns
as a dependency in your pubspec.yaml file. - Using
createPushConnector()
method, configure push service according to your needs.PushConnector
closely resemblesFirebaseMessaging
, so Firebase samples may be useful during implementation. You should create the connector as soon as possible to get the onLaunch callback working on closed app launch.
import 'package:flutter_apns/apns.dart';
final connector = createPushConnector();
connector.configure(
onLaunch: _onLaunch,
onResume: _onResume,
onMessage: _onMessage,
);
connector.requestNotificationPermissions()
- Build on device and test your solution using Firebase Console and NWPusher app.
final connector = createPushConnector();
if (connector is ApnsPushConnector) {
connector.shouldPresent = (x) => Future.value(true);
}
Firstly, configure supported actions:
final connector = createPushConnector();
if (connector is ApnsPushConnector) {
connector.setNotificationCategories([
UNNotificationCategory(
identifier: 'MEETING_INVITATION',
actions: [
UNNotificationAction(
identifier: 'ACCEPT_ACTION',
title: 'Accept',
options: [],
),
UNNotificationAction(
identifier: 'DECLINE_ACTION',
title: 'Decline',
options: [],
),
],
intentIdentifiers: [],
options: [],
),
]);
}
Then, handle possible actions in your push handler:
Future<dynamic> onPush(String name, Map<String, dynamic> payload) {
storage.append('$name: $payload');
final action = UNNotificationAction.getIdentifier(payload);
if (action == 'MEETING_INVITATION') {
// do something
}
return Future.value(true);
}
Note: if user clickes your notification while app is in the background, push will be delivered through onResume without actually waking up the app. Make sure your handling of given action is quick and error free, as execution time in for apps running in the background is very limited.
Check the example project for fully working code.
- Ensure that you are testing on actual device. NOTE: this may not be needed from 11.4: https://ohmyswift.com/blog/2020/02/13/simulating-remote-push-notifications-in-a-simulator/
- If onToken method is not being called, add error logging to your AppDelegate, see code below.
- Open Console app for macOS, connect your device, and run your app. Search for "PUSH registration failed" string in logs. The error message will tell you what was wrong.
swift
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
NSLog("PUSH registration failed: \(error)")
}
}
objc
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"%@", error);
}
@end