Sample Navigation
Code demonstrating how to navigate to the SDK view with SwiftUI or UIKit
Standard Experience
SwiftUI - Navigation Destination
Not currently supported
SwiftUI - Full Screeen Cover
import SwiftUI
struct ContentView: View {
@State private var viewModel: ViewModel = .init()
var body: some View {
NavigationStack {
Button("ReadyRemit SDK v10.0.0") {
viewModel.showReadyRemitSDK()
}
.fullScreenCover(item: $viewModel.readyRemitItem) {
AnyView($0.view)
}
.navigationTitle("SwiftUI - Full Screen Cover")
}
}
}
#Preview {
ContentView()
}
import ReadyRemitSDK
import SwiftUI
@Observable
class ViewModel {
struct ReadyRemitItem: Identifiable {
let id = UUID()
let view: any View
}
private let themeConfiguration: String? = nil
var readyRemitItem: ReadyRemitItem?
func showReadyRemitSDK() {
ReadyRemit.shared.startSDK(
themeConfiguration: themeConfiguration,
fetchAccessTokenDetails: fetchAccessTokenDetails,
verifyFundsAndCreateTransfer: verifyFundsAndCreateTransfer,
onDismiss: { [weak self] in
guard let self else { return }
self.readyRemitItem = nil
}
) { [weak self] readyRemitSDKView in
guard let self else { return }
self.readyRemitItem = .init(view: readyRemitSDKView)
}
}
private func fetchAccessTokenDetails() async throws -> AccessTokenDetails {
guard let url = URL(string: "https://example.com/v1/oauth/token") else {
throw URLError(.badURL)
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
let (data, urlResponse) = try await URLSession.shared.data(for: urlRequest)
guard let httpURLResponse = urlResponse as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
switch httpURLResponse.statusCode {
case 200...299:
// CreateAccessTokenDetailsResponse must conform to AccessTokenDetails
return try JSONDecoder().decode(CreateAccessTokenDetailsResponse.self, from: data)
default:
throw CustomError.unsuccessfulResponse
}
}
private func verifyFundsAndCreateTransfer(
transferRequest: ReadyRemit.TransferRequest
) async throws(ReadyRemitError) -> TransferDetails {
do {
guard let url = URL(string: "https://example.com/v1/verifyFundsAndCreateTransfer") else {
throw URLError(.badURL)
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.httpBody = try JSONEncoder().encode(transferRequest)
let (data, urlResponse) = try await URLSession.shared.data(for: urlRequest)
guard let httpURLResponse = urlResponse as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
switch httpURLResponse.statusCode {
case 200...299:
// CreateTransferDetailsResponse must conform to TransferDetails
return try JSONDecoder().decode(CreateTransferDetailsResponse.self, from: data)
default:
throw ReadyRemitError(code: .none, message: "Insufficient Funds")
}
} catch let error as ReadyRemitError {
throw error
} catch {
throw ReadyRemitError(code: .none, message: "Error: \(error.localizedDescription)")
}
}
}UIKit - Push View Controller
This assumes ContentViewController is the root view controller of a UINativationController.
import SwiftUI
class ContentViewController: UIViewController {
private let viewModel: ViewModel = .init()
override func viewDidLoad() {
super.viewDidLoad()
title = "UIKit - Push"
setupButton()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setupObservation()
}
private func setupButton() {
let action = UIAction { _ in
self.viewModel.showReadyRemitSDK()
}
let button = UIButton(primaryAction: action)
button.setTitle("ReadyRemit SDK v10.0.0", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
private func setupObservation() {
withObservationTracking {
_ = viewModel.readyRemitItem
} onChange: { [weak self] in
guard let self else { return }
Task {
await MainActor.run {
if let readyRemitItem = self.viewModel.readyRemitItem {
let hostingController = UIHostingController(rootView: AnyView(readyRemitItem.view))
hostingController.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(hostingController, animated: true)
}
}
}
}
}
}import ReadyRemitSDK
import SwiftUI
@Observable
class ViewModel {
struct ReadyRemitItem: Identifiable {
let id = UUID()
let view: any View
}
private let themeConfiguration: String? = nil
var readyRemitItem: ReadyRemitItem?
func showReadyRemitSDK() {
ReadyRemit.shared.startSDK(
themeConfiguration: themeConfiguration,
fetchAccessTokenDetails: fetchAccessTokenDetails,
verifyFundsAndCreateTransfer: verifyFundsAndCreateTransfer,
onDismiss: { [weak self] in
guard let self else { return }
self.readyRemitItem = nil
}
) { [weak self] readyRemitSDKView in
guard let self else { return }
self.readyRemitItem = .init(view: readyRemitSDKView)
}
}
private func fetchAccessTokenDetails() async throws -> AccessTokenDetails {
guard let url = URL(string: "https://example.com/v1/oauth/token") else {
throw URLError(.badURL)
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
let (data, urlResponse) = try await URLSession.shared.data(for: urlRequest)
guard let httpURLResponse = urlResponse as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
switch httpURLResponse.statusCode {
case 200...299:
// CreateAccessTokenDetailsResponse must conform to AccessTokenDetails
return try JSONDecoder().decode(CreateAccessTokenDetailsResponse.self, from: data)
default:
throw CustomError.unsuccessfulResponse
}
}
private func verifyFundsAndCreateTransfer(
transferRequest: ReadyRemit.TransferRequest
) async throws(ReadyRemitError) -> TransferDetails {
do {
guard let url = URL(string: "https://example.com/v1/verifyFundsAndCreateTransfer") else {
throw URLError(.badURL)
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.httpBody = try JSONEncoder().encode(transferRequest)
let (data, urlResponse) = try await URLSession.shared.data(for: urlRequest)
guard let httpURLResponse = urlResponse as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
switch httpURLResponse.statusCode {
case 200...299:
// CreateTransferDetailsResponse must conform to TransferDetails
return try JSONDecoder().decode(CreateTransferDetailsResponse.self, from: data)
default:
throw ReadyRemitError(code: .none, message: "Insufficient Funds")
}
} catch let error as ReadyRemitError {
throw error
} catch {
throw ReadyRemitError(code: .none, message: "Error: \(error.localizedDescription)")
}
}
}UIKit - Present View Controller
import SwiftUI
class ContentViewController: UIViewController {
private let viewModel: ViewModel = .init()
override func viewDidLoad() {
super.viewDidLoad()
title = "UIKit - Present"
setupButton()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setupObservation()
}
private func setupButton() {
let action = UIAction { _ in
self.viewModel.showReadyRemitSDK()
}
let button = UIButton(primaryAction: action)
button.setTitle("ReadyRemit SDK v10.0.0", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
private func setupObservation() {
withObservationTracking {
_ = viewModel.readyRemitItem
} onChange: { [weak self] in
guard let self else { return }
Task {
await MainActor.run {
if let readyRemitItem = self.viewModel.readyRemitItem {
let hostingController = UIHostingController(rootView: AnyView(readyRemitItem.view))
hostingController.modalPresentationStyle = .fullScreen
self.present(hostingController, animated: true)
}
}
}
}
}
}
import ReadyRemitSDK
import SwiftUI
@Observable
class ViewModel {
struct ReadyRemitItem: Identifiable {
let id = UUID()
let view: any View
}
private let themeConfiguration: String? = nil
var readyRemitItem: ReadyRemitItem?
func showReadyRemitSDK() {
ReadyRemit.shared.startSDK(
themeConfiguration: themeConfiguration,
fetchAccessTokenDetails: fetchAccessTokenDetails,
verifyFundsAndCreateTransfer: verifyFundsAndCreateTransfer,
onDismiss: { [weak self] in
guard let self else { return }
self.readyRemitItem = nil
}
) { [weak self] readyRemitSDKView in
guard let self else { return }
self.readyRemitItem = .init(view: readyRemitSDKView)
}
}
private func fetchAccessTokenDetails() async throws -> AccessTokenDetails {
guard let url = URL(string: "https://example.com/v1/oauth/token") else {
throw URLError(.badURL)
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
let (data, urlResponse) = try await URLSession.shared.data(for: urlRequest)
guard let httpURLResponse = urlResponse as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
switch httpURLResponse.statusCode {
case 200...299:
// CreateAccessTokenDetailsResponse must conform to AccessTokenDetails
return try JSONDecoder().decode(CreateAccessTokenDetailsResponse.self, from: data)
default:
throw CustomError.unsuccessfulResponse
}
}
private func verifyFundsAndCreateTransfer(
transferRequest: ReadyRemit.TransferRequest
) async throws(ReadyRemitError) -> TransferDetails {
do {
guard let url = URL(string: "https://example.com/v1/verifyFundsAndCreateTransfer") else {
throw URLError(.badURL)
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.httpBody = try JSONEncoder().encode(transferRequest)
let (data, urlResponse) = try await URLSession.shared.data(for: urlRequest)
guard let httpURLResponse = urlResponse as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
switch httpURLResponse.statusCode {
case 200...299:
// CreateTransferDetailsResponse must conform to TransferDetails
return try JSONDecoder().decode(CreateTransferDetailsResponse.self, from: data)
default:
throw ReadyRemitError(code: .none, message: "Insufficient Funds")
}
} catch let error as ReadyRemitError {
throw error
} catch {
throw ReadyRemitError(code: .none, message: "Error: \(error.localizedDescription)")
}
}
}Transfer Experience
SwiftUI - Navigation Destination
Not currently supported
SwiftUI - Full Screen Cover
import SwiftUI
struct ContentView: View {
@State private var viewModel: ViewModel
init(transferId: String) {
_viewModel = State(initialValue: ViewModel(transferId: transferId))
}
var body: some View {
NavigationStack {
Button("ReadyRemit SDK v10.0.0") {
viewModel.showReadyRemitSDK(transferId: viewModel.transferId)
}
.fullScreenCover(item: $viewModel.readyRemitItem) {
AnyView($0.view)
}
.navigationTitle("SwiftUI - Full Screen Cover")
}
}
}
#Preview {
ContentView()
}
import ReadyRemitSDK
import SwiftUI
@Observable
class ViewModel {
struct ReadyRemitItem: Identifiable {
let id = UUID()
let view: any View
}
let transferId: String
private let themeConfiguration: String? = nil
var readyRemitItem: ReadyRemitItem?
init(transferId: String) {
self.transferId = transferId
}
func showReadyRemitSDK(transferId: String) {
ReadyRemit.shared.showTransfer(
transferId: transferId,
themeConfiguration: themeConfiguration,
fetchAccessTokenDetails: fetchAccessTokenDetails,
onDismiss: { [weak self] in
guard let self else { return }
self.readyRemitItem = nil
}
) { [weak self] readyRemitSDKView in
guard let self else { return }
self.readyRemitItem = .init(view: readyRemitSDKView)
}
}
private func fetchAccessTokenDetails() async throws -> AccessTokenDetails {
guard let url = URL(string: "https://example.com/v1/oauth/token") else {
throw URLError(.badURL)
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
let (data, urlResponse) = try await URLSession.shared.data(for: urlRequest)
guard let httpURLResponse = urlResponse as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
switch httpURLResponse.statusCode {
case 200...299:
// CreateAccessTokenDetailsResponse must conform to AccessTokenDetails
return try JSONDecoder().decode(CreateAccessTokenDetailsResponse.self, from: data)
default:
throw CustomError.unsuccessfulResponse
}
}
}UIKit - Push View Controller
This assumes ContentViewController is the root view controller of a UINativationController.
import SwiftUI
class ContentViewController: UIViewController {
private let viewModel: ViewModel
init(transferId: String) {
self.viewModel = ViewModel(transferId: transferId)
}
override func viewDidLoad() {
super.viewDidLoad()
title = "UIKit - Push"
setupButton()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setupObservation()
}
private func setupButton() {
let action = UIAction { _ in
self.viewModel.showReadyRemitSDK(transferId: viewModel.transferId)
}
let button = UIButton(primaryAction: action)
button.setTitle("ReadyRemit SDK v10.0.0", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
private func setupObservation() {
withObservationTracking {
_ = viewModel.readyRemitItem
} onChange: { [weak self] in
guard let self else { return }
Task {
await MainActor.run {
if let readyRemitItem = self.viewModel.readyRemitItem {
let hostingController = UIHostingController(rootView: AnyView(readyRemitItem.view))
hostingController.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(hostingController, animated: true)
}
}
}
}
}
}import ReadyRemitSDK
import SwiftUI
@Observable
class ViewModel {
struct ReadyRemitItem: Identifiable {
let id = UUID()
let view: any View
}
let transferId: String
private let themeConfiguration: String? = nil
var readyRemitItem: ReadyRemitItem?
init(transferId: String) {
self.transferId = transferId
}
func showReadyRemitSDK(transferId: String) {
ReadyRemit.shared.showTransfer(
transferId: transferId,
themeConfiguration: themeConfiguration,
fetchAccessTokenDetails: fetchAccessTokenDetails,
onDismiss: { [weak self] in
guard let self else { return }
self.readyRemitItem = nil
}
) { [weak self] readyRemitSDKView in
guard let self else { return }
self.readyRemitItem = .init(view: readyRemitSDKView)
}
}
private func fetchAccessTokenDetails() async throws -> AccessTokenDetails {
guard let url = URL(string: "https://example.com/v1/oauth/token") else {
throw URLError(.badURL)
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
let (data, urlResponse) = try await URLSession.shared.data(for: urlRequest)
guard let httpURLResponse = urlResponse as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
switch httpURLResponse.statusCode {
case 200...299:
// CreateAccessTokenDetailsResponse must conform to AccessTokenDetails
return try JSONDecoder().decode(CreateAccessTokenDetailsResponse.self, from: data)
default:
throw CustomError.unsuccessfulResponse
}
}
}UIKit - Present View Controller
import SwiftUI
class ContentViewController: UIViewController {
private let viewModel: ViewModel
init(transferId: String) {
self.viewModel = ViewModel(transferId: transferId)
}
override func viewDidLoad() {
super.viewDidLoad()
title = "UIKit - Present"
setupButton()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setupObservation()
}
private func setupButton() {
let action = UIAction { _ in
self.viewModel.showReadyRemitSDK(transferId: viewModel.transferId)
}
let button = UIButton(primaryAction: action)
button.setTitle("ReadyRemit SDK v10.0.0", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
private func setupObservation() {
withObservationTracking {
_ = viewModel.readyRemitItem
} onChange: { [weak self] in
guard let self else { return }
Task {
await MainActor.run {
if let readyRemitItem = self.viewModel.readyRemitItem {
let hostingController = UIHostingController(rootView: AnyView(readyRemitItem.view))
hostingController.modalPresentationStyle = .fullScreen
self.present(hostingController, animated: true)
}
}
}
}
}
}
import ReadyRemitSDK
import SwiftUI
@Observable
class ViewModel {
struct ReadyRemitItem: Identifiable {
let id = UUID()
let view: any View
}
let transferId: String
private let themeConfiguration: String? = nil
var readyRemitItem: ReadyRemitItem?
init(transferId: String) {
self.transferId = transferId
}
func showReadyRemitSDK(transferId: String) {
ReadyRemit.shared.showTransfer(
transferId: transferId,
themeConfiguration: themeConfiguration,
fetchAccessTokenDetails: fetchAccessTokenDetails,
onDismiss: { [weak self] in
guard let self else { return }
self.readyRemitItem = nil
}
) { [weak self] readyRemitSDKView in
guard let self else { return }
self.readyRemitItem = .init(view: readyRemitSDKView)
}
}
private func fetchAccessTokenDetails() async throws -> AccessTokenDetails {
guard let url = URL(string: "https://example.com/v1/oauth/token") else {
throw URLError(.badURL)
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
let (data, urlResponse) = try await URLSession.shared.data(for: urlRequest)
guard let httpURLResponse = urlResponse as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
switch httpURLResponse.statusCode {
case 200...299:
// CreateAccessTokenDetailsResponse must conform to AccessTokenDetails
return try JSONDecoder().decode(CreateAccessTokenDetailsResponse.self, from: data)
default:
throw CustomError.unsuccessfulResponse
}
}
}Updated 8 days ago
