Skip to content

Commit 5d7361f

Browse files
Merge pull request #711 from BranchMetrics/SDK-1407
[SDK-1407] Add Branch QR code methods
2 parents 103cfb5 + 10b5cda commit 5d7361f

File tree

6 files changed

+236
-11
lines changed

6 files changed

+236
-11
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ npm-debug.log*
99
yarn-error.log*
1010
.vscode
1111
.idea
12+
cordova-ionic-phonegap-branch-deep-linking-attribution.iml
1213
src/android/.idea

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "branch-cordova-sdk",
33
"description": "Branch Metrics Cordova SDK",
44
"main": "src/index.js",
5-
"version": "5.1.0",
5+
"version": "5.2.0",
66
"homepage": "https://github.com/BranchMetrics/cordova-ionic-phonegap-branch-deep-linking",
77
"repository": {
88
"type": "git",

plugin.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ SOFTWARE.
6363
<!-- Manifest configuration is done via a js script. We should move it to this config in the future. -->
6464

6565
<source-file src="src/android/io/branch/BranchSDK.java" target-dir="src/io/branch" />
66-
<framework src="io.branch.sdk.android:library:5.1.5"/>
66+
<framework src="io.branch.sdk.android:library:5.2.0"/>
6767
</platform>
6868

6969
<!-- iOS -->
@@ -87,7 +87,7 @@ SOFTWARE.
8787
<source url="https://cdn.cocoapods.org/"/>
8888
</config>
8989
<pods>
90-
<pod name="Branch" spec="~> 1.42.0" />
90+
<pod name="Branch" spec="~> 1.43.1" />
9191
</pods>
9292
</podspec>
9393
</platform>

src/android/io/branch/BranchSDK.java

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import android.net.Uri;
77
import android.os.Build;
88
import android.util.Log;
9+
import android.util.Base64;
910

1011
import org.apache.cordova.CallbackContext;
1112
import org.apache.cordova.CordovaPlugin;
@@ -16,6 +17,7 @@
1617

1718
import java.util.ArrayList;
1819
import java.util.Iterator;
20+
import java.io.IOException;
1921

2022
import io.branch.indexing.BranchUniversalObject;
2123
import io.branch.referral.Branch;
@@ -24,13 +26,15 @@
2426
import io.branch.referral.ServerRequestGetCPID.BranchCrossPlatformIdListener;
2527
import io.branch.referral.ServerRequestGetLATD.BranchLastAttributedTouchDataListener;
2628
import io.branch.referral.SharingHelper;
29+
import io.branch.referral.QRCode.BranchQRCode;
2730
import io.branch.referral.util.BRANCH_STANDARD_EVENT;
2831
import io.branch.referral.util.BranchCPID;
2932
import io.branch.referral.util.BranchEvent;
3033
import io.branch.referral.util.ContentMetadata;
3134
import io.branch.referral.util.CurrencyType;
3235
import io.branch.referral.util.ShareSheetStyle;
3336

37+
3438
public class BranchSDK extends CordovaPlugin {
3539

3640
static class BranchLinkProperties extends io.branch.referral.util.LinkProperties {
@@ -137,14 +141,14 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
137141
return true;
138142
} else if (action.equals("userCompletedAction")) {
139143
if (args.length() < 1 && args.length() > 2) {
140-
callbackContext.error(String.format("Parameter mismatched. 1-2 is required but %d is given", args.length()));
144+
callbackContext.error(String.format("Parameter count mismatch"));
141145
return false;
142146
}
143147
cordova.getActivity().runOnUiThread(r);
144148
return true;
145149
} else if (action.equals("sendBranchEvent")) {
146150
if (args.length() < 1 && args.length() > 2) {
147-
callbackContext.error(String.format("Parameter mismatched. 1-2 is required but %d is given", args.length()));
151+
callbackContext.error(String.format("Parameter count mismatch"));
148152
return false;
149153
}
150154
cordova.getActivity().runOnUiThread(r);
@@ -160,7 +164,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
160164
return true;
161165
} else if (action.equals("createBranchUniversalObject")) {
162166
if (args.length() != 1) {
163-
callbackContext.error(String.format("Parameter mismatched. 1 is required but %d is given", args.length()));
167+
callbackContext.error(String.format("Parameter count mismatch"));
164168
return false;
165169
}
166170
cordova.getActivity().runOnUiThread(r);
@@ -176,21 +180,21 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
176180

177181
} else if (action.equals(("generateShortUrl"))) {
178182
if (args.length() != 3) {
179-
callbackContext.error(String.format("Parameter mismatched. 3 is required but %d is given", args.length()));
183+
callbackContext.error(String.format("Parameter count mismatch"));
180184
return false;
181185
}
182186
cordova.getActivity().runOnUiThread(r);
183187
return true;
184188
} else if (action.equals("registerView")) {
185189
if (args.length() != 1) {
186-
callbackContext.error(String.format("Parameter mismatched. 1 is required but %d is given", args.length()));
190+
callbackContext.error(String.format("Parameter count mismatch"));
187191
return false;
188192
}
189193
cordova.getActivity().runOnUiThread(r);
190194
return true;
191195
} else if (action.equals("showShareSheet")) {
192196
if (args.length() < 3) {
193-
callbackContext.error(String.format("Parameter mismatched. 3 is required but %d is given", args.length()));
197+
callbackContext.error(String.format("Parameter count mismatch"));
194198
return false;
195199
}
196200
cordova.getActivity().runOnUiThread(r);
@@ -223,6 +227,13 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
223227

224228
branchObjectWrappers.set(args.getInt(0), branchObjWrapper);
225229

230+
} else if (action.equals("getBranchQRCode")) {
231+
if (args.length() != 4) {
232+
callbackContext.error(String.format("Parameter count mismatch"));
233+
return false;
234+
}
235+
cordova.getActivity().runOnUiThread(r);
236+
return true;
226237
}
227238

228239
return true;
@@ -508,6 +519,70 @@ private void generateShortUrl(int instanceIdx, JSONObject options, JSONObject co
508519

509520
}
510521

522+
/**
523+
* Generate a QR code.
524+
*
525+
* @param qrCodeSettings A {@link JSONObject} value to set QR cide options.
526+
* @param instanceIdx The instance index from branchObjects array
527+
* @param options A {@link JSONObject} value to set URL options.
528+
* @param controlParams A {@link JSONObject} value to set the URL control parameters.
529+
*/
530+
private void getBranchQRCode(JSONObject qrCodeSettings, int instanceIdx, JSONObject options, JSONObject controlParams, CallbackContext callbackContext) throws JSONException {
531+
532+
BranchLinkProperties linkProperties = createLinkProperties(options, controlParams);
533+
534+
BranchUniversalObjectWrapper branchUniversalWrapper = (BranchUniversalObjectWrapper) this.branchObjectWrappers.get(instanceIdx);
535+
BranchUniversalObject buo = branchUniversalWrapper.branchUniversalObj;
536+
537+
BranchQRCode branchQRCode = new BranchQRCode();
538+
if (qrCodeSettings.has("codeColor")) {
539+
branchQRCode.setCodeColor(qrCodeSettings.getString("codeColor"));
540+
}
541+
if (qrCodeSettings.has("backgroundColor")) {
542+
branchQRCode.setBackgroundColor(qrCodeSettings.getString("backgroundColor"));
543+
}
544+
if (qrCodeSettings.has("centerLogo")) {
545+
branchQRCode.setCenterLogo(qrCodeSettings.getString("centerLogo"));
546+
}
547+
if (qrCodeSettings.has("width")) {
548+
branchQRCode.setWidth(qrCodeSettings.getInt("width"));
549+
}
550+
if (qrCodeSettings.has("margin")) {
551+
branchQRCode.setMargin(qrCodeSettings.getInt("margin"));
552+
}
553+
if (qrCodeSettings.has("imageFormat")) {
554+
String imageFormat = qrCodeSettings.getString("imageFormat");
555+
if (imageFormat != null ) {
556+
if (imageFormat.equals("JPEG")) {
557+
branchQRCode.setImageFormat(BranchQRCode.BranchImageFormat.JPEG);
558+
} else {
559+
branchQRCode.setImageFormat(BranchQRCode.BranchImageFormat.PNG);
560+
}
561+
}
562+
}
563+
564+
try {
565+
branchQRCode.getQRCodeAsData(this.activity, buo, linkProperties, new BranchQRCode.BranchQRCodeDataHandler() {
566+
@Override
567+
public void onSuccess(byte[] qrCodeData) {
568+
String qrCodeString = Base64.encodeToString(qrCodeData, Base64.DEFAULT);
569+
Log.d(LCAT, qrCodeString);
570+
callbackContext.success(qrCodeString);
571+
}
572+
573+
@Override
574+
public void onFailure(Exception e) {
575+
Log.d(LCAT, e.getMessage());
576+
callbackContext.error(e.getMessage());
577+
}
578+
});
579+
} catch (IOException e) {
580+
e.printStackTrace();
581+
Log.d(LCAT, e.getMessage());
582+
callbackContext.error(e.getMessage());
583+
}
584+
}
585+
511586
/**
512587
* <p>Sets the cookie based matching for all incoming requests.</p>
513588
* <p>If you want cookie based matching, call this <b>before</b> initUserSession</p>
@@ -1017,7 +1092,7 @@ public void onLinkCreate(String url, BranchError error) {
10171092
}
10181093

10191094
}
1020-
1095+
10211096
protected class ShowShareSheetListener implements Branch.BranchLinkShareListener {
10221097

10231098
private CallbackContext _onShareLinkDialogLaunched;
@@ -1197,6 +1272,8 @@ public void run() {
11971272
lastAttributedTouchData(this.callbackContext);
11981273
} else if (this.action.equals(("generateShortUrl"))) {
11991274
generateShortUrl(this.args.getInt(0), this.args.getJSONObject(1), this.args.getJSONObject(2), this.callbackContext);
1275+
} else if (this.action.equals(("getBranchQRCode"))) {
1276+
getBranchQRCode(this.args.getJSONObject(0), this.args.getInt(1), this.args.getJSONObject(2), this.args.getJSONObject(3), this.callbackContext);
12001277
} else if (this.action.equals("registerView")) {
12011278
registerView(this.args.getInt(0), this.callbackContext);
12021279
} else if (this.action.equals("showShareSheet")) {

src/index.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ var Branch = function Branch() {
3939
this.sessionInitialized = false;
4040
};
4141

42-
// JavsSript to SDK wrappers
42+
// JavaScript to SDK wrappers
4343
function execute(method, params) {
4444
var output = !params ? [] : params;
4545

@@ -314,5 +314,29 @@ Branch.prototype.lastAttributedTouchData = function lastAttributedTouchData() {
314314
return execute("lastAttributedTouchData");
315315
};
316316

317+
Branch.prototype.getBranchQRCode = function getBranchQRCode(
318+
qrCodeSettings,
319+
branchUniversalObject,
320+
analytics,
321+
properties
322+
) {
323+
var args = [];
324+
if (qrCodeSettings) {
325+
args.push(qrCodeSettings);
326+
}
327+
if (branchUniversalObject) {
328+
args.push(branchUniversalObject.instanceId);
329+
}
330+
if (analytics) {
331+
args.push(analytics);
332+
}
333+
if (properties) {
334+
args.push(properties);
335+
}
336+
337+
return execute("getBranchQRCode", args);
338+
};
339+
340+
317341
// export Branch object
318342
module.exports = new Branch();

src/ios/BranchSDK.m

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,129 @@ - (void)lastAttributedTouchData:(CDVInvokedUrlCommand *)command {
648648
}];
649649
}
650650

651+
- (void)getBranchQRCode:(CDVInvokedUrlCommand*)command
652+
{
653+
int branchUniversalObjectId = [[command.arguments objectAtIndex:1] intValue];
654+
NSMutableDictionary *branchUniversalObjDict = [self.branchUniversalObjArray objectAtIndex:branchUniversalObjectId];
655+
BranchUniversalObject *branchUniversalObj = [branchUniversalObjDict objectForKey:@"branchUniversalObj"];
656+
657+
BranchLinkProperties *linkProperties = [BranchLinkProperties new];
658+
659+
NSDictionary *arg1 = [command.arguments objectAtIndex:2];
660+
NSDictionary *arg2 = [command.arguments objectAtIndex:3];
661+
662+
for (id key in arg1) {
663+
if ([key isEqualToString:@"duration"]) {
664+
linkProperties.matchDuration = (NSUInteger)[((NSNumber *)[arg1 objectForKey:key]) integerValue];
665+
}
666+
else if ([key isEqualToString:@"feature"]) {
667+
linkProperties.feature = [arg1 objectForKey:key];
668+
}
669+
else if ([key isEqualToString:@"stage"]) {
670+
linkProperties.stage = [arg1 objectForKey:key];
671+
}
672+
else if ([key isEqualToString:@"campaign"]) {
673+
linkProperties.campaign = [arg1 objectForKey:key];
674+
}
675+
else if ([key isEqualToString:@"alias"]) {
676+
linkProperties.alias = [arg1 objectForKey:key];
677+
}
678+
else if ([key isEqualToString:@"channel"]) {
679+
linkProperties.channel = [arg1 objectForKey:key];
680+
}
681+
else if ([key isEqualToString:@"tags"] && [[arg1 objectForKey:key] isKindOfClass:[NSArray class]]) {
682+
linkProperties.tags = [arg1 objectForKey:key];
683+
}
684+
}
685+
if (arg2) {
686+
for (id key in arg2) {
687+
[linkProperties addControlParam:key withValue:[arg2 objectForKey:key]];
688+
}
689+
}
690+
691+
NSMutableDictionary *qrCodeSettingsMap = [command.arguments objectAtIndex:0];
692+
693+
BranchQRCode *qrCode = [BranchQRCode new];
694+
695+
if (qrCodeSettingsMap[@"codeColor"]) {
696+
qrCode.codeColor = [self colorWithHexString:qrCodeSettingsMap[@"codeColor"]];
697+
}
698+
if (qrCodeSettingsMap[@"backgroundColor"]) {
699+
qrCode.backgroundColor = [self colorWithHexString:qrCodeSettingsMap[@"backgroundColor"]];
700+
}
701+
if (qrCodeSettingsMap[@"centerLogo"]) {
702+
qrCode.centerLogo = qrCodeSettingsMap[@"centerLogo"];
703+
}
704+
if (qrCodeSettingsMap[@"width"]) {
705+
qrCode.width = qrCodeSettingsMap[@"width"];
706+
}
707+
if (qrCodeSettingsMap[@"margin"]) {
708+
qrCode.margin = qrCodeSettingsMap[@"margin"];
709+
}
710+
if (qrCodeSettingsMap[@"imageFormat"]) {
711+
if ([qrCodeSettingsMap[@"imageFormat"] isEqual:@"JPEG"]) {
712+
qrCode.imageFormat = BranchQRCodeImageFormatJPEG;
713+
} else {
714+
qrCode.imageFormat = BranchQRCodeImageFormatPNG;
715+
}
716+
}
717+
718+
[qrCode getQRCodeAsData:branchUniversalObj linkProperties:linkProperties completion:^(NSData * _Nonnull qrCodeData, NSError * _Nonnull error) {
719+
CDVPluginResult* pluginResult = nil;
720+
721+
if (!error) {
722+
NSString* imageString = [qrCodeData base64EncodedStringWithOptions:nil];
723+
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:imageString];
724+
} else {
725+
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[error localizedDescription]];
726+
}
727+
728+
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
729+
}];
730+
}
731+
732+
- (UIColor *) colorWithHexString: (NSString *) hexString {
733+
NSString *colorString = [[hexString stringByReplacingOccurrencesOfString: @"#" withString: @""] uppercaseString];
734+
CGFloat alpha, red, blue, green;
735+
switch ([colorString length]) {
736+
case 3: // #RGB
737+
alpha = 1.0f;
738+
red = [self colorComponentFrom: colorString start: 0 length: 1];
739+
green = [self colorComponentFrom: colorString start: 1 length: 1];
740+
blue = [self colorComponentFrom: colorString start: 2 length: 1];
741+
break;
742+
case 4: // #ARGB
743+
alpha = [self colorComponentFrom: colorString start: 0 length: 1];
744+
red = [self colorComponentFrom: colorString start: 1 length: 1];
745+
green = [self colorComponentFrom: colorString start: 2 length: 1];
746+
blue = [self colorComponentFrom: colorString start: 3 length: 1];
747+
break;
748+
case 6: // #RRGGBB
749+
alpha = 1.0f;
750+
red = [self colorComponentFrom: colorString start: 0 length: 2];
751+
green = [self colorComponentFrom: colorString start: 2 length: 2];
752+
blue = [self colorComponentFrom: colorString start: 4 length: 2];
753+
break;
754+
case 8: // #AARRGGBB
755+
alpha = [self colorComponentFrom: colorString start: 0 length: 2];
756+
red = [self colorComponentFrom: colorString start: 2 length: 2];
757+
green = [self colorComponentFrom: colorString start: 4 length: 2];
758+
blue = [self colorComponentFrom: colorString start: 6 length: 2];
759+
break;
760+
default:
761+
NSLog(@"Error: Invalid color value. It should be a hex value of the form #RBG, #ARGB, #RRGGBB, or #AARRGGBB");
762+
break;
763+
}
764+
return [UIColor colorWithRed: red green: green blue: blue alpha: alpha];
765+
}
766+
767+
- (CGFloat) colorComponentFrom: (NSString *) string start: (NSUInteger) start length: (NSUInteger) length {
768+
NSString *substring = [string substringWithRange: NSMakeRange(start, length)];
769+
NSString *fullHex = length == 2 ? substring : [NSString stringWithFormat: @"%@%@", substring, substring];
770+
unsigned hexComponent;
771+
[[NSScanner scannerWithString: fullHex] scanHexInt: &hexComponent];
772+
return hexComponent / 255.0;
773+
}
651774

652775
#pragma mark - URL Methods (not fully implemented YET!)
653776

0 commit comments

Comments
 (0)