Skip to content

Commit

Permalink
Merge pull request #8 from blinkcard/release/v2.9.1
Browse files Browse the repository at this point in the history
Release/v2.9.1
  • Loading branch information
mparadina authored May 14, 2024
2 parents 6adb56f + 12f6b9b commit 88af5e3
Show file tree
Hide file tree
Showing 14 changed files with 744 additions and 225 deletions.
2 changes: 1 addition & 1 deletion BlinkCard/blinkcard-react-native.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ Pod::Spec.new do |s|
s.source = { :git => "https://github.com/BlinkCard/blinkcard-react-native.git", :tag => "v#{s.version}" }
s.source_files = "src/ios", "src/ios/**/*.{h,m}"
s.dependency 'React'
s.dependency 'MBBlinkCard', '~> 2.9.0'
s.dependency 'MBBlinkCard', '~> 2.9.1'
s.frameworks = 'UIKit'
end
69 changes: 69 additions & 0 deletions BlinkCard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,33 @@ const BlinkCardNative = Platform.select({
* licensee: String,
* showTrialLicenseKeyWarning: Boolean
* }
*
* -> 'scanWithDirectApi' takes the following parameters:
* 1. RecognizerCollection recognizerCollection: object containing recognizers to use for scanning
* 2. String frontImage: a Base64 format string that represents the image of the card where the card number is located that will be used for processing with DirectAPI
* 3. String backImage: a Base64 format string that represents the second side of the card that will be used for processing with DirectAPI
* - backImage parameter is optional for cards that have all of the information located on one side, or if the BlinkCardRecognizer information extraction
* settings, that are enabled, are located only on one side of the card
* - Pass 'null' or an empty string "" for this parameter in this case
* 4. String license: BlinkCard base64 license key bound to application ID for Android or iOS. To obtain
* valid license key, please visit http://microblink.com/login or
* contact us at http://help.microblink.com
*
* OR
*
* Object license: containing:
* - mandatory parameter 'licenseKey': base64 license key bound to application ID
* for Android or iOS. To obtain valid license key, please visit
* http://microblink.com/login or contact us at http://help.microblink.com
* - optioanl parameter 'licensee' when license for multiple apps is used
* - optional flag 'showTrialLicenseKeyWarning' which indicates
* whether warning for trial license key will be shown
* in format
* {
* licenseKey: '<base64iOSLicense or base64AndroidLicense>',
* licensee: String,
* showTrialLicenseKeyWarning: Boolean
* }
*/
class BlinkCardWrapper {
async scanWithCamera(overlaySettings, recognizerCollection, license) {
Expand Down Expand Up @@ -66,6 +93,48 @@ class BlinkCardWrapper {
return [];
}
}

async scanWithDirectApi(recognizerCollection, frontImage, backImage, license) {
try {
var licenseObject = license;
if (typeof license === 'string' || license instanceof String) {
licenseObject = { licenseKey: license };
}

var frontImageObject = frontImage;
if (typeof frontImage === 'string' || frontImage instanceof String) {
frontImageObject = { frontImage: frontImage };
}

var backImageObject = backImage;
if (typeof backImage === 'string' || backImage instanceof String) {
backImageObject = { backImage: backImage };
}

const nativeResults = await BlinkCardNative.scanWithDirectApi(recognizerCollection, frontImageObject, backImageObject, licenseObject);
if (nativeResults.length != recognizerCollection.recognizerArray.length) {
console.log("INTERNAL ERROR: native plugin returned wrong number of results!");
return [];
} else {
let results = [];
for (let i = 0; i < nativeResults.length; ++i) {
// native plugin must ensure types match
// recognizerCollection.recognizerArray[i].result = recognizerCollection.recognizerArray[i].createResultFromNative(nativeResults[i]);

// unlike Cordova, ReactNative does not allow mutation of user-provided recognizers, so we need to
// return results and let user handle them manually.
let result = recognizerCollection.recognizerArray[i].createResultFromNative(nativeResults[i]);
if (result.resultState != RecognizerResultState.empty) {
results.push(result);
}
}
return results;
}
} catch (error) {
console.log(error);
return [];
}
}
}

export var BlinkCard = new BlinkCardWrapper();
Expand Down
2 changes: 1 addition & 1 deletion BlinkCard/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion BlinkCard/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@microblink/blinkcard-react-native",
"version": "2.9.0",
"version": "2.9.1",
"description": "AI-driven credit card scanning for cross-platform apps built with ReactNative.",
"main": "index.js",
"repository": {
Expand Down
7 changes: 3 additions & 4 deletions BlinkCard/src/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ rootProject.allprojects {
apply plugin: 'com.android.library'

android {
compileSdkVersion 33
buildToolsVersion "28.0.3"
compileSdkVersion 34

defaultConfig {
minSdkVersion 21
targetSdkVersion 33
targetSdkVersion 34
}
buildTypes {
release {
Expand All @@ -26,7 +25,7 @@ android {

dependencies {
implementation 'com.facebook.react:react-native:+'
implementation('com.microblink:blinkcard:2.9.0@aar') {
implementation('com.microblink:blinkcard:2.9.3@aar') {
transitive = true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import android.app.Activity;
import android.content.Intent;
import androidx.annotation.NonNull;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;

import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.BaseActivityEventListener;
Expand All @@ -20,6 +24,13 @@
import com.microblink.blinkcard.reactnative.overlays.OverlaySettingsSerializers;
import com.microblink.blinkcard.uisettings.ActivityRunner;
import com.microblink.blinkcard.locale.LanguageUtils;
import com.microblink.blinkcard.directApi.DirectApiErrorListener;
import com.microblink.blinkcard.directApi.RecognizerRunner;
import com.microblink.blinkcard.hardware.orientation.Orientation;
import com.microblink.blinkcard.metadata.MetadataCallbacks;
import com.microblink.blinkcard.metadata.recognition.FirstSideRecognitionCallback;
import com.microblink.blinkcard.recognition.RecognitionSuccessType;
import com.microblink.blinkcard.view.recognition.ScanResultListener;

import com.microblink.blinkcard.uisettings.UISettings;
import com.microblink.blinkcard.reactnative.recognizers.RecognizerSerializers;
Expand All @@ -37,6 +48,8 @@ public class MicroblinkModule extends ReactContextBaseJavaModule {
private static final String PARAM_LICENSE_KEY = "licenseKey";
private static final String PARAM_LICENSEE = "licensee";
private static final String PARAM_SHOW_TRIAL_LICENSE_WARNING = "showTrialLicenseKeyWarning";
private static final String PARAM_FRONT_IMAGE = "frontImage";
private static final String PARAM_BACK_IMAGE = "backImage";

/**
* Request code for scan activity
Expand All @@ -45,6 +58,8 @@ public class MicroblinkModule extends ReactContextBaseJavaModule {

private Promise mScanPromise;
private RecognizerBundle mRecognizerBundle;
private RecognizerRunner mRecognizerRunner;
private boolean mFirstSideScanned = false;

public MicroblinkModule(ReactApplicationContext reactContext) {
super(reactContext);
Expand All @@ -71,6 +86,70 @@ public void scanWithCamera(ReadableMap jsonOverlaySettings, ReadableMap jsonReco
ActivityRunner.startActivityForResult(getCurrentActivity(), REQUEST_CODE, overlaySettings);
}

@ReactMethod
private void scanWithDirectApi(ReadableMap jsonRecognizerCollection, ReadableMap frontImage, ReadableMap backImage, ReadableMap license, Promise promise) {
//DirectAPI processing
mScanPromise = promise;
prepareScanning(license, promise);

ScanResultListener mScanResultListenerBackSide = new ScanResultListener() {
@Override
public void onScanningDone(@NonNull RecognitionSuccessType recognitionSuccessType) {
mFirstSideScanned = false;
handleDirectApiResult(recognitionSuccessType);
}
@Override
public void onUnrecoverableError(@NonNull Throwable throwable) {
promise.reject(throwable);
}
};

FirstSideRecognitionCallback mFirstSideRecognitionCallback = new FirstSideRecognitionCallback() {
@Override
public void onFirstSideRecognitionFinished() {
mFirstSideScanned = true;
}
};

ScanResultListener mScanResultListenerFrontSide = new ScanResultListener() {
@Override
public void onScanningDone(@NonNull RecognitionSuccessType recognitionSuccessType) {
if (mFirstSideScanned == true) {
//multiside recognizer used
try {
if (backImage != null) {
processImage(backImage.getString(PARAM_BACK_IMAGE), mScanResultListenerBackSide);
} else if (recognitionSuccessType != RecognitionSuccessType.UNSUCCESSFUL) {
handleDirectApiResult(recognitionSuccessType);
} else {
handleDirectApiError("Could not extract the information from the front side and back side is empty!", promise);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
} else if (mFirstSideScanned == false && recognitionSuccessType != RecognitionSuccessType.UNSUCCESSFUL){
//singleside recognizer used
handleDirectApiResult(recognitionSuccessType);
} else {
mFirstSideScanned = false;
handleDirectApiError("Could not extract the information with DirectAPI!", promise);
}
}
@Override
public void onUnrecoverableError(@NonNull Throwable throwable) {
promise.reject(throwable);
}
};

setupRecognizerRunner(jsonRecognizerCollection, mFirstSideRecognitionCallback, promise);

if (frontImage != null) {
processImage(frontImage.getString(PARAM_FRONT_IMAGE), mScanResultListenerFrontSide);
} else {
handleDirectApiError("The provided image for the 'frontImage' parameter is empty!", promise);
}
}

private void prepareScanning(ReadableMap license, Promise promise) {
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
Expand All @@ -96,6 +175,64 @@ private void prepareScanning(ReadableMap license, Promise promise) {
setLicense(licenseKey, licensee, showTrialLicenseKeyWarning);
}

private void setupRecognizerRunner(ReadableMap jsonRecognizerCollection, FirstSideRecognitionCallback mFirstSideRecognitionCallback, Promise promise) {
if (mRecognizerRunner != null) {
mRecognizerRunner.terminate();
}

mRecognizerBundle = RecognizerSerializers.INSTANCE.deserializeRecognizerCollection(jsonRecognizerCollection);

try {
mRecognizerRunner = RecognizerRunner.getSingletonInstance();
} catch (Exception e) {
handleDirectApiError("DirectAPI not support: " + e.getMessage(), promise);
}

MetadataCallbacks metadataCallbacks = new MetadataCallbacks();
metadataCallbacks.setFirstSideRecognitionCallback(mFirstSideRecognitionCallback);
mRecognizerRunner.setMetadataCallbacks(metadataCallbacks);
mRecognizerRunner.initialize(getCurrentActivity(), mRecognizerBundle, new DirectApiErrorListener() {
@Override
public void onRecognizerError(@NonNull Throwable throwable) {
handleDirectApiError("Failed to initialize recognizer with DirectAPI: " + throwable.getMessage(), promise);
}
});
}

private void processImage(String base64Image, ScanResultListener scanResultListener) {
Bitmap image = base64ToBitmap(base64Image);
if (image != null) {
mRecognizerRunner.recognizeBitmap(
base64ToBitmap(base64Image),
Orientation.ORIENTATION_LANDSCAPE_RIGHT,
scanResultListener
);
} else {
handleDirectApiError("Could not decode the Base64 image!", mScanPromise);
}
}

private void handleDirectApiResult(RecognitionSuccessType recognitionSuccessType) {
if (recognitionSuccessType != RecognitionSuccessType.UNSUCCESSFUL) {
WritableArray resultList = RecognizerSerializers.INSTANCE.serializeRecognizerResults(mRecognizerBundle.getRecognizers());
mScanPromise.resolve(resultList);
} else {
handleDirectApiError("Unexpected error with DirectAPI scanning", mScanPromise);
}
}

private void handleDirectApiError(String errorMessage, Promise promise) {
promise.reject(errorMessage);
if (mRecognizerRunner != null) {
mRecognizerRunner.resetRecognitionState(true);
}
}

private Bitmap base64ToBitmap(String base64String) {
byte[] decodedBytes = Base64.decode(base64String, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
}

private void setLicense( String licenseKey, String licensee, Boolean showTrialLicenseKeyWarning ) {
if (showTrialLicenseKeyWarning != null) {
MicroblinkSDK.setShowTrialLicenseWarning(showTrialLicenseKeyWarning);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,4 @@ public static WritableMap serializeDocumentLivenessCheckResult(DocumentLivenessC
public static MatchLevel deserializeMatchLevel(int value) {
return MatchLevel.values()[value];
}

}
Loading

0 comments on commit 88af5e3

Please sign in to comment.