Skip to content

Commit 710d5ad

Browse files
committed
WIP: Messaging
1 parent 6d408cd commit 710d5ad

File tree

6 files changed

+327
-23
lines changed

6 files changed

+327
-23
lines changed

ios/Firestack/Firestack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
}
1616

1717
+ (void) registerForNotification:(NSString *) typeStr andToken:(NSData *)deviceToken;
18+
+ (void) setup:(UIApplication *) application;
1819

1920
@property (nonatomic) BOOL debug;
2021
@property (atomic) BOOL configured;

ios/Firestack/Firestack.m

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
@import Firebase;
1313

1414
@implementation Firestack
15+
typedef void (^UserWithTokenResponse)(NSDictionary *, NSError *);
1516

1617
- (void)dealloc
1718
{
@@ -25,7 +26,10 @@ - (void)dealloc
2526
}];
2627
}
2728

28-
typedef void (^UserWithTokenResponse)(NSDictionary *, NSError *);
29+
+ (void) setup:(UIApplication *) application
30+
{
31+
[FirestackCloudMessaging setup:application];
32+
}
2933

3034
RCT_EXPORT_MODULE(Firestack);
3135

@@ -277,11 +281,6 @@ - (void)dealloc
277281

278282
#pragma mark Messaging
279283

280-
+ (void) registerForNotification:(NSString *) typeStr andToken:(NSData *)deviceToken
281-
{
282-
[FirestackCloudMessaging registerForNotification:typeStr andToken:deviceToken];
283-
}
284-
285284
#pragma mark Helpers
286285

287286
- (NSDictionary *) getConfig

ios/Firestack/FirestackCloudMessaging.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@
66
// Copyright © 2016 Facebook. All rights reserved.
77
//
88

9+
#import "Firebase.h"
10+
#import "RCTEventEmitter.h"
911
#import "RCTBridgeModule.h"
12+
#import "RCTUtils.h"
1013

11-
@interface FirestackCloudMessaging : NSObject <RCTBridgeModule> {
14+
@import FirebaseMessaging;
15+
16+
@interface FirestackCloudMessaging : RCTEventEmitter <RCTBridgeModule> {
1217

1318
}
1419

15-
+ (void) registerForNotification:(NSString *) typeStr andToken:(NSData *)deviceToken;
20+
+ (void) setup;
1621

1722
@end

ios/Firestack/FirestackCloudMessaging.m

Lines changed: 268 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,43 +6,243 @@
66
// Copyright © 2016 Facebook. All rights reserved.
77
//
88

9-
#import "FirestackCloudMessaging.h"
9+
#import <Foundation/Foundation.h>
1010
#import <NotificationCenter/NotificationCenter.h>
11+
#import "FirestackCloudMessaging.h"
12+
#import "FirestackEvents.h"
13+
#import "RCTConvert.h"
1114

1215
@import FirebaseInstanceID;
1316
@import FirebaseMessaging;
1417

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+
1539
@implementation FirestackCloudMessaging
1640

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
1862
{
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")) {
1994
UIUserNotificationType allNotificationTypes =
2095
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
2196
UIUserNotificationSettings *settings =
2297
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
2398
[[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];
25144

26-
[[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) {
27-
NSLog(@"Connected: %@", [error debugDescription]);
28-
}];
145+
}
146+
}];
29147
}
30148

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+
}
32159

33-
+ (void) getToken:(NSString *) typeStr andToken:(NSData *)deviceToken
160+
- (void) handleRemoteNotificationReceived:(NSNotification *) n
34161
{
162+
NSMutableDictionary *props = [[NSMutableDictionary alloc] initWithDictionary: n.userInfo];
163+
[self sendJSEvent:MESSAGING_MESSAGE_RECEIVED_REMOTE props: props];
35164
}
36165

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+
37184
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+
39237

40238
RCT_EXPORT_METHOD(send:(NSString *) senderId
41239
messageId:(NSString *) messageId
42240
messageType:(NSString *) messageType
43241
msg: (NSString *) msg
44242
callback:(RCTResponseSenderBlock)callback)
45-
{}
243+
{
244+
245+
}
46246

47247
RCT_EXPORT_METHOD(listenForTokenRefresh:(RCTResponseSenderBlock)callback)
48248
{}
@@ -52,11 +252,41 @@ + (void) getToken:(NSString *) typeStr andToken:(NSData *)deviceToken
52252

53253
RCT_EXPORT_METHOD(subscribeToTopic:(NSString *) topic
54254
callback:(RCTResponseSenderBlock)callback)
55-
{}
255+
{
256+
[[FIRMessaging messaging] subscribeToTopic:topic];
257+
callback(@[[NSNull null], @{
258+
@"result": @"success",
259+
@"topic": topic
260+
}]);
261+
}
56262

57263
RCT_EXPORT_METHOD(unsubscribeFromTopic:(NSString *) topic
58264
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+
}
60290

61291
RCT_EXPORT_METHOD(listenForReceiveNotification:(RCTResponseSenderBlock)callback)
62292
{}
@@ -70,4 +300,30 @@ + (void) getToken:(NSString *) typeStr andToken:(NSData *)deviceToken
70300
RCT_EXPORT_METHOD(unlistenForReceiveUpstreamSend:(RCTResponseSenderBlock)callback)
71301
{}
72302

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+
73329
@end

0 commit comments

Comments
 (0)