# Enabling Elements for Apple iOS Like other platforms, iOS requires the same two or three simple steps: Add a web view, handle events/messages, and, in some cases, authenticate the user. ## 1. Set Up a Web View Component used: [WKWebView](https://developer.apple.com/documentation/webkit/wkwebview) Note: iOS 26 introduced [WebKit for SwiftUI](https://developer.apple.com/documentation/webkit/webkit-for-swiftui) which has not yet been tested with Elements. No problems are expected, but implementation details may change. Required Web View Configuration - Enable JavaScript - Enable Web Storage (DOM Storage) #### Web View Sample elements-in-ios.swift // Step 1: Set Up a Web View WebView( url: url, onTokenReceived: { token in self.token = token self.showTokenAlert = true }, onFullResponseReceived: { response in handleCardTokenizeResponse(response) } ) .edgesIgnoringSafeArea(.all) ## Step 2. Set Up Event/Message Handling ### Sending Events Component used: [WKUserContentController](https://developer.apple.com/documentation/webkit/wkusercontentcontroller) Note: iOS 26 introduced [WebKit for SwiftUI](https://developer.apple.com/documentation/webkit/webkit-for-swiftui) which has not yet been tested with Elements. No problems are expected, but implementation details may change. #### Send Message Sample Code elements-in-ios.swift // Step 2: Set Up Communications: Event/Message Handling // Step 2a: Send Event to Elements ### Listening for Events Component used: [WKUserContentController](https://developer.apple.com/documentation/webkit/wkusercontentcontroller) #### Receive Message Sample Code elements-in-ios.swift // Step 2b: Listen for events from Elements 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) } } ## Step 3. Set Up User Authentication (Optional) elements-in-ios.swift // Step 3: Setup Authentication // // Code sample coming soon // ## Full Sample Code elements-in-ios.swift 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 } // Step 2: Set Up Communications: Event/Message Handling // Step 2a: Send Event to Elements // Step 2b: Listen for events from Elements 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) } } // Step 2 End } // Step 3: Setup Authentication // // Code sample coming soon // // Step 3 End 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://elements.uat.dailypay.com/v1/debit-card-tokenization?client_id=REPLACE_WITH_YOUR_CLIENT_ID&implementation_id=REPLACE_WITH_YOUR_IMPLEMENTATION_ID" @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) { // Step 1: Set Up a Web View WebView( url: url, onTokenReceived: { token in self.token = token self.showTokenAlert = true }, onFullResponseReceived: { response in handleCardTokenizeResponse(response) } ) .edgesIgnoringSafeArea(.all) // Step 1 End } else { Text("Invalid URL") } } .alert(isPresented: $showTokenAlert) { Alert( title: Text("Token Received"), message: Text(token ?? "No token"), dismissButton: .default(Text("OK")) ) } } } #Preview { ContentView() }