Skip to content

Commit

Permalink
Merge pull request #711 from BranchMetrics/SDK-1407
Browse files Browse the repository at this point in the history
[SDK-1407] Add Branch QR code methods
  • Loading branch information
nsingh-branch authored Aug 8, 2022
2 parents 103cfb5 + 10b5cda commit 5d7361f
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 11 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ npm-debug.log*
yarn-error.log*
.vscode
.idea
cordova-ionic-phonegap-branch-deep-linking-attribution.iml
src/android/.idea
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "branch-cordova-sdk",
"description": "Branch Metrics Cordova SDK",
"main": "src/index.js",
"version": "5.1.0",
"version": "5.2.0",
"homepage": "https://github.com/BranchMetrics/cordova-ionic-phonegap-branch-deep-linking",
"repository": {
"type": "git",
Expand Down
4 changes: 2 additions & 2 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ SOFTWARE.
<!-- Manifest configuration is done via a js script. We should move it to this config in the future. -->

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

<!-- iOS -->
Expand All @@ -87,7 +87,7 @@ SOFTWARE.
<source url="https://cdn.cocoapods.org/"/>
</config>
<pods>
<pod name="Branch" spec="~> 1.42.0" />
<pod name="Branch" spec="~> 1.43.1" />
</pods>
</podspec>
</platform>
Expand Down
91 changes: 84 additions & 7 deletions src/android/io/branch/BranchSDK.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import android.util.Base64;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
Expand All @@ -16,6 +17,7 @@

import java.util.ArrayList;
import java.util.Iterator;
import java.io.IOException;

import io.branch.indexing.BranchUniversalObject;
import io.branch.referral.Branch;
Expand All @@ -24,13 +26,15 @@
import io.branch.referral.ServerRequestGetCPID.BranchCrossPlatformIdListener;
import io.branch.referral.ServerRequestGetLATD.BranchLastAttributedTouchDataListener;
import io.branch.referral.SharingHelper;
import io.branch.referral.QRCode.BranchQRCode;
import io.branch.referral.util.BRANCH_STANDARD_EVENT;
import io.branch.referral.util.BranchCPID;
import io.branch.referral.util.BranchEvent;
import io.branch.referral.util.ContentMetadata;
import io.branch.referral.util.CurrencyType;
import io.branch.referral.util.ShareSheetStyle;


public class BranchSDK extends CordovaPlugin {

static class BranchLinkProperties extends io.branch.referral.util.LinkProperties {
Expand Down Expand Up @@ -137,14 +141,14 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
return true;
} else if (action.equals("userCompletedAction")) {
if (args.length() < 1 && args.length() > 2) {
callbackContext.error(String.format("Parameter mismatched. 1-2 is required but %d is given", args.length()));
callbackContext.error(String.format("Parameter count mismatch"));
return false;
}
cordova.getActivity().runOnUiThread(r);
return true;
} else if (action.equals("sendBranchEvent")) {
if (args.length() < 1 && args.length() > 2) {
callbackContext.error(String.format("Parameter mismatched. 1-2 is required but %d is given", args.length()));
callbackContext.error(String.format("Parameter count mismatch"));
return false;
}
cordova.getActivity().runOnUiThread(r);
Expand All @@ -160,7 +164,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
return true;
} else if (action.equals("createBranchUniversalObject")) {
if (args.length() != 1) {
callbackContext.error(String.format("Parameter mismatched. 1 is required but %d is given", args.length()));
callbackContext.error(String.format("Parameter count mismatch"));
return false;
}
cordova.getActivity().runOnUiThread(r);
Expand All @@ -176,21 +180,21 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo

} else if (action.equals(("generateShortUrl"))) {
if (args.length() != 3) {
callbackContext.error(String.format("Parameter mismatched. 3 is required but %d is given", args.length()));
callbackContext.error(String.format("Parameter count mismatch"));
return false;
}
cordova.getActivity().runOnUiThread(r);
return true;
} else if (action.equals("registerView")) {
if (args.length() != 1) {
callbackContext.error(String.format("Parameter mismatched. 1 is required but %d is given", args.length()));
callbackContext.error(String.format("Parameter count mismatch"));
return false;
}
cordova.getActivity().runOnUiThread(r);
return true;
} else if (action.equals("showShareSheet")) {
if (args.length() < 3) {
callbackContext.error(String.format("Parameter mismatched. 3 is required but %d is given", args.length()));
callbackContext.error(String.format("Parameter count mismatch"));
return false;
}
cordova.getActivity().runOnUiThread(r);
Expand Down Expand Up @@ -223,6 +227,13 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo

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

} else if (action.equals("getBranchQRCode")) {
if (args.length() != 4) {
callbackContext.error(String.format("Parameter count mismatch"));
return false;
}
cordova.getActivity().runOnUiThread(r);
return true;
}

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

}

/**
* Generate a QR code.
*
* @param qrCodeSettings A {@link JSONObject} value to set QR cide options.
* @param instanceIdx The instance index from branchObjects array
* @param options A {@link JSONObject} value to set URL options.
* @param controlParams A {@link JSONObject} value to set the URL control parameters.
*/
private void getBranchQRCode(JSONObject qrCodeSettings, int instanceIdx, JSONObject options, JSONObject controlParams, CallbackContext callbackContext) throws JSONException {

BranchLinkProperties linkProperties = createLinkProperties(options, controlParams);

BranchUniversalObjectWrapper branchUniversalWrapper = (BranchUniversalObjectWrapper) this.branchObjectWrappers.get(instanceIdx);
BranchUniversalObject buo = branchUniversalWrapper.branchUniversalObj;

BranchQRCode branchQRCode = new BranchQRCode();
if (qrCodeSettings.has("codeColor")) {
branchQRCode.setCodeColor(qrCodeSettings.getString("codeColor"));
}
if (qrCodeSettings.has("backgroundColor")) {
branchQRCode.setBackgroundColor(qrCodeSettings.getString("backgroundColor"));
}
if (qrCodeSettings.has("centerLogo")) {
branchQRCode.setCenterLogo(qrCodeSettings.getString("centerLogo"));
}
if (qrCodeSettings.has("width")) {
branchQRCode.setWidth(qrCodeSettings.getInt("width"));
}
if (qrCodeSettings.has("margin")) {
branchQRCode.setMargin(qrCodeSettings.getInt("margin"));
}
if (qrCodeSettings.has("imageFormat")) {
String imageFormat = qrCodeSettings.getString("imageFormat");
if (imageFormat != null ) {
if (imageFormat.equals("JPEG")) {
branchQRCode.setImageFormat(BranchQRCode.BranchImageFormat.JPEG);
} else {
branchQRCode.setImageFormat(BranchQRCode.BranchImageFormat.PNG);
}
}
}

try {
branchQRCode.getQRCodeAsData(this.activity, buo, linkProperties, new BranchQRCode.BranchQRCodeDataHandler() {
@Override
public void onSuccess(byte[] qrCodeData) {
String qrCodeString = Base64.encodeToString(qrCodeData, Base64.DEFAULT);
Log.d(LCAT, qrCodeString);
callbackContext.success(qrCodeString);
}

@Override
public void onFailure(Exception e) {
Log.d(LCAT, e.getMessage());
callbackContext.error(e.getMessage());
}
});
} catch (IOException e) {
e.printStackTrace();
Log.d(LCAT, e.getMessage());
callbackContext.error(e.getMessage());
}
}

/**
* <p>Sets the cookie based matching for all incoming requests.</p>
* <p>If you want cookie based matching, call this <b>before</b> initUserSession</p>
Expand Down Expand Up @@ -1017,7 +1092,7 @@ public void onLinkCreate(String url, BranchError error) {
}

}

protected class ShowShareSheetListener implements Branch.BranchLinkShareListener {

private CallbackContext _onShareLinkDialogLaunched;
Expand Down Expand Up @@ -1197,6 +1272,8 @@ public void run() {
lastAttributedTouchData(this.callbackContext);
} else if (this.action.equals(("generateShortUrl"))) {
generateShortUrl(this.args.getInt(0), this.args.getJSONObject(1), this.args.getJSONObject(2), this.callbackContext);
} else if (this.action.equals(("getBranchQRCode"))) {
getBranchQRCode(this.args.getJSONObject(0), this.args.getInt(1), this.args.getJSONObject(2), this.args.getJSONObject(3), this.callbackContext);
} else if (this.action.equals("registerView")) {
registerView(this.args.getInt(0), this.callbackContext);
} else if (this.action.equals("showShareSheet")) {
Expand Down
26 changes: 25 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ var Branch = function Branch() {
this.sessionInitialized = false;
};

// JavsSript to SDK wrappers
// JavaScript to SDK wrappers
function execute(method, params) {
var output = !params ? [] : params;

Expand Down Expand Up @@ -314,5 +314,29 @@ Branch.prototype.lastAttributedTouchData = function lastAttributedTouchData() {
return execute("lastAttributedTouchData");
};

Branch.prototype.getBranchQRCode = function getBranchQRCode(
qrCodeSettings,
branchUniversalObject,
analytics,
properties
) {
var args = [];
if (qrCodeSettings) {
args.push(qrCodeSettings);
}
if (branchUniversalObject) {
args.push(branchUniversalObject.instanceId);
}
if (analytics) {
args.push(analytics);
}
if (properties) {
args.push(properties);
}

return execute("getBranchQRCode", args);
};


// export Branch object
module.exports = new Branch();
123 changes: 123 additions & 0 deletions src/ios/BranchSDK.m
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,129 @@ - (void)lastAttributedTouchData:(CDVInvokedUrlCommand *)command {
}];
}

- (void)getBranchQRCode:(CDVInvokedUrlCommand*)command
{
int branchUniversalObjectId = [[command.arguments objectAtIndex:1] intValue];
NSMutableDictionary *branchUniversalObjDict = [self.branchUniversalObjArray objectAtIndex:branchUniversalObjectId];
BranchUniversalObject *branchUniversalObj = [branchUniversalObjDict objectForKey:@"branchUniversalObj"];

BranchLinkProperties *linkProperties = [BranchLinkProperties new];

NSDictionary *arg1 = [command.arguments objectAtIndex:2];
NSDictionary *arg2 = [command.arguments objectAtIndex:3];

for (id key in arg1) {
if ([key isEqualToString:@"duration"]) {
linkProperties.matchDuration = (NSUInteger)[((NSNumber *)[arg1 objectForKey:key]) integerValue];
}
else if ([key isEqualToString:@"feature"]) {
linkProperties.feature = [arg1 objectForKey:key];
}
else if ([key isEqualToString:@"stage"]) {
linkProperties.stage = [arg1 objectForKey:key];
}
else if ([key isEqualToString:@"campaign"]) {
linkProperties.campaign = [arg1 objectForKey:key];
}
else if ([key isEqualToString:@"alias"]) {
linkProperties.alias = [arg1 objectForKey:key];
}
else if ([key isEqualToString:@"channel"]) {
linkProperties.channel = [arg1 objectForKey:key];
}
else if ([key isEqualToString:@"tags"] && [[arg1 objectForKey:key] isKindOfClass:[NSArray class]]) {
linkProperties.tags = [arg1 objectForKey:key];
}
}
if (arg2) {
for (id key in arg2) {
[linkProperties addControlParam:key withValue:[arg2 objectForKey:key]];
}
}

NSMutableDictionary *qrCodeSettingsMap = [command.arguments objectAtIndex:0];

BranchQRCode *qrCode = [BranchQRCode new];

if (qrCodeSettingsMap[@"codeColor"]) {
qrCode.codeColor = [self colorWithHexString:qrCodeSettingsMap[@"codeColor"]];
}
if (qrCodeSettingsMap[@"backgroundColor"]) {
qrCode.backgroundColor = [self colorWithHexString:qrCodeSettingsMap[@"backgroundColor"]];
}
if (qrCodeSettingsMap[@"centerLogo"]) {
qrCode.centerLogo = qrCodeSettingsMap[@"centerLogo"];
}
if (qrCodeSettingsMap[@"width"]) {
qrCode.width = qrCodeSettingsMap[@"width"];
}
if (qrCodeSettingsMap[@"margin"]) {
qrCode.margin = qrCodeSettingsMap[@"margin"];
}
if (qrCodeSettingsMap[@"imageFormat"]) {
if ([qrCodeSettingsMap[@"imageFormat"] isEqual:@"JPEG"]) {
qrCode.imageFormat = BranchQRCodeImageFormatJPEG;
} else {
qrCode.imageFormat = BranchQRCodeImageFormatPNG;
}
}

[qrCode getQRCodeAsData:branchUniversalObj linkProperties:linkProperties completion:^(NSData * _Nonnull qrCodeData, NSError * _Nonnull error) {
CDVPluginResult* pluginResult = nil;

if (!error) {
NSString* imageString = [qrCodeData base64EncodedStringWithOptions:nil];
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:imageString];
} else {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[error localizedDescription]];
}

[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}];
}

- (UIColor *) colorWithHexString: (NSString *) hexString {
NSString *colorString = [[hexString stringByReplacingOccurrencesOfString: @"#" withString: @""] uppercaseString];
CGFloat alpha, red, blue, green;
switch ([colorString length]) {
case 3: // #RGB
alpha = 1.0f;
red = [self colorComponentFrom: colorString start: 0 length: 1];
green = [self colorComponentFrom: colorString start: 1 length: 1];
blue = [self colorComponentFrom: colorString start: 2 length: 1];
break;
case 4: // #ARGB
alpha = [self colorComponentFrom: colorString start: 0 length: 1];
red = [self colorComponentFrom: colorString start: 1 length: 1];
green = [self colorComponentFrom: colorString start: 2 length: 1];
blue = [self colorComponentFrom: colorString start: 3 length: 1];
break;
case 6: // #RRGGBB
alpha = 1.0f;
red = [self colorComponentFrom: colorString start: 0 length: 2];
green = [self colorComponentFrom: colorString start: 2 length: 2];
blue = [self colorComponentFrom: colorString start: 4 length: 2];
break;
case 8: // #AARRGGBB
alpha = [self colorComponentFrom: colorString start: 0 length: 2];
red = [self colorComponentFrom: colorString start: 2 length: 2];
green = [self colorComponentFrom: colorString start: 4 length: 2];
blue = [self colorComponentFrom: colorString start: 6 length: 2];
break;
default:
NSLog(@"Error: Invalid color value. It should be a hex value of the form #RBG, #ARGB, #RRGGBB, or #AARRGGBB");
break;
}
return [UIColor colorWithRed: red green: green blue: blue alpha: alpha];
}

- (CGFloat) colorComponentFrom: (NSString *) string start: (NSUInteger) start length: (NSUInteger) length {
NSString *substring = [string substringWithRange: NSMakeRange(start, length)];
NSString *fullHex = length == 2 ? substring : [NSString stringWithFormat: @"%@%@", substring, substring];
unsigned hexComponent;
[[NSScanner scannerWithString: fullHex] scanHexInt: &hexComponent];
return hexComponent / 255.0;
}

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

Expand Down

0 comments on commit 5d7361f

Please sign in to comment.