capacitor-microblink 0.0.1 → 0.2.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.
@@ -13,6 +13,7 @@ Pod::Spec.new do |s|
13
13
  s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
14
14
  s.ios.deployment_target = '16.0'
15
15
  s.dependency 'Capacitor'
16
+ s.dependency 'BlinkCard', '2.12.0'
16
17
  s.dependency 'MicroblinkPlatform', '1.7.0'
17
18
  s.swift_version = '5.9'
18
19
  end
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Otto The Agent
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/Package.swift CHANGED
@@ -19,6 +19,7 @@ let package = Package(
19
19
  dependencies: [
20
20
  .product(name: "Capacitor", package: "capacitor-swift-pm"),
21
21
  .product(name: "Cordova", package: "capacitor-swift-pm"),
22
+ .product(name: "BlinkCard", package: "microblink-platform-ios"),
22
23
  .product(name: "MicroblinkPlatform", package: "microblink-platform-ios")
23
24
  ],
24
25
  path: "ios/Sources/MicroblinkPlugin"),
package/README.md CHANGED
@@ -14,6 +14,7 @@ npx cap sync
14
14
  <docgen-index>
15
15
 
16
16
  * [`startVerification(...)`](#startverification)
17
+ * [`scanCard(...)`](#scancard)
17
18
  * [Interfaces](#interfaces)
18
19
  * [Type Aliases](#type-aliases)
19
20
 
@@ -39,6 +40,23 @@ Starts Microblink identity verification flow.
39
40
  --------------------
40
41
 
41
42
 
43
+ ### scanCard(...)
44
+
45
+ ```typescript
46
+ scanCard(options: ScanCardOptions) => Promise<ScanCardResult>
47
+ ```
48
+
49
+ Starts BlinkCard card scanning flow.
50
+
51
+ | Param | Type |
52
+ | ------------- | ----------------------------------------------------------- |
53
+ | **`options`** | <code><a href="#scancardoptions">ScanCardOptions</a></code> |
54
+
55
+ **Returns:** <code>Promise&lt;<a href="#scancardresult">ScanCardResult</a>&gt;</code>
56
+
57
+ --------------------
58
+
59
+
42
60
  ### Interfaces
43
61
 
44
62
 
@@ -80,6 +98,45 @@ Starts Microblink identity verification flow.
80
98
  | **`workflowInfoPath`** | <code>string</code> |
81
99
 
82
100
 
101
+ #### ScanCardResult
102
+
103
+ | Prop | Type |
104
+ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
105
+ | **`canceled`** | <code>boolean</code> |
106
+ | **`resultState`** | <code>'empty' \| 'uncertain' \| 'valid' \| 'stageValid'</code> |
107
+ | **`processingStatus`** | <code>'success' \| 'detectionFailed' \| 'imagePreprocessingFailed' \| 'stabilityTestFailed' \| 'scanningWrongSide' \| 'fieldIdentificationFailed' \| 'imageReturnFailed' \| 'unsupportedCard'</code> |
108
+ | **`cardNumber`** | <code>string</code> |
109
+ | **`cardNumberValid`** | <code>boolean</code> |
110
+ | **`cardNumberPrefix`** | <code>string</code> |
111
+ | **`owner`** | <code>string</code> |
112
+ | **`cvv`** | <code>string</code> |
113
+ | **`iban`** | <code>string</code> |
114
+ | **`expiryDate`** | <code><a href="#blinkcarddate">BlinkCardDate</a> \| null</code> |
115
+
116
+
117
+ #### BlinkCardDate
118
+
119
+ | Prop | Type |
120
+ | ----------- | ------------------- |
121
+ | **`day`** | <code>number</code> |
122
+ | **`month`** | <code>number</code> |
123
+ | **`year`** | <code>number</code> |
124
+
125
+
126
+ #### ScanCardOptions
127
+
128
+ | Prop | Type |
129
+ | ---------------------------- | -------------------- |
130
+ | **`licenseKey`** | <code>string</code> |
131
+ | **`licensee`** | <code>string</code> |
132
+ | **`extractOwner`** | <code>boolean</code> |
133
+ | **`extractExpiryDate`** | <code>boolean</code> |
134
+ | **`extractCvv`** | <code>boolean</code> |
135
+ | **`extractIban`** | <code>boolean</code> |
136
+ | **`allowInvalidCardNumber`** | <code>boolean</code> |
137
+ | **`enableEditScreen`** | <code>boolean</code> |
138
+
139
+
83
140
  ### Type Aliases
84
141
 
85
142
 
@@ -56,6 +56,7 @@ dependencies {
56
56
  implementation fileTree(dir: 'libs', include: ['*.jar'])
57
57
  implementation project(':capacitor-android')
58
58
  implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
59
+ implementation "com.microblink:blinkcard:2.12.0"
59
60
  implementation "com.microblink:microblink-platform:1.7.0"
60
61
  testImplementation "junit:junit:$junitVersion"
61
62
  androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
@@ -1,10 +1,25 @@
1
1
  package com.otto.microblink;
2
2
 
3
+ import android.content.Intent;
4
+
5
+ import androidx.activity.result.ActivityResult;
6
+
3
7
  import com.getcapacitor.JSObject;
4
8
  import com.getcapacitor.Plugin;
5
9
  import com.getcapacitor.PluginCall;
6
10
  import com.getcapacitor.PluginMethod;
11
+ import com.getcapacitor.annotation.ActivityCallback;
7
12
  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;
8
23
  import com.microblink.platform.CardScanResult;
9
24
  import com.microblink.platform.MicroblinkPlatform;
10
25
  import com.microblink.platform.MicroblinkPlatformCancelState;
@@ -26,12 +41,12 @@ import java.util.Map;
26
41
  @CapacitorPlugin(name = "Microblink")
27
42
  public class MicroblinkPlugin extends Plugin {
28
43
 
29
- private PluginCall pendingCall;
30
- private JSObject pendingCardScanResult;
44
+ private PluginCall pendingVerificationCall;
45
+ private JSObject pendingVerificationCardScanResult;
31
46
 
32
47
  @PluginMethod
33
48
  public void startVerification(PluginCall call) {
34
- if (pendingCall != null) {
49
+ if (pendingVerificationCall != null) {
35
50
  call.reject("A verification flow is already running.");
36
51
  return;
37
52
  }
@@ -115,8 +130,8 @@ public class MicroblinkPlugin extends Plugin {
115
130
  payload.put("canceled", false);
116
131
  payload.put("transactionId", result.getTransactionId());
117
132
  payload.put("status", toResultStatus(result.getState()));
118
- if (pendingCardScanResult != null) {
119
- payload.put("cardScanResult", pendingCardScanResult);
133
+ if (pendingVerificationCardScanResult != null) {
134
+ payload.put("cardScanResult", pendingVerificationCardScanResult);
120
135
  }
121
136
  resolvePending(payload);
122
137
  }
@@ -127,8 +142,8 @@ public class MicroblinkPlugin extends Plugin {
127
142
  payload.put("canceled", true);
128
143
  payload.put("transactionId", cancelState.getTransactionId());
129
144
  payload.put("cancelReason", toCancelReason(cancelState.getCancelReason()));
130
- if (pendingCardScanResult != null) {
131
- payload.put("cardScanResult", pendingCardScanResult);
145
+ if (pendingVerificationCardScanResult != null) {
146
+ payload.put("cardScanResult", pendingVerificationCardScanResult);
132
147
  }
133
148
  resolvePending(payload);
134
149
  }
@@ -142,7 +157,7 @@ public class MicroblinkPlugin extends Plugin {
142
157
  cardScan.put("expiryDate", formatExpiry(cardResult));
143
158
  cardScan.put("owner", cardResult.getOwner());
144
159
  cardScan.put("cvv", cardResult.getCvv());
145
- pendingCardScanResult = cardScan;
160
+ pendingVerificationCardScanResult = cardScan;
146
161
  }
147
162
  };
148
163
 
@@ -153,8 +168,8 @@ public class MicroblinkPlugin extends Plugin {
153
168
  cardScanResultListener
154
169
  );
155
170
 
156
- pendingCall = call;
157
- pendingCardScanResult = null;
171
+ pendingVerificationCall = call;
172
+ pendingVerificationCardScanResult = null;
158
173
 
159
174
  if (getActivity() == null) {
160
175
  clearPendingState();
@@ -165,6 +180,154 @@ public class MicroblinkPlugin extends Plugin {
165
180
  getActivity().runOnUiThread(() -> MicroblinkPlatform.INSTANCE.startVerification(getActivity(), config));
166
181
  }
167
182
 
183
+ @PluginMethod
184
+ public void scanCard(PluginCall call) {
185
+ if (pendingVerificationCall != null) {
186
+ call.reject("A verification flow is already running.");
187
+ return;
188
+ }
189
+
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");
196
+
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
+ }
207
+
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));
214
+
215
+ RecognizerBundle recognizerBundle = new RecognizerBundle(recognizer);
216
+ BlinkCardUISettings uiSettings = new BlinkCardUISettings(recognizerBundle);
217
+ uiSettings.setEditScreenEnabled(call.getBoolean("enableEditScreen", true));
218
+
219
+ MbScan scanContract = new MbScan();
220
+ Intent scanIntent = scanContract.createIntent(getContext(), uiSettings);
221
+ startActivityForResult(call, scanIntent, "handleBlinkCardScanResult");
222
+ }
223
+
224
+ @ActivityCallback
225
+ private void handleBlinkCardScanResult(PluginCall call, ActivityResult activityResult) {
226
+ MbScan scanContract = new MbScan();
227
+ ScanResult scanResult = scanContract.parseResult(activityResult.getResultCode(), activityResult.getData());
228
+
229
+ if (scanResult.getResultStatus() == ResultStatus.CANCELLED) {
230
+ JSObject payload = new JSObject();
231
+ payload.put("canceled", true);
232
+ call.resolve(payload);
233
+ return;
234
+ }
235
+
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);
240
+ return;
241
+ }
242
+
243
+ Intent resultIntent = scanResult.getResult();
244
+ if (resultIntent == null) {
245
+ call.reject("BlinkCard scan did not return any result data.");
246
+ return;
247
+ }
248
+
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
+ }
254
+
255
+ BlinkCardRecognizer blinkCardRecognizer = null;
256
+ for (Recognizer<?> recognizer : resultBundle.getRecognizers()) {
257
+ if (recognizer instanceof BlinkCardRecognizer) {
258
+ blinkCardRecognizer = (BlinkCardRecognizer) recognizer;
259
+ break;
260
+ }
261
+ }
262
+ if (blinkCardRecognizer == null) {
263
+ call.reject("BlinkCard recognizer result was not found.");
264
+ return;
265
+ }
266
+
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
+ call.resolve(payload);
280
+ }
281
+
282
+ private JSObject toBlinkCardDate(SimpleDate simpleDate) {
283
+ if (simpleDate == null) {
284
+ return null;
285
+ }
286
+ JSObject date = new JSObject();
287
+ date.put("day", simpleDate.getDay());
288
+ date.put("month", simpleDate.getMonth());
289
+ date.put("year", simpleDate.getYear());
290
+ return date;
291
+ }
292
+
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
+
168
331
  private String toResultStatus(MicroblinkPlatformResult.FinishedState state) {
169
332
  if (state == MicroblinkPlatformResult.FinishedState.Accept) {
170
333
  return "accept";
@@ -197,17 +360,17 @@ public class MicroblinkPlugin extends Plugin {
197
360
  }
198
361
 
199
362
  private synchronized void resolvePending(JSObject payload) {
200
- if (pendingCall == null) {
363
+ if (pendingVerificationCall == null) {
201
364
  clearPendingState();
202
365
  return;
203
366
  }
204
- PluginCall call = pendingCall;
367
+ PluginCall call = pendingVerificationCall;
205
368
  clearPendingState();
206
369
  call.resolve(payload);
207
370
  }
208
371
 
209
372
  private synchronized void clearPendingState() {
210
- pendingCall = null;
211
- pendingCardScanResult = null;
373
+ pendingVerificationCall = null;
374
+ pendingVerificationCardScanResult = null;
212
375
  }
213
376
  }
package/dist/docs.json CHANGED
@@ -23,6 +23,25 @@
23
23
  "StartVerificationOptions"
24
24
  ],
25
25
  "slug": "startverification"
26
+ },
27
+ {
28
+ "name": "scanCard",
29
+ "signature": "(options: ScanCardOptions) => Promise<ScanCardResult>",
30
+ "parameters": [
31
+ {
32
+ "name": "options",
33
+ "docs": "",
34
+ "type": "ScanCardOptions"
35
+ }
36
+ ],
37
+ "returns": "Promise<ScanCardResult>",
38
+ "tags": [],
39
+ "docs": "Starts BlinkCard card scanning flow.",
40
+ "complexTypes": [
41
+ "ScanCardResult",
42
+ "ScanCardOptions"
43
+ ],
44
+ "slug": "scancard"
26
45
  }
27
46
  ],
28
47
  "properties": []
@@ -198,6 +217,182 @@
198
217
  "type": "string | undefined"
199
218
  }
200
219
  ]
220
+ },
221
+ {
222
+ "name": "ScanCardResult",
223
+ "slug": "scancardresult",
224
+ "docs": "",
225
+ "tags": [],
226
+ "methods": [],
227
+ "properties": [
228
+ {
229
+ "name": "canceled",
230
+ "tags": [],
231
+ "docs": "",
232
+ "complexTypes": [],
233
+ "type": "boolean"
234
+ },
235
+ {
236
+ "name": "resultState",
237
+ "tags": [],
238
+ "docs": "",
239
+ "complexTypes": [],
240
+ "type": "'empty' | 'uncertain' | 'valid' | 'stageValid' | undefined"
241
+ },
242
+ {
243
+ "name": "processingStatus",
244
+ "tags": [],
245
+ "docs": "",
246
+ "complexTypes": [],
247
+ "type": "'success' | 'detectionFailed' | 'imagePreprocessingFailed' | 'stabilityTestFailed' | 'scanningWrongSide' | 'fieldIdentificationFailed' | 'imageReturnFailed' | 'unsupportedCard' | undefined"
248
+ },
249
+ {
250
+ "name": "cardNumber",
251
+ "tags": [],
252
+ "docs": "",
253
+ "complexTypes": [],
254
+ "type": "string | undefined"
255
+ },
256
+ {
257
+ "name": "cardNumberValid",
258
+ "tags": [],
259
+ "docs": "",
260
+ "complexTypes": [],
261
+ "type": "boolean | undefined"
262
+ },
263
+ {
264
+ "name": "cardNumberPrefix",
265
+ "tags": [],
266
+ "docs": "",
267
+ "complexTypes": [],
268
+ "type": "string | undefined"
269
+ },
270
+ {
271
+ "name": "owner",
272
+ "tags": [],
273
+ "docs": "",
274
+ "complexTypes": [],
275
+ "type": "string | undefined"
276
+ },
277
+ {
278
+ "name": "cvv",
279
+ "tags": [],
280
+ "docs": "",
281
+ "complexTypes": [],
282
+ "type": "string | undefined"
283
+ },
284
+ {
285
+ "name": "iban",
286
+ "tags": [],
287
+ "docs": "",
288
+ "complexTypes": [],
289
+ "type": "string | undefined"
290
+ },
291
+ {
292
+ "name": "expiryDate",
293
+ "tags": [],
294
+ "docs": "",
295
+ "complexTypes": [
296
+ "BlinkCardDate"
297
+ ],
298
+ "type": "BlinkCardDate | null | undefined"
299
+ }
300
+ ]
301
+ },
302
+ {
303
+ "name": "BlinkCardDate",
304
+ "slug": "blinkcarddate",
305
+ "docs": "",
306
+ "tags": [],
307
+ "methods": [],
308
+ "properties": [
309
+ {
310
+ "name": "day",
311
+ "tags": [],
312
+ "docs": "",
313
+ "complexTypes": [],
314
+ "type": "number"
315
+ },
316
+ {
317
+ "name": "month",
318
+ "tags": [],
319
+ "docs": "",
320
+ "complexTypes": [],
321
+ "type": "number"
322
+ },
323
+ {
324
+ "name": "year",
325
+ "tags": [],
326
+ "docs": "",
327
+ "complexTypes": [],
328
+ "type": "number"
329
+ }
330
+ ]
331
+ },
332
+ {
333
+ "name": "ScanCardOptions",
334
+ "slug": "scancardoptions",
335
+ "docs": "",
336
+ "tags": [],
337
+ "methods": [],
338
+ "properties": [
339
+ {
340
+ "name": "licenseKey",
341
+ "tags": [],
342
+ "docs": "",
343
+ "complexTypes": [],
344
+ "type": "string"
345
+ },
346
+ {
347
+ "name": "licensee",
348
+ "tags": [],
349
+ "docs": "",
350
+ "complexTypes": [],
351
+ "type": "string | undefined"
352
+ },
353
+ {
354
+ "name": "extractOwner",
355
+ "tags": [],
356
+ "docs": "",
357
+ "complexTypes": [],
358
+ "type": "boolean | undefined"
359
+ },
360
+ {
361
+ "name": "extractExpiryDate",
362
+ "tags": [],
363
+ "docs": "",
364
+ "complexTypes": [],
365
+ "type": "boolean | undefined"
366
+ },
367
+ {
368
+ "name": "extractCvv",
369
+ "tags": [],
370
+ "docs": "",
371
+ "complexTypes": [],
372
+ "type": "boolean | undefined"
373
+ },
374
+ {
375
+ "name": "extractIban",
376
+ "tags": [],
377
+ "docs": "",
378
+ "complexTypes": [],
379
+ "type": "boolean | undefined"
380
+ },
381
+ {
382
+ "name": "allowInvalidCardNumber",
383
+ "tags": [],
384
+ "docs": "",
385
+ "complexTypes": [],
386
+ "type": "boolean | undefined"
387
+ },
388
+ {
389
+ "name": "enableEditScreen",
390
+ "tags": [],
391
+ "docs": "",
392
+ "complexTypes": [],
393
+ "type": "boolean | undefined"
394
+ }
395
+ ]
201
396
  }
202
397
  ],
203
398
  "enums": [],
@@ -24,9 +24,40 @@ export interface StartVerificationResult {
24
24
  cancelReason?: 'userCanceled' | 'consentDenied';
25
25
  cardScanResult?: CardScanResult;
26
26
  }
27
+ export interface BlinkCardDate {
28
+ day: number;
29
+ month: number;
30
+ year: number;
31
+ }
32
+ export interface ScanCardOptions {
33
+ licenseKey: string;
34
+ licensee?: string;
35
+ extractOwner?: boolean;
36
+ extractExpiryDate?: boolean;
37
+ extractCvv?: boolean;
38
+ extractIban?: boolean;
39
+ allowInvalidCardNumber?: boolean;
40
+ enableEditScreen?: boolean;
41
+ }
42
+ export interface ScanCardResult {
43
+ canceled: boolean;
44
+ resultState?: 'empty' | 'uncertain' | 'valid' | 'stageValid';
45
+ processingStatus?: 'success' | 'detectionFailed' | 'imagePreprocessingFailed' | 'stabilityTestFailed' | 'scanningWrongSide' | 'fieldIdentificationFailed' | 'imageReturnFailed' | 'unsupportedCard';
46
+ cardNumber?: string;
47
+ cardNumberValid?: boolean;
48
+ cardNumberPrefix?: string;
49
+ owner?: string;
50
+ cvv?: string;
51
+ iban?: string;
52
+ expiryDate?: BlinkCardDate | null;
53
+ }
27
54
  export interface MicroblinkPlugin {
28
55
  /**
29
56
  * Starts Microblink identity verification flow.
30
57
  */
31
58
  startVerification(options: StartVerificationOptions): Promise<StartVerificationResult>;
59
+ /**
60
+ * Starts BlinkCard card scanning flow.
61
+ */
62
+ scanCard(options: ScanCardOptions): Promise<ScanCardResult>;
32
63
  }
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface StartVerificationOptions {\n workflowId: string;\n url: string;\n userId: string;\n isProcessingStoringAllowed: boolean;\n isTrainingAllowed: boolean;\n note?: string;\n givenOn?: number;\n additionalRequestHeaders?: Record<string, string>;\n startTransactionPath?: string;\n cancelWorkflowPath?: string;\n workflowInfoPath?: string;\n}\n\nexport interface CardScanResult {\n cardNumber: string;\n expiryDate: string;\n owner: string;\n cvv: string;\n}\n\nexport interface StartVerificationResult {\n canceled: boolean;\n transactionId: string | null;\n status?: 'accept' | 'review' | 'reject';\n cancelReason?: 'userCanceled' | 'consentDenied';\n cardScanResult?: CardScanResult;\n}\n\nexport interface MicroblinkPlugin {\n /**\n * Starts Microblink identity verification flow.\n */\n startVerification(\n options: StartVerificationOptions,\n ): Promise<StartVerificationResult>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface StartVerificationOptions {\n workflowId: string;\n url: string;\n userId: string;\n isProcessingStoringAllowed: boolean;\n isTrainingAllowed: boolean;\n note?: string;\n givenOn?: number;\n additionalRequestHeaders?: Record<string, string>;\n startTransactionPath?: string;\n cancelWorkflowPath?: string;\n workflowInfoPath?: string;\n}\n\nexport interface CardScanResult {\n cardNumber: string;\n expiryDate: string;\n owner: string;\n cvv: string;\n}\n\nexport interface StartVerificationResult {\n canceled: boolean;\n transactionId: string | null;\n status?: 'accept' | 'review' | 'reject';\n cancelReason?: 'userCanceled' | 'consentDenied';\n cardScanResult?: CardScanResult;\n}\n\nexport interface BlinkCardDate {\n day: number;\n month: number;\n year: number;\n}\n\nexport interface ScanCardOptions {\n licenseKey: string;\n licensee?: string;\n extractOwner?: boolean;\n extractExpiryDate?: boolean;\n extractCvv?: boolean;\n extractIban?: boolean;\n allowInvalidCardNumber?: boolean;\n enableEditScreen?: boolean;\n}\n\nexport interface ScanCardResult {\n canceled: boolean;\n resultState?: 'empty' | 'uncertain' | 'valid' | 'stageValid';\n processingStatus?:\n | 'success'\n | 'detectionFailed'\n | 'imagePreprocessingFailed'\n | 'stabilityTestFailed'\n | 'scanningWrongSide'\n | 'fieldIdentificationFailed'\n | 'imageReturnFailed'\n | 'unsupportedCard';\n cardNumber?: string;\n cardNumberValid?: boolean;\n cardNumberPrefix?: string;\n owner?: string;\n cvv?: string;\n iban?: string;\n expiryDate?: BlinkCardDate | null;\n}\n\nexport interface MicroblinkPlugin {\n /**\n * Starts Microblink identity verification flow.\n */\n startVerification(\n options: StartVerificationOptions,\n ): Promise<StartVerificationResult>;\n\n /**\n * Starts BlinkCard card scanning flow.\n */\n scanCard(options: ScanCardOptions): Promise<ScanCardResult>;\n}\n"]}
package/dist/esm/web.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { WebPlugin } from '@capacitor/core';
2
- import type { MicroblinkPlugin, StartVerificationOptions, StartVerificationResult } from './definitions';
2
+ import type { MicroblinkPlugin, ScanCardOptions, ScanCardResult, StartVerificationOptions, StartVerificationResult } from './definitions';
3
3
  export declare class MicroblinkWeb extends WebPlugin implements MicroblinkPlugin {
4
4
  startVerification(_options: StartVerificationOptions): Promise<StartVerificationResult>;
5
+ scanCard(_options: ScanCardOptions): Promise<ScanCardResult>;
5
6
  }
package/dist/esm/web.js CHANGED
@@ -3,5 +3,8 @@ export class MicroblinkWeb extends WebPlugin {
3
3
  async startVerification(_options) {
4
4
  throw this.unimplemented('Microblink is only available on Android and iOS.');
5
5
  }
6
+ async scanCard(_options) {
7
+ throw this.unimplemented('BlinkCard is only available on Android and iOS.');
8
+ }
6
9
  }
7
10
  //# sourceMappingURL=web.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAQ5C,MAAM,OAAO,aAAc,SAAQ,SAAS;IAC1C,KAAK,CAAC,iBAAiB,CACrB,QAAkC;QAElC,MAAM,IAAI,CAAC,aAAa,CAAC,kDAAkD,CAAC,CAAC;IAC/E,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type {\n MicroblinkPlugin,\n StartVerificationOptions,\n StartVerificationResult,\n} from './definitions';\n\nexport class MicroblinkWeb extends WebPlugin implements MicroblinkPlugin {\n async startVerification(\n _options: StartVerificationOptions,\n ): Promise<StartVerificationResult> {\n throw this.unimplemented('Microblink is only available on Android and iOS.');\n }\n}\n"]}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAU5C,MAAM,OAAO,aAAc,SAAQ,SAAS;IAC1C,KAAK,CAAC,iBAAiB,CACrB,QAAkC;QAElC,MAAM,IAAI,CAAC,aAAa,CAAC,kDAAkD,CAAC,CAAC;IAC/E,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,QAAyB;QACtC,MAAM,IAAI,CAAC,aAAa,CAAC,iDAAiD,CAAC,CAAC;IAC9E,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type {\n MicroblinkPlugin,\n ScanCardOptions,\n ScanCardResult,\n StartVerificationOptions,\n StartVerificationResult,\n} from './definitions';\n\nexport class MicroblinkWeb extends WebPlugin implements MicroblinkPlugin {\n async startVerification(\n _options: StartVerificationOptions,\n ): Promise<StartVerificationResult> {\n throw this.unimplemented('Microblink is only available on Android and iOS.');\n }\n\n async scanCard(_options: ScanCardOptions): Promise<ScanCardResult> {\n throw this.unimplemented('BlinkCard is only available on Android and iOS.');\n }\n}\n"]}
@@ -10,6 +10,9 @@ class MicroblinkWeb extends core.WebPlugin {
10
10
  async startVerification(_options) {
11
11
  throw this.unimplemented('Microblink is only available on Android and iOS.');
12
12
  }
13
+ async scanCard(_options) {
14
+ throw this.unimplemented('BlinkCard is only available on Android and iOS.');
15
+ }
13
16
  }
14
17
 
15
18
  var web = /*#__PURE__*/Object.freeze({
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst Microblink = registerPlugin('Microblink', {\n web: () => import('./web').then((m) => new m.MicroblinkWeb()),\n});\nexport * from './definitions';\nexport { Microblink };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class MicroblinkWeb extends WebPlugin {\n async startVerification(_options) {\n throw this.unimplemented('Microblink is only available on Android and iOS.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,UAAU,GAAGA,mBAAc,CAAC,YAAY,EAAE;AAChD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;AACjE,CAAC;;ACFM,MAAM,aAAa,SAASC,cAAS,CAAC;AAC7C,IAAI,MAAM,iBAAiB,CAAC,QAAQ,EAAE;AACtC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,kDAAkD,CAAC;AACpF,IAAI;AACJ;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst Microblink = registerPlugin('Microblink', {\n web: () => import('./web').then((m) => new m.MicroblinkWeb()),\n});\nexport * from './definitions';\nexport { Microblink };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class MicroblinkWeb extends WebPlugin {\n async startVerification(_options) {\n throw this.unimplemented('Microblink is only available on Android and iOS.');\n }\n async scanCard(_options) {\n throw this.unimplemented('BlinkCard is only available on Android and iOS.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,UAAU,GAAGA,mBAAc,CAAC,YAAY,EAAE;AAChD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;AACjE,CAAC;;ACFM,MAAM,aAAa,SAASC,cAAS,CAAC;AAC7C,IAAI,MAAM,iBAAiB,CAAC,QAAQ,EAAE;AACtC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,kDAAkD,CAAC;AACpF,IAAI;AACJ,IAAI,MAAM,QAAQ,CAAC,QAAQ,EAAE;AAC7B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,iDAAiD,CAAC;AACnF,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js CHANGED
@@ -9,6 +9,9 @@ var capacitorMicroblink = (function (exports, core) {
9
9
  async startVerification(_options) {
10
10
  throw this.unimplemented('Microblink is only available on Android and iOS.');
11
11
  }
12
+ async scanCard(_options) {
13
+ throw this.unimplemented('BlinkCard is only available on Android and iOS.');
14
+ }
12
15
  }
13
16
 
14
17
  var web = /*#__PURE__*/Object.freeze({
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst Microblink = registerPlugin('Microblink', {\n web: () => import('./web').then((m) => new m.MicroblinkWeb()),\n});\nexport * from './definitions';\nexport { Microblink };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class MicroblinkWeb extends WebPlugin {\n async startVerification(_options) {\n throw this.unimplemented('Microblink is only available on Android and iOS.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,UAAU,GAAGA,mBAAc,CAAC,YAAY,EAAE;IAChD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;IACjE,CAAC;;ICFM,MAAM,aAAa,SAASC,cAAS,CAAC;IAC7C,IAAI,MAAM,iBAAiB,CAAC,QAAQ,EAAE;IACtC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,kDAAkD,CAAC;IACpF,IAAI;IACJ;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst Microblink = registerPlugin('Microblink', {\n web: () => import('./web').then((m) => new m.MicroblinkWeb()),\n});\nexport * from './definitions';\nexport { Microblink };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class MicroblinkWeb extends WebPlugin {\n async startVerification(_options) {\n throw this.unimplemented('Microblink is only available on Android and iOS.');\n }\n async scanCard(_options) {\n throw this.unimplemented('BlinkCard is only available on Android and iOS.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,UAAU,GAAGA,mBAAc,CAAC,YAAY,EAAE;IAChD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;IACjE,CAAC;;ICFM,MAAM,aAAa,SAASC,cAAS,CAAC;IAC7C,IAAI,MAAM,iBAAiB,CAAC,QAAQ,EAAE;IACtC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,kDAAkD,CAAC;IACpF,IAAI;IACJ,IAAI,MAAM,QAAQ,CAAC,QAAQ,EAAE;IAC7B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,iDAAiD,CAAC;IACnF,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -1,21 +1,27 @@
1
1
  import Foundation
2
2
  import Capacitor
3
+ import BlinkCard
3
4
  import MicroblinkPlatform
4
5
 
5
6
  @objc(MicroblinkPlugin)
6
- public class MicroblinkPlugin: CAPPlugin, CAPBridgedPlugin, MicroblinkPlatformSDKDelegate {
7
+ public class MicroblinkPlugin: CAPPlugin, CAPBridgedPlugin, MicroblinkPlatformSDKDelegate, MBCBlinkCardOverlayViewControllerDelegate {
7
8
  public let identifier = "MicroblinkPlugin"
8
9
  public let jsName = "Microblink"
9
10
  public let pluginMethods: [CAPPluginMethod] = [
10
- CAPPluginMethod(name: "startVerification", returnType: CAPPluginReturnPromise)
11
+ CAPPluginMethod(name: "startVerification", returnType: CAPPluginReturnPromise),
12
+ CAPPluginMethod(name: "scanCard", returnType: CAPPluginReturnPromise)
11
13
  ]
12
- private var pendingCallId: String?
13
- private var sdk: MicroblinkPlatformSDK?
14
- private var pendingCardScanResult: [String: Any]?
14
+ private var pendingVerificationCallId: String?
15
+ private var verificationSDK: MicroblinkPlatformSDK?
16
+ private var pendingVerificationCardScanResult: [String: Any]?
17
+
18
+ private var pendingBlinkCardCallId: String?
19
+ private var blinkCardRecognizer: MBCBlinkCardRecognizer?
20
+ private weak var blinkCardRunnerViewController: UIViewController?
15
21
 
16
22
  @objc public func startVerification(_ call: CAPPluginCall) {
17
- if pendingCallId != nil {
18
- call.reject("A verification flow is already running.")
23
+ if pendingVerificationCallId != nil || pendingBlinkCardCallId != nil {
24
+ call.reject("A native flow is already running.")
19
25
  return
20
26
  }
21
27
  guard let workflowId = call.getString("workflowId"), !workflowId.isEmpty else {
@@ -69,20 +75,81 @@ public class MicroblinkPlugin: CAPPlugin, CAPBridgedPlugin, MicroblinkPlatformSD
69
75
  serviceSettings.getWorkflowInfo = workflowInfo
70
76
  }
71
77
 
72
- pendingCardScanResult = nil
78
+ pendingVerificationCardScanResult = nil
73
79
  bridge?.saveCall(call)
74
- pendingCallId = call.callbackId
75
- sdk = MicroblinkPlatformSDK(serviceSettings: serviceSettings, delegate: self)
80
+ pendingVerificationCallId = call.callbackId
81
+ verificationSDK = MicroblinkPlatformSDK(serviceSettings: serviceSettings, delegate: self)
76
82
 
77
- let sdkViewController = sdk?.startSDK()
83
+ let sdkViewController = verificationSDK?.startSDK()
78
84
  guard let sdkViewController else {
79
- clearPendingState()
85
+ clearPendingVerificationState()
80
86
  call.reject("Unable to start verification.")
81
87
  return
82
88
  }
83
89
  vc.present(sdkViewController, animated: true)
84
90
  }
85
91
 
92
+ @objc public func scanCard(_ call: CAPPluginCall) {
93
+ if pendingVerificationCallId != nil || pendingBlinkCardCallId != nil {
94
+ call.reject("A native flow is already running.")
95
+ return
96
+ }
97
+ guard let licenseKey = call.getString("licenseKey"), !licenseKey.isEmpty else {
98
+ call.reject("Missing required field: licenseKey.")
99
+ return
100
+ }
101
+ guard let vc = bridge?.viewController else {
102
+ call.reject("No view controller available")
103
+ return
104
+ }
105
+
106
+ bridge?.saveCall(call)
107
+ pendingBlinkCardCallId = call.callbackId
108
+
109
+ let licenseErrorHandler: MBCLicenseErrorBlock = { [weak self] licenseError in
110
+ guard let self, let pendingBlinkCardCallId, let pendingCall = self.bridge?.savedCall(withID: pendingBlinkCardCallId) else {
111
+ return
112
+ }
113
+ self.clearPendingBlinkCardState()
114
+ pendingCall.reject("Failed to initialize BlinkCard license (\(licenseError.rawValue)).")
115
+ self.bridge?.releaseCall(withID: pendingBlinkCardCallId)
116
+ }
117
+
118
+ if let licensee = call.getString("licensee"), !licensee.isEmpty {
119
+ MBCMicroblinkSDK.shared().setLicenseKey(licenseKey, andLicensee: licensee, errorCallback: licenseErrorHandler)
120
+ } else {
121
+ MBCMicroblinkSDK.shared().setLicenseKey(licenseKey, errorCallback: licenseErrorHandler)
122
+ }
123
+
124
+ let recognizer = MBCBlinkCardRecognizer()
125
+ recognizer.extractOwner = call.getBool("extractOwner") ?? true
126
+ recognizer.extractExpiryDate = call.getBool("extractExpiryDate") ?? true
127
+ recognizer.extractCvv = call.getBool("extractCvv") ?? true
128
+ recognizer.extractIban = call.getBool("extractIban") ?? true
129
+ recognizer.allowInvalidCardNumber = call.getBool("allowInvalidCardNumber") ?? false
130
+
131
+ let recognizerCollection = MBCRecognizerCollection(recognizers: [recognizer])
132
+ let overlaySettings = MBCBlinkCardOverlaySettings()
133
+ overlaySettings.enableEditScreen = call.getBool("enableEditScreen") ?? true
134
+
135
+ let overlayViewController = MBCBlinkCardOverlayViewController(
136
+ settings: overlaySettings,
137
+ recognizerCollection: recognizerCollection,
138
+ delegate: self
139
+ )
140
+ guard let runnerViewController = MBCViewControllerFactory.recognizerRunnerViewController(withOverlayViewController: overlayViewController) else {
141
+ clearPendingBlinkCardState()
142
+ bridge?.releaseCall(withID: call.callbackId)
143
+ call.reject("Unable to create BlinkCard runner view controller.")
144
+ return
145
+ }
146
+
147
+ blinkCardRecognizer = recognizer
148
+ blinkCardRunnerViewController = runnerViewController
149
+
150
+ vc.present(runnerViewController, animated: true)
151
+ }
152
+
86
153
  public func microblinkPlatformSDKDidFinish(
87
154
  viewController: UIViewController,
88
155
  result: MicroblinkPlatformResult
@@ -92,8 +159,8 @@ public class MicroblinkPlugin: CAPPlugin, CAPBridgedPlugin, MicroblinkPlatformSD
92
159
  "transactionId": result.transactionId,
93
160
  "status": mapStatus(result.status)
94
161
  ]
95
- if let pendingCardScanResult {
96
- payload["cardScanResult"] = pendingCardScanResult
162
+ if let pendingVerificationCardScanResult {
163
+ payload["cardScanResult"] = pendingVerificationCardScanResult
97
164
  }
98
165
  finalize(viewController: viewController, payload: payload)
99
166
  }
@@ -107,8 +174,8 @@ public class MicroblinkPlugin: CAPPlugin, CAPBridgedPlugin, MicroblinkPlatformSD
107
174
  "transactionId": cancelState.transactionId as Any,
108
175
  "cancelReason": mapCancelReason(cancelState.cancelReason)
109
176
  ]
110
- if let pendingCardScanResult {
111
- payload["cardScanResult"] = pendingCardScanResult
177
+ if let pendingVerificationCardScanResult {
178
+ payload["cardScanResult"] = pendingVerificationCardScanResult
112
179
  }
113
180
  finalize(viewController: viewController, payload: payload)
114
181
  }
@@ -117,7 +184,7 @@ public class MicroblinkPlugin: CAPPlugin, CAPBridgedPlugin, MicroblinkPlatformSD
117
184
  viewController: UIViewController,
118
185
  cardScanResult: MicroblinkPlatformResultCardScanResult
119
186
  ) {
120
- pendingCardScanResult = [
187
+ pendingVerificationCardScanResult = [
121
188
  "cardNumber": cardScanResult.cardNumber,
122
189
  "expiryDate": cardScanResult.expiryDate,
123
190
  "owner": cardScanResult.owner,
@@ -125,6 +192,34 @@ public class MicroblinkPlugin: CAPPlugin, CAPBridgedPlugin, MicroblinkPlatformSD
125
192
  ]
126
193
  }
127
194
 
195
+ public func blinkCardOverlayViewControllerDidFinishScanning(
196
+ _ blinkCardOverlayViewController: MBCBlinkCardOverlayViewController,
197
+ state: MBCRecognizerResultState
198
+ ) {
199
+ let result = blinkCardRecognizer?.result
200
+ var payload: [String: Any] = [
201
+ "canceled": false,
202
+ "resultState": mapBlinkCardResultState(state)
203
+ ]
204
+ if let result {
205
+ payload["processingStatus"] = mapBlinkCardProcessingStatus(result.processingStatus)
206
+ payload["cardNumber"] = result.cardNumber
207
+ payload["cardNumberValid"] = result.cardNumberValid
208
+ payload["cardNumberPrefix"] = result.cardNumberPrefix
209
+ payload["owner"] = result.owner
210
+ payload["cvv"] = result.cvv
211
+ payload["iban"] = result.iban
212
+ payload["expiryDate"] = mapBlinkCardDate(result.expiryDate)
213
+ }
214
+ finalizeBlinkCard(payload: payload)
215
+ }
216
+
217
+ public func blinkCardOverlayViewControllerDidTapClose(
218
+ _ blinkCardOverlayViewController: MBCBlinkCardOverlayViewController
219
+ ) {
220
+ finalizeBlinkCard(payload: ["canceled": true])
221
+ }
222
+
128
223
  private func mapStatus(_ status: MicroblinkPlatformResultStatus) -> String {
129
224
  switch status {
130
225
  case .accept:
@@ -151,18 +246,87 @@ public class MicroblinkPlugin: CAPPlugin, CAPBridgedPlugin, MicroblinkPlatformSD
151
246
 
152
247
  private func finalize(viewController: UIViewController, payload: [String: Any]) {
153
248
  viewController.dismiss(animated: true)
154
- guard let pendingCallId, let call = bridge?.savedCall(withID: pendingCallId) else {
155
- clearPendingState()
249
+ guard let pendingVerificationCallId, let call = bridge?.savedCall(withID: pendingVerificationCallId) else {
250
+ clearPendingVerificationState()
156
251
  return
157
252
  }
158
- clearPendingState()
253
+ clearPendingVerificationState()
159
254
  call.resolve(payload)
160
- bridge?.releaseCall(withID: pendingCallId)
255
+ bridge?.releaseCall(withID: pendingVerificationCallId)
256
+ }
257
+
258
+ private func clearPendingVerificationState() {
259
+ pendingVerificationCallId = nil
260
+ pendingVerificationCardScanResult = nil
261
+ verificationSDK = nil
262
+ }
263
+
264
+ private func clearPendingBlinkCardState() {
265
+ pendingBlinkCardCallId = nil
266
+ blinkCardRecognizer = nil
267
+ blinkCardRunnerViewController = nil
268
+ }
269
+
270
+ private func finalizeBlinkCard(payload: [String: Any]) {
271
+ DispatchQueue.main.async {
272
+ let pendingCallId = self.pendingBlinkCardCallId
273
+ self.blinkCardRunnerViewController?.dismiss(animated: true)
274
+ guard let pendingCallId, let call = self.bridge?.savedCall(withID: pendingCallId) else {
275
+ self.clearPendingBlinkCardState()
276
+ return
277
+ }
278
+ self.clearPendingBlinkCardState()
279
+ call.resolve(payload)
280
+ self.bridge?.releaseCall(withID: pendingCallId)
281
+ }
161
282
  }
162
283
 
163
- private func clearPendingState() {
164
- pendingCallId = nil
165
- pendingCardScanResult = nil
166
- sdk = nil
284
+ private func mapBlinkCardResultState(_ state: MBCRecognizerResultState) -> String {
285
+ switch state {
286
+ case .empty:
287
+ return "empty"
288
+ case .uncertain:
289
+ return "uncertain"
290
+ case .valid:
291
+ return "valid"
292
+ case .stageValid:
293
+ return "stageValid"
294
+ @unknown default:
295
+ return "empty"
296
+ }
297
+ }
298
+
299
+ private func mapBlinkCardProcessingStatus(_ status: MBCBlinkCardProcessingStatus) -> String {
300
+ switch status {
301
+ case .success:
302
+ return "success"
303
+ case .detectionFailed:
304
+ return "detectionFailed"
305
+ case .imagePreprocessingFailed:
306
+ return "imagePreprocessingFailed"
307
+ case .stabilityTestFailed:
308
+ return "stabilityTestFailed"
309
+ case .scanningWrongSide:
310
+ return "scanningWrongSide"
311
+ case .fieldIdentificationFailed:
312
+ return "fieldIdentificationFailed"
313
+ case .imageReturnFailed:
314
+ return "imageReturnFailed"
315
+ case .unsupportedCard:
316
+ return "unsupportedCard"
317
+ @unknown default:
318
+ return "unsupportedCard"
319
+ }
320
+ }
321
+
322
+ private func mapBlinkCardDate(_ date: MBCDate?) -> [String: Int]? {
323
+ guard let date else {
324
+ return nil
325
+ }
326
+ return [
327
+ "day": Int(date.day),
328
+ "month": Int(date.month),
329
+ "year": Int(date.year)
330
+ ]
167
331
  }
168
332
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-microblink",
3
- "version": "0.0.1",
3
+ "version": "0.2.0",
4
4
  "description": "Capacitor plugin for microblink",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",