211 lines
7.8 KiB
Objective-C
211 lines
7.8 KiB
Objective-C
#import "RNFirebaseInvites.h"
|
|
|
|
#if __has_include(<FirebaseInvites/FirebaseInvites.h>)
|
|
#import "RNFirebaseEvents.h"
|
|
#import "RNFirebaseLinks.h"
|
|
#import "RNFirebaseUtil.h"
|
|
#import <FirebaseInvites/FirebaseInvites.h>
|
|
|
|
#import <React/RCTEventDispatcher.h>
|
|
#import <React/RCTConvert.h>
|
|
#import <React/RCTUtils.h>
|
|
|
|
@implementation RNFirebaseInvites
|
|
|
|
static RNFirebaseInvites *theRNFirebaseInvites = nil;
|
|
static NSString *initialInvite = nil;
|
|
static bool jsReady = FALSE;
|
|
|
|
+ (nonnull instancetype)instance {
|
|
// If an event comes in before the bridge has initialised the native module
|
|
// then we create a temporary instance which handles events until the bridge
|
|
// and JS side are ready
|
|
if (theRNFirebaseInvites == nil) {
|
|
theRNFirebaseInvites = [[RNFirebaseInvites alloc] init];
|
|
}
|
|
return theRNFirebaseInvites;
|
|
}
|
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
- (id)init {
|
|
self = [super init];
|
|
if (self != nil) {
|
|
NSLog(@"Setting up RNFirebaseInvites instance");
|
|
// Set static instance for use from AppDelegate
|
|
theRNFirebaseInvites = self;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
// *******************************************************
|
|
// ** Start AppDelegate methods
|
|
// *******************************************************
|
|
|
|
- (BOOL)application:(UIApplication *)app
|
|
openURL:(NSURL *)url
|
|
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
|
return [self handleUrl:url];
|
|
}
|
|
|
|
- (BOOL)application:(UIApplication *)application
|
|
continueUserActivity:(NSUserActivity *)userActivity
|
|
restorationHandler:(void (^)(NSArray *))restorationHandler {
|
|
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
|
|
return [self handleUrl:userActivity.webpageURL];
|
|
}
|
|
return NO;
|
|
}
|
|
// *******************************************************
|
|
// ** Finish AppDelegate methods
|
|
// *******************************************************
|
|
|
|
// *******************************************************
|
|
// ** Start FIRInviteDelegate methods
|
|
// *******************************************************
|
|
|
|
// Listen for invitation response
|
|
- (void)inviteFinishedWithInvitations:(NSArray *)invitationIds error:(NSError *)error {
|
|
if (error) {
|
|
if (error.code == -402) {
|
|
_invitationsRejecter(@"invites/invitation-cancelled", @"Invitation cancelled", nil);
|
|
} else if (error.code == -404) {
|
|
_invitationsRejecter(@"invites/invitation-error", @"User must be signed in with GoogleSignIn", nil);
|
|
} else {
|
|
_invitationsRejecter(@"invites/invitation-error", @"Invitation failed to send", error);
|
|
}
|
|
} else {
|
|
_invitationsResolver(invitationIds);
|
|
}
|
|
_invitationsRejecter = nil;
|
|
_invitationsResolver = nil;
|
|
}
|
|
|
|
// *******************************************************
|
|
// ** Finish FIRInviteDelegate methods
|
|
// *******************************************************
|
|
|
|
// ** Start React Module methods **
|
|
RCT_EXPORT_METHOD(getInitialInvitation:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
|
NSURL* url = nil;
|
|
if (self.bridge.launchOptions[UIApplicationLaunchOptionsURLKey]) {
|
|
url = (NSURL*)self.bridge.launchOptions[UIApplicationLaunchOptionsURLKey];
|
|
} else if (self.bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey]) {
|
|
NSDictionary *dictionary = self.bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey];
|
|
if ([dictionary[UIApplicationLaunchOptionsUserActivityTypeKey] isEqual:NSUserActivityTypeBrowsingWeb]) {
|
|
NSUserActivity* userActivity = (NSUserActivity*) dictionary[@"UIApplicationLaunchOptionsUserActivityKey"];
|
|
url = userActivity.webpageURL;
|
|
}
|
|
}
|
|
|
|
if (url) {
|
|
[FIRInvites handleUniversalLink:url completion:^(FIRReceivedInvite * _Nullable receivedInvite, NSError * _Nullable error) {
|
|
if (error) {
|
|
NSLog(@"Failed to handle universal link: %@", [error localizedDescription]);
|
|
reject(@"invites/initial-invitation-error", @"Failed to handle invitation", error);
|
|
} else if (receivedInvite && receivedInvite.inviteId) {
|
|
resolve(@{
|
|
@"deepLink": receivedInvite.deepLink,
|
|
@"invitationId": receivedInvite.inviteId,
|
|
});
|
|
} else {
|
|
resolve(initialInvite);
|
|
}
|
|
}];
|
|
} else {
|
|
resolve(initialInvite);
|
|
}
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(sendInvitation:(NSDictionary *) invitation
|
|
resolve:(RCTPromiseResolveBlock) resolve
|
|
reject:(RCTPromiseRejectBlock) reject) {
|
|
if (!invitation[@"message"]) {
|
|
reject(@"invites/invalid-invitation", @"The supplied invitation is missing a 'message' field", nil);
|
|
}
|
|
if (!invitation[@"title"]) {
|
|
reject(@"invites/invalid-invitation", @"The supplied invitation is missing a 'title' field", nil);
|
|
}
|
|
id<FIRInviteBuilder> inviteDialog = [FIRInvites inviteDialog];
|
|
[inviteDialog setInviteDelegate: self];
|
|
[inviteDialog setMessage:invitation[@"message"]];
|
|
[inviteDialog setTitle:invitation[@"title"]];
|
|
|
|
if (invitation[@"androidClientId"]) {
|
|
FIRInvitesTargetApplication *targetApplication = [[FIRInvitesTargetApplication alloc] init];
|
|
targetApplication.androidClientID = invitation[@"androidClientId"];
|
|
[inviteDialog setOtherPlatformsTargetApplication:targetApplication];
|
|
}
|
|
if (invitation[@"androidMinimumVersionCode"]) {
|
|
[inviteDialog setAndroidMinimumVersionCode:invitation[@"androidMinimumVersionCode"]];
|
|
}
|
|
if (invitation[@"callToActionText"]) {
|
|
[inviteDialog setCallToActionText:invitation[@"callToActionText"]];
|
|
}
|
|
if (invitation[@"customImage"]) {
|
|
[inviteDialog setCustomImage:invitation[@"customImage"]];
|
|
}
|
|
if (invitation[@"deepLink"]) {
|
|
[inviteDialog setDeepLink:invitation[@"deepLink"]];
|
|
}
|
|
|
|
// Save the promise details for later
|
|
_invitationsRejecter = reject;
|
|
_invitationsResolver = resolve;
|
|
|
|
// Open the invitation dialog
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[inviteDialog open];
|
|
});
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(jsInitialised:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
|
jsReady = TRUE;
|
|
resolve(nil);
|
|
}
|
|
|
|
// ** Start internals **
|
|
- (BOOL)handleUrl:(NSURL *)url {
|
|
return [FIRInvites handleUniversalLink:url completion:^(FIRReceivedInvite * _Nullable receivedInvite, NSError * _Nullable error) {
|
|
if (error) {
|
|
NSLog(@"Failed to handle invitation: %@", [error localizedDescription]);
|
|
} else if (receivedInvite && receivedInvite.inviteId) {
|
|
[self sendJSEvent:self name:INVITES_INVITATION_RECEIVED body:@{
|
|
@"deepLink": receivedInvite.deepLink,
|
|
@"invitationId": receivedInvite.inviteId,
|
|
}];
|
|
} else {
|
|
[[RNFirebaseLinks instance] sendLink:receivedInvite.deepLink];
|
|
}
|
|
}];
|
|
}
|
|
|
|
// Because of the time delay between the app starting and the bridge being initialised
|
|
// we catch any events that are received before the JS is ready to receive them
|
|
- (void)sendJSEvent:(RCTEventEmitter *)emitter name:(NSString *)name body:(id)body {
|
|
if (emitter.bridge && jsReady) {
|
|
[RNFirebaseUtil sendJSEvent:emitter name:name body:body];
|
|
} else if (!initialInvite) {
|
|
initialInvite = body;
|
|
} else {
|
|
NSLog(@"Multiple invite events received before the JS invites module has been initialised");
|
|
}
|
|
}
|
|
|
|
- (NSArray<NSString *> *)supportedEvents {
|
|
return @[INVITES_INVITATION_RECEIVED];
|
|
}
|
|
|
|
+ (BOOL)requiresMainQueueSetup
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
#else
|
|
@implementation RNFirebaseInvites
|
|
@end
|
|
#endif
|
|
|