# [iOS - Swift] How to communicate with iFrames inside WebView To provide better shopping experience for [Onefill](http://onefill.com/) users, we want to support as many shopping site as we can by injecting our JavaScript engine into those sites. However, some of them are using iframe which is outdated HTML tag to implement some forms like payment and signup. And due to security issue JavaScript can’t communicate with iframe unless it’s same domain or it’s your domain. So here is the approach we did to support iframe under iOS web view and so we can communicate with it. * Xcode: Version 8.2.1 (8C1002) * Swift: Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1) ## Conclusion first 1. Use WKWebView instead UIWebView or WebView for 2 reasons: * Apple [Recommand](https://developer.apple.com/reference/webkit/wkwebview) * There is an [API](https://developer.apple.com/reference/webkit/wkuserscript) to inject JS into iFrame 2. Use built-in API [WKUserScript](https://developer.apple.com/reference/webkit/wkuserscript) inject JS, set `forMainFrameOnly` as false to inject JS into every frames (including iframe) 3. To communicate between iframe and app, use JS webkit API ## Code ### inject JS into iframe Use `WKUserScript` inject JavaScript into all frames Example: Inject a script to make every h1 tag red. ```swift import UIKit import WebKit class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate { var webView: WKWebView! override func loadView() { let webConfiguration = WKWebViewConfiguration() let contentController = WKUserContentController() let js: String = "var h1s = document.querySelectorAll('h1'); for (var i = 0; i < h1s.length; i++) { h1s[i].style.color = 'red' };" let userScript = WKUserScript(source: js, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: false) contentController.addUserScript(userScript) webConfiguration.userContentController = contentController webView = WKWebView(frame: .zero, configuration: webConfiguration) webView.uiDelegate = self webView.navigationDelegate = self view = webView } override func viewDidLoad() { super.viewDidLoad() let myURL = URL(string: "http://localhost:3000") let myRequest = URLRequest(url: myURL!) webView.load(myRequest) } } ``` ### Communicate with iFrame Use JavaScript webkit API Almost same as “inject JS into iframe”, however, we need to implement `WKScriptMessageHandler` protocol to receive message sent by JavaScript. ```swift import UIKit import WebKit class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler { var webView: WKWebView! override func loadView() { let webConfiguration = WKWebViewConfiguration() let contentController = WKUserContentController() // Inject JavaScript which sending message to App let js: String = "window.webkit.messageHandlers.callbackHandler.postMessage('Hello from JavaScript');" let userScript = WKUserScript(source: js, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: false) contentController.removeAllUserScripts() contentController.addUserScript(userScript) // Add ScriptMessageHandler contentController.add( self, name: "callbackHandler" ) webConfiguration.userContentController = contentController webView = WKWebView(frame: .zero, configuration: webConfiguration) webView.uiDelegate = self webView.navigationDelegate = self view = webView } override func viewDidLoad() { super.viewDidLoad() let myURL = URL(string: "http://localhost:3000") let myRequest = URLRequest(url: myURL!) webView.load(myRequest) } // Implement `WKScriptMessageHandler`,handle message which been sent by JavaScript func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if(message.name == "callbackHandler") { print("JavaScript is sending a message \(message.body)") } } } ``` ## References 1. [wkwebview-and-javascript-in-ios-8-using-swift](https://kinderas.com/technology/2014/6/15/wkwebview-and-javascript-in-ios-8-using-swift) 2. [WKWebit](http://nshipster.com/wkwebkit/) 3. [2014 WWDC about WKWebView](https://developer.apple.com/videos/play/wwdc2014/206/) 4. Apple API Docs: * [WKUserScript](https://developer.apple.com/reference/webkit/wkuserscript) * [WKUserContentController](https://developer.apple.com/reference/webkit/wkusercontentcontroller) * [WKWebView](https://developer.apple.com/reference/webkit/wkwebview)