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 |
|
10 | NSString * const RNBranchLinkOpenedNotification = @"RNBranchLinkOpenedNotification";
|
11 | NSString * const RNBranchLinkOpenedNotificationErrorKey = @"error";
|
12 | NSString * const RNBranchLinkOpenedNotificationParamsKey = @"params";
|
13 | NSString * const RNBranchLinkOpenedNotificationUriKey = @"uri";
|
14 | NSString * const RNBranchLinkOpenedNotificationBranchUniversalObjectKey = @"branch_universal_object";
|
15 | NSString * const RNBranchLinkOpenedNotificationLinkPropertiesKey = @"link_properties";
|
16 |
|
17 |
|
18 | static NSDictionary *initSessionWithLaunchOptionsResult;
|
19 | static BOOL useTestInstance = NO;
|
20 | static NSDictionary *savedLaunchOptions;
|
21 | static BOOL savedIsReferrable;
|
22 | static NSString *branchKey;
|
23 | static BOOL deferInitializationForJSLoad = NO;
|
24 | static NSURL *originalURL;
|
25 |
|
26 | static NSString * const IdentFieldName = @"ident";
|
27 |
|
28 | // These are only really exposed to the JS layer, so keep them internal for now.
|
29 | static NSString * const RNBranchErrorDomain = @"RNBranchErrorDomain";
|
30 | static 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 |
|
45 | RCT_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 |
|
179 |
|
180 |
|
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 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
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
|
308 | RCT_EXPORT_METHOD(
|
309 | clearPartnerParameters
|
310 | ) {
|
311 | [self.class.branch clearPartnerParameters];
|
312 | }
|
313 |
|
314 | #pragma mark addFacebookPartnerParameter
|
315 | RCT_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
|
323 | RCT_EXPORT_METHOD(
|
324 | disableTracking:(BOOL)disable
|
325 | ) {
|
326 | [Branch setTrackingDisabled: disable];
|
327 | }
|
328 |
|
329 | #pragma mark isTrackingDisabled
|
330 | RCT_EXPORT_METHOD(
|
331 | isTrackingDisabled:(RCTPromiseResolveBlock)resolve
|
332 | rejecter:(__unused RCTPromiseRejectBlock)reject
|
333 | ) {
|
334 | resolve([Branch trackingDisabled] ? @YES : @NO);
|
335 | }
|
336 |
|
337 | #pragma mark initializeBranch
|
338 | RCT_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 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 | }
|
362 |
|
363 | #pragma mark redeemInitSessionResult
|
364 | RCT_EXPORT_METHOD(
|
365 | redeemInitSessionResult:(RCTPromiseResolveBlock)resolve
|
366 | rejecter:(__unused RCTPromiseRejectBlock)reject
|
367 | ) {
|
368 | resolve(initSessionWithLaunchOptionsResult ?: [NSNull null]);
|
369 | }
|
370 |
|
371 | #pragma mark getLatestReferringParams
|
372 | RCT_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
|
384 | RCT_EXPORT_METHOD(
|
385 | getFirstReferringParams:(RCTPromiseResolveBlock)resolve
|
386 | rejecter:(__unused RCTPromiseRejectBlock)reject
|
387 | ) {
|
388 | resolve([self.class.branch getFirstReferringParams]);
|
389 | }
|
390 |
|
391 | #pragma mark lastAttributedTouchData
|
392 | RCT_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
|
404 | RCT_EXPORT_METHOD(
|
405 | setIdentity:(NSString *)identity
|
406 | ) {
|
407 | [self.class.branch setIdentity:identity];
|
408 | }
|
409 |
|
410 | #pragma mark setRequestMetadataKey
|
411 | RCT_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
|
419 | RCT_EXPORT_METHOD(
|
420 | logout
|
421 | ) {
|
422 | [self.class.branch logout];
|
423 | }
|
424 |
|
425 | #pragma mark openURL
|
426 | RCT_EXPORT_METHOD(
|
427 | openURL:(NSString *)urlString
|
428 | ) {
|
429 | [self.class.branch handleDeepLinkWithNewSession:[NSURL URLWithString:urlString]];
|
430 | }
|
431 |
|
432 | #pragma mark sendCommerceEvent
|
433 | RCT_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
|
446 | RCT_EXPORT_METHOD(
|
447 | userCompletedAction:(NSString *)event withState:(NSDictionary *)appState
|
448 | ) {
|
449 | [self.class.branch userCompletedAction:event withState:appState];
|
450 | }
|
451 |
|
452 | #pragma mark userCompletedActionOnUniversalObject
|
453 | RCT_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
|
467 | RCT_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
|
482 | RCT_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
|
513 | RCT_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
|
558 | RCT_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
|
576 | RCT_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
|
603 | RCT_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
|
623 | RCT_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
|
648 | RCT_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
|
662 | RCT_EXPORT_METHOD(
|
663 | releaseUniversalObject:(NSString *)identifier
|
664 | ) {
|
665 | [self.universalObjectMap removeObjectForKey:identifier];
|
666 | }
|
667 |
|
668 | #pragma mark handleATTAuthorizationStatus
|
669 | RCT_EXPORT_METHOD(
|
670 | handleATTAuthorizationStatus:(NSUInteger)authorizationStatus
|
671 | ) {
|
672 | [self.class.branch handleATTAuthorizationStatus:authorizationStatus];
|
673 | }
|
674 |
|
675 | @end
|