@veriff/react-native-sdk 2.7.0 → 2.8.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.
@@ -0,0 +1,3 @@
1
+ {
2
+ "java.configuration.updateBuildConfiguration": "automatic"
3
+ }
@@ -33,7 +33,7 @@ buildscript {
33
33
  jcenter()
34
34
  }
35
35
  dependencies {
36
- classpath 'com.android.tools.build:gradle:3.4.1'
36
+ classpath 'com.android.tools.build:gradle:3.4.3'
37
37
  }
38
38
  }
39
39
  }
@@ -70,15 +70,16 @@ repositories {
70
70
  // Android JSC is installed from npm
71
71
  url "$rootDir/../node_modules/jsc-android/dist"
72
72
  }
73
- maven { url "https://cdn.veriff.me/android/" } //veriff
73
+ maven { url "https://cdn.veriff.me/android/" } //veriff public repo
74
74
  google()
75
75
  jcenter()
76
+ mavenCentral()
76
77
  }
77
78
 
78
79
  dependencies {
79
80
  //noinspection GradleDynamicVersion
80
- implementation 'com.facebook.react:react-native:+' // From node_modules
81
- implementation 'com.veriff:veriff-library:4.+'
81
+ implementation 'com.facebook.react:react-native:+'
82
+ implementation 'com.veriff:veriff-library:4.6.0'
82
83
  }
83
84
 
84
85
  def configureReactNativePom(def pom) {
@@ -0,0 +1,100 @@
1
+ package com.veriff.sdk.reactnative;
2
+
3
+ import android.content.Context;
4
+ import android.graphics.Bitmap;
5
+ import android.graphics.drawable.BitmapDrawable;
6
+ import android.graphics.drawable.Drawable;
7
+ import android.os.Handler;
8
+ import android.os.Looper;
9
+ import android.util.Log;
10
+ import com.facebook.common.references.CloseableReference;
11
+ import com.facebook.datasource.DataSource;
12
+ import com.facebook.drawee.backends.pipeline.Fresco;
13
+ import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
14
+ import com.facebook.imagepipeline.image.CloseableImage;
15
+ import com.facebook.imagepipeline.request.ImageRequest;
16
+ import com.facebook.imagepipeline.request.ImageRequestBuilder;
17
+
18
+ import java.io.IOException;
19
+ import java.util.concurrent.CountDownLatch;
20
+ import java.util.concurrent.atomic.AtomicReference;
21
+
22
+ public class ImageLoader {
23
+ private static final String TAG = "ImageLoader";
24
+
25
+ private final Handler main = new Handler(Looper.getMainLooper());
26
+
27
+ public Drawable load(Context context, String url) throws IOException {
28
+ ImageRequest request = ImageRequestBuilder.fromRequest(ImageRequest.fromUri(url)).build();
29
+
30
+ if (!Fresco.hasBeenInitialized()) {
31
+ Fresco.initialize(context);
32
+ }
33
+
34
+ DataSource<CloseableReference<CloseableImage>> source =
35
+ Fresco.getImagePipeline().fetchDecodedImage(request, null);
36
+
37
+ CountDownLatch imageLoadLatch = new CountDownLatch(1);
38
+ AtomicReference<Result> atomicResult = new AtomicReference<>(null);
39
+ source.subscribe(new BaseBitmapDataSubscriber() {
40
+ @Override
41
+ protected void onNewResultImpl(Bitmap bitmap) {
42
+ if (bitmap == null) {
43
+ Log.w(TAG, "Null bitmap: " + url);
44
+ atomicResult.set(new Result(new IOException("Loaded bitmap was null")));
45
+ } else {
46
+ Log.w(TAG, "Non-Null bitmap: " + url);
47
+ atomicResult.set(new Result(bitmap.copy(bitmap.getConfig(), false)));
48
+ }
49
+ imageLoadLatch.countDown();
50
+ }
51
+
52
+ @Override
53
+ protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
54
+ Throwable failure = dataSource.getFailureCause();
55
+ if (failure == null) {
56
+ atomicResult.set(new Result(new IOException("Provided failure cause was null")));
57
+ } else if (failure instanceof IOException) {
58
+ atomicResult.set(new Result((IOException) failure));
59
+ } else {
60
+ atomicResult.set(new Result(new IOException("Failed loading image", failure)));
61
+ }
62
+ imageLoadLatch.countDown();
63
+ }
64
+ }, main::post);
65
+
66
+
67
+ try {
68
+ imageLoadLatch.await();
69
+ Result result = atomicResult.get();
70
+
71
+ if (result.error != null) {
72
+ Log.w(TAG, "Loading image from " + url + " failed", result.error);
73
+ throw result.error;
74
+ } else {
75
+ Log.w(TAG, "Loading image got a bitmap with size w=" + result.bitmap.getWidth() + " h=" + result.bitmap.getHeight());
76
+ return new BitmapDrawable(context.getResources(), result.bitmap);
77
+ }
78
+ } catch (InterruptedException e) {
79
+ Thread.currentThread().interrupt(); // preserve interrupt status
80
+ throw new IOException("Interrupted while loading image");
81
+ }
82
+ }
83
+
84
+ private static class Result {
85
+ private final IOException error;
86
+
87
+ private final Bitmap bitmap;
88
+
89
+ private Result(IOException error) {
90
+ this.error = error;
91
+ this.bitmap = null;
92
+ }
93
+
94
+ private Result(Bitmap bitmap) {
95
+ this.error = null;
96
+ this.bitmap = bitmap;
97
+ }
98
+ }
99
+
100
+ }
@@ -0,0 +1,105 @@
1
+ package com.veriff.sdk.reactnative;
2
+
3
+ import android.content.Context;
4
+ import android.graphics.Typeface;
5
+ import android.graphics.drawable.Drawable;
6
+ import android.os.Parcel;
7
+ import android.os.Parcelable;
8
+ import android.util.Log;
9
+ import androidx.annotation.NonNull;
10
+ import androidx.annotation.Nullable;
11
+ import com.veriff.Branding;
12
+ import com.veriff.Branding.ExternalResources.Image;
13
+ import com.veriff.Branding.ExternalResources.Lottie;
14
+
15
+ import java.io.IOException;
16
+ import java.util.HashMap;
17
+ import java.util.Map;
18
+
19
+ import static com.veriff.sdk.reactnative.VeriffSdkModule.TAG;
20
+
21
+ public class ReactNativeExternalResources implements Branding.ExternalResources, Parcelable {
22
+ private final ImageLoader imageLoader = new ImageLoader();
23
+
24
+ private final Map<Image, String> imageUrls;
25
+ private final Map<Lottie, String> lottieJson;
26
+
27
+ protected ReactNativeExternalResources(Parcel in) {
28
+ imageUrls = readMapFromParcel(in, Image.values());
29
+ lottieJson = readMapFromParcel(in, Lottie.values());
30
+ }
31
+
32
+ public ReactNativeExternalResources(Map<Image, String> imageUrls, Map<Lottie, String> lottieJson) {
33
+ this.imageUrls = imageUrls;
34
+ this.lottieJson = lottieJson;
35
+ }
36
+
37
+ @Nullable
38
+ @Override
39
+ public Drawable loadImage(@NonNull Context context, @NonNull Image target) throws IOException {
40
+ String imageUrl = imageUrls.get(target);
41
+ if (imageUrl != null) {
42
+ return imageLoader.load(context, imageUrl);
43
+ } else {
44
+ return null;
45
+ }
46
+ }
47
+
48
+ @Nullable
49
+ @Override
50
+ public String getLottieJson(Context context, @NonNull Lottie target) {
51
+ return lottieJson.get(target);
52
+ }
53
+
54
+ public static final Creator<ReactNativeExternalResources> CREATOR = new Creator<ReactNativeExternalResources>() {
55
+ @Override
56
+ public ReactNativeExternalResources createFromParcel(Parcel in) {
57
+ return new ReactNativeExternalResources(in);
58
+ }
59
+
60
+ @Override
61
+ public ReactNativeExternalResources[] newArray(int size) {
62
+ return new ReactNativeExternalResources[size];
63
+ }
64
+ };
65
+
66
+ @Override
67
+ public int describeContents() {
68
+ return 0;
69
+ }
70
+
71
+ @Override
72
+ public void writeToParcel(Parcel dest, int flags) {
73
+ writeMapToParcel(dest, imageUrls);
74
+ writeMapToParcel(dest, lottieJson);
75
+ }
76
+
77
+ private <E extends Enum<E>> void writeMapToParcel(Parcel dest, Map<E, String> map) {
78
+ dest.writeInt(map.size());
79
+ for (Map.Entry<E, String> entry : map.entrySet()) {
80
+ dest.writeInt(entry.getKey().ordinal());
81
+ dest.writeString(entry.getValue());
82
+ Log.d(TAG, String.format("Write to parcel [%s] -> [%s]", entry.getKey().ordinal(), entry.getValue()));
83
+ }
84
+ }
85
+
86
+ public <E extends Enum<E>> Map<E, String> readMapFromParcel(Parcel in, E[] values) {
87
+ int count = in.readInt();
88
+
89
+ Map<E, String> map = new HashMap<>(count);
90
+
91
+ int i = 0;
92
+ while (i < count) {
93
+ i++;
94
+
95
+ int ordinal = in.readInt();
96
+ String value = in.readString();
97
+ Log.d(TAG, String.format("Read from parcel [%s] -> [%s]", ordinal, value));
98
+
99
+ E key = values[ordinal];
100
+ map.put(key, value);
101
+ }
102
+
103
+ return map;
104
+ }
105
+ }
@@ -10,9 +10,6 @@ import android.os.Parcel;
10
10
  import android.os.Parcelable;
11
11
  import android.util.Log;
12
12
 
13
- import androidx.annotation.NonNull;
14
- import androidx.annotation.WorkerThread;
15
-
16
13
  import com.facebook.common.references.CloseableReference;
17
14
  import com.facebook.datasource.DataSource;
18
15
  import com.facebook.drawee.backends.pipeline.Fresco;
@@ -22,9 +19,6 @@ import com.facebook.imagepipeline.request.ImageRequest;
22
19
  import com.facebook.imagepipeline.request.ImageRequestBuilder;
23
20
  import com.veriff.Branding;
24
21
 
25
- import org.jetbrains.annotations.NotNull;
26
- import org.jetbrains.annotations.Nullable;
27
-
28
22
  import java.io.IOException;
29
23
  import java.util.concurrent.CountDownLatch;
30
24
  import java.util.concurrent.atomic.AtomicReference;
@@ -44,11 +38,8 @@ public class ReactNativeImageProvider implements Branding.DrawableProvider, Parc
44
38
  this(in.readString());
45
39
  }
46
40
 
47
- @NonNull
48
- @NotNull
49
41
  @Override
50
- @WorkerThread
51
- public Drawable loadImage(@NonNull @NotNull Context context) throws IOException {
42
+ public Drawable loadImage(Context context) throws IOException {
52
43
  ImageRequest request = ImageRequestBuilder.fromRequest(ImageRequest.fromUri(this.url)).build();
53
44
  DataSource<CloseableReference<CloseableImage>> source =
54
45
  Fresco.getImagePipeline().fetchDecodedImage(request, null);
@@ -58,7 +49,7 @@ public class ReactNativeImageProvider implements Branding.DrawableProvider, Parc
58
49
 
59
50
  source.subscribe(new BaseBitmapDataSubscriber() {
60
51
  @Override
61
- protected void onNewResultImpl(@Nullable Bitmap bitmap) {
52
+ protected void onNewResultImpl(Bitmap bitmap) {
62
53
  if (bitmap == null) {
63
54
  atomicResult.set(new Result(new IOException("Loaded bitmap was null")));
64
55
  } else {
@@ -100,10 +91,8 @@ public class ReactNativeImageProvider implements Branding.DrawableProvider, Parc
100
91
  }
101
92
 
102
93
  private static class Result {
103
- @Nullable
104
94
  private final IOException error;
105
95
 
106
- @Nullable
107
96
  private final Bitmap bitmap;
108
97
 
109
98
  private Result(IOException error) {
@@ -3,6 +3,7 @@ package com.veriff.sdk.reactnative;
3
3
  import android.app.Activity;
4
4
  import android.content.Context;
5
5
  import android.content.Intent;
6
+ import android.content.res.Resources;
6
7
  import android.graphics.Color;
7
8
  import android.text.TextUtils;
8
9
  import android.util.Log;
@@ -19,15 +20,15 @@ import com.facebook.react.bridge.ReadableType;
19
20
  import com.facebook.react.bridge.WritableMap;
20
21
  import com.veriff.Branding;
21
22
  import com.veriff.Configuration;
23
+ import com.veriff.Font;
22
24
  import com.veriff.Result;
23
25
  import com.veriff.Result.Status;
24
26
  import com.veriff.Sdk;
25
27
 
26
- import java.util.HashMap;
27
- import java.util.Locale;
28
- import java.util.Map;
28
+ import java.util.*;
29
29
 
30
30
  import com.veriff.GeneralConfig;
31
+ import com.veriff.sdk.reactnative.mapper.ExternalResourcesMapper;
31
32
  import okhttp3.HttpUrl;
32
33
 
33
34
  import static android.app.Activity.RESULT_CANCELED;
@@ -62,7 +63,7 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
62
63
  private static final String STATUS_ERROR = "STATUS_ERROR";
63
64
 
64
65
  private static final String DEFAULT_BASE_URL = "https://magic.veriff.me";
65
- private static final String TAG = "@veriff/react-native-sdk";
66
+ public static final String TAG = "@veriff/RN-SDK";
66
67
  private static final String JS_NAME = "VeriffSdk";
67
68
 
68
69
  private static final int VERIFF_REQUEST_CODE = 47239;
@@ -86,8 +87,13 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
86
87
  public static final String KEY_PRIMARY_BUTTON_BACKGROUND_COLOR = "primaryButtonBackgroundColor";
87
88
  public static final String KEY_BUTTON_CORNER_RADIUS = "buttonCornerRadius";
88
89
  private static final String KEY_CUSTOM_INTRO_SCREEN = "customIntroScreen";
90
+ public static final String KEY_ADVANCED_CONFIGURATIONS = "advancedConfigurations";
89
91
  private static final String KEY_RN_IMAGE_URI = "uri";
90
92
 
93
+ private static final String KEY_FONT = "androidFont";
94
+ private static final String KEY_FONT_NORMAL = "regularFontName";
95
+ private static final String KEY_FONT_BOLD = "boldFontName";
96
+
91
97
  private static final String ERROR_UNABLE_TO_ACCESS_CAMERA = "UNABLE_TO_ACCESS_CAMERA";
92
98
  private static final String ERROR_UNABLE_TO_RECORD_AUDIO = "UNABLE_TO_RECORD_AUDIO";
93
99
  private static final String ERROR_UNABLE_TO_START_CAMERA = "UNABLE_TO_START_CAMERA";
@@ -159,19 +165,19 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
159
165
  } else {
160
166
  sessionToken = configuration.hasKey(KEY_TOKEN) ? configuration.getString(KEY_TOKEN) : null;
161
167
  if (TextUtils.isEmpty(sessionToken)) {
162
- promise.reject(ERROR_INVALID_ARGS, "No sessionToken in Veriff SDK configuration");
163
- return;
168
+ promise.reject(ERROR_INVALID_ARGS, "No sessionToken in Veriff SDK configuration");
169
+ return;
164
170
  }
165
171
 
166
172
  String baseUrl = null;
167
173
  if (configuration.hasKey(KEY_BASE_URL)) {
168
- baseUrl = configuration.getString(KEY_BASE_URL);
174
+ baseUrl = configuration.getString(KEY_BASE_URL);
169
175
  }
170
176
  if (TextUtils.isEmpty(baseUrl)) {
171
- baseUrl = DEFAULT_BASE_URL;
177
+ baseUrl = DEFAULT_BASE_URL;
172
178
  }
173
179
  if (baseUrl.endsWith("/")) {
174
- baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
180
+ baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
175
181
  }
176
182
  startUrl = baseUrl + "/v/" + sessionToken;
177
183
  }
@@ -203,11 +209,11 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
203
209
 
204
210
  Status status = resultCode == RESULT_CANCELED ? CANCELED : ERROR;
205
211
  if (veriffResult != null) {
206
- status = veriffResult.getStatus();
212
+ status = veriffResult.getStatus();
207
213
  }
208
214
  result.putString(KEY_STATUS, statusToString(status));
209
- if (veriffResult != null && veriffResult.getError() != null){
210
- result.putString(KEY_ERROR, codeToError(veriffResult.getError()));
215
+ if (veriffResult != null && veriffResult.getError() != null) {
216
+ result.putString(KEY_ERROR, codeToError(veriffResult.getError()));
211
217
  }
212
218
 
213
219
  promise.resolve(result);
@@ -255,7 +261,15 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
255
261
  branding.primaryButtonBackgroundColor(parseColor(brandConfig.getString(KEY_PRIMARY_BUTTON_BACKGROUND_COLOR)));
256
262
  }
257
263
  if (brandConfig.hasKey(KEY_BUTTON_CORNER_RADIUS)) {
258
- branding.buttonCornerRadius((float)brandConfig.getDouble(KEY_BUTTON_CORNER_RADIUS));
264
+ branding.buttonCornerRadius((float) brandConfig.getDouble(KEY_BUTTON_CORNER_RADIUS));
265
+ }
266
+ handleExternalResources(brandConfig, branding);
267
+ handleAdvancedConfigurations(brandConfig, branding);
268
+
269
+ if (brandConfig.hasKey(KEY_FONT)) {
270
+ ReadableMap srcFont = brandConfig.getMap(KEY_FONT);
271
+ Font font = buildFont(activity, srcFont);
272
+ branding.font(font);
259
273
  }
260
274
  configBuilder.branding(branding.build());
261
275
  }
@@ -269,11 +283,44 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
269
283
  activity.startActivityForResult(intent, VERIFF_REQUEST_CODE);
270
284
 
271
285
  } catch (Throwable t) {
272
- Log.e(TAG, "starting verification failed", t);
273
- promise.reject(t);
286
+ Log.e(TAG, "starting verification failed", t);
287
+ promise.reject(t);
274
288
  }
275
289
  }
276
290
 
291
+ private Font buildFont(Context context, ReadableMap src) {
292
+ int normalFont = getFontId(context, src.getString(KEY_FONT_NORMAL));
293
+ int boldFont = getFontId(context, src.getString(KEY_FONT_BOLD));
294
+
295
+ Log.v(TAG, String.format("Normal font: [%s], value [%s]",
296
+ src.getString(KEY_FONT_NORMAL), normalFont));
297
+
298
+ Log.v(TAG, String.format("Bold font: [%s], value [%s]",
299
+ src.getString(KEY_FONT_BOLD), boldFont));
300
+
301
+ return new Font.Builder()
302
+ .setNormalAndBold(normalFont, boldFont)
303
+ .build();
304
+ }
305
+
306
+
307
+ private void handleExternalResources(ReadableMap brandConfig, Branding.Builder branding) {
308
+ ExternalResourcesMapper mapper = new ExternalResourcesMapper();
309
+
310
+ branding.externalResources(mapper.map(brandConfig));
311
+ }
312
+
313
+ private void handleAdvancedConfigurations(ReadableMap brandConfig, Branding.Builder branding) {
314
+ Map<String, Object> result = new HashMap<>();
315
+
316
+ if (brandConfig.hasKey(KEY_ADVANCED_CONFIGURATIONS)) {
317
+ ReadableMap config = brandConfig.getMap(KEY_ADVANCED_CONFIGURATIONS);
318
+ result.put("customer", config.getString("customer"));
319
+ }
320
+
321
+ branding.advancedConfigurations(result);
322
+ }
323
+
277
324
  private void handleLogo(Context context, String key, Branding.Builder branding, ReadableMap brandConfig) {
278
325
  ReadableType type = brandConfig.getType(key);
279
326
  if (ReadableType.String.equals(type)) {
@@ -295,7 +342,6 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
295
342
  Log.w(TAG, "Image url is empty: " + url);
296
343
  }
297
344
  } else {
298
- Log.w(TAG, "Provided image does not have " + KEY_RN_IMAGE_URI + " key. Keys: ");
299
345
  for (String imageKey : image.toHashMap().keySet()) {
300
346
  Log.w(TAG, imageKey);
301
347
  }
@@ -304,7 +350,7 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
304
350
  Log.w(TAG, "Provided image is null");
305
351
  }
306
352
  } else {
307
- Log.w(TAG, "Unexpected image type: " + type);
353
+ Log.w(TAG, "Unexpected image type: " + type);
308
354
  }
309
355
  }
310
356
 
@@ -322,12 +368,12 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
322
368
  long color = Long.parseLong(hexcolor, 16);
323
369
  int a = 255;
324
370
  if (hexcolor.length() > 6) {
325
- a = ((int)color) & 0xff;
371
+ a = ((int) color) & 0xff;
326
372
  color = color >>> 8;
327
373
  }
328
- int r = ((int)(color >>> 16)) & 0xff;
329
- int g = ((int)(color >>> 8)) & 0xff;
330
- int b = ((int)(color >>> 0)) & 0xff;
374
+ int r = ((int) (color >>> 16)) & 0xff;
375
+ int g = ((int) (color >>> 8)) & 0xff;
376
+ int b = ((int) (color >>> 0)) & 0xff;
331
377
  return Color.argb(a, r, g, b);
332
378
  }
333
379
 
@@ -335,6 +381,10 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
335
381
  return context.getResources().getIdentifier(name, "drawable", context.getPackageName());
336
382
  }
337
383
 
384
+ private static int getFontId(Context context, String name) {
385
+ return context.getResources().getIdentifier(name, "font", context.getPackageName());
386
+ }
387
+
338
388
  private static String codeToError(Result.Error error) {
339
389
  switch (error) {
340
390
  case UNABLE_TO_ACCESS_CAMERA:
@@ -344,17 +394,17 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
344
394
  case UNABLE_TO_START_CAMERA:
345
395
  return ERROR_UNABLE_TO_START_CAMERA;
346
396
  case UNSUPPORTED_SDK_VERSION:
347
- return ERROR_UNSUPPORTED_SDK_VERSION;
397
+ return ERROR_UNSUPPORTED_SDK_VERSION;
348
398
  case SESSION_ERROR:
349
- return ERROR_SESSION;
399
+ return ERROR_SESSION;
350
400
  case NETWORK_ERROR:
351
- return ERROR_NETWORK;
401
+ return ERROR_NETWORK;
352
402
  case SETUP_ERROR:
353
- return ERROR_SETUP;
403
+ return ERROR_SETUP;
354
404
  case NFC_DISABLED:
355
- return ERROR_NFC_DISABLED;
405
+ return ERROR_NFC_DISABLED;
356
406
  case DEVICE_HAS_NO_NFC:
357
- return ERROR_DEVICE_HAS_NO_NFC;
407
+ return ERROR_DEVICE_HAS_NO_NFC;
358
408
  case UNKNOWN_ERROR:
359
409
  default:
360
410
  return ERROR_UNKNOWN;
@@ -362,11 +412,13 @@ public class VeriffSdkModule extends ReactContextBaseJavaModule {
362
412
  }
363
413
 
364
414
  private static String statusToString(Status status) {
365
- switch (status){
366
- case DONE: return STATUS_DONE;
367
- case CANCELED: return STATUS_CANCELED;
368
- default: return STATUS_ERROR;
369
- }
415
+ switch (status) {
416
+ case DONE:
417
+ return STATUS_DONE;
418
+ case CANCELED:
419
+ return STATUS_CANCELED;
420
+ default:
421
+ return STATUS_ERROR;
422
+ }
370
423
  }
371
-
372
424
  }
@@ -0,0 +1,114 @@
1
+ package com.veriff.sdk.reactnative.mapper;
2
+
3
+ import android.graphics.Typeface;
4
+ import android.util.JsonWriter;
5
+ import android.util.Log;
6
+ import androidx.annotation.NonNull;
7
+ import com.facebook.infer.annotation.Assertions;
8
+ import com.facebook.react.bridge.Dynamic;
9
+ import com.facebook.react.bridge.ReadableArray;
10
+ import com.facebook.react.bridge.ReadableMap;
11
+ import com.facebook.react.bridge.ReadableNativeMap;
12
+ import com.veriff.sdk.reactnative.ImageLoader;
13
+ import com.veriff.sdk.reactnative.ReactNativeExternalResources;
14
+ import com.veriff.Branding;
15
+ import com.veriff.Branding.ExternalResources.Image;
16
+ import com.veriff.Branding.ExternalResources.Lottie;
17
+
18
+ import java.util.HashMap;
19
+ import java.util.Iterator;
20
+ import java.util.LinkedHashMap;
21
+ import java.util.Map;
22
+
23
+ import static com.veriff.sdk.reactnative.VeriffSdkModule.KEY_ADVANCED_CONFIGURATIONS;
24
+ import static com.veriff.sdk.reactnative.VeriffSdkModule.TAG;
25
+
26
+ public class ExternalResourcesMapper {
27
+ public ReactNativeExternalResources map(ReadableMap brandConfig) {
28
+ Map<Image, String> images = mapImages(brandConfig);
29
+ Map<Lottie, String> lottie = mapLottie(brandConfig);
30
+
31
+ if (!images.isEmpty() || !lottie.isEmpty()) {
32
+ return new ReactNativeExternalResources(images, lottie);
33
+ } else {
34
+ return null;
35
+ }
36
+ }
37
+
38
+ private Map<Image, String> mapImages(ReadableMap brandConfig) {
39
+ Map<Image, String> images = new HashMap();
40
+ if (brandConfig.hasKey(KEY_ADVANCED_CONFIGURATIONS)) {
41
+ ReadableMap config = brandConfig.getMap(KEY_ADVANCED_CONFIGURATIONS);
42
+
43
+ appendImage(config, KEY_DOCUMENT_FRONT, images, Image.DOCUMENT_FRONT);
44
+ appendImage(config, KEY_DOCUMENT_BACK, images, Image.DOCUMENT_BACK_END);
45
+ appendImage(config, KEY_BANNER_ERROR_ICON, images, Image.BANNER_ICON_ERROR);
46
+ appendImage(config, KEY_CAMERA_ERROR, images, Image.ERROR_CAMERA);
47
+ appendImage(config, KEY_MICROPHONE_ERROR, images, Image.ERROR_MICROPHONE);
48
+ appendImage(config, KEY_SERVER_ERROR, images, Image.ERROR_SYSTEM);
49
+ appendImage(config, KEY_LOCAL_ERROR, images, Image.ERROR_SYSTEM);
50
+ appendImage(config, KEY_NETWORK_ERROR, images, Image.ERROR_NETWORK);
51
+ appendImage(config, KEY_VERSION_ERROR, images, Image.ERROR_VERSION);
52
+ appendImage(config, KEY_UNKNOWN_ERROR, images, Image.ERROR_UNKNOWN);
53
+ appendImage(config, KEY_CONSENT_ICON, images, Image.CONSENT_IMAGE);
54
+ }
55
+
56
+ return images;
57
+ }
58
+
59
+ private void appendImage(
60
+ ReadableMap advancedConfig,
61
+ String configKey,
62
+ Map<Branding.ExternalResources.Image, String> map,
63
+ Branding.ExternalResources.Image mapKey
64
+ ) {
65
+ if (advancedConfig.hasKey(configKey)) {
66
+ ReadableMap item = advancedConfig.getMap(configKey);
67
+ String url = item.getString("uri");
68
+ if (url != null) {
69
+ map.put(mapKey, url);
70
+ }
71
+ }
72
+ }
73
+
74
+ private Map<Lottie, String> mapLottie(ReadableMap brandConfig) {
75
+ Map<Lottie, String> lottie = new HashMap();
76
+
77
+ if (brandConfig.hasKey(KEY_ADVANCED_CONFIGURATIONS)) {
78
+ ReadableMap config = brandConfig.getMap(KEY_ADVANCED_CONFIGURATIONS);
79
+
80
+ appendLottie(config, KEY_LOTTIE_PROGRESS, lottie, Lottie.PROGRESS);
81
+
82
+ }
83
+
84
+ return lottie;
85
+ }
86
+
87
+ private void appendLottie(
88
+ ReadableMap advancedConfig,
89
+ String configKey,
90
+ Map<Lottie, String> map,
91
+ Lottie mapKey
92
+ ) {
93
+ if (advancedConfig.hasKey(configKey)) {
94
+ String lottie = advancedConfig.getString(configKey);
95
+
96
+ map.put(mapKey, lottie);
97
+ }
98
+ }
99
+
100
+ private final String KEY_DOCUMENT_FRONT = "documentFrontIcon";
101
+ private final String KEY_DOCUMENT_BACK = "documentBackIcon";
102
+ private final String KEY_BANNER_ERROR_ICON = "bannerErrorIcon";
103
+ private final String KEY_CONSENT_ICON = "consentIcon";
104
+
105
+ private final String KEY_CAMERA_ERROR = "cameraUnavailableErrorIcon";
106
+ private final String KEY_MICROPHONE_ERROR = "microphoneUnavailableErrorIcon";
107
+ private final String KEY_SERVER_ERROR = "serverErrorIcon";
108
+ private final String KEY_LOCAL_ERROR = "localErrorIcon";
109
+ private final String KEY_NETWORK_ERROR = "networkErrorIcon";
110
+ private final String KEY_VERSION_ERROR = "deprecatedSDKVersionErrorIcon";
111
+ private final String KEY_UNKNOWN_ERROR = "unknownErrorIcon";
112
+
113
+ private final String KEY_LOTTIE_PROGRESS = "loadingAnimation";
114
+ }
package/app.plugin.js CHANGED
@@ -18,7 +18,7 @@ function getUpdatedProjectGradle(buildGradle) {
18
18
  }
19
19
 
20
20
  function withVeriffProjectGradle(expoConfig) {
21
- return withProjectBuildGradle(expoConfig, config => {
21
+ return withProjectBuildGradle(expoConfig, (config) => {
22
22
  config.modResults.contents = getUpdatedProjectGradle(
23
23
  config.modResults.contents,
24
24
  );
package/ios/Podfile CHANGED
@@ -4,6 +4,7 @@ require_relative '../node_modules/@react-native-community/cli-platform-ios/nativ
4
4
  target 'VeriffSdk' do
5
5
  # Pods for VeriffSdk
6
6
  pod 'VeriffSDK'
7
+ pod 'lottie-ios'
7
8
 
8
9
  pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
9
10
  pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
@@ -1,6 +1,7 @@
1
1
  import Foundation
2
2
  import Veriff
3
3
  import UIKit
4
+ import Lottie
4
5
 
5
6
  @objc(VeriffSdkReactWrapper)
6
7
  class VeriffSdk: NSObject {
@@ -28,7 +29,6 @@ class VeriffSdk: NSObject {
28
29
  private static let BRANDING = "branding"
29
30
  private static let LOCALE = "locale"
30
31
  private static let THEME_COLOR = "themeColor"
31
- static let NAVIGATION_BAR_IMAGE = "navigationBarImage"
32
32
  static let LOGO = "logo"
33
33
  private static let BACKGROUND_COLOR = "backgroundColor"
34
34
  private static let STATUS_BAR_COLOR = "statusBarColor"
@@ -37,6 +37,8 @@ class VeriffSdk: NSObject {
37
37
  private static let PRIMARY_BUTTON_BACKGROUND_COLOR = "primaryButtonBackgroundColor"
38
38
  private static let BUTTON_CORNER_RADIUS = "buttonCornerRadius"
39
39
  private static let USE_CUSTOM_INTRO_SCREEN = "customIntroScreen"
40
+ private static let ADVANCED_CONFIGURATIONS = "advancedConfigurations"
41
+ private static let FONT = "iOSFont"
40
42
 
41
43
  private static let STATUS = "status"
42
44
  private static let ERROR = "error"
@@ -69,7 +71,7 @@ class VeriffSdk: NSObject {
69
71
  if let brandingConfig = (configuration[VeriffSdk.BRANDING] as? [String: AnyObject]) {
70
72
  let color = (brandingConfig[VeriffSdk.THEME_COLOR] as? String).map { VeriffSdk.parseColor(hexcolor: $0) }
71
73
 
72
- let imageProvider = VeriffSdkImageProvider(configuration: brandingConfig)
74
+ let imageProvider = VeriffSdkImageProvider(imageSource: brandingConfig[VeriffSdk.LOGO])
73
75
 
74
76
  if let imageURI = brandingConfig[VeriffSdk.LOGO],
75
77
  let imageDict = imageURI as? [String: AnyObject],
@@ -97,6 +99,50 @@ class VeriffSdk: NSObject {
97
99
  branding?.secondaryTextColor = (brandingConfig[VeriffSdk.SECONDARY_TEXT_COLOR] as? String).map { VeriffSdk.parseColor(hexcolor: $0) }
98
100
  branding?.primaryButtonBackgroundColor = (brandingConfig[VeriffSdk.PRIMARY_BUTTON_BACKGROUND_COLOR] as? String).map { VeriffSdk.parseColor(hexcolor: $0) }
99
101
  branding?.buttonCornerRadius = (brandingConfig[VeriffSdk.BUTTON_CORNER_RADIUS] as? Double).map { CGFloat($0) }
102
+ if let rnAdvancedConfigurations = brandingConfig[VeriffSdk.ADVANCED_CONFIGURATIONS] as? [String: Any] {
103
+ var advancedConfigurations: [String: Any] = [:]
104
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "rotateToPortraitIcon"), for: "rotateToPortraitIcon")
105
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "rotateToLandscapeIcon"), for: "rotateToLandscapeIcon")
106
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "documentFrontIcon"), for: "documentFrontIcon")
107
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "documentBackIcon"), for: "documentBackIcon")
108
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "cameraUnavailableErrorIcon"), for: "cameraUnavailableErrorIcon")
109
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "microphoneUnavailableErrorIcon"), for: "microphoneUnavailableErrorIcon")
110
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "serverErrorIcon"), for: "serverErrorIcon")
111
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "localErrorIcon"), for: "localErrorIcon")
112
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "networkErrorIcon"), for: "networkErrorIcon")
113
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "uploadErrorIcon"), for: "uploadErrorIcon")
114
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "videoFailedErrorIcon"), for: "videoFailedErrorIcon")
115
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "deprecatedSDKVersionErrorIcon"), for: "deprecatedSDKVersionErrorIcon")
116
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "unknownErrorIcon"), for: "unknownErrorIcon")
117
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "bannerErrorIcon"), for: "bannerErrorIcon")
118
+ advancedConfigurations.addValue(rnAdvancedConfigurations.image(for: "consentIcon"), for: "consentIcon")
119
+ advancedConfigurations.addValue(rnAdvancedConfigurations["customer"], for: "customer")
120
+ if let loadingAnimationString = rnAdvancedConfigurations["loadingAnimation"] as? String {
121
+ if
122
+ let jsonData = loadingAnimationString.data(using: .utf8),
123
+ let animation = try? JSONDecoder().decode(Lottie.Animation.self, from: jsonData)
124
+ {
125
+ let animationView: () -> UIView = {
126
+ let animationView = Lottie.AnimationView(animation: animation)
127
+ animationView.backgroundBehavior = .pauseAndRestore
128
+ animationView.loopMode = .loop
129
+ animationView.play(completion: nil)
130
+ return animationView
131
+ }
132
+ advancedConfigurations["loadingAnimation"] = animationView
133
+ }
134
+ }
135
+ branding?.advancedConfigurations = advancedConfigurations
136
+ }
137
+ if
138
+ let font = brandingConfig[VeriffSdk.FONT] as? [String: Any],
139
+ let regular = font["regularFontName"] as? String,
140
+ let light = font["lightFontName"] as? String,
141
+ let semiBold = font["semiBoldFontName"] as? String,
142
+ let bold = font["boldFontName"] as? String
143
+ {
144
+ branding?.font = Veriff.VeriffSdk.Branding.Font(regularFontName: regular, lightFontName: light, semiBoldFontName: semiBold, boldFontName: bold)
145
+ }
100
146
  }
101
147
 
102
148
  if let sUrl = configuration[VeriffSdk.SESSION_URL] as? String {
@@ -212,3 +258,25 @@ extension VeriffSdk: VeriffSdkDelegate {
212
258
  self.resolve?(resultDict)
213
259
  }
214
260
  }
261
+
262
+ private extension Dictionary where Key == String, Value == Any {
263
+ func image(for key: String) -> Any? {
264
+ let imageProvider = VeriffSdkImageProvider(imageSource: self[key])
265
+ if
266
+ let imageDict = self[key] as? [String: AnyObject],
267
+ let urlString = imageDict["uri"] as? String,
268
+ let url = URL(string: urlString),
269
+ !url.isFileURL,
270
+ let data = try? Data(contentsOf: url)
271
+ {
272
+ return UIImage(data: data)
273
+ } else {
274
+ return imageProvider.loadLocalAsset()
275
+ }
276
+ }
277
+
278
+ mutating func addValue(_ value: Any?, for key: String) {
279
+ guard let value = value else { return }
280
+ self[key] = value
281
+ }
282
+ }
@@ -4,15 +4,15 @@ import UIKit.UIImage
4
4
 
5
5
  @objc(VeriffSdkImageProvider)
6
6
  final class VeriffSdkImageProvider: NSObject {
7
- private let configuration: [String: AnyObject]
7
+ private let imageSource: Any?
8
8
 
9
- init(configuration: [String: AnyObject]) {
10
- self.configuration = configuration
9
+ init(imageSource: Any?) {
10
+ self.imageSource = imageSource
11
11
  super.init()
12
12
  }
13
13
 
14
14
  func loadLocalAsset() -> UIImage? {
15
- if let imageURI = configuration[VeriffSdk.LOGO] {
15
+ if let imageURI = imageSource {
16
16
  if let imageDict = imageURI as? [String: AnyObject],
17
17
  let urlString = imageDict["uri"] as? String {
18
18
  if let url = URL(string: urlString),
@@ -26,9 +26,7 @@ final class VeriffSdkImageProvider: NSObject {
26
26
  return UIImage(named: imageKey)
27
27
  }
28
28
  } else {
29
- let imageKey = configuration[VeriffSdk.NAVIGATION_BAR_IMAGE]
30
- let image = (imageKey as? String).flatMap { UIImage(named: $0) }
31
- return image
29
+ return UIImage()
32
30
  }
33
31
  }
34
32
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@veriff/react-native-sdk",
3
3
  "title": "React Native Veriff SDK",
4
- "version": "2.7.0",
4
+ "version": "2.8.0",
5
5
  "description": "React Native SDK for Veriff identity verification",
6
6
  "main": "index.js",
7
7
  "scripts": {
@@ -25,13 +25,35 @@
25
25
  "licenseFilename": "LICENSE",
26
26
  "readmeFilename": "README.md",
27
27
  "peerDependencies": {
28
- "react": "^16.8.1",
29
- "react-native": ">=0.59.0-rc.0 <1.0.x"
28
+ "react": "*",
29
+ "react-native": "*"
30
30
  },
31
31
  "devDependencies": {
32
- "react": "^16.8.3",
33
- "react-native": "^0.59.10",
34
- "@react-native-community/eslint-config": "^0.0.5",
35
- "eslint": "^6.5.1"
32
+ "react": "16.11.0",
33
+ "react-native": "0.62.3",
34
+ "@react-native-community/eslint-config": "^2.0.0",
35
+ "eslint": "^7.2.0"
36
+ },
37
+ "resolutions": {
38
+ "ansi-regex": "^5.0.1",
39
+ "minimist": "^0.2.1",
40
+ "lodash": "^4.17.21",
41
+ "ua-parser-js": "^0.7.24",
42
+ "path-parse": "^1.0.7",
43
+ "tmpl": "^1.0.5",
44
+ "node-fetch": "^2.6.7",
45
+ "plist": "^3.0.4",
46
+ "ajv": "^6.12.3"
47
+ },
48
+ "resolutionComments": {
49
+ "ansi-regex": "Resolving to 5.0.1 to fix vulnerability (https://github.com/advisories/GHSA-93q8-gq69-wqmw)",
50
+ "minimist": "Resolving to 0.2.1 to fix vulnerability (https://www.npmjs.com/advisories/1066649)",
51
+ "lodash": "Resolving to 4.17.21 to fix vulnerability (https://www.npmjs.com/advisories/1065397)",
52
+ "ua-parser-js": "Resolving to 0.7.24 to fix vulnerability (https://www.npmjs.com/advisories/1065393)",
53
+ "path-parse": "Resolving to 1.0.7 to fix vulnerability (https://www.npmjs.com/advisories/1064972)",
54
+ "tmpl": "Resolving to 1.0.5 to fix vulnerability (https://www.npmjs.com/advisories/1064907)",
55
+ "node-fetch": "Resolving to 2.6.7 to fix vulnerability (https://www.npmjs.com/advisories/1064646)",
56
+ "plist": "Resolving to 3.0.4 to fix vulnerability (https://www.npmjs.com/advisories/1064605)",
57
+ "ajv": "Resolving to 6.12.3 to fix vulnerability (https://www.npmjs.com/advisories/1065159)"
36
58
  }
37
59
  }
@@ -20,5 +20,6 @@ Pod::Spec.new do |s|
20
20
  s.requires_arc = true
21
21
 
22
22
  s.dependency "React"
23
- s.dependency "VeriffSDK", ">= 4.18.0"
23
+ s.dependency "VeriffSDK", ">= 4.34.0"
24
+ s.dependency "lottie-ios"
24
25
  end