Skip to content
This repository was archived by the owner on Jul 28, 2022. It is now read-only.

Commit fd0a1d5

Browse files
committed
Add BatchPush.getInitialURL
1 parent 15ab39f commit fd0a1d5

File tree

5 files changed

+130
-17
lines changed

5 files changed

+130
-17
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,28 @@ import { Batch } from '@bam.tech/react-native-batch';
253253
Batch.optOutAndWipeData();
254254
```
255255

256+
### Handling push notification initial deeplink
257+
258+
On iOS, `Linking.getInitialURL` might return null even when the app was started as a result of a Batch push notification with a deeplink.
259+
This is because the iOS Batch SDK opens the deep-link related to your push notification, after the app has already started.
260+
261+
In order to workaround this, you can use the following:
262+
263+
```ts
264+
import { BatchPush } from '@bam.tech/react-native-batch';
265+
266+
BatchPush.getInitialURL().then((url: string | null) => {
267+
console.log('received initial url', url)
268+
});
269+
```
270+
271+
This is a replacement of `Linking.getInitialURL` that you can use on Android or iOS:
272+
`Batch.getInitialURL` first checks if `Linking.getInitialURL` returns something, and then if it doesn't on iOS, it calls a custom native function of this module that gets the first deeplink it has ever seen.
273+
Subsequent calls to this native function will return `null` to prevent a future JS reload to see an old initial URL.
274+
Because of this, you have to make sure to call this method only once in the app lifetime.
275+
276+
Make sure to also listen for the Linking `url` event in case Batch opens your deep-link after you call getInitialURL.
277+
256278
<hr>
257279

258280
## Troubleshooting

ios/RNBatch.m

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
# import <React/RCTConvert.h>
22
# import "RNBatch.h"
3+
# import "RNBatchOpenedNotificationObserver.h"
34

45
@implementation RNBatch
56

67
+ (BOOL)requiresMainQueueSetup
78
{
8-
return NO;
9+
return NO;
910
}
1011
- (id)safeNilValue: (id)value
1112
{
1213
if (value == (id)[NSNull null]) {
1314
return nil;
1415
}
15-
return value;
16+
return value;
1617
}
1718
RCT_EXPORT_MODULE()
1819

@@ -83,6 +84,12 @@ + (void)start
8384
resolve(lastKnownPushToken);
8485
}
8586

87+
RCT_EXPORT_METHOD(push_getInitialDeeplink:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
88+
{
89+
resolve([RNBatchOpenedNotificationObserver getInitialDeeplink]);
90+
}
91+
92+
8693
// User module
8794

8895
RCT_EXPORT_METHOD(userData_getInstallationId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
@@ -324,14 +331,14 @@ + (void)start
324331

325332
if (error) {
326333
NSString* errorMsg = [NSString stringWithFormat:@"Failed to fetch new notifications %@", [error localizedDescription]];
327-
reject(@"Inbox", errorMsg, error);
328-
} else {
329-
NSMutableArray *mutableArray = [NSMutableArray new];
330-
for (BatchInboxNotificationContent *notification in notifications) {
331-
[mutableArray addObject:[self dictionaryWithNotification:notification]];
332-
}
334+
reject(@"Inbox", errorMsg, error);
335+
} else {
336+
NSMutableArray *mutableArray = [NSMutableArray new];
337+
for (BatchInboxNotificationContent *notification in notifications) {
338+
[mutableArray addObject:[self dictionaryWithNotification:notification]];
339+
}
333340

334-
resolve(mutableArray);
341+
resolve(mutableArray);
335342
}
336343

337344
}];
@@ -375,13 +382,13 @@ - (NSDictionary*) dictionaryWithNotification:(BatchInboxNotificationContent*)not
375382
NSString *title = notification.title;
376383

377384
NSDictionary *output = @{
378-
@"identifier": notification.identifier,
379-
@"body": notification.body,
380-
@"is_unread": @(notification.isUnread),
381-
@"date": [NSNumber numberWithDouble:notification.date.timeIntervalSince1970 * 1000],
382-
@"source": source,
383-
@"payload": notification.payload
384-
};
385+
@"identifier": notification.identifier,
386+
@"body": notification.body,
387+
@"is_unread": @(notification.isUnread),
388+
@"date": [NSNumber numberWithDouble:notification.date.timeIntervalSince1970 * 1000],
389+
@"source": source,
390+
@"payload": notification.payload
391+
};
385392

386393
if (title != nil) {
387394
NSMutableDictionary *mutableOutput = [output mutableCopy];
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@import Batch;
2+
3+
@interface RNBatchOpenedNotificationObserver : NSObject
4+
5+
@property(class, nonatomic, copy) NSString * _Nullable firstDeeplink;
6+
7+
+ (nullable NSString *)getInitialDeeplink;
8+
9+
@end
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# import "RNBatchOpenedNotificationObserver.h"
2+
3+
@implementation RNBatchOpenedNotificationObserver
4+
5+
static dispatch_once_t onceToken;
6+
7+
static NSString *_firstDeeplink = nil;
8+
9+
+ (NSString *)firstDeeplink {
10+
return _firstDeeplink;
11+
}
12+
13+
+ (void)setFirstDeeplink:(NSString *)newFirstDeeplink {
14+
if (_firstDeeplink == nil) {
15+
_firstDeeplink = [newFirstDeeplink copy];
16+
}
17+
}
18+
19+
+ (nullable NSString *)getInitialDeeplink {
20+
if (_firstDeeplink != nil) {
21+
NSString *initialDeeplink = [_firstDeeplink copy];
22+
_firstDeeplink = nil;
23+
return initialDeeplink;
24+
}
25+
26+
return nil;
27+
}
28+
29+
+ (void)load {
30+
[[NSNotificationCenter defaultCenter] addObserver:[RNBatchOpenedNotificationObserver class]
31+
selector:@selector(pushOpenedNotification:)
32+
name:BatchPushOpenedNotification object:nil];
33+
}
34+
35+
+ (void)pushOpenedNotification:(NSNotification *)notification
36+
{
37+
if (notification.userInfo == nil) {
38+
return;
39+
}
40+
41+
id payload = notification.userInfo[BatchPushOpenedNotificationPayloadKey];
42+
if (![payload isKindOfClass:NSDictionary.class]) {
43+
return;
44+
}
45+
46+
NSString *deeplink = [BatchPush deeplinkFromUserInfo:payload];
47+
if (deeplink == nil) {
48+
return;
49+
}
50+
51+
dispatch_once(&onceToken, ^{
52+
[self setFirstDeeplink: deeplink];
53+
});
54+
}
55+
56+
@end

src/BatchPush.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NativeModules } from 'react-native';
1+
import { Linking, NativeModules, Platform } from 'react-native';
22
const RNBatch = NativeModules.RNBatch;
33

44
export interface IAndroidNotificationTypes {
@@ -67,4 +67,23 @@ export const BatchPush = {
6767
*/
6868
getLastKnownPushToken: (): Promise<string> =>
6969
RNBatch.push_getLastKnownPushToken(),
70+
71+
/**
72+
* Gets the app's initial URL.
73+
*
74+
* On iOS, make sure to call this only once
75+
* (only the first call will return something, if Linking.getInitialURL doesn't return anything)
76+
*/
77+
getInitialURL: async (): Promise<string | null> => {
78+
const initialURL = await Linking.getInitialURL();
79+
if (initialURL) {
80+
return initialURL;
81+
}
82+
83+
if (Platform.OS === 'ios') {
84+
return (await RNBatch.push_getInitialDeeplink()) || null;
85+
}
86+
87+
return null;
88+
},
7089
};

0 commit comments

Comments
 (0)