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

Commit

Permalink
Add BatchPush.getInitialURL
Browse files Browse the repository at this point in the history
  • Loading branch information
Minishlink committed May 14, 2021
1 parent 15ab39f commit fd0a1d5
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 17 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,28 @@ import { Batch } from '@bam.tech/react-native-batch';
Batch.optOutAndWipeData();
```

### Handling push notification initial deeplink

On iOS, `Linking.getInitialURL` might return null even when the app was started as a result of a Batch push notification with a deeplink.
This is because the iOS Batch SDK opens the deep-link related to your push notification, after the app has already started.

In order to workaround this, you can use the following:

```ts
import { BatchPush } from '@bam.tech/react-native-batch';

BatchPush.getInitialURL().then((url: string | null) => {
console.log('received initial url', url)
});
```

This is a replacement of `Linking.getInitialURL` that you can use on Android or iOS:
`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.
Subsequent calls to this native function will return `null` to prevent a future JS reload to see an old initial URL.
Because of this, you have to make sure to call this method only once in the app lifetime.

Make sure to also listen for the Linking `url` event in case Batch opens your deep-link after you call getInitialURL.

<hr>

## Troubleshooting
Expand Down
39 changes: 23 additions & 16 deletions ios/RNBatch.m
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# import <React/RCTConvert.h>
# import "RNBatch.h"
# import "RNBatchOpenedNotificationObserver.h"

@implementation RNBatch

+ (BOOL)requiresMainQueueSetup
{
return NO;
return NO;
}
- (id)safeNilValue: (id)value
{
if (value == (id)[NSNull null]) {
return nil;
}
return value;
return value;
}
RCT_EXPORT_MODULE()

Expand Down Expand Up @@ -83,6 +84,12 @@ + (void)start
resolve(lastKnownPushToken);
}

RCT_EXPORT_METHOD(push_getInitialDeeplink:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
resolve([RNBatchOpenedNotificationObserver getInitialDeeplink]);
}


// User module

RCT_EXPORT_METHOD(userData_getInstallationId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
Expand Down Expand Up @@ -324,14 +331,14 @@ + (void)start

if (error) {
NSString* errorMsg = [NSString stringWithFormat:@"Failed to fetch new notifications %@", [error localizedDescription]];
reject(@"Inbox", errorMsg, error);
} else {
NSMutableArray *mutableArray = [NSMutableArray new];
for (BatchInboxNotificationContent *notification in notifications) {
[mutableArray addObject:[self dictionaryWithNotification:notification]];
}
reject(@"Inbox", errorMsg, error);
} else {
NSMutableArray *mutableArray = [NSMutableArray new];
for (BatchInboxNotificationContent *notification in notifications) {
[mutableArray addObject:[self dictionaryWithNotification:notification]];
}

resolve(mutableArray);
resolve(mutableArray);
}

}];
Expand Down Expand Up @@ -375,13 +382,13 @@ - (NSDictionary*) dictionaryWithNotification:(BatchInboxNotificationContent*)not
NSString *title = notification.title;

NSDictionary *output = @{
@"identifier": notification.identifier,
@"body": notification.body,
@"is_unread": @(notification.isUnread),
@"date": [NSNumber numberWithDouble:notification.date.timeIntervalSince1970 * 1000],
@"source": source,
@"payload": notification.payload
};
@"identifier": notification.identifier,
@"body": notification.body,
@"is_unread": @(notification.isUnread),
@"date": [NSNumber numberWithDouble:notification.date.timeIntervalSince1970 * 1000],
@"source": source,
@"payload": notification.payload
};

if (title != nil) {
NSMutableDictionary *mutableOutput = [output mutableCopy];
Expand Down
9 changes: 9 additions & 0 deletions ios/RNBatchOpenedNotificationObserver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import Batch;

@interface RNBatchOpenedNotificationObserver : NSObject

@property(class, nonatomic, copy) NSString * _Nullable firstDeeplink;

+ (nullable NSString *)getInitialDeeplink;

@end
56 changes: 56 additions & 0 deletions ios/RNBatchOpenedNotificationObserver.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# import "RNBatchOpenedNotificationObserver.h"

@implementation RNBatchOpenedNotificationObserver

static dispatch_once_t onceToken;

static NSString *_firstDeeplink = nil;

+ (NSString *)firstDeeplink {
return _firstDeeplink;
}

+ (void)setFirstDeeplink:(NSString *)newFirstDeeplink {
if (_firstDeeplink == nil) {
_firstDeeplink = [newFirstDeeplink copy];
}
}

+ (nullable NSString *)getInitialDeeplink {
if (_firstDeeplink != nil) {
NSString *initialDeeplink = [_firstDeeplink copy];
_firstDeeplink = nil;
return initialDeeplink;
}

return nil;
}

+ (void)load {
[[NSNotificationCenter defaultCenter] addObserver:[RNBatchOpenedNotificationObserver class]
selector:@selector(pushOpenedNotification:)
name:BatchPushOpenedNotification object:nil];
}

+ (void)pushOpenedNotification:(NSNotification *)notification
{
if (notification.userInfo == nil) {
return;
}

id payload = notification.userInfo[BatchPushOpenedNotificationPayloadKey];
if (![payload isKindOfClass:NSDictionary.class]) {
return;
}

NSString *deeplink = [BatchPush deeplinkFromUserInfo:payload];
if (deeplink == nil) {
return;
}

dispatch_once(&onceToken, ^{
[self setFirstDeeplink: deeplink];
});
}

@end
21 changes: 20 additions & 1 deletion src/BatchPush.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NativeModules } from 'react-native';
import { Linking, NativeModules, Platform } from 'react-native';
const RNBatch = NativeModules.RNBatch;

export interface IAndroidNotificationTypes {
Expand Down Expand Up @@ -67,4 +67,23 @@ export const BatchPush = {
*/
getLastKnownPushToken: (): Promise<string> =>
RNBatch.push_getLastKnownPushToken(),

/**
* Gets the app's initial URL.
*
* On iOS, make sure to call this only once
* (only the first call will return something, if Linking.getInitialURL doesn't return anything)
*/
getInitialURL: async (): Promise<string | null> => {
const initialURL = await Linking.getInitialURL();
if (initialURL) {
return initialURL;
}

if (Platform.OS === 'ios') {
return (await RNBatch.push_getInitialDeeplink()) || null;
}

return null;
},
};

0 comments on commit fd0a1d5

Please sign in to comment.