UNPKG

26.8 kBPlain TextView Raw
1#import "RNBranch.h"
2#import <React/RCTEventDispatcher.h>
3#import <React/RCTLog.h>
4#import "BranchEvent+RNBranch.h"
5#import "BranchLinkProperties+RNBranch.h"
6#import "BranchUniversalObject+RNBranch.h"
7#import "RNBranchAgingDictionary.h"
8#import "RNBranchEventEmitter.h"
9
10NSString * const RNBranchLinkOpenedNotification = @"RNBranchLinkOpenedNotification";
11NSString * const RNBranchLinkOpenedNotificationErrorKey = @"error";
12NSString * const RNBranchLinkOpenedNotificationParamsKey = @"params";
13NSString * const RNBranchLinkOpenedNotificationUriKey = @"uri";
14NSString * const RNBranchLinkOpenedNotificationBranchUniversalObjectKey = @"branch_universal_object";
15NSString * const RNBranchLinkOpenedNotificationLinkPropertiesKey = @"link_properties";
16
17
18static NSDictionary *initSessionWithLaunchOptionsResult;
19static BOOL useTestInstance = NO;
20static NSDictionary *savedLaunchOptions;
21static BOOL savedIsReferrable;
22static NSString *branchKey;
23static BOOL deferInitializationForJSLoad = NO;
24static NSURL *originalURL;
25
26static NSString * const IdentFieldName = @"ident";
27
28// These are only really exposed to the JS layer, so keep them internal for now.
29static NSString * const RNBranchErrorDomain = @"RNBranchErrorDomain";
30static NSInteger const RNBranchUniversalObjectNotFoundError = 1;
31
32#pragma mark - Private RNBranch declarations
33
34@interface RNBranch()
35@property (nonatomic, readonly) UIViewController *currentViewController;
36@property (nonatomic) RNBranchAgingDictionary<NSString *, BranchUniversalObject *> *universalObjectMap;
37
38+ (void)willOpenURL:(NSURL * _Nullable)url;
39@end
40
41#pragma mark - RNBranch implementation
42
43@implementation RNBranch
44
45RCT_EXPORT_MODULE();
46
47+ (Branch *)branch
48{
49 @synchronized(self) {
50 static Branch *instance;
51 static dispatch_once_t once = 0;
52 dispatch_once(&once, ^{
53 if (branchKey) {
54 // Override the Info.plist if these are present.
55 instance = [Branch getInstance: branchKey];
56 }
57 else {
58 [Branch setUseTestBranchKey:useTestInstance];
59 instance = [Branch getInstance];
60 }
61 });
62 return instance;
63 }
64}
65
66+ (BOOL)requiresMainQueueSetup {
67 return YES;
68}
69
70- (NSDictionary<NSString *, NSString *> *)constantsToExport {
71 return @{
72 // RN events transmitted to JS by event emitter
73 @"INIT_SESSION_START": kRNBranchInitSessionStart,
74 @"INIT_SESSION_SUCCESS": kRNBranchInitSessionSuccess,
75 @"INIT_SESSION_ERROR": kRNBranchInitSessionError,
76
77 // constants for use with BranchEvent
78
79 // Commerce events
80 @"STANDARD_EVENT_ADD_TO_CART": BranchStandardEventAddToCart,
81 @"STANDARD_EVENT_ADD_TO_WISHLIST": BranchStandardEventAddToWishlist,
82 @"STANDARD_EVENT_VIEW_CART": BranchStandardEventViewCart,
83 @"STANDARD_EVENT_INITIATE_PURCHASE": BranchStandardEventInitiatePurchase,
84 @"STANDARD_EVENT_ADD_PAYMENT_INFO": BranchStandardEventAddPaymentInfo,
85 @"STANDARD_EVENT_PURCHASE": BranchStandardEventPurchase,
86 @"STANDARD_EVENT_VIEW_AD": BranchStandardEventViewAd,
87 @"STANDARD_EVENT_CLICK_AD": BranchStandardEventClickAd,
88
89 // Content Events
90 @"STANDARD_EVENT_SEARCH": BranchStandardEventSearch,
91 @"STANDARD_EVENT_VIEW_ITEM": BranchStandardEventViewItem,
92 @"STANDARD_EVENT_VIEW_ITEMS": BranchStandardEventViewItems,
93 @"STANDARD_EVENT_RATE": BranchStandardEventRate,
94 @"STANDARD_EVENT_SHARE": BranchStandardEventShare,
95
96 // User Lifecycle Events
97 @"STANDARD_EVENT_COMPLETE_REGISTRATION": BranchStandardEventCompleteRegistration,
98 @"STANDARD_EVENT_COMPLETE_TUTORIAL": BranchStandardEventCompleteTutorial,
99 @"STANDARD_EVENT_ACHIEVE_LEVEL": BranchStandardEventAchieveLevel,
100 @"STANDARD_EVENT_UNLOCK_ACHIEVEMENT": BranchStandardEventUnlockAchievement,
101 @"STANDARD_EVENT_INVITE": BranchStandardEventInvite,
102 @"STANDARD_EVENT_LOGIN": BranchStandardEventLogin,
103 @"STANDARD_EVENT_RESERVE": BranchStandardEventReserve,
104 @"STANDARD_EVENT_SUBSCRIBE": BranchStandardEventSubscribe,
105 @"STANDARD_EVENT_START_TRIAL": BranchStandardEventStartTrial
106 };
107}
108
109#pragma mark - Class methods
110
111+ (void)setDebug
112{
113 [self.branch setDebug];
114}
115
116+ (void)enableLogging
117{
118 [self.branch enableLogging];
119}
120
121+ (void)delayInitToCheckForSearchAds
122{
123 [self.branch delayInitToCheckForSearchAds];
124}
125
126+ (void)useTestInstance {
127 useTestInstance = YES;
128}
129
130+ (void)deferInitializationForJSLoad
131{
132 deferInitializationForJSLoad = YES;
133}
134
135//Called by AppDelegate.m -- stores initSession result in static variables and posts RNBranchLinkOpened event that's captured by the RNBranch instance to emit it to React Native
136+ (void)initSessionWithLaunchOptions:(NSDictionary *)launchOptions isReferrable:(BOOL)isReferrable {
137 savedLaunchOptions = launchOptions;
138 savedIsReferrable = isReferrable;
139
140 [self.branch registerPluginName:@"ReactNative" version:RNBRANCH_VERSION];
141
142 // Can't currently support this on Android.
143 // if (!deferInitializationForJSLoad && !BranchJsonConfig.instance.deferInitializationForJSLoad) [self initializeBranchSDK];
144 [self initializeBranchSDK];
145}
146
147+ (void)initializeBranchSDK
148{
149 // Universal Links
150 NSUserActivity *coldLaunchUserActivity = savedLaunchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey][@"UIApplicationLaunchOptionsUserActivityKey"];
151 if (coldLaunchUserActivity.webpageURL) {
152 [self willOpenURL:coldLaunchUserActivity.webpageURL];
153 }
154
155 // URI schemes
156 NSURL *coldLaunchURL = savedLaunchOptions[UIApplicationLaunchOptionsURLKey];
157 if (coldLaunchURL) {
158 [self willOpenURL:coldLaunchURL];
159 }
160
161 [self.branch initSessionWithLaunchOptions:savedLaunchOptions isReferrable:savedIsReferrable andRegisterDeepLinkHandler:^(NSDictionary *params, NSError *error) {
162 NSMutableDictionary *result = [NSMutableDictionary dictionary];
163 if (error) result[RNBranchLinkOpenedNotificationErrorKey] = error;
164 if (params) {
165 result[RNBranchLinkOpenedNotificationParamsKey] = params;
166 BOOL clickedBranchLink = [params[@"+clicked_branch_link"] boolValue];
167
168 if (clickedBranchLink) {
169 BranchUniversalObject *branchUniversalObject = [BranchUniversalObject objectWithDictionary:params];
170 if (branchUniversalObject) result[RNBranchLinkOpenedNotificationBranchUniversalObjectKey] = branchUniversalObject;
171
172 BranchLinkProperties *linkProperties = [BranchLinkProperties getBranchLinkPropertiesFromDictionary:params];
173 if (linkProperties) result[RNBranchLinkOpenedNotificationLinkPropertiesKey] = linkProperties;
174 }
175 }
176
177 /*
178 * originalURL will be nil in case of deferred deep links, Spotlight items, etc.
179 * Note that deferred deep link checks will not trigger an onOpenStart call in JS
180 * (RNBranch.INIT_SESSION_START).
181 */
182 if (originalURL) {
183 result[RNBranchLinkOpenedNotificationUriKey] = originalURL;
184 originalURL = nil;
185 }
186
187 [[NSNotificationCenter defaultCenter] postNotificationName:RNBranchLinkOpenedNotification object:nil userInfo:result];
188 }];
189}
190
191+ (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
192{
193 [self willOpenURL:url];
194 return [self.branch application:application openURL:url options:options];
195}
196
197+ (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
198{
199 [self willOpenURL:url];
200 return [self.branch application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
201}
202
203#pragma clang diagnostic push
204#pragma clang diagnostic ignored "-Wpartial-availability"
205+ (BOOL)continueUserActivity:(NSUserActivity *)userActivity {
206 [self willOpenURL:userActivity.webpageURL];
207 return [self.branch continueUserActivity:userActivity];
208}
209#pragma clang diagnostic pop
210
211+ (void)willOpenURL:(NSURL *)url
212{
213 /*
214 * This should be consistent with the behavior of the underlying SDK.
215 * If an open is pending, and a new open is received, the first open is
216 * dropped. No response is expected for the first open. JS will generate
217 * two calls to onOpenStart with potentially different URIs. Only the
218 * last one should be expected to get a response.
219 *
220 * Behavior on Android is probably different.
221 */
222 originalURL = url;
223 [RNBranchEventEmitter initSessionWillStartWithURI:url];
224}
225
226#pragma mark - Object lifecycle
227
228- (instancetype)init {
229 self = [super init];
230
231 if (self) {
232 _universalObjectMap = [RNBranchAgingDictionary dictionaryWithTtl:3600.0];
233
234 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onInitSessionFinished:) name:RNBranchLinkOpenedNotification object:nil];
235 }
236
237 return self;
238}
239
240- (void) dealloc {
241 [[NSNotificationCenter defaultCenter] removeObserver:self];
242}
243
244#pragma mark - Utility methods
245
246- (UIViewController *)currentViewController
247{
248 UIViewController *current = [UIApplication sharedApplication].keyWindow.rootViewController;
249 while (current.presentedViewController && ![current.presentedViewController isKindOfClass:UIAlertController.class]) {
250 current = current.presentedViewController;
251 }
252 return current;
253}
254
255- (void) onInitSessionFinished:(NSNotification*) notification {
256 NSURL *uri = notification.userInfo[RNBranchLinkOpenedNotificationUriKey];
257 NSError *error = notification.userInfo[RNBranchLinkOpenedNotificationErrorKey];
258 NSDictionary *params = notification.userInfo[RNBranchLinkOpenedNotificationParamsKey];
259
260 initSessionWithLaunchOptionsResult = @{
261 RNBranchLinkOpenedNotificationErrorKey: error.localizedDescription ?: NSNull.null,
262 RNBranchLinkOpenedNotificationParamsKey: params ?: NSNull.null,
263 RNBranchLinkOpenedNotificationUriKey: uri.absoluteString ?: NSNull.null
264 };
265
266 // If there is an error, fire error event
267 if (error) {
268 [RNBranchEventEmitter initSessionDidEncounterErrorWithPayload:initSessionWithLaunchOptionsResult];
269 }
270
271 // otherwise notify the session is finished
272 else {
273 [RNBranchEventEmitter initSessionDidSucceedWithPayload:initSessionWithLaunchOptionsResult];
274 }
275}
276
277- (BranchLinkProperties*) createLinkProperties:(NSDictionary *)linkPropertiesMap withControlParams:(NSDictionary *)controlParamsMap
278{
279 BranchLinkProperties *linkProperties = [[BranchLinkProperties alloc] initWithMap:linkPropertiesMap];
280
281 linkProperties.controlParams = controlParamsMap;
282 return linkProperties;
283}
284
285- (BranchUniversalObject *)findUniversalObjectWithIdent:(NSString *)ident rejecter:(RCTPromiseRejectBlock)reject
286{
287 BranchUniversalObject *universalObject = self.universalObjectMap[ident];
288
289 if (!universalObject) {
290 NSString *errorMessage = [NSString stringWithFormat:@"BranchUniversalObject for ident %@ not found.", ident];
291
292 NSError *error = [NSError errorWithDomain:RNBranchErrorDomain
293 code:RNBranchUniversalObjectNotFoundError
294 userInfo:@{IdentFieldName : ident,
295 NSLocalizedDescriptionKey: errorMessage
296 }];
297
298 reject(@"RNBranch::Error::BUONotFound", errorMessage, error);
299 }
300
301 return universalObject;
302}
303
304#pragma mark - Methods exported to React Native
305
306
307#pragma mark clearPartnerParameters
308RCT_EXPORT_METHOD(
309 clearPartnerParameters
310 ) {
311 [self.class.branch clearPartnerParameters];
312}
313
314#pragma mark addFacebookPartnerParameter
315RCT_EXPORT_METHOD(
316 addFacebookPartnerParameter:(NSString *)name
317 value:(NSString *)value
318 ) {
319 [self.class.branch addFacebookPartnerParameterWithName:name value:value];
320}
321
322#pragma mark disableTracking
323RCT_EXPORT_METHOD(
324 disableTracking:(BOOL)disable
325 ) {
326 [Branch setTrackingDisabled: disable];
327}
328
329#pragma mark isTrackingDisabled
330RCT_EXPORT_METHOD(
331 isTrackingDisabled:(RCTPromiseResolveBlock)resolve
332 rejecter:(__unused RCTPromiseRejectBlock)reject
333 ) {
334 resolve([Branch trackingDisabled] ? @YES : @NO);
335}
336
337#pragma mark initializeBranch
338RCT_EXPORT_METHOD(initializeBranch:(NSString *)key
339 resolver:(RCTPromiseResolveBlock)resolve
340 rejecter:(RCTPromiseRejectBlock)reject
341 ) {
342 NSError *error = [NSError errorWithDomain:RNBranchErrorDomain
343 code:-1
344 userInfo:nil];
345
346 reject(@"RNBranch::Error::Unsupported", @"Initializing the Branch SDK from JS will be supported in a future release.", error);
347
348 /*
349 if (!deferInitializationForJSLoad && !BranchJsonConfig.instance.deferInitializationForJSLoad) {
350 // This is a no-op from JS unless [RNBranch deferInitializationForJSLoad] is called.
351 resolve(0);
352 return;
353 }
354
355 RCTLogTrace(@"Initializing Branch SDK. Key from JS: %@", key);
356 branchKey = key;
357
358 [self.class initializeBranchSDK];
359 resolve(0);
360 // */
361}
362
363#pragma mark redeemInitSessionResult
364RCT_EXPORT_METHOD(
365 redeemInitSessionResult:(RCTPromiseResolveBlock)resolve
366 rejecter:(__unused RCTPromiseRejectBlock)reject
367 ) {
368 resolve(initSessionWithLaunchOptionsResult ?: [NSNull null]);
369}
370
371#pragma mark getLatestReferringParams
372RCT_EXPORT_METHOD(
373 getLatestReferringParams:(NSNumber* __nonnull)synchronous
374 resolver:(RCTPromiseResolveBlock)resolve
375 rejecter:(__unused RCTPromiseRejectBlock)reject
376 ) {
377 if (synchronous.boolValue)
378 resolve([self.class.branch getLatestReferringParamsSynchronous]);
379 else
380 resolve([self.class.branch getLatestReferringParams]);
381}
382
383#pragma mark getFirstReferringParams
384RCT_EXPORT_METHOD(
385 getFirstReferringParams:(RCTPromiseResolveBlock)resolve
386 rejecter:(__unused RCTPromiseRejectBlock)reject
387 ) {
388 resolve([self.class.branch getFirstReferringParams]);
389}
390
391#pragma mark lastAttributedTouchData
392RCT_EXPORT_METHOD(
393 lastAttributedTouchData:(NSNumber* __nonnull)window
394 resolver:(RCTPromiseResolveBlock)resolve
395 rejecter:(__unused RCTPromiseRejectBlock)reject
396 ) {
397 [self.class.branch lastAttributedTouchDataWithAttributionWindow:window.integerValue completion:^(BranchLastAttributedTouchData *r, NSError *e){
398 // TODO: pass back the error to JS
399 resolve(r);
400 }];
401}
402
403#pragma mark setIdentity
404RCT_EXPORT_METHOD(
405 setIdentity:(NSString *)identity
406 ) {
407 [self.class.branch setIdentity:identity];
408}
409
410#pragma mark setRequestMetadataKey
411RCT_EXPORT_METHOD(
412 setRequestMetadataKey:(NSString *)key
413 value:(NSString *)value
414 ) {
415 [self.class.branch setRequestMetadataKey:key value:value];
416}
417
418#pragma mark logout
419RCT_EXPORT_METHOD(
420 logout
421 ) {
422 [self.class.branch logout];
423}
424
425#pragma mark openURL
426RCT_EXPORT_METHOD(
427 openURL:(NSString *)urlString
428 ) {
429 [self.class.branch handleDeepLinkWithNewSession:[NSURL URLWithString:urlString]];
430}
431
432#pragma mark sendCommerceEvent
433RCT_EXPORT_METHOD(
434 sendCommerceEvent:(NSString *)revenue
435 metadata:(NSDictionary *)metadata
436 resolver:(RCTPromiseResolveBlock)resolve
437 rejecter:(__unused RCTPromiseRejectBlock)reject
438 ) {
439 BNCCommerceEvent *commerceEvent = [BNCCommerceEvent new];
440 commerceEvent.revenue = [NSDecimalNumber decimalNumberWithString:revenue];
441 [self.class.branch sendCommerceEvent:commerceEvent metadata:metadata withCompletion:^(NSDictionary *r, NSError *e){}];
442 resolve(NSNull.null);
443}
444
445#pragma mark userCompletedAction
446RCT_EXPORT_METHOD(
447 userCompletedAction:(NSString *)event withState:(NSDictionary *)appState
448 ) {
449 [self.class.branch userCompletedAction:event withState:appState];
450}
451
452#pragma mark userCompletedActionOnUniversalObject
453RCT_EXPORT_METHOD(
454 userCompletedActionOnUniversalObject:(NSString *)identifier
455 event:(NSString *)event
456 resolver:(RCTPromiseResolveBlock)resolve
457 rejecter:(RCTPromiseRejectBlock)reject
458) {
459 BranchUniversalObject *branchUniversalObject = [self findUniversalObjectWithIdent:identifier rejecter:reject];
460 if (!branchUniversalObject) return;
461
462 [branchUniversalObject userCompletedAction:event];
463 resolve(NSNull.null);
464}
465
466#pragma mark userCompletedActionOnUniversalObject
467RCT_EXPORT_METHOD(
468 userCompletedActionOnUniversalObject:(NSString *)identifier
469 event:(NSString *)event
470 state:(NSDictionary *)state
471 resolver:(RCTPromiseResolveBlock)resolve
472 rejecter:(RCTPromiseRejectBlock)reject
473 ) {
474 BranchUniversalObject *branchUniversalObject = [self findUniversalObjectWithIdent:identifier rejecter:reject];
475 if (!branchUniversalObject) return;
476
477 [branchUniversalObject userCompletedAction:event withState:state];
478 resolve(NSNull.null);
479}
480
481#pragma mark logEvent
482RCT_EXPORT_METHOD(
483 logEvent:(NSArray *)identifiers
484 eventName:(NSString *)eventName
485 params:(NSDictionary *)params
486 resolver:(RCTPromiseResolveBlock)resolve
487 rejecter:(RCTPromiseRejectBlock)reject
488 ) {
489 BranchEvent *event = [[BranchEvent alloc] initWithName:eventName map:params];
490
491 NSMutableArray<BranchUniversalObject *> *buos = @[].mutableCopy;
492 for (NSString *identifier in identifiers) {
493 BranchUniversalObject *buo = [self findUniversalObjectWithIdent:identifier rejecter:reject];
494 if (!buo) return;
495
496 [buos addObject:buo];
497 }
498
499 event.contentItems = buos;
500 if ([eventName isEqualToString:BranchStandardEventViewItem] && params.count == 0) {
501 for (BranchUniversalObject *buo in buos) {
502 if (!buo.locallyIndex) continue;
503 // for now at least, pending possible changes to the native SDK
504 [buo listOnSpotlight];
505 }
506 }
507
508 [event logEvent];
509 resolve(NSNull.null);
510}
511
512#pragma mark showShareSheet
513RCT_EXPORT_METHOD(
514 showShareSheet:(NSString *)identifier
515 withShareOptions:(NSDictionary *)shareOptionsMap
516 withLinkProperties:(NSDictionary *)linkPropertiesMap
517 withControlParams:(NSDictionary *)controlParamsMap
518 resolver:(RCTPromiseResolveBlock)resolve
519 rejecter:(RCTPromiseRejectBlock)reject
520 ) {
521 BranchUniversalObject *branchUniversalObject = [self findUniversalObjectWithIdent:identifier rejecter:reject];
522 if (!branchUniversalObject) return;
523
524 dispatch_async(dispatch_get_main_queue(), ^{
525 NSMutableDictionary *mutableControlParams = controlParamsMap.mutableCopy;
526 if (shareOptionsMap && shareOptionsMap[@"emailSubject"]) {
527 mutableControlParams[@"$email_subject"] = shareOptionsMap[@"emailSubject"];
528 }
529
530 BranchLinkProperties *linkProperties = [self createLinkProperties:linkPropertiesMap withControlParams:mutableControlParams];
531
532 [branchUniversalObject showShareSheetWithLinkProperties:linkProperties
533 andShareText:shareOptionsMap[@"messageBody"]
534 fromViewController:self.currentViewController
535 completionWithError:^(NSString * _Nullable activityType, BOOL completed, NSError * _Nullable activityError){
536 if (activityError) {
537 NSString *errorCodeString = [NSString stringWithFormat:@"%ld", (long)activityError.code];
538 reject(errorCodeString, activityError.localizedDescription, activityError);
539 return;
540 }
541
542 NSDictionary *result = @{
543 @"channel" : activityType ?: [NSNull null],
544 @"completed" : @(completed),
545 @"error" : [NSNull null]
546 };
547
548 // SDK-854 do not callback more than once.
549 // The native iOS code calls back with status even if the user just cancelled.
550 if (completed) {
551 resolve(result);
552 }
553 }];
554 });
555}
556
557#pragma mark registerView
558RCT_EXPORT_METHOD(
559 registerView:(NSString *)identifier
560 resolver:(RCTPromiseResolveBlock)resolve
561 rejecter:(RCTPromiseRejectBlock)reject
562 ) {
563 BranchUniversalObject *branchUniversalObject = [self findUniversalObjectWithIdent:identifier rejecter:reject];
564 if (!branchUniversalObject) return;
565
566 [branchUniversalObject registerViewWithCallback:^(NSDictionary *params, NSError *error) {
567 if (!error) {
568 resolve([NSNull null]);
569 } else {
570 reject([NSString stringWithFormat: @"%lu", (long)error.code], error.localizedDescription, error);
571 }
572 }];
573}
574
575#pragma mark generateShortUrl
576RCT_EXPORT_METHOD(
577 generateShortUrl:(NSString *)identifier
578 withLinkProperties:(NSDictionary *)linkPropertiesMap
579 withControlParams:(NSDictionary *)controlParamsMap
580 resolver:(RCTPromiseResolveBlock)resolve
581 rejecter:(RCTPromiseRejectBlock)reject
582 ) {
583 BranchUniversalObject *branchUniversalObject = [self findUniversalObjectWithIdent:identifier rejecter:reject];
584 if (!branchUniversalObject) return;
585
586 BranchLinkProperties *linkProperties = [self createLinkProperties:linkPropertiesMap withControlParams:controlParamsMap];
587
588 [branchUniversalObject getShortUrlWithLinkProperties:linkProperties andCallback:^(NSString *url, NSError *error) {
589 if (!error) {
590 RCTLogInfo(@"RNBranch Success");
591 resolve(@{ @"url": url });
592 }
593 else if (error.code == BNCDuplicateResourceError) {
594 reject(@"RNBranch::Error::DuplicateResourceError", error.localizedDescription, error);
595 }
596 else {
597 reject(@"RNBranch::Error", error.localizedDescription, error);
598 }
599 }];
600}
601
602#pragma mark listOnSpotlight
603RCT_EXPORT_METHOD(
604 listOnSpotlight:(NSString *)identifier
605 resolver:(RCTPromiseResolveBlock)resolve
606 rejecter:(RCTPromiseRejectBlock)reject
607 ) {
608 BranchUniversalObject *branchUniversalObject = [self findUniversalObjectWithIdent:identifier rejecter:reject];
609 if (!branchUniversalObject) return;
610
611 [branchUniversalObject listOnSpotlightWithCallback:^(NSString *string, NSError *error) {
612 if (!error) {
613 NSDictionary *data = @{@"result":string};
614 resolve(data);
615 } else {
616 reject([NSString stringWithFormat: @"%lu", (long)error.code], error.localizedDescription, error);
617 }
618 }];
619}
620
621// @TODO can this be removed? legacy, short url should be created from BranchUniversalObject
622#pragma mark getShortUrl
623RCT_EXPORT_METHOD(
624 getShortUrl:(NSDictionary *)linkPropertiesMap
625 resolver:(RCTPromiseResolveBlock)resolve
626 rejecter:(RCTPromiseRejectBlock)reject
627 ) {
628 NSString *feature = linkPropertiesMap[@"feature"];
629 NSString *channel = linkPropertiesMap[@"channel"];
630 NSString *stage = linkPropertiesMap[@"stage"];
631 NSArray *tags = linkPropertiesMap[@"tags"];
632
633 [self.class.branch getShortURLWithParams:linkPropertiesMap
634 andTags:tags
635 andChannel:channel
636 andFeature:feature
637 andStage:stage
638 andCallback:^(NSString *url, NSError *error) {
639 if (error) {
640 RCTLogError(@"RNBranch::Error: %@", error.localizedDescription);
641 reject(@"RNBranch::Error", @"getShortURLWithParams", error);
642 }
643 resolve(url);
644 }];
645}
646
647#pragma mark createUniversalObject
648RCT_EXPORT_METHOD(
649 createUniversalObject:(NSDictionary *)universalObjectProperties
650 resolver:(RCTPromiseResolveBlock)resolve
651 rejecter:(__unused RCTPromiseRejectBlock)reject
652 ) {
653 BranchUniversalObject *universalObject = [[BranchUniversalObject alloc] initWithMap:universalObjectProperties];
654 NSString *identifier = [NSUUID UUID].UUIDString;
655 self.universalObjectMap[identifier] = universalObject;
656 NSDictionary *response = @{IdentFieldName: identifier};
657
658 resolve(response);
659}
660
661#pragma mark releaseUniversalObject
662RCT_EXPORT_METHOD(
663 releaseUniversalObject:(NSString *)identifier
664 ) {
665 [self.universalObjectMap removeObjectForKey:identifier];
666}
667
668#pragma mark handleATTAuthorizationStatus
669RCT_EXPORT_METHOD(
670 handleATTAuthorizationStatus:(NSUInteger)authorizationStatus
671 ) {
672 [self.class.branch handleATTAuthorizationStatus:authorizationStatus];
673}
674
675@end