import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
let url: URL
let handlerName = "iosListener"
var onTokenReceived: ((String) -> Void)?
var onFullResponseReceived: ((DailypayCardTokenizeResponse) -> Void)?
class Coordinator: NSObject, WKScriptMessageHandler {
var onIssuerReceived: ((String) -> Void)?
var onTokenReceived: ((String) -> Void)?
var onFullResponseReceived: ((DailypayCardTokenizeResponse) -> Void)?
init(onTokenReceived: ((String) -> Void)?, onFullResponseReceived: ((DailypayCardTokenizeResponse) -> Void)?) {
self.onTokenReceived = onTokenReceived
self.onFullResponseReceived = onFullResponseReceived
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("Received postMessage: \(message.body)")
var data: Data? = nil
if let dict = message.body as? [String: Any] {
data = try? JSONSerialization.data(withJSONObject: dict)
} else if let str = message.body as? String {
data = str.data(using: .utf8)
}
if let data, let msg = try? JSONDecoder().decode(DailypayCardTokenizeMessage.self, from: data),
msg.type == "DAILYPAY_CARD_TOKENIZE_RESPONSE" {
onIssuerReceived?(msg.response.issuer)
onTokenReceived?(msg.response.token)
onFullResponseReceived?(msg.response)
}
}
}
func makeCoordinator() -> Coordinator {
Coordinator(onTokenReceived: onTokenReceived, onFullResponseReceived: onFullResponseReceived)
}
func makeUIView(context: Context) -> WKWebView {
let contentController = WKUserContentController()
contentController.add(context.coordinator, name: handlerName)
let config = WKWebViewConfiguration()
config.userContentController = contentController
// Forward window.postMessage to iOS
let js = """
window.postMessage = function(data) {
window.webkit.messageHandlers.\(handlerName).postMessage(data);
};
"""
let userScript = WKUserScript(source: js, injectionTime: .atDocumentStart, forMainFrameOnly: false)
contentController.addUserScript(userScript)
let webView = WKWebView(frame: .zero, configuration: config)
let request = URLRequest(url: url)
webView.load(request)
return webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
// No-op
}
}
struct DailypayCardTokenizeResponse: Decodable {
let firstName: String
let lastName: String
let addressLineOne: String
let addressLineTwo: String
let addressCity: String
let addressState: String
let addressZipCode: String
let expirationMonth: String
let expirationYear: String
let addressCountry: String
let issuer: String
let token: String
enum CodingKeys: String, CodingKey {
case firstName = "first_name"
case lastName = "last_name"
case addressLineOne = "address_line_one"
case addressLineTwo = "address_line_two"
case addressCity = "address_city"
case addressState = "address_state"
case addressZipCode = "address_zip_code"
case expirationMonth = "expiration_month"
case expirationYear = "expiration_year"
case addressCountry = "address_country"
case issuer
case token
}
}
struct DailypayCardTokenizeMessage: Decodable {
let type: String
let response: DailypayCardTokenizeResponse
let success: Bool
}
struct ContentView: View {
// Replace client_id and implementation_id with values supplied by DailyPay
// that are unique to you and your application
@State private var urlString: String = "https://companion.workloads.production.dailypay.com/v1/widgets/debitcard/tokenizer?client_id=123&implementation_id=3213"
@State private var showAlert = false
@State private var issuer: String? = nil
@State private var showTokenAlert = false
@State private var token: String? = nil
func handleCardTokenizeResponse(_ response: DailypayCardTokenizeResponse) {
// Add card to DailyPay using POST /accounts
// See https://developer.dailypay.com/tag/Accounts#operation/createAccount
print("Ready to send to the DailyPay REST API: \(response)")
}
var body: some View {
VStack {
TextField("Enter URL", text: $urlString)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
if let url = URL(string: urlString) {
WebView(
url: url,
onTokenReceived: { token in
self.token = token
self.showTokenAlert = true
},
onFullResponseReceived: { response in
handleCardTokenizeResponse(response)
}
)
.edgesIgnoringSafeArea(.all)
} else {
Text("Invalid URL")
}
}
.alert(isPresented: $showTokenAlert) {
Alert(
title: Text("Token Received"),
message: Text(token ?? "No token"),
dismissButton: .default(Text("OK"))
)
}
}
}
#Preview {
ContentView()
}Last updated