2626 */
2727
2828#import " OneSignalPlugin.h"
29+ #import " XOneSignalNotificationService.h"
2930#import " OSFlutterCategories.h"
3031#import " OSFlutterTagsController.h"
3132#import " OSFlutterInAppMessagesController.h"
@@ -35,6 +36,8 @@ @interface OneSignalPlugin ()
3536
3637@property (strong , nonatomic ) FlutterMethodChannel *channel;
3738
39+ @property (strong , nonatomic ) FlutterEngine *headlessRunner;
40+ @property (strong , nonatomic ) NSObject <FlutterPluginRegistrar> *registrar;
3841/*
3942 Will be true if the SDK is waiting for the
4043 user's consent before initializing.
@@ -56,6 +59,8 @@ it will add the observers (ie. subscription)
5659@property (strong , nonatomic ) NSMutableDictionary * notificationCompletionCache;
5760@property (strong , nonatomic ) NSMutableDictionary * receivedNotificationCache;
5861
62+ @property (strong , nonatomic ) NSUserDefaults *persistentState;
63+
5964@end
6065
6166@implementation OneSignalPlugin
@@ -74,6 +79,9 @@ + (instancetype)sharedInstance {
7479 return sharedInstance;
7580}
7681
82+ static FlutterPluginRegistrantCallback registerPlugins = nil ;
83+ static BOOL backgroundIsolateRun = NO ;
84+
7785#pragma mark FlutterPlugin
7886+ (void )registerWithRegistrar : (NSObject <FlutterPluginRegistrar>*)registrar {
7987
@@ -88,13 +96,36 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
8896 methodChannelWithName: @" OneSignal"
8997 binaryMessenger: [registrar messenger ]];
9098
99+ OneSignalPlugin.sharedInstance .registrar = registrar;
100+ OneSignalPlugin.sharedInstance .headlessRunner = [[FlutterEngine alloc ]
101+ initWithName: @" OneSignalHeadlessRunner"
102+ project: nil
103+ allowHeadlessExecution: YES ];
104+
105+ OneSignalPlugin.sharedInstance .persistentState = [NSUserDefaults standardUserDefaults ];
106+
107+
108+ OneSignalPlugin.sharedInstance .callbackChannel =
109+ [FlutterMethodChannel methodChannelWithName: @" OneSignalBackground"
110+ binaryMessenger: OneSignalPlugin.sharedInstance.headlessRunner.binaryMessenger];
111+
91112 [registrar addMethodCallDelegate: OneSignalPlugin.sharedInstance channel: OneSignalPlugin.sharedInstance.channel];
113+ // [registrar addMethodCallDelegate:OneSignalPlugin.sharedInstance channel:OneSignalPlugin.sharedInstance.callbackChannel];
92114
93115 [OSFlutterTagsController registerWithRegistrar: registrar];
94116 [OSFlutterInAppMessagesController registerWithRegistrar: registrar];
95117 [OSFlutterOutcomeEventsController registerWithRegistrar: registrar];
96118}
97119
120+ + (void )setPluginRegistrantCallback : (FlutterPluginRegistrantCallback)callback {
121+ registerPlugins = callback;
122+ }
123+
124+ - (BOOL )application : (UIApplication *)application didFinishLaunchingWithOptions : (NSDictionary *)launchOptions {
125+ [self initNotificationWillShowHandlerParamsById: [self getCallbackDispatcherHandle ] withNotification: [self getCallbackNotificationHandle ]];
126+ return YES ;
127+ }
128+
98129- (void )addObservers {
99130 [OneSignal addSubscriptionObserver: self ];
100131 [OneSignal addPermissionObserver: self ];
@@ -150,8 +181,12 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
150181 [self initInAppMessageClickedHandlerParams ];
151182 else if ([@" OneSignal#initNotificationWillShowInForegroundHandlerParams" isEqualToString: call.method])
152183 [self initNotificationWillShowInForegroundHandlerParams ];
184+ else if ([@" OneSignal#initNotificationWillShowHandlerParams" isEqualToString: call.method])
185+ [self initNotificationWillShowHandlerParams: call withResult: result];
153186 else if ([@" OneSignal#completeNotification" isEqualToString: call.method])
154187 [self completeNotification: call withResult: result];
188+ else if ([@" OneSignal#backgroundHandlerInitialized" isEqualToString: call.method])
189+ NSLog (@" Background channel ready" );
155190 else
156191 result (FlutterMethodNotImplemented);
157192}
@@ -350,6 +385,65 @@ - (void)initNotificationWillShowInForegroundHandlerParams {
350385 self.hasSetNotificationWillShowInForegroundHandler = YES ;
351386}
352387
388+ - (int64_t )getCallbackDispatcherHandle {
389+ id handle = [OneSignalPlugin.sharedInstance.persistentState objectForKey: @" callback_dispatcher_handle" ];
390+ if (handle == nil ) {
391+ return 0 ;
392+ }
393+ return [handle longLongValue ];
394+ }
395+
396+ - (void )setCallbackDispatcherHandle : (int64_t )handle {
397+ [OneSignalPlugin.sharedInstance.persistentState setObject: [NSNumber numberWithLongLong: handle]
398+ forKey: @" callback_dispatcher_handle" ];
399+ }
400+
401+ - (int64_t )getCallbackNotificationHandle {
402+ id handle = [OneSignalPlugin.sharedInstance.persistentState objectForKey: @" callback_notification_handle" ];
403+ if (handle == nil ) {
404+ return 0 ;
405+ }
406+ return [handle longLongValue ];
407+ }
408+
409+ - (void )setCallbackNotificationHandle : (int64_t )handle {
410+ [OneSignalPlugin.sharedInstance.persistentState setObject: [NSNumber numberWithLongLong: handle]
411+ forKey: @" callback_notification_handle" ];
412+ }
413+
414+ - (void )initNotificationWillShowHandlerParams : (FlutterMethodCall*)call withResult : (FlutterResult)result {
415+ int64_t pluginCallbackHandle = [call.arguments[@" pluginCallbackHandle" ] longValue ];
416+ int64_t notificationCallbackHandle = [call.arguments[@" notificationCallbackHandle" ] longValue ];
417+ [self initNotificationWillShowHandlerParamsById: pluginCallbackHandle withNotification: notificationCallbackHandle];
418+ }
419+
420+ - (void )initNotificationWillShowHandlerParamsById : (int64_t )dispatcherCallbackHandle withNotification : (int64_t )notificationCallbackHandle {
421+ NSLog (@" Initializing Headless Runner" );
422+
423+ NSAssert (dispatcherCallbackHandle != 0 , @" dispatcherCallbackHandle can't be 0" );
424+ NSAssert (notificationCallbackHandle != 0 , @" notificationCallbackHandle can't be 0" );
425+
426+ [self setCallbackDispatcherHandle: dispatcherCallbackHandle];
427+ [self setCallbackNotificationHandle: notificationCallbackHandle];
428+
429+ FlutterCallbackInformation *info = [FlutterCallbackCache lookupCallbackInformation: dispatcherCallbackHandle];
430+ NSAssert (info != nil , @" failed to find callback" );
431+
432+ NSString *entrypoint = info.callbackName ;
433+ NSString *uri = info.callbackLibraryPath ;
434+ [OneSignalPlugin.sharedInstance.headlessRunner runWithEntrypoint: entrypoint libraryURI: uri];
435+
436+ // Once our headless runner has been started, we need to register the application's plugins
437+ // with the runner in order for them to work on the background isolate. `registerPlugins` is
438+ // a callback set from AppDelegate.m in the main application. This callback should register
439+ // all relevant plugins (excluding those which require UI).
440+ [OneSignalPlugin.sharedInstance.registrar addMethodCallDelegate: self channel: OneSignalPlugin.sharedInstance.callbackChannel];
441+ if (!backgroundIsolateRun && registerPlugins != nil ) {
442+ registerPlugins (OneSignalPlugin.sharedInstance .headlessRunner );
443+ }
444+ backgroundIsolateRun = YES ;
445+ }
446+
353447#pragma mark Opened Notification Handlers
354448- (void )handleNotificationOpened : (OSNotificationOpenedResult *)result {
355449 [self .channel invokeMethod: @" OneSignal#handleOpenedNotification" arguments: result.toJson];
0 commit comments