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