6
6
// Copyright © 2016 Facebook. All rights reserved.
7
7
//
8
8
9
- #import " FirestackCloudMessaging.h "
9
+ #import < Foundation/Foundation.h >
10
10
#import < NotificationCenter/NotificationCenter.h>
11
+ #import " FirestackCloudMessaging.h"
12
+ #import " FirestackEvents.h"
13
+ #import " RCTConvert.h"
11
14
12
15
@import FirebaseInstanceID;
13
16
@import FirebaseMessaging;
14
17
18
+ // https://github.com/facebook/react-native/blob/master/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
19
+ @implementation RCTConvert (UILocalNotification)
20
+
21
+ + (UILocalNotification *)UILocalNotification : (id )json
22
+ {
23
+ NSDictionary <NSString *, id > *details = [self NSDictionary: json];
24
+ UILocalNotification *notification = [UILocalNotification new ];
25
+ notification.fireDate = [RCTConvert NSDate: details[@" fireDate" ]] ?: [NSDate date ];
26
+ notification.alertBody = [RCTConvert NSString: details[@" alertBody" ]];
27
+ notification.alertAction = [RCTConvert NSString: details[@" alertAction" ]];
28
+ notification.soundName = [RCTConvert NSString: details[@" soundName" ]] ?: UILocalNotificationDefaultSoundName;
29
+ notification.userInfo = [RCTConvert NSDictionary: details[@" userInfo" ]];
30
+ notification.category = [RCTConvert NSString: details[@" category" ]];
31
+ if (details[@" applicationIconBadgeNumber" ]) {
32
+ notification.applicationIconBadgeNumber = [RCTConvert NSInteger: details[@" applicationIconBadgeNumber" ]];
33
+ }
34
+ return notification;
35
+ }
36
+
37
+ @end
38
+
15
39
@implementation FirestackCloudMessaging
16
40
17
- + (void ) registerForNotification : (NSString *) typeStr andToken : (NSData *)deviceToken
41
+ // https://github.com/facebook/react-native/blob/master/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
42
+ static NSDictionary *RCTFormatLocalNotification (UILocalNotification *notification)
43
+ {
44
+ NSMutableDictionary *formattedLocalNotification = [NSMutableDictionary dictionary ];
45
+ if (notification.fireDate ) {
46
+ NSDateFormatter *formatter = [NSDateFormatter new ];
47
+ [formatter setDateFormat: @" yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ" ];
48
+ NSString *fireDateString = [formatter stringFromDate: notification.fireDate];
49
+ formattedLocalNotification[@" fireDate" ] = fireDateString;
50
+ }
51
+ formattedLocalNotification[@" alertAction" ] = RCTNullIfNil (notification.alertAction );
52
+ formattedLocalNotification[@" alertBody" ] = RCTNullIfNil (notification.alertBody );
53
+ formattedLocalNotification[@" applicationIconBadgeNumber" ] = @(notification.applicationIconBadgeNumber );
54
+ formattedLocalNotification[@" category" ] = RCTNullIfNil (notification.category );
55
+ formattedLocalNotification[@" soundName" ] = RCTNullIfNil (notification.soundName );
56
+ formattedLocalNotification[@" userInfo" ] = RCTNullIfNil (RCTJSONClean (notification.userInfo ));
57
+ formattedLocalNotification[@" remote" ] = @NO ;
58
+ return formattedLocalNotification;
59
+ }
60
+
61
+ - (void ) dealloc
18
62
{
63
+ [[NSNotificationCenter defaultCenter ] removeObserver: self ];
64
+ }
65
+
66
+ + (void ) setup : (UIApplication *) application
67
+ {
68
+ [[NSNotificationCenter defaultCenter ] addObserver: self
69
+ selector: @selector (connectToFirebase )
70
+ name: UIApplicationDidEnterBackgroundNotification
71
+ object: nil ];
72
+
73
+ [[NSNotificationCenter defaultCenter ] addObserver: self
74
+ selector: @selector (disconnectFromFirebase )
75
+ name: UIApplicationDidBecomeActiveNotification
76
+ object: nil ];
77
+
78
+ [[NSNotificationCenter defaultCenter ] addObserver: self
79
+ selector: @selector (handleRemoteNotificationReceived: )
80
+ name: MESSAGING_MESSAGE_RECEIVED_REMOTE
81
+ object: nil ];
82
+
83
+ [[NSNotificationCenter defaultCenter ] addObserver: self
84
+ selector: @selector (handleLocalNotificationReceived: )
85
+ name: MESSAGING_MESSAGE_RECEIVED_LOCAL
86
+ object: nil ];
87
+
88
+ [[NSNotificationCenter defaultCenter ] addObserver: self
89
+ selector: @selector (handleTokenRefresh )
90
+ name: kFIRInstanceIDTokenRefreshNotification
91
+ object: nil ];
92
+
93
+ if (SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO (@" 9.0" )) {
19
94
UIUserNotificationType allNotificationTypes =
20
95
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
21
96
UIUserNotificationSettings *settings =
22
97
[UIUserNotificationSettings settingsForTypes: allNotificationTypes categories: nil ];
23
98
[[UIApplication sharedApplication ] registerUserNotificationSettings: settings];
24
- [[UIApplication sharedApplication ] registerForRemoteNotifications ];
99
+ } else {
100
+ // iOS 10 or later
101
+ #if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
102
+ UNAuthorizationOptions authOptions =
103
+ UNAuthorizationOptionAlert
104
+ | UNAuthorizationOptionSound
105
+ | UNAuthorizationOptionBadge ;
106
+ [[UNUserNotificationCenter currentNotificationCenter ]
107
+ requestAuthorizationWithOptions: authOptions
108
+ completionHandler: ^(BOOL granted, NSError * _Nullable error) {
109
+ }
110
+ ];
111
+
112
+ // For iOS 10 display notification (sent via APNS)
113
+ [[UNUserNotificationCenter currentNotificationCenter ] setDelegate: self ];
114
+ // For iOS 10 data message (sent via FCM)
115
+ [[FIRMessaging messaging ] setRemoteMessageDelegate: self ];
116
+ #endif
117
+ }
118
+
119
+ [[UIApplication sharedApplication ] registerForRemoteNotifications ];
120
+ }
121
+
122
+ #pragma mark callbacks
123
+ - (void ) connectToFirebase
124
+ {
125
+ [[FIRMessaging messaging ] connectWithCompletion: ^(NSError *error) {
126
+ NSDictionary *evt;
127
+ NSString *evtName;
128
+ if (error != nil ) {
129
+ NSLog (@" Error connecting: %@ " , [error debugDescription ]);
130
+ evtName = MESSAGING_SUBSYSTEM_ERROR;
131
+ evt = @{
132
+ @" eventName" : MESSAGING_SUBSYSTEM_ERROR,
133
+ @" msg" : [error debugDescription ]
134
+ };
135
+ } else {
136
+ NSLog (@" Connected to Firebase messaging" );
137
+ evtName = MESSAGING_SUBSYSTEM_EVENT;
138
+ evt = @{
139
+ @" result" : @" connected"
140
+ };
141
+ [self
142
+ sendJSEvent: evtName
143
+ props: evt];
25
144
26
- [[FIRMessaging messaging ] connectWithCompletion: ^(NSError * _Nullable error) {
27
- NSLog (@" Connected: %@ " , [error debugDescription ]);
28
- }];
145
+ }
146
+ }];
29
147
}
30
148
31
- RCT_EXPORT_MODULE (FirestackCloudMessaging);
149
+ - (void ) disconnectFromFirebase
150
+ {
151
+ [[FIRMessaging messaging ] disconnect ];
152
+ NSLog (@" Disconnect from Firebase" );
153
+ [self
154
+ sendJSEvent: MESSAGING_SUBSYSTEM_EVENT
155
+ props: @{
156
+ @" status" : @" disconnected"
157
+ }];
158
+ }
32
159
33
- + (void ) getToken : ( NSString *) typeStr andToken : ( NSData *) deviceToken
160
+ - (void ) handleRemoteNotificationReceived : ( NSNotification *) n
34
161
{
162
+ NSMutableDictionary *props = [[NSMutableDictionary alloc ] initWithDictionary: n.userInfo];
163
+ [self sendJSEvent: MESSAGING_MESSAGE_RECEIVED_REMOTE props: props];
35
164
}
36
165
166
+ - (void ) handleLocalNotificationReceived : (NSNotification *) n
167
+ {
168
+ NSMutableDictionary *props = [[NSMutableDictionary alloc ] initWithDictionary: n.userInfo];
169
+ [self sendJSEvent: MESSAGING_MESSAGE_RECEIVED_LOCAL props: props];
170
+ }
171
+
172
+ - (void ) handleTokenRefresh
173
+ {
174
+ NSDictionary *props = @{
175
+ @" status" : @" token_refreshed" ,
176
+ @" token" : [[FIRInstanceID instanceID ] token ]
177
+ };
178
+ [self sendJSEvent: MESSAGING_TOKEN_REFRESH props: props];
179
+ }
180
+
181
+ RCT_EXPORT_MODULE (FirestackCloudMessaging);
182
+
183
+
37
184
RCT_EXPORT_METHOD (getToken:(RCTResponseSenderBlock)callback)
38
- {}
185
+ {
186
+ NSString *token = [[FIRInstanceID instanceID ] token ];
187
+ callback (@[[NSNull null ], @{
188
+ @" status" : @" success" ,
189
+ @" token" : token
190
+ }]);
191
+ }
192
+
193
+ RCT_EXPORT_METHOD (sendLocal:(UILocalNotification *)notification
194
+ callback:(RCTResponseSenderBlock) callback)
195
+ {
196
+ NSLog (@" sendLocal called with notification: %@ " , notification);
197
+ [RCTSharedApplication () presentLocalNotificationNow: notification];
198
+ }
199
+ RCT_EXPORT_METHOD (scheduleLocal:(UILocalNotification *)notification
200
+ callback:(RCTResponseSenderBlock) callback)
201
+ {
202
+ [RCTSharedApplication () scheduleLocalNotification: notification];
203
+ }
204
+
205
+ RCT_EXPORT_METHOD (cancelAllLocalNotifications)
206
+ {
207
+ [RCTSharedApplication () cancelAllLocalNotifications ];
208
+ }
209
+
210
+ RCT_EXPORT_METHOD (cancelLocalNotifications:(NSDictionary <NSString *, id > *)userInfo)
211
+ {
212
+ for (UILocalNotification *notification in [UIApplication sharedApplication ].scheduledLocalNotifications ) {
213
+ __block BOOL matchesAll = YES ;
214
+ NSDictionary <NSString *, id > *notificationInfo = notification.userInfo ;
215
+ // Note: we do this with a loop instead of just `isEqualToDictionary:`
216
+ // because we only require that all specified userInfo values match the
217
+ // notificationInfo values - notificationInfo may contain additional values
218
+ // which we don't care about.
219
+ [userInfo enumerateKeysAndObjectsUsingBlock: ^(NSString *key, id obj, BOOL *stop) {
220
+ if (![notificationInfo[key] isEqual: obj]) {
221
+ matchesAll = NO ;
222
+ *stop = YES ;
223
+ }
224
+ }];
225
+ if (matchesAll) {
226
+ [[UIApplication sharedApplication ] cancelLocalNotification: notification];
227
+ }
228
+ }
229
+ }
230
+
231
+ RCT_EXPORT_METHOD (sendRemote:(UILocalNotification *)notification
232
+ callback:(RCTResponseSenderBlock) callback)
233
+ {
234
+
235
+ }
236
+
39
237
40
238
RCT_EXPORT_METHOD (send:(NSString *) senderId
41
239
messageId:(NSString *) messageId
42
240
messageType:(NSString *) messageType
43
241
msg: (NSString *) msg
44
242
callback:(RCTResponseSenderBlock)callback)
45
- {}
243
+ {
244
+
245
+ }
46
246
47
247
RCT_EXPORT_METHOD (listenForTokenRefresh:(RCTResponseSenderBlock)callback)
48
248
{}
@@ -52,11 +252,41 @@ + (void) getToken:(NSString *) typeStr andToken:(NSData *)deviceToken
52
252
53
253
RCT_EXPORT_METHOD (subscribeToTopic:(NSString *) topic
54
254
callback:(RCTResponseSenderBlock)callback)
55
- {}
255
+ {
256
+ [[FIRMessaging messaging ] subscribeToTopic: topic];
257
+ callback (@[[NSNull null ], @{
258
+ @" result" : @" success" ,
259
+ @" topic" : topic
260
+ }]);
261
+ }
56
262
57
263
RCT_EXPORT_METHOD (unsubscribeFromTopic:(NSString *) topic
58
264
callback: (RCTResponseSenderBlock)callback)
59
- {}
265
+ {
266
+ [[FIRMessaging messaging ] unsubscribeFromTopic: topic];
267
+ callback (@[[NSNull null ], @{
268
+ @" result" : @" success" ,
269
+ @" topic" : topic
270
+ }]);
271
+ }
272
+
273
+ RCT_EXPORT_METHOD (setBadge:(NSInteger ) number
274
+ callback:(RCTResponseSenderBlock) callback)
275
+ {
276
+ RCTSharedApplication ().applicationIconBadgeNumber = number;
277
+ callback (@[[NSNull null ], @{
278
+ @" result" : @" success" ,
279
+ @" number" : @(number)
280
+ }]);
281
+ }
282
+
283
+ RCT_EXPORT_METHOD (getBadge:(RCTResponseSenderBlock) callback)
284
+ {
285
+ callback (@[[NSNull null ], @{
286
+ @" result" : @" success" ,
287
+ @" number" : @(RCTSharedApplication ().applicationIconBadgeNumber )
288
+ }]);
289
+ }
60
290
61
291
RCT_EXPORT_METHOD (listenForReceiveNotification:(RCTResponseSenderBlock)callback)
62
292
{}
@@ -70,4 +300,30 @@ + (void) getToken:(NSString *) typeStr andToken:(NSData *)deviceToken
70
300
RCT_EXPORT_METHOD (unlistenForReceiveUpstreamSend:(RCTResponseSenderBlock)callback)
71
301
{}
72
302
303
+ // Not sure how to get away from this... yet
304
+ - (NSArray <NSString *> *)supportedEvents {
305
+ return @[
306
+ MESSAGING_SUBSYSTEM_EVENT,
307
+ MESSAGING_SUBSYSTEM_ERROR,
308
+ MESSAGING_TOKEN_REFRESH,
309
+ MESSAGING_MESSAGE_RECEIVED_LOCAL,
310
+ MESSAGING_MESSAGE_RECEIVED_REMOTE ];
311
+ }
312
+
313
+ - (void ) sendJSEvent : (NSString *)title
314
+ props : (NSDictionary *)props
315
+ {
316
+ @try {
317
+ [self sendEventWithName: title
318
+ body: @{
319
+ @" eventName" : title,
320
+ @" body" : props
321
+ }];
322
+ }
323
+ @catch (NSException *err) {
324
+ NSLog (@" An error occurred in sendJSEvent: %@ " , [err debugDescription ]);
325
+ NSLog (@" Tried to send: %@ with %@ " , title, props);
326
+ }
327
+ }
328
+
73
329
@end
0 commit comments