From 03fa03aa76e7b5c4c595bc2928080fd488be19ac Mon Sep 17 00:00:00 2001 From: Jimmy Dee Date: Tue, 14 Mar 2017 15:46:52 -0700 Subject: [PATCH 1/2] Support for custom params in BUO.userCompletedAction --- README.md | 1 + .../io/branch/rnbranch/RNBranchModule.java | 28 ++++++++- ios/BranchUniversalObject+RNBranch.h | 2 + ios/BranchUniversalObject+RNBranch.m | 58 +++++++++++++++++++ ios/RNBranch.m | 15 +++++ src/branchUniversalObject.js | 4 +- testbed/testbed_cocoapods/android/app/app.iml | 17 ------ 7 files changed, 104 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index adda04556..67dc10b99 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ let branchUniversalObject = branch.createBranchUniversalObject('canonicalIdentif title: 'Cool Content!', contentDescription: 'Cool Content Description'}) let actionResult = await branchUniversalObject.userCompletedAction(RegisterViewEvent) +let customActionResult = await branchUniversalObject.userCompletedAction('Custom Action', { key: 'value' }) let shareOptions = { messageHeader: 'Check this out', messageBody: 'No really, check this out!' } let linkProperties = { feature: 'share', channel: 'RNApp' } diff --git a/android/src/main/java/io/branch/rnbranch/RNBranchModule.java b/android/src/main/java/io/branch/rnbranch/RNBranchModule.java index 9008cb1c5..bbcb16d9c 100644 --- a/android/src/main/java/io/branch/rnbranch/RNBranchModule.java +++ b/android/src/main/java/io/branch/rnbranch/RNBranchModule.java @@ -168,11 +168,11 @@ public void userCompletedAction(String event, ReadableMap appState) throws JSONE } @ReactMethod - public void userCompletedActionOnUniversalObject(String ident, String event, Promise promise) { + public void userCompletedActionOnUniversalObject(String ident, String event, ReadableMap state, Promise promise) { BranchUniversalObject universalObject = findUniversalObjectOrReject(ident, promise); if (universalObject == null) return; - universalObject.userCompletedAction(event); + universalObject.userCompletedAction(event, convertMapToParams(state)); promise.resolve(null); } @@ -693,4 +693,28 @@ private static WritableArray convertJsonToArray(JSONArray jsonArray) throws JSON } return array; } + + // Convert an arbitrary ReadableMap to a string-string hash of custom params for userCompletedAction. + private static HashMap convertMapToParams(ReadableMap map) { + if (map == null) return null; + + HashMap hash = new HashMap<>(); + + ReadableMapKeySetIterator iterator = map.keySetIterator(); + while (iterator.hasNextKey()) { + String key = iterator.nextKey(); + switch (map.getType(key)) { + case String: + hash.put(key, map.getString(key)); + case Boolean: + hash.put(key, "" + map.getBoolean(key)); + case Number: + hash.put(key, "" + map.getDouble(key)); + default: + Log.w(REACT_CLASS, "Unsupported data type in params, ignoring"); + } + } + + return hash; + } } diff --git a/ios/BranchUniversalObject+RNBranch.h b/ios/BranchUniversalObject+RNBranch.h index ccd5eede9..ba2d3456b 100644 --- a/ios/BranchUniversalObject+RNBranch.h +++ b/ios/BranchUniversalObject+RNBranch.h @@ -16,4 +16,6 @@ - (instancetype)initWithMap:(NSDictionary *)map; +- (void)userCompletedAction:(NSString *)action withState:(NSDictionary *)state; + @end diff --git a/ios/BranchUniversalObject+RNBranch.m b/ios/BranchUniversalObject+RNBranch.m index d0af1df63..e15417e92 100644 --- a/ios/BranchUniversalObject+RNBranch.m +++ b/ios/BranchUniversalObject+RNBranch.m @@ -8,6 +8,8 @@ #import +#import + #import "BranchUniversalObject+RNBranch.h" #import "NSObject+RNBranch.h" #import "RNBranchProperty.h" @@ -93,4 +95,60 @@ - (void)setExpirationDateWithString:(NSString *)expirationDate self.expirationDate = [NSDate dateWithTimeIntervalSince1970:timegm(&expiration)]; } +#pragma mark - Code to support userCompletedAction:withState: + +/* + * Until the native SDK supports this, the following is largely lifted from BUO.m. + */ + +- (void)userCompletedAction:(NSString *)action withState:(NSDictionary *)state +{ + NSMutableDictionary *actionPayload = [[NSMutableDictionary alloc] init]; + NSDictionary *linkParams = [self getParamsForServerRequest]; + if (self.canonicalIdentifier && linkParams) { + actionPayload[BNCCanonicalIdList] = @[self.canonicalIdentifier]; + actionPayload[self.canonicalIdentifier] = linkParams; + + // Add in custom params + [actionPayload addEntriesFromDictionary:state]; + + [[Branch getInstance] userCompletedAction:action withState:actionPayload]; + if (self.automaticallyListOnSpotlight && [action isEqualToString:BNCRegisterViewEvent]) + [self listOnSpotlight]; + } +} + +- (NSDictionary *)getParamsForServerRequest { + NSMutableDictionary *temp = [[NSMutableDictionary alloc] init]; + [self safeSetValue:self.canonicalIdentifier forKey:BRANCH_LINK_DATA_KEY_CANONICAL_IDENTIFIER onDict:temp]; + [self safeSetValue:self.canonicalUrl forKey:BRANCH_LINK_DATA_KEY_CANONICAL_URL onDict:temp]; + [self safeSetValue:self.title forKey:BRANCH_LINK_DATA_KEY_OG_TITLE onDict:temp]; + [self safeSetValue:self.contentDescription forKey:BRANCH_LINK_DATA_KEY_OG_DESCRIPTION onDict:temp]; + [self safeSetValue:self.imageUrl forKey:BRANCH_LINK_DATA_KEY_OG_IMAGE_URL onDict:temp]; + if (self.contentIndexMode == ContentIndexModePrivate) { + [self safeSetValue:@(0) forKey:BRANCH_LINK_DATA_KEY_PUBLICLY_INDEXABLE onDict:temp]; + } + else { + [self safeSetValue:@(1) forKey:BRANCH_LINK_DATA_KEY_PUBLICLY_INDEXABLE onDict:temp]; + } + [self safeSetValue:self.keywords forKey:BRANCH_LINK_DATA_KEY_KEYWORDS onDict:temp]; + [self safeSetValue:@(1000 * [self.expirationDate timeIntervalSince1970]) forKey:BRANCH_LINK_DATA_KEY_CONTENT_EXPIRATION_DATE onDict:temp]; + [self safeSetValue:self.type forKey:BRANCH_LINK_DATA_KEY_CONTENT_TYPE onDict:temp]; + [self safeSetValue:self.currency forKey:BNCPurchaseCurrency onDict:temp]; + if (self.price) { + // have to add if statement because safeSetValue only accepts objects so even if self.price is not set + // a valid NSNumber object will be created and the request will have amount:0 in all cases. + [self safeSetValue:[NSNumber numberWithFloat:self.price] forKey:BNCPurchaseAmount onDict:temp]; + } + + [temp addEntriesFromDictionary:[self.metadata copy]]; + return [temp copy]; +} + +- (void)safeSetValue:(NSObject *)value forKey:(NSString *)key onDict:(NSMutableDictionary *)dict { + if (value) { + dict[key] = value; + } +} + @end diff --git a/ios/RNBranch.m b/ios/RNBranch.m index 18db6eafe..8085fb992 100644 --- a/ios/RNBranch.m +++ b/ios/RNBranch.m @@ -210,6 +210,21 @@ - (BranchUniversalObject *)findUniversalObjectWithIdent:(NSString *)ident reject resolve(NSNull.null); } +#pragma mark userCompletedActionOnUniversalObject +RCT_EXPORT_METHOD( + userCompletedActionOnUniversalObject:(NSString *)identifier + event:(NSString *)event + state:(NSDictionary *)state + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject + ) { + BranchUniversalObject *branchUniversalObject = [self findUniversalObjectWithIdent:identifier rejecter:reject]; + if (!branchUniversalObject) return; + + [branchUniversalObject userCompletedAction:event withState:state]; + resolve(NSNull.null); +} + #pragma mark showShareSheet RCT_EXPORT_METHOD( showShareSheet:(NSString *)identifier diff --git a/src/branchUniversalObject.js b/src/branchUniversalObject.js index e5aec84bc..ee3f39bf9 100644 --- a/src/branchUniversalObject.js +++ b/src/branchUniversalObject.js @@ -41,8 +41,8 @@ export default async function createBranchUniversalObject(identifier, options = if (Platform.OS !== 'ios') return Promise.resolve() return this._tryFunction(RNBranch.listOnSpotlight) }, - userCompletedAction(event) { - return this._tryFunction(RNBranch.userCompletedActionOnUniversalObject, event) + userCompletedAction(event, state = {}) { + return this._tryFunction(RNBranch.userCompletedActionOnUniversalObject, event, state) }, release() { RNBranch.releaseUniversalObject(this.ident) diff --git a/testbed/testbed_cocoapods/android/app/app.iml b/testbed/testbed_cocoapods/android/app/app.iml index 649772f36..34768293e 100644 --- a/testbed/testbed_cocoapods/android/app/app.iml +++ b/testbed/testbed_cocoapods/android/app/app.iml @@ -128,22 +128,5 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file From 70d0b028e9cc2cdd99b05416917b53ef84d1c7aa Mon Sep 17 00:00:00 2001 From: Jimmy Dee Date: Tue, 14 Mar 2017 15:57:40 -0700 Subject: [PATCH 2/2] Anticipate that the native SDK may eventually support userCompletedAction:withState: --- ios/BranchUniversalObject+RNBranch.h | 2 +- ios/BranchUniversalObject+RNBranch.m | 9 ++++++++- ios/RNBranch.m | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ios/BranchUniversalObject+RNBranch.h b/ios/BranchUniversalObject+RNBranch.h index ba2d3456b..c6a13af4b 100644 --- a/ios/BranchUniversalObject+RNBranch.h +++ b/ios/BranchUniversalObject+RNBranch.h @@ -16,6 +16,6 @@ - (instancetype)initWithMap:(NSDictionary *)map; -- (void)userCompletedAction:(NSString *)action withState:(NSDictionary *)state; +- (void)rnbranchUserCompletedAction:(NSString *)action withState:(NSDictionary *)state; @end diff --git a/ios/BranchUniversalObject+RNBranch.m b/ios/BranchUniversalObject+RNBranch.m index e15417e92..963d6514d 100644 --- a/ios/BranchUniversalObject+RNBranch.m +++ b/ios/BranchUniversalObject+RNBranch.m @@ -101,8 +101,15 @@ - (void)setExpirationDateWithString:(NSString *)expirationDate * Until the native SDK supports this, the following is largely lifted from BUO.m. */ -- (void)userCompletedAction:(NSString *)action withState:(NSDictionary *)state +- (void)rnbranchUserCompletedAction:(NSString *)action withState:(NSDictionary *)state { + // Anticipate that the native SDK will support this. + SEL sdkMethod = @selector(userCompletedAction:withState:); + if ([self respondsToSelector:sdkMethod]) { + [self performSelector:sdkMethod withObject:action withObject:state]; + return; + } + NSMutableDictionary *actionPayload = [[NSMutableDictionary alloc] init]; NSDictionary *linkParams = [self getParamsForServerRequest]; if (self.canonicalIdentifier && linkParams) { diff --git a/ios/RNBranch.m b/ios/RNBranch.m index 8085fb992..77039276d 100644 --- a/ios/RNBranch.m +++ b/ios/RNBranch.m @@ -221,7 +221,7 @@ - (BranchUniversalObject *)findUniversalObjectWithIdent:(NSString *)ident reject BranchUniversalObject *branchUniversalObject = [self findUniversalObjectWithIdent:identifier rejecter:reject]; if (!branchUniversalObject) return; - [branchUniversalObject userCompletedAction:event withState:state]; + [branchUniversalObject rnbranchUserCompletedAction:event withState:state]; resolve(NSNull.null); }