Skip to content

Commit

Permalink
iOS UI customization (#4)
Browse files Browse the repository at this point in the history
* feat: implement ui customization ability (iOS)

* update README.md

* fix: remove unused code

* revert yarn bootstrap script

* extend types

Co-authored-by: Artem Basov <abasov@newage.io>
  • Loading branch information
basart and Artem Basov committed Mar 30, 2022
1 parent 592552b commit 797f830
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 23 deletions.
114 changes: 113 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# react-native-onfido-auth-sdk

## Table of contents

- [Overview](#overview)
- [Installation](#installation)
- [Usage](#usage)
- [1. Creating the SDK configuration](#1-creating-the-sdk-configuration)
- [2. Parameter details](#2-parameter-details)
- [3. Success Response](#3-success-response)
- [4. Failure Response](#4-failure-response)
- [UI Customization](#ui-customization)
- [iOS](#ui-customization-ios)
- [Android](#ui-customization-android)
- [Contributing](#contributing)
- [License](#license)

## Overview

The Onfido Authentication SDK provides a set of screens for React Native applications to capture 3D face scans for the purpose of identity authentication.

## Installation
Expand All @@ -10,6 +27,8 @@ yarn add react-native-onfido-auth-sdk

## Usage

You can launch the app with a call to `OnfidoAuth.start`.

```js
import { OnfidoAuth } from 'react-native-onfido-auth-sdk';
// ...
Expand All @@ -18,11 +37,104 @@ OnfidoAuth.start({ sdkToken: 'sdkToken' })
.catch(/* ... */);
```

### 1. Creating the SDK configuration

Once you have an added the SDK as a dependency and you have a SDK token, you can configure the SDK:

Example configuration:

```js
config = {
sdkToken: 'EXAMPLE-TOKEN-123',
retryCount: 2,
}
```

### 2. Parameter details

* **`sdkToken`**: Required. This is the JWT sdk token obtained by making a call to the SDK token API.
* **`retryCount`**: Optional. This value is used to set the number of repeat attempts a user can do after the first unsuccessful try.

### 3. Success Response

Success is when the user has reached the end of the flow. The result has the `verified`, `uuid` and `token` properties. If authentication was successful, `verified` will be `true` and `token` will be the JWT. This JWT token can be used to validate the response.

Example:

```js
{
token: 'EXAMPLE-TOKEN-456',
uuid: 'uuid',
verified: true,
}
```

### 4. Failure Response

The SDK will reject the promise any time the OnfidoAuth SDK exits without a success. Error messages are not in a presentable format to the end user and are not localised.

## UI Customization

### iOS

T.B.D.
You can customize the iOS UI by adding a `customization.ios.json` file to your project at the same level as your `node_modules` directory. The file should contain a single json object with the desired keys and values. For example:

```json
{
"onfidoPrimaryTextColor": "",
"onfidoPrimaryTextDynamicDimmingColor": "",

"onfidoPrimaryButtonColor": "#4BC0B1",
"onfidoPrimaryButtonDynamicDimmingColor": "",
"onfidoPrimaryButtonPressedColor": "#2EAC9C",
"onfidoPrimaryButtonDisabledColor": "",
"onfidoPrimaryButtonDisabledDynamicDimmingColor": "",
"onfidoPrimaryButtonTextColor": "#FFFFFF",
"onfidoPrimaryButtonTextDynamicDimmingColor": "",
"onfidoPrimaryButtonTextPressedColor": "",
"onfidoPrimaryButtonTextDisabledColor": "",
"onfidoPrimaryButtonTextDisabledDynamicDimmingColor": "",

"onfidoSecondaryButtonPressedColor": "",
"onfidoDualSpinnerColor": "",
"onfidoRetryScreenOvalStrokeColor": "",
"onfidoUploadProgressFillColor": "",

"onfidoButtonCornerRadius": 24,

"onfidoFontRegular": "",
"onfidoFontMedium": "",
"onfidoFontBold": ""
}

```

Once you've added the `customization.ios.json` to your project, you should add `customization.ios.json` file to your xcode project as bundle resource. You can create symbolic link (rather than copy paste) to prevent redundancy. Then when running on an iOS device the values will be picked up dynamically at runtime.

Below is a description of all available keys:

| Color | Description |
| -----|-------|
| `onfidoPrimaryTextColor` | Color of most text |
| `onfidoPrimaryTextDynamicDimmingColor` | Color of text in Dynamic Dimming mode<br/><br/>Dynamic Dimming mode is automatically enabled in certain lighting conditions and will include UI differences such as the background turning black |
| `onfidoPrimaryButtonColor` | Background color of buttons |
| `onfidoPrimaryButtonDynamicDimmingColor` | Background color of buttons in Dynamic Dimming mode<br/><br/>Dynamic Dimming mode is automatically enabled in certain lighting conditions and will include UI differences such as the background turning black |
| `onfidoPrimaryButtonPressedColor` | Background color of buttons while being pressed |
| `onfidoPrimaryButtonDisabledColor` | Background color of buttons that are disabled |
| `onfidoPrimaryButtonDisabledDynamicDimmingColor` | Background color of buttons that are disabled in Dynamic Dimming mode<br/><br/>Dynamic Dimming mode is automatically enabled in certain lighting conditions and will include UI differences such as the background turning black |
| `onfidoPrimaryButtonTextColor` | Color of text in buttons |
| `onfidoPrimaryButtonTextDynamicDimmingColor` | Color of text in buttons in Dynamic Dimming mode<br/><br/>Dynamic Dimming mode is automatically enabled in certain lighting conditions and will include UI differences such as the background turning black |
| `onfidoPrimaryButtonTextPressedColor` | Color of text in buttons while being pressed |
| `onfidoPrimaryButtonTextDisabledColor` | Color of text in buttons that are disabled |
| `onfidoPrimaryButtonTextDisabledDynamicDimmingColor` | Color of text in buttons that are disabled in Dynamic Dimming mode<br/><br/>Dynamic Dimming mode is automatically enabled in certain lighting conditions and will include UI differences such as the background turning black |
| `onfidoSecondaryButtonPressedColor` | Background color of secondary button (currently this is only the “Do not accept” button in the optional consent screen) |
| `onfidoDualSpinnerColor` | Color of dual spinner rotating around selfie preview |
| `onfidoRetryScreenOvalStrokeColor` | Stroke color of oval on ideal selfie image in retry screen |
| `onfidoUploadProgressFillColor` | Color of completed portion of upload progress bar |
| `onfidoButtonCornerRadius` | Corner radius of buttons (should be set to 40 maximum, otherwise will not work on some buttons) |
| `onfidoFontRegular` | Name of font to use on regular text |
| `onfidoFontMedium` | Name of font to use on medium text |
| `onfidoFontBold` | Name of font to use on bold text |

### Android
You can customize the Android UI by adding a `customization.android.json` file to your project at the same level as your `node_modules` directory. The file should contain a single json object with the desired keys and values. For example:
Expand Down
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ PODS:
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsinspector (0.63.4)
- react-native-onfido-auth-sdk (0.1.0):
- react-native-onfido-auth-sdk (0.2.1):
- OnfidoAuth (~> 0.2.3)
- React-Core
- React-RCTActionSheet (0.63.4):
Expand Down Expand Up @@ -365,7 +365,7 @@ SPEC CHECKSUMS:
React-jsi: a0418934cf48f25b485631deb27c64dc40fb4c31
React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949
React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
react-native-onfido-auth-sdk: bcb2988d9adc14b11af6a8704b90ec9796043aa0
react-native-onfido-auth-sdk: a5700d963945f46f3ffecd42e3349cec1bed23ce
React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336
React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b
React-RCTBlob: a97d378b527740cc667e03ebfa183a75231ab0f0
Expand Down
77 changes: 77 additions & 0 deletions ios/Appearance.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import Foundation
import OnfidoAuth

/**
* Load appearance data from the specified file. If the file cannot be loaded, use the default values.
*/
public func loadAppearanceFromFile(filePath: String?) throws -> OnfidoAuthAppearance {

do {
let jsonResult:Any
do {
guard let path = filePath else { return OnfidoAuthAppearance() }
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
} catch let e as NSError where e.code == NSFileNoSuchFileError || e.code == NSFileReadNoSuchFileError {
jsonResult = Dictionary<String, AnyObject>()
}
if let jsonResult = jsonResult as? Dictionary<String, AnyObject> {
return OnfidoAuthAppearance(
primaryTextColor: UIColor.from(hex: jsonResult["onfidoPrimaryTextColor"] as? String),
primaryTextDynamicDimmingColor: UIColor.from(hex: jsonResult["onfidoPrimaryTextDynamicDimmingColor"] as? String),
primaryButtonColor: UIColor.from(hex: jsonResult["onfidoPrimaryButtonColor"] as? String),
primaryButtonDynamicDimmingColor: UIColor.from(hex: jsonResult["onfidoPrimaryButtonDynamicDimmingColor"] as? String),
primaryButtonPressedColor: UIColor.from(hex: jsonResult["onfidoPrimaryButtonPressedColor"] as? String),
primaryButtonDisabledColor: UIColor.from(hex: jsonResult["onfidoPrimaryButtonDisabledColor"] as? String),
primaryButtonDisabledDynamicDimmingColor: UIColor.from(hex: jsonResult["onfidoPrimaryButtonDisabledDynamicDimmingColor"] as? String),
primaryButtonTextColor: UIColor.from(hex: jsonResult["onfidoPrimaryButtonTextColor"] as? String),
primaryButtonTextDynamicDimmingColor: UIColor.from(hex: jsonResult["onfidoPrimaryButtonTextDynamicDimmingColor"] as? String),
primaryButtonTextPressedColor: UIColor.from(hex: jsonResult["onfidoPrimaryButtonTextPressedColor"] as? String),
primaryButtonTextDisabledColor: UIColor.from(hex: jsonResult["onfidoPrimaryButtonTextDisabledColor"] as? String),
primaryButtonTextDisabledDynamicDimmingColor: UIColor.from(hex: jsonResult["onfidoPrimaryButtonTextDisabledDynamicDimmingColor"] as? String),
secondaryButtonPressedColor: UIColor.from(hex: jsonResult["onfidoSecondaryButtonPressedColor"] as? String),
dualSpinnerColor: UIColor.from(hex: jsonResult["onfidoDualSpinnerColor"] as? String),
retryScreenOvalStrokeColor: UIColor.from(hex: jsonResult["onfidoRetryScreenOvalStrokeColor"] as? String),
uploadProgressFillColor: UIColor.from(hex: jsonResult["onfidoUploadProgressFillColor"] as? String),
buttonCornerRadius: jsonResult["onfidoButtonCornerRadius"] as? CGFloat,
fontRegular: jsonResult["onfidoFontRegular"] as? String,
fontMedium: jsonResult["onfidoFontMedium"] as? String,
fontBold: jsonResult["onfidoFontBold"] as? String
)
} else {
return OnfidoAuthAppearance()
}
} catch let error {
throw NSError(domain: "There was an error setting colors for OnfidoAuthAppearance: \(error)", code: 0)
}
}

extension UIColor {

static func from(hex: String?) -> UIColor? {
guard let hex = hex else {
return nil
}

let hexString = hex.trimmingCharacters(in: .whitespacesAndNewlines)
let scanner = Scanner(string: hexString)

if hexString.hasPrefix("#") {
scanner.scanLocation = 1
}

var color: UInt32 = 0
scanner.scanHexInt32(&color)

let mask = 0x000000FF
let redInt = Int(color >> 16) & mask
let greenInt = Int(color >> 8) & mask
let blueInt = Int(color) & mask

let red = CGFloat(redInt) / 255.0
let green = CGFloat(greenInt) / 255.0
let blue = CGFloat(blueInt) / 255.0

return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
}
}
14 changes: 9 additions & 5 deletions ios/OnfidoAuthSdk.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import Foundation
import OnfidoAuth


public func buildOnfidoAuthConfig(config:NSDictionary) throws -> OnfidoAuth.OnfidoAuthConfigBuilder {
public func buildOnfidoAuthConfig(config:NSDictionary, appearance: OnfidoAuthAppearance) throws -> OnfidoAuth.OnfidoAuthConfigBuilder {
let sdkToken:String = config["sdkToken"] as! String

var onfidoAuthConfig = OnfidoAuthConfig.builder()
.withSDKToken(sdkToken)

.withAppearance(appearance)

if let retryCount = (config["retryCount"] as? Int) {
onfidoAuthConfig = onfidoAuthConfig.withRetryCount(retryCount)
}
Expand Down Expand Up @@ -76,8 +77,11 @@ class OnfidoAuthSdk: NSObject {
return;
}
}

let appearanceFilePath = Bundle.main.path(forResource: "customization.ios", ofType: "json")
let appearance = try loadAppearanceFromFile(filePath: appearanceFilePath)

let onfidoAuthConfig = try buildOnfidoAuthConfig(config: config)
let onfidoAuthConfig = try buildOnfidoAuthConfig(config: config, appearance: appearance)
let builtOnfidoAuthConfig = try onfidoAuthConfig.build()

let onfidoAuthFlow = OnfidoAuthFlow(withConfiguration: builtOnfidoAuthConfig)
Expand Down Expand Up @@ -121,8 +125,8 @@ class OnfidoAuthSdk: NSObject {
private func run(withConfig config: NSDictionary,
resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
resolve("Simulator");
return;
resolve("Simulator");
return;
}

}
Expand Down
20 changes: 5 additions & 15 deletions ios/OnfidoAuthSdk.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
objects = {

/* Begin PBXBuildFile section */

5E555C0D2413F4C50049A1A2 /* OnfidoAuthSdk.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* OnfidoAuthSdk.m */; };
F4FF95D7245B92E800C19C63 /* OnfidoAuthSdk.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* OnfidoAuthSdk.swift */; };

E31D727827F3129000B2F403 /* Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = E31D727727F3129000B2F403 /* Appearance.swift */; };
F4FF95D7245B92E800C19C63 /* OnfidoAuthSdk.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* OnfidoAuthSdk.swift */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand All @@ -27,11 +25,10 @@

/* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libOnfidoAuthSdk.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libOnfidoAuthSdk.a; sourceTree = BUILT_PRODUCTS_DIR; };

B3E7B5891CC2AC0600A0062D /* OnfidoAuthSdk.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OnfidoAuthSdk.m; sourceTree = "<group>"; };
E31D727727F3129000B2F403 /* Appearance.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = Appearance.swift; sourceTree = "<group>"; tabWidth = 2; };
F4FF95D5245B92E700C19C63 /* OnfidoAuthSdk-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OnfidoAuthSdk-Bridging-Header.h"; sourceTree = "<group>"; };
F4FF95D6245B92E800C19C63 /* OnfidoAuthSdk.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnfidoAuthSdk.swift; sourceTree = "<group>"; };

/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -56,11 +53,10 @@
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (

E31D727727F3129000B2F403 /* Appearance.swift */,
F4FF95D6245B92E800C19C63 /* OnfidoAuthSdk.swift */,
B3E7B5891CC2AC0600A0062D /* OnfidoAuthSdk.m */,
F4FF95D5245B92E700C19C63 /* OnfidoAuthSdk-Bridging-Header.h */,

134814211AA4EA7D00B7C361 /* Products */,
);
sourceTree = "<group>";
Expand Down Expand Up @@ -122,10 +118,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (

F4FF95D7245B92E800C19C63 /* OnfidoAuthSdk.swift in Sources */,
B3E7B58A1CC2AC0600A0062D /* OnfidoAuthSdk.m in Sources */,

E31D727827F3129000B2F403 /* Appearance.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -238,11 +232,9 @@
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = OnfidoAuthSdk;
SKIP_INSTALL = YES;

SWIFT_OBJC_BRIDGING_HEADER = "OnfidoAuthSdk-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;

};
name = Debug;
};
Expand All @@ -259,10 +251,8 @@
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = OnfidoAuthSdk;
SKIP_INSTALL = YES;

SWIFT_OBJC_BRIDGING_HEADER = "OnfidoAuthSdk-Bridging-Header.h";
SWIFT_VERSION = 5.0;

};
name = Release;
};
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"release": "release-it",
"example": "yarn --cwd example",
"pods": "cd example && pod-install --quiet",
"bootstrap": "yarn example && yarn && yarn pods",
"updateColors": "node scripts/customize_android.js"
},
"keywords": [
Expand Down
29 changes: 29 additions & 0 deletions scripts/bootstrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const os = require('os');
const path = require('path');
const child_process = require('child_process');

const root = path.resolve(__dirname, '..');
const args = process.argv.slice(2);
const options = {
cwd: process.cwd(),
env: process.env,
stdio: 'inherit',
encoding: 'utf-8',
};

if (os.type() === 'Windows_NT') {
options.shell = true
}

let result;

if (process.cwd() !== root || args.length) {
// We're not in the root of the project, or additional arguments were passed
// In this case, forward the command to `yarn`
result = child_process.spawnSync('yarn', args, options);
} else {
// If `yarn` is run without arguments, perform bootstrap
result = child_process.spawnSync('yarn', ['bootstrap'], options);
}

process.exitCode = result.status;
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@ export type OnfidoAuthConfig = {
sdkToken: string;
retryCount?: number;
};

export type OnfidoAuthResult = {
token: string;
uuid: string;
verified: boolean;
};

0 comments on commit 797f830

Please sign in to comment.