mirror of
https://github.com/selfxyz/self.git
synced 2026-04-27 03:01:15 -04:00
* feat: add iOS native shell package (NSL-02) Plain Swift implementation of the WebView host with bridge handlers for secure storage (Keychain), crypto (EC P-256), and lifecycle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add Android native shell package (NSL-01) Plain Kotlin implementation of the WebView host with bridge handlers for secure storage (EncryptedSharedPreferences), crypto (Android Keystore EC P-256), and lifecycle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: integrate Sumsub Web SDK into ProviderLaunchScreen (WV-05) Rewrites ProviderLaunchScreen to launch Sumsub Web SDK, adds KYC provider types, result normalization, and a ProviderResultScreen for displaying verification outcomes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: update spec status for NSL-01, NSL-02, WV-05 to in-progress All three items are code-complete but need integration testing before marking done. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add build-pipeline workstream specs, update NSL-03 and BP-01 status Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add WebView bundle build pipeline (BP-01) Build script copies webview-app dist into both native shell asset directories. Gradle preBuild validation fails fast when bundle is missing. Root package.json gets build:sdk-* scripts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SDK test apps for Android and iOS (NSL-03) Minimal test apps to exercise native shells end-to-end: - Android: Jetpack Compose app using SelfSdk.launch() via composite build - iOS: SwiftUI app using SelfSdk.createViewController() via local SPM dep Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * update lockfile * fix: address CodeRabbit PR review findings for native shells - Fix iOS double callback: add hasEmittedResult flag to LifecycleHandler so dismiss() won't fire onCancelled after onResult already emitted - Fix Android error result codes: use RESULT_FIRST_USER for failed verifications instead of always RESULT_OK; add dedicated handler in SelfSdk.handleResult - Fix iOS production query params: append params to file URL via URLComponents so WebView receives teeUrl/verificationId/userId - Fix build:sdk-ios false-green: chain swift build after bundle script - Add expectedRequestCode param to handleResult for flexibility - Upgrade security-crypto 1.1.0-alpha06 → 1.1.0 stable - Improve callback type safety: onSuccess takes raw JSON string, onFailure takes SelfSdkException instead of generic Exception - Add requireBiometric intent comments to both SecureStorageHandlers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address remaining CodeRabbit PR review findings (round 2) - iOS BridgeResponse: add requestId/success fields, rename result→data to match JS bridge contract - iOS test app: fix callback deallocation with Coordinator pattern - ProviderLaunchScreen: fail closed on missing verificationId, fix retry via retryCount state - ProviderResultScreen: guard unknown status with fallback to error config - build-webview-bundle.sh: validate index.html before deleting targets - Package.swift: fix SPM resource path with target path/sources Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
78 lines
2.4 KiB
Swift
78 lines
2.4 KiB
Swift
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
import Foundation
|
|
import UIKit
|
|
|
|
public final class SelfSdk {
|
|
public static func createViewController(
|
|
config: SelfSdkConfig,
|
|
callback: SelfSdkCallback
|
|
) -> UIViewController {
|
|
let viewController = SelfSdkViewController(config: config, callback: callback)
|
|
viewController.modalPresentationStyle = .fullScreen
|
|
return viewController
|
|
}
|
|
}
|
|
|
|
final class SelfSdkViewController: UIViewController {
|
|
private let config: SelfSdkConfig
|
|
private weak var callback: SelfSdkCallback?
|
|
private var webViewHost: SelfWebViewHost?
|
|
|
|
init(config: SelfSdkConfig, callback: SelfSdkCallback) {
|
|
self.config = config
|
|
self.callback = callback
|
|
super.init(nibName: nil, bundle: nil)
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) is not supported")
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
view.backgroundColor = .black
|
|
setupWebView()
|
|
}
|
|
|
|
private func setupWebView() {
|
|
let lifecycleHandler = LifecycleHandler(
|
|
viewController: self,
|
|
onResult: { [weak self] result in
|
|
if let dict = result as? [String: Any] {
|
|
self?.callback?.onSuccess(result: dict)
|
|
} else {
|
|
self?.callback?.onSuccess(result: [:])
|
|
}
|
|
},
|
|
onDismiss: { [weak self] in
|
|
self?.callback?.onCancelled()
|
|
}
|
|
)
|
|
|
|
let router = MessageRouter { [weak self] js in
|
|
self?.webViewHost?.evaluateJs(js)
|
|
}
|
|
router.register(handler: SecureStorageHandler())
|
|
router.register(handler: CryptoHandler())
|
|
router.register(handler: lifecycleHandler)
|
|
|
|
let host = SelfWebViewHost(router: router, isDebugMode: config.isDebugMode)
|
|
self.webViewHost = host
|
|
|
|
let webView = host.createWebView()
|
|
webView.translatesAutoresizingMaskIntoConstraints = false
|
|
view.addSubview(webView)
|
|
|
|
NSLayoutConstraint.activate([
|
|
webView.topAnchor.constraint(equalTo: view.topAnchor),
|
|
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
|
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
|
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
|
|
])
|
|
|
|
host.loadContent(queryParams: config.toQueryParams())
|
|
}
|
|
}
|