Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove consent screen from Biometric KYC #98

Merged
merged 3 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@

## 10.0.0-beta12 (unreleased)

### Added
- Consent Screen SwiftUI View

### Changed

### Fixed

### Removed
- Biometric KYC no longer bundles the Consent Screen
- Biometric KYC no longer bundles an ID Type selector or input

## 10.0.0-beta11

Expand Down
6 changes: 3 additions & 3 deletions Example/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
PODS:
- netfox (1.21.0)
- SmileID (10.0.0-beta10):
- SmileID (10.0.0-beta11):
- Zip (~> 2.1.0)
- SwiftLint (0.52.4)
- Zip (2.1.2)
Expand All @@ -22,10 +22,10 @@ EXTERNAL SOURCES:

SPEC CHECKSUMS:
netfox: 9d5cc727fe7576c4c7688a2504618a156b7d44b7
SmileID: 5975f6130f357bfa08e9b1f731f9ce3e2d91c216
SmileID: fafe73ce2afa5b50d9c3b32e870b40562ff1827b
SwiftLint: 1cc5cd61ba9bacb2194e340aeb47a2a37fda00b3
Zip: b3fef584b147b6e582b2256a9815c897d60ddc67

PODFILE CHECKSUM: b024c66547f30afaee4b2f86d064c8edcba8cbef

COCOAPODS: 1.12.1
COCOAPODS: 1.13.0
34 changes: 25 additions & 9 deletions Example/SmileID.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,18 @@
1ED53F732A2F28590020BEFB /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED53F692A2F28590020BEFB /* HomeView.swift */; };
1EFAB3172A375265008E3C13 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; };
585BE4882AC7748E0091DDD8 /* RestartableTimerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585BE4872AC7748E0091DDD8 /* RestartableTimerTest.swift */; };
58C5F1D82B05925800A6080C /* BiometricKycWithIdInputScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C5F1D72B05925800A6080C /* BiometricKycWithIdInputScreen.swift */; };
58C7118C2A69DE920062BBFB /* EnhancedKycTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C7118B2A69DE920062BBFB /* EnhancedKycTest.swift */; };
607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; };
607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
6AC9802B9D1A630961B5454B /* CodeScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC98436935FFEA40E632182 /* CodeScanner.swift */; };
6AC983F056A8F9088D6CF3F7 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC982147640002B81F72DEC /* SettingsView.swift */; };
6AC984526F49F4E8F52C7494 /* ScannerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC98BA00298258573CBCBD4 /* ScannerViewController.swift */; };
6AC984F8CA1753050C98F14B /* IdInfoInputViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC987C6B5794E2B1241AA51 /* IdInfoInputViewModel.swift */; };
6AC9870BB28E40FCACC75947 /* DocumentVerificationIdTypeSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC9868BCF06ECE5F65DF248 /* DocumentVerificationIdTypeSelector.swift */; };
6AC98856053013D0E8ABB188 /* OnboardingScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC982F34F80CAE1AA5569AB /* OnboardingScreen.swift */; };
6AC9886EEE4DE8AE1A31896A /* IdInfoInputScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC980D3CB9C357AD1B13D80 /* IdInfoInputScreen.swift */; };
6AC98976E04EBF5C45A2E857 /* BiometricKycWithIdInputScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC988EEBD0EAB45DC9AC13B /* BiometricKycWithIdInputScreenViewModel.swift */; };
6AC98990097662789B0107EB /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC98BC49871655D87C7DEE3 /* SettingsViewModel.swift */; };
6AC98B6FFA753C5463F7216F /* SmileConfigEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC984E484EEF69069C705C7 /* SmileConfigEntryView.swift */; };
6AC98C0E9305B4B3EB66ED35 /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC980584C522B17A099E098 /* Util.swift */; };
Expand Down Expand Up @@ -78,6 +82,7 @@
262BF9A8643DF9220FD233E3 /* Pods-SmileID_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SmileID_Example.release.xcconfig"; path = "Target Support Files/Pods-SmileID_Example/Pods-SmileID_Example.release.xcconfig"; sourceTree = "<group>"; };
287986BB9E93D632523CC13A /* Pods_SmileID_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SmileID_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
585BE4872AC7748E0091DDD8 /* RestartableTimerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestartableTimerTest.swift; sourceTree = "<group>"; };
58C5F1D72B05925800A6080C /* BiometricKycWithIdInputScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BiometricKycWithIdInputScreen.swift; sourceTree = "<group>"; };
58C7118B2A69DE920062BBFB /* EnhancedKycTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnhancedKycTest.swift; sourceTree = "<group>"; };
607FACD01AFB9204008FA782 /* Smile ID.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Smile ID.app"; sourceTree = BUILT_PRODUCTS_DIR; };
607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
Expand All @@ -89,11 +94,14 @@
607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
67420F8D15457A4FC46AFB84 /* Pods-SmileID_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SmileID_Example.debug.xcconfig"; path = "Target Support Files/Pods-SmileID_Example/Pods-SmileID_Example.debug.xcconfig"; sourceTree = "<group>"; };
6AC980584C522B17A099E098 /* Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Util.swift; sourceTree = "<group>"; };
6AC980D3CB9C357AD1B13D80 /* IdInfoInputScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdInfoInputScreen.swift; sourceTree = "<group>"; };
6AC982147640002B81F72DEC /* SettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
6AC982F34F80CAE1AA5569AB /* OnboardingScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingScreen.swift; sourceTree = "<group>"; };
6AC98436935FFEA40E632182 /* CodeScanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodeScanner.swift; sourceTree = "<group>"; };
6AC984E484EEF69069C705C7 /* SmileConfigEntryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SmileConfigEntryView.swift; sourceTree = "<group>"; };
6AC9868BCF06ECE5F65DF248 /* DocumentVerificationIdTypeSelector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DocumentVerificationIdTypeSelector.swift; sourceTree = "<group>"; };
6AC987C6B5794E2B1241AA51 /* IdInfoInputViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdInfoInputViewModel.swift; sourceTree = "<group>"; };
6AC988EEBD0EAB45DC9AC13B /* BiometricKycWithIdInputScreenViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BiometricKycWithIdInputScreenViewModel.swift; sourceTree = "<group>"; };
6AC9893915EBA33F6984A6D9 /* DocumentSelectorViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DocumentSelectorViewModel.swift; sourceTree = "<group>"; };
6AC98BA00298258573CBCBD4 /* ScannerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScannerViewController.swift; sourceTree = "<group>"; };
6AC98BC49871655D87C7DEE3 /* SettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -136,6 +144,17 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
58C5F1D62B05922100A6080C /* BiometricKYC */ = {
isa = PBXGroup;
children = (
58C5F1D72B05925800A6080C /* BiometricKycWithIdInputScreen.swift */,
6AC988EEBD0EAB45DC9AC13B /* BiometricKycWithIdInputScreenViewModel.swift */,
6AC980D3CB9C357AD1B13D80 /* IdInfoInputScreen.swift */,
6AC987C6B5794E2B1241AA51 /* IdInfoInputViewModel.swift */,
);
path = BiometricKYC;
sourceTree = "<group>";
};
607FACC71AFB9204008FA782 = {
isa = PBXGroup;
children = (
Expand All @@ -160,7 +179,8 @@
607FACD21AFB9204008FA782 /* Example */ = {
isa = PBXGroup;
children = (
91D9FBC52AB49C3400A8D36B /* CountrySelector */,
58C5F1D62B05922100A6080C /* BiometricKYC */,
91CB21A42AC10C61005AEBF5 /* NavigationBar.swift */,
1ECAE3862A2F69BC00653FCA /* ToastView.swift */,
1ED53F672A2F28590020BEFB /* EnterUserIDView.swift */,
1ED53F692A2F28590020BEFB /* HomeView.swift */,
Expand Down Expand Up @@ -312,14 +332,6 @@
path = ../../Tests/SmartSelfie;
sourceTree = "<group>";
};
91D9FBC52AB49C3400A8D36B /* CountrySelector */ = {
isa = PBXGroup;
children = (
91CB21A42AC10C61005AEBF5 /* NavigationBar.swift */,
);
name = CountrySelector;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -532,6 +544,7 @@
1ED53F6B2A2F28590020BEFB /* ProductCell.swift in Sources */,
1E60ED382A29C306002695FF /* Constants.swift in Sources */,
1ED53F712A2F28590020BEFB /* EnterUserIDView.swift in Sources */,
58C5F1D82B05925800A6080C /* BiometricKycWithIdInputScreen.swift in Sources */,
1ED53F732A2F28590020BEFB /* HomeView.swift in Sources */,
1E60ED3B2A29C306002695FF /* CopyableLabel.swift in Sources */,
6AC98C0E9305B4B3EB66ED35 /* Util.swift in Sources */,
Expand All @@ -543,6 +556,9 @@
6AC98856053013D0E8ABB188 /* OnboardingScreen.swift in Sources */,
6AC9802B9D1A630961B5454B /* CodeScanner.swift in Sources */,
6AC984526F49F4E8F52C7494 /* ScannerViewController.swift in Sources */,
6AC98976E04EBF5C45A2E857 /* BiometricKycWithIdInputScreenViewModel.swift in Sources */,
6AC9886EEE4DE8AE1A31896A /* IdInfoInputScreen.swift in Sources */,
6AC984F8CA1753050C98F14B /* IdInfoInputViewModel.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import Foundation
import SmileID
import SwiftUI

struct BiometricKycWithIdInputScreen: View {
let delegate: BiometricKycResultDelegate

@State private var selectedCountry: CountryInfo?
@ObservedObject private var viewModel = BiometricKycWithIdInputScreenViewModel()

var body: some View {
switch viewModel.step {
case .loading(let messageKey):
VStack {
ActivityIndicator(isAnimating: true).padding()
Text(SmileIDResourcesHelper.localizedString(for: messageKey))
.font(SmileID.theme.body)
.foregroundColor(SmileID.theme.onLight)
}
.frame(maxWidth: .infinity)
case .idTypeSelection(let countryList):
SearchableDropdownSelector(
items: countryList,
selectedItem: selectedCountry,
itemDisplayName: { $0.name },
onItemSelected: { selectedCountry = $0 }
)
if let selectedCountry = selectedCountry {
RadioGroupSelector(
title: "Select ID Type",
items: selectedCountry.availableIdTypes,
itemDisplayName: { $0.label },
onItemSelected: { idType in
viewModel.onIdTypeSelected(
country: selectedCountry.countryCode,
idType: idType.idTypeKey,
requiredFields: idType.requiredFields ?? []
)
}
)
}
case .consent(let country, let idType, let requiredFields):
SmileID.consentScreen(
partnerIcon: UIImage(named: "SmileLogo")!,
partnerName: "Smile ID",
productName: "ID",
partnerPrivacyPolicy: URL(string: "https://usesmileid.com")!,
showAttribution: true,
onConsentGranted: {
viewModel.onConsentGranted(
country: country,
idType: idType,
requiredFields: requiredFields)
},
onConsentDenied: { delegate.didError(error: SmileIDError.consentDenied) }
)
case .idInput(let country, let idType, let requiredFields):
IdInfoInputScreen(
selectedCountry: country,
selectedIdType: idType,
header: "Enter ID Information",
requiredFields: requiredFields,
onResult: viewModel.onIdFieldsEntered
).frame(maxWidth: .infinity)
case .sdk(let idInfo):
SmileID.biometricKycScreen(
idInfo: idInfo,
allowAgentMode: true,
delegate: delegate
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import Foundation
import SmileID

enum BiometricKycWithIdInputScreenStep {
case loading(String)
case idTypeSelection([CountryInfo])
case consent(country: String, idType: String, requiredFields: [RequiredField])
case idInput(country: String, idType: String, requiredFields: [RequiredField])
case sdk(IdInfo)
}

class BiometricKycWithIdInputScreenViewModel: ObservableObject {
private let userId = generateUserId()
private let jobId = generateJobId()

@Published @MainActor var step = BiometricKycWithIdInputScreenStep.loading("Loading ID Types…")

init() {
loadIdTypes()
}

private func loadIdTypes() {
let authRequest = AuthenticationRequest(
jobType: .biometricKyc,
enrollment: false,
jobId: jobId,
userId: userId
)
DispatchQueue.main.async {
self.step = .loading("Loading ID Types…")
}
Task {
do {
let authResponse = try await SmileID.api.authenticate(request: authRequest).async()
let productsConfigRequest = ProductsConfigRequest(
timestamp: authResponse.timestamp,
signature: authResponse.signature
)
let productsConfigResponse = try await SmileID.api.getProductsConfig(
request: productsConfigRequest
).async()
let supportedCountries = productsConfigResponse.idSelection.biometricKyc
let servicesResponse = try await SmileID.api.getServices().async()
let servicesCountryInfo = servicesResponse.hostedWeb.biometricKyc
// sort by country name
let countryList = servicesCountryInfo
.filter { supportedCountries.keys.contains($0.countryCode) }
.sorted { $0.name < $1.name }
DispatchQueue.main.async { self.step = .idTypeSelection(countryList) }
} catch {
print("Error loading id types: \(error)")
DispatchQueue.main.async {
self.step = .loading("Error loading ID Types. Please try again.")
}
}
}
}

private func loadConsent(
country: String,
idType: String,
requiredFields: [RequiredField]
) {
let authRequest = AuthenticationRequest(
jobType: .biometricKyc,
enrollment: false,
jobId: jobId,
userId: userId,
country: country,
idType: idType
)
DispatchQueue.main.async {
self.step = .loading("Loading Consent…")
}
Task {
do {
let authResponse = try await SmileID.api.authenticate(request: authRequest).async()
if authResponse.consentInfo?.consentRequired == true {
DispatchQueue.main.async {
self.step = .consent(
country: country,
idType: idType,
requiredFields: requiredFields
)
}
} else {
// We don't need consent. Proceed forward as if consent has already been granted
onConsentGranted(
country: country,
idType: idType,
requiredFields: requiredFields
)
}
} catch {
print("Error loading consent: \(error)")
DispatchQueue.main.async {
self.step = .loading("Error loading consent. Please try again.")
}
}
}
}

func onIdTypeSelected(country: String, idType: String, requiredFields: [RequiredField]) {
loadConsent(country: country, idType: idType, requiredFields: requiredFields)
}

func onConsentGranted(country: String, idType: String, requiredFields: [RequiredField]) {
DispatchQueue.main.async {
self.step = .idInput(
country: country,
idType: idType,
requiredFields: requiredFields
)
}
}

func onIdFieldsEntered(idInfo: IdInfo) {
DispatchQueue.main.async { self.step = .sdk(idInfo) }
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import SmileID
import SwiftUI

/// Allows user to enter ID info. Requires that the user has already selected a country and ID type.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Combine
import SmileID
import SwiftUI
import UIKit

Expand Down
8 changes: 1 addition & 7 deletions Example/SmileID/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,7 @@ struct HomeView: View {
image: "biometric",
name: "Biometric KYC",
content: {
SmileID.biometricKycScreen(
partnerIcon: UIImage(named: "SmileLogo")!,
partnerName: "Smile ID",
productName: "ID",
partnerPrivacyPolicy: URL(string: "https://usesmileid.com")!,
delegate: viewModel
)
BiometricKycWithIdInputScreen(delegate: viewModel)
}
)
].map { AnyView($0) }
Expand Down
Loading
Loading