capacitor-microblink 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  package com.otto.microblink;
2
2
 
3
3
  import android.content.Intent;
4
+ import android.os.Build;
4
5
 
5
6
  import androidx.activity.result.ActivityResult;
6
7
 
@@ -10,367 +11,214 @@ import com.getcapacitor.PluginCall;
10
11
  import com.getcapacitor.PluginMethod;
11
12
  import com.getcapacitor.annotation.ActivityCallback;
12
13
  import com.getcapacitor.annotation.CapacitorPlugin;
13
- import com.microblink.blinkcard.MicroblinkSDK;
14
- import com.microblink.blinkcard.activity.result.ResultStatus;
15
- import com.microblink.blinkcard.activity.result.ScanResult;
16
- import com.microblink.blinkcard.activity.result.contract.MbScan;
17
- import com.microblink.blinkcard.entities.recognizers.Recognizer;
18
- import com.microblink.blinkcard.entities.recognizers.RecognizerBundle;
19
- import com.microblink.blinkcard.entities.recognizers.blinkcard.BlinkCardProcessingStatus;
20
- import com.microblink.blinkcard.entities.recognizers.blinkcard.BlinkCardRecognizer;
21
- import com.microblink.blinkcard.results.date.SimpleDate;
22
- import com.microblink.blinkcard.uisettings.BlinkCardUISettings;
23
- import com.microblink.platform.CardScanResult;
24
- import com.microblink.platform.MicroblinkPlatform;
25
- import com.microblink.platform.MicroblinkPlatformCancelState;
26
- import com.microblink.platform.MicroblinkPlatformCardScanResultListener;
27
- import com.microblink.platform.MicroblinkPlatformConfig;
28
- import com.microblink.platform.MicroblinkPlatformConsent;
29
- import com.microblink.platform.MicroblinkPlatformProxySettings;
30
- import com.microblink.platform.MicroblinkPlatformResult;
31
- import com.microblink.platform.MicroblinkPlatformResultListener;
32
- import com.microblink.platform.MicroblinkPlatformServiceSettings;
33
- import com.microblink.platform.MicroblinkPlatformUiSettings;
34
-
35
- import org.json.JSONException;
36
-
37
- import java.util.HashMap;
38
- import java.util.Iterator;
39
- import java.util.Map;
14
+ import com.microblink.blinkcard.core.BlinkCardSdkSettings;
15
+ import com.microblink.blinkcard.core.result.CardAccountResult;
16
+ import com.microblink.blinkcard.core.result.DateResult;
17
+ import com.microblink.blinkcard.core.session.BlinkCardScanningResult;
18
+ import com.microblink.blinkcard.core.session.BlinkCardSessionSettings;
19
+ import com.microblink.blinkcard.core.settings.ExtractionSettings;
20
+ import com.microblink.blinkcard.core.settings.ScanningSettings;
21
+ import com.microblink.blinkcard.ux.contract.BlinkCardScanActivityResult;
22
+ import com.microblink.blinkcard.ux.contract.BlinkCardScanActivitySettings;
23
+ import com.microblink.blinkcard.ux.contract.MbBlinkCardScan;
24
+ import com.microblink.blinkcard.ux.contract.ScanActivityResultStatus;
25
+
26
+ import java.util.List;
27
+ import java.util.function.Consumer;
40
28
 
41
29
  @CapacitorPlugin(name = "Microblink")
42
30
  public class MicroblinkPlugin extends Plugin {
43
31
 
44
- private PluginCall pendingVerificationCall;
45
- private JSObject pendingVerificationCardScanResult;
32
+ private boolean isBlinkCardInitialized;
33
+ private String blinkCardLicenseKey;
34
+ private String blinkCardLicensee;
46
35
 
47
36
  @PluginMethod
48
- public void startVerification(PluginCall call) {
49
- if (pendingVerificationCall != null) {
50
- call.reject("A verification flow is already running.");
37
+ public void scanCard(PluginCall call) {
38
+ String providedLicenseKey = normalized(call.getString("licenseKey"));
39
+ String providedLicensee = normalized(call.getString("licensee"));
40
+
41
+ if (providedLicenseKey != null) {
42
+ initializeBlinkCardLicense(providedLicenseKey, providedLicensee, errorMessage -> {
43
+ if (errorMessage != null) {
44
+ call.reject(errorMessage);
45
+ return;
46
+ }
47
+ startBlinkCardScan(call, providedLicenseKey, providedLicensee);
48
+ });
51
49
  return;
52
50
  }
53
51
 
54
- String workflowId = call.getString("workflowId");
55
- String url = call.getString("url");
56
- String userId = call.getString("userId");
57
- Boolean isProcessingStoringAllowed = call.getBoolean("isProcessingStoringAllowed");
58
- Boolean isTrainingAllowed = call.getBoolean("isTrainingAllowed");
59
- String note = call.getString("note", "");
60
- Long givenOn = call.getLong("givenOn", System.currentTimeMillis());
61
-
62
- if (workflowId == null || workflowId.isEmpty()) {
63
- call.reject("Missing required field: workflowId.");
64
- return;
65
- }
66
- if (url == null || url.isEmpty()) {
67
- call.reject("Missing required field: url.");
68
- return;
69
- }
70
- if (userId == null || userId.isEmpty()) {
71
- call.reject("Missing required field: userId.");
72
- return;
73
- }
74
- if (isProcessingStoringAllowed == null) {
75
- call.reject("Missing required field: isProcessingStoringAllowed.");
76
- return;
77
- }
78
- if (isTrainingAllowed == null) {
79
- call.reject("Missing required field: isTrainingAllowed.");
52
+ if (!isBlinkCardInitialized || blinkCardLicenseKey == null) {
53
+ call.reject("BlinkCard is not initialized. Call initializeBlinkCard first or provide licenseKey in scanCard.");
80
54
  return;
81
55
  }
82
56
 
83
- MicroblinkPlatformConsent consent = new MicroblinkPlatformConsent(
84
- userId,
85
- isProcessingStoringAllowed,
86
- isTrainingAllowed,
87
- note,
88
- givenOn
89
- );
57
+ startBlinkCardScan(call, blinkCardLicenseKey, blinkCardLicensee);
58
+ }
90
59
 
91
- Map<String, String> additionalHeaders = new HashMap<>();
92
- JSObject headersObject = call.getObject("additionalRequestHeaders");
93
- if (headersObject != null) {
94
- Iterator<String> keys = headersObject.keys();
95
- while (keys.hasNext()) {
96
- String key = keys.next();
97
- try {
98
- Object rawValue = headersObject.get(key);
99
- if (rawValue != null) {
100
- additionalHeaders.put(key, String.valueOf(rawValue));
101
- }
102
- } catch (JSONException ignored) {
103
- // Ignore malformed header value.
104
- }
105
- }
60
+ @PluginMethod
61
+ public void initializeBlinkCard(PluginCall call) {
62
+ String licenseKey = normalized(call.getString("licenseKey"));
63
+ if (licenseKey == null) {
64
+ call.reject("Missing required field: licenseKey.");
65
+ return;
106
66
  }
107
67
 
108
- String startTransactionPath = call.getString("startTransactionPath", "");
109
- String cancelWorkflowPath = call.getString("cancelWorkflowPath", "");
110
- String workflowInfoPath = call.getString("workflowInfoPath", "");
111
-
112
- MicroblinkPlatformProxySettings proxySettings = new MicroblinkPlatformProxySettings(
113
- url,
114
- startTransactionPath,
115
- cancelWorkflowPath,
116
- workflowInfoPath,
117
- additionalHeaders
118
- );
119
- MicroblinkPlatformServiceSettings serviceSettings = new MicroblinkPlatformServiceSettings(
120
- workflowId,
121
- proxySettings,
122
- consent
123
- );
124
- MicroblinkPlatformUiSettings uiSettings = new MicroblinkPlatformUiSettings();
125
-
126
- MicroblinkPlatformResultListener resultListener = new MicroblinkPlatformResultListener() {
127
- @Override
128
- public void onVerificationFinished(MicroblinkPlatformResult result) {
129
- JSObject payload = new JSObject();
130
- payload.put("canceled", false);
131
- payload.put("transactionId", result.getTransactionId());
132
- payload.put("status", toResultStatus(result.getState()));
133
- if (pendingVerificationCardScanResult != null) {
134
- payload.put("cardScanResult", pendingVerificationCardScanResult);
135
- }
136
- resolvePending(payload);
68
+ String licensee = normalized(call.getString("licensee"));
69
+ initializeBlinkCardLicense(licenseKey, licensee, errorMessage -> {
70
+ if (errorMessage != null) {
71
+ call.reject(errorMessage);
72
+ return;
137
73
  }
138
74
 
139
- @Override
140
- public void onVerificationCanceled(MicroblinkPlatformCancelState cancelState) {
141
- JSObject payload = new JSObject();
142
- payload.put("canceled", true);
143
- payload.put("transactionId", cancelState.getTransactionId());
144
- payload.put("cancelReason", toCancelReason(cancelState.getCancelReason()));
145
- if (pendingVerificationCardScanResult != null) {
146
- payload.put("cardScanResult", pendingVerificationCardScanResult);
147
- }
148
- resolvePending(payload);
149
- }
150
- };
151
-
152
- MicroblinkPlatformCardScanResultListener cardScanResultListener = new MicroblinkPlatformCardScanResultListener() {
153
- @Override
154
- public void onCardScanned(CardScanResult cardResult) {
155
- JSObject cardScan = new JSObject();
156
- cardScan.put("cardNumber", cardResult.getCardNumber());
157
- cardScan.put("expiryDate", formatExpiry(cardResult));
158
- cardScan.put("owner", cardResult.getOwner());
159
- cardScan.put("cvv", cardResult.getCvv());
160
- pendingVerificationCardScanResult = cardScan;
161
- }
162
- };
163
-
164
- MicroblinkPlatformConfig config = new MicroblinkPlatformConfig(
165
- resultListener,
166
- serviceSettings,
167
- uiSettings,
168
- cardScanResultListener
169
- );
170
-
171
- pendingVerificationCall = call;
172
- pendingVerificationCardScanResult = null;
173
-
174
- if (getActivity() == null) {
175
- clearPendingState();
176
- call.reject("Unable to start verification: Activity is unavailable.");
177
- return;
178
- }
179
-
180
- getActivity().runOnUiThread(() -> MicroblinkPlatform.INSTANCE.startVerification(getActivity(), config));
75
+ JSObject payload = new JSObject();
76
+ payload.put("initialized", true);
77
+ call.resolve(payload);
78
+ });
181
79
  }
182
80
 
183
- @PluginMethod
184
- public void scanCard(PluginCall call) {
185
- if (pendingVerificationCall != null) {
186
- call.reject("A verification flow is already running.");
81
+ private void startBlinkCardScan(PluginCall call, String licenseKey, String licensee) {
82
+ if (getContext() == null) {
83
+ call.reject("Unable to start BlinkCard scan: Context is unavailable.");
187
84
  return;
188
85
  }
189
86
 
190
- String licenseKey = call.getString("licenseKey");
191
- if (licenseKey == null || licenseKey.isEmpty()) {
192
- call.reject("Missing required field: licenseKey.");
193
- return;
194
- }
195
- String licensee = call.getString("licensee");
87
+ ExtractionSettings extractionSettings = new ExtractionSettings(
88
+ call.getBoolean("extractIban", true),
89
+ call.getBoolean("extractExpiryDate", true),
90
+ call.getBoolean("extractOwner", true),
91
+ call.getBoolean("extractCvv", true),
92
+ call.getBoolean("allowInvalidCardNumber", false)
93
+ );
196
94
 
197
- try {
198
- if (licensee != null && !licensee.isEmpty()) {
199
- MicroblinkSDK.setLicenseKey(licenseKey, licensee, getContext());
200
- } else {
201
- MicroblinkSDK.setLicenseKey(licenseKey, getContext());
202
- }
203
- } catch (RuntimeException ex) {
204
- call.reject("Failed to initialize BlinkCard license: " + ex.getMessage());
205
- return;
206
- }
95
+ ScanningSettings baseScanningSettings = new ScanningSettings();
96
+ ScanningSettings scanningSettings = baseScanningSettings.copy(
97
+ baseScanningSettings.getSkipImagesWithBlur(),
98
+ baseScanningSettings.getTiltDetectionLevel(),
99
+ baseScanningSettings.getInputImageMargin(),
100
+ extractionSettings,
101
+ baseScanningSettings.getCroppedImageSettings(),
102
+ baseScanningSettings.getLivenessSettings(),
103
+ baseScanningSettings.getAnonymizationSettings()
104
+ );
207
105
 
208
- BlinkCardRecognizer recognizer = new BlinkCardRecognizer();
209
- recognizer.setExtractOwner(call.getBoolean("extractOwner", true));
210
- recognizer.setExtractExpiryDate(call.getBoolean("extractExpiryDate", true));
211
- recognizer.setExtractCvv(call.getBoolean("extractCvv", true));
212
- recognizer.setExtractIban(call.getBoolean("extractIban", true));
213
- recognizer.setAllowInvalidCardNumber(call.getBoolean("allowInvalidCardNumber", false));
106
+ BlinkCardSessionSettings baseSessionSettings = new BlinkCardSessionSettings();
107
+ BlinkCardSessionSettings sessionSettings = baseSessionSettings.copy(
108
+ baseSessionSettings.getInputImageSource(),
109
+ scanningSettings
110
+ );
214
111
 
215
- RecognizerBundle recognizerBundle = new RecognizerBundle(recognizer);
216
- BlinkCardUISettings uiSettings = new BlinkCardUISettings(recognizerBundle);
217
- uiSettings.setEditScreenEnabled(call.getBoolean("enableEditScreen", true));
112
+ BlinkCardSdkSettings sdkSettings = licensee == null
113
+ ? new BlinkCardSdkSettings(licenseKey)
114
+ : new BlinkCardSdkSettings(licenseKey, licensee);
218
115
 
219
- MbScan scanContract = new MbScan();
220
- Intent scanIntent = scanContract.createIntent(getContext(), uiSettings);
116
+ BlinkCardScanActivitySettings activitySettings = new BlinkCardScanActivitySettings(sdkSettings, sessionSettings);
117
+ MbBlinkCardScan scanContract = new MbBlinkCardScan();
118
+ Intent scanIntent = scanContract.createIntent(getContext(), activitySettings);
221
119
  startActivityForResult(call, scanIntent, "handleBlinkCardScanResult");
222
120
  }
223
121
 
224
122
  @ActivityCallback
225
123
  private void handleBlinkCardScanResult(PluginCall call, ActivityResult activityResult) {
226
- MbScan scanContract = new MbScan();
227
- ScanResult scanResult = scanContract.parseResult(activityResult.getResultCode(), activityResult.getData());
124
+ MbBlinkCardScan scanContract = new MbBlinkCardScan();
125
+ BlinkCardScanActivityResult scanResult = scanContract.parseResult(
126
+ activityResult.getResultCode(),
127
+ activityResult.getData()
128
+ );
228
129
 
229
- if (scanResult.getResultStatus() == ResultStatus.CANCELLED) {
130
+ if (scanResult == null) {
131
+ call.reject("BlinkCard scan did not return any result data.");
132
+ return;
133
+ }
134
+
135
+ ScanActivityResultStatus status = scanResult.getStatus();
136
+ if (status == ScanActivityResultStatus.Canceled) {
230
137
  JSObject payload = new JSObject();
231
138
  payload.put("canceled", true);
232
139
  call.resolve(payload);
233
140
  return;
234
141
  }
235
142
 
236
- if (scanResult.getResultStatus() == ResultStatus.EXCEPTION) {
237
- Throwable exception = scanResult.getException();
238
- String message = exception != null ? exception.getMessage() : "BlinkCard scan failed with unknown exception.";
239
- call.reject(message);
143
+ if (status == ScanActivityResultStatus.ErrorSdkInit) {
144
+ call.reject("BlinkCard scan failed because SDK initialization in scan activity failed.");
240
145
  return;
241
146
  }
242
147
 
243
- Intent resultIntent = scanResult.getResult();
244
- if (resultIntent == null) {
245
- call.reject("BlinkCard scan did not return any result data.");
148
+ BlinkCardScanningResult result = scanResult.getResult();
149
+ if (result == null) {
150
+ call.reject("BlinkCard scan finished without scan result.");
246
151
  return;
247
152
  }
248
153
 
249
- RecognizerBundle resultBundle = RecognizerBundle.createFromIntent(resultIntent);
250
- if (resultBundle == null || resultBundle.getRecognizers() == null || resultBundle.getRecognizers().length == 0) {
251
- call.reject("BlinkCard result bundle is empty.");
252
- return;
253
- }
154
+ JSObject payload = new JSObject();
155
+ payload.put("canceled", false);
156
+ payload.put("resultState", "valid");
157
+ payload.put("processingStatus", "success");
158
+ payload.put("owner", result.getCardholderName());
159
+ payload.put("iban", result.getIban());
254
160
 
255
- BlinkCardRecognizer blinkCardRecognizer = null;
256
- for (Recognizer<?> recognizer : resultBundle.getRecognizers()) {
257
- if (recognizer instanceof BlinkCardRecognizer) {
258
- blinkCardRecognizer = (BlinkCardRecognizer) recognizer;
259
- break;
161
+ List<CardAccountResult> cardAccounts = result.getCardAccounts();
162
+ if (cardAccounts != null && !cardAccounts.isEmpty()) {
163
+ CardAccountResult primaryAccount = null;
164
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
165
+ primaryAccount = cardAccounts.getFirst();
166
+ payload.put("cardNumber", primaryAccount.getCardNumber());
167
+ payload.put("cardNumberValid", primaryAccount.getCardNumberValid());
168
+ payload.put("cardNumberPrefix", primaryAccount.getCardNumberPrefix());
169
+ payload.put("cvv", primaryAccount.getCvv());
170
+ payload.put("expiryDate", toBlinkCardDate(primaryAccount.getExpiryDate()));
171
+ } else {
172
+ primaryAccount = cardAccounts.get(0);
173
+ payload.put("cardNumber", primaryAccount.getCardNumber());
174
+ payload.put("cardNumberValid", primaryAccount.getCardNumberValid());
175
+ payload.put("cardNumberPrefix", primaryAccount.getCardNumberPrefix());
176
+ payload.put("cvv", primaryAccount.getCvv());
177
+ payload.put("expiryDate", toBlinkCardDate(primaryAccount.getExpiryDate()));
260
178
  }
261
- }
262
- if (blinkCardRecognizer == null) {
263
- call.reject("BlinkCard recognizer result was not found.");
264
- return;
179
+
265
180
  }
266
181
 
267
- BlinkCardRecognizer.Result result = blinkCardRecognizer.getResult();
268
- JSObject payload = new JSObject();
269
- payload.put("canceled", false);
270
- payload.put("resultState", toBlinkCardResultState(result.getResultState()));
271
- payload.put("processingStatus", toBlinkCardProcessingStatus(result.getProcessingStatus()));
272
- payload.put("cardNumber", result.getCardNumber());
273
- payload.put("cardNumberValid", result.isCardNumberValid());
274
- payload.put("cardNumberPrefix", result.getCardNumberPrefix());
275
- payload.put("owner", result.getOwner());
276
- payload.put("cvv", result.getCvv());
277
- payload.put("iban", result.getIban());
278
- payload.put("expiryDate", toBlinkCardDate(result.getExpiryDate() != null ? result.getExpiryDate().getDate() : null));
279
182
  call.resolve(payload);
280
183
  }
281
184
 
282
- private JSObject toBlinkCardDate(SimpleDate simpleDate) {
283
- if (simpleDate == null) {
185
+ private JSObject toBlinkCardDate(DateResult<String> dateResult) {
186
+ if (dateResult == null || dateResult.getDay() == null || dateResult.getMonth() == null || dateResult.getYear() == null) {
284
187
  return null;
285
188
  }
189
+
286
190
  JSObject date = new JSObject();
287
- date.put("day", simpleDate.getDay());
288
- date.put("month", simpleDate.getMonth());
289
- date.put("year", simpleDate.getYear());
191
+ date.put("day", dateResult.getDay());
192
+ date.put("month", dateResult.getMonth());
193
+ date.put("year", dateResult.getYear());
290
194
  return date;
291
195
  }
292
196
 
293
- private String toBlinkCardResultState(Recognizer.Result.State state) {
294
- if (state == Recognizer.Result.State.Valid) {
295
- return "valid";
296
- }
297
- if (state == Recognizer.Result.State.Uncertain) {
298
- return "uncertain";
299
- }
300
- if (state == Recognizer.Result.State.StageValid) {
301
- return "stageValid";
302
- }
303
- return "empty";
304
- }
305
-
306
- private String toBlinkCardProcessingStatus(BlinkCardProcessingStatus status) {
307
- if (status == BlinkCardProcessingStatus.Success) {
308
- return "success";
309
- }
310
- if (status == BlinkCardProcessingStatus.DetectionFailed) {
311
- return "detectionFailed";
312
- }
313
- if (status == BlinkCardProcessingStatus.ImagePreprocessingFailed) {
314
- return "imagePreprocessingFailed";
315
- }
316
- if (status == BlinkCardProcessingStatus.StabilityTestFailed) {
317
- return "stabilityTestFailed";
318
- }
319
- if (status == BlinkCardProcessingStatus.ScanningWrongSide) {
320
- return "scanningWrongSide";
321
- }
322
- if (status == BlinkCardProcessingStatus.FieldIdentificationFailed) {
323
- return "fieldIdentificationFailed";
324
- }
325
- if (status == BlinkCardProcessingStatus.ImageReturnFailed) {
326
- return "imageReturnFailed";
327
- }
328
- return "unsupportedCard";
329
- }
330
-
331
- private String toResultStatus(MicroblinkPlatformResult.FinishedState state) {
332
- if (state == MicroblinkPlatformResult.FinishedState.Accept) {
333
- return "accept";
334
- }
335
- if (state == MicroblinkPlatformResult.FinishedState.Reject) {
336
- return "reject";
197
+ private void initializeBlinkCardLicense(String licenseKey, String licensee, Consumer<String> callback) {
198
+ if (getContext() == null) {
199
+ callback.accept("Unable to initialize BlinkCard SDK: Context is unavailable.");
200
+ return;
337
201
  }
338
- return "review";
339
- }
340
202
 
341
- private String toCancelReason(MicroblinkPlatformCancelState.CancelReason reason) {
342
- if (reason == MicroblinkPlatformCancelState.CancelReason.ConsentDenied) {
343
- return "consentDenied";
344
- }
345
- return "userCanceled";
346
- }
203
+ BlinkCardInitBridge.initialize(getContext(), licenseKey, licensee, error -> {
204
+ if (error != null) {
205
+ isBlinkCardInitialized = false;
206
+ callback.accept("Init failed: " + error.getMessage());
207
+ return null;
208
+ }
347
209
 
348
- private String formatExpiry(CardScanResult cardResult) {
349
- if (cardResult.getExpiryDate() == null) {
350
- return "";
351
- }
352
- Integer month = cardResult.getExpiryDate().getMonth();
353
- Integer year = cardResult.getExpiryDate().getYear();
354
- if (month == null && year == null) {
355
- return "";
356
- }
357
- String monthPart = month == null ? "00" : String.format("%02d", month);
358
- String yearPart = year == null ? "0000" : String.valueOf(year);
359
- return monthPart + "/" + yearPart;
210
+ isBlinkCardInitialized = true;
211
+ blinkCardLicenseKey = licenseKey;
212
+ blinkCardLicensee = licensee;
213
+ callback.accept(null);
214
+ return null;
215
+ });
360
216
  }
361
217
 
362
- private synchronized void resolvePending(JSObject payload) {
363
- if (pendingVerificationCall == null) {
364
- clearPendingState();
365
- return;
218
+ private String normalized(String value) {
219
+ if (value == null || value.isEmpty()) {
220
+ return null;
366
221
  }
367
- PluginCall call = pendingVerificationCall;
368
- clearPendingState();
369
- call.resolve(payload);
370
- }
371
-
372
- private synchronized void clearPendingState() {
373
- pendingVerificationCall = null;
374
- pendingVerificationCardScanResult = null;
222
+ return value;
375
223
  }
376
224
  }