OAuthSwift WKWebView opens and closes in a constant loop - ios

I am trying to authenticate an iOS app with the Spotify API using OAuth2.
For this I am using OAuthSwift.
When my application loads, I am redirected to Spotify, I can log in and allow my app access to my account.
When I am redirected back to my app however, the WebView is dismissed, however immediately re opens on the previous page, dismissed itself and re opens.
This continues in a loop indefinitely.
I wondered if this is something todo with having my initAuthFlow function called in viewDidAppear, however moving this to viewDidLoad complains about
Warning: Attempt to present <OAuthKeyChainApp.WKWebViewController: 0x7fb42b505160> on <OAuthKeyChainApp.HomeController: 0x7fb42b50cf30> whose view is not in the window hierarchy!
and the controller is never presented.
HomeController.swift
class HomeController: OAuthViewController {
let oauthSwift = OAuth2Swift(
consumerKey: "xxxxxx",
consumerSecret: "xxxxxx",
authorizeUrl: "https://accounts.spotify.com/en/authorize",
accessTokenUrl: "https://accounts.spotify.com/api/token",
responseType: "code"
)
lazy var internalWebViewController: WKWebViewController = {
let controller = WKWebViewController()
controller.view = UIView(frame: UIScreen.main.bounds)
controller.loadView()
controller.viewDidLoad()
return controller
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .purple
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
initAuthFlow()
}
fileprivate func initAuthFlow() -> Void {
oauthSwift.authorizeURLHandler = internalWebViewController
guard let callbackURL = URL(string: "oauthkeychainapp://oauthkeychain-callback") else { return }
oauthSwift.authorize(
withCallbackURL: callbackURL,
scope: "user-library-modify",
state: generateState(withLength: 20),
success: { (credential, response, params) in
print(credential)
}) { (error) in
print(error.localizedDescription)
}
}
}
extension HomeController: OAuthWebViewControllerDelegate {
func oauthWebViewControllerDidPresent() { }
func oauthWebViewControllerDidDismiss() { }
func oauthWebViewControllerWillAppear() { }
func oauthWebViewControllerDidAppear() { }
func oauthWebViewControllerWillDisappear() { }
func oauthWebViewControllerDidDisappear() { oauthSwift.cancel() }
}
WKWebViewController.swift
import UIKit
import WebKit
import OAuthSwift
class WKWebViewController: OAuthWebViewController {
var webView: WKWebView!
var targetURL: URL?
override func viewDidLoad() {
super.viewDidLoad()
}
override func handle(_ url: URL) {
targetURL = url
super.handle(url)
loadAddressURL()
}
func loadAddressURL() {
guard let url = targetURL else { return }
let req = URLRequest(url: url)
self.webView?.load(req)
}
}
extension WKWebViewController: WKUIDelegate, WKNavigationDelegate {
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.allowsBackForwardNavigationGestures = true
webView.uiDelegate = self
webView.navigationDelegate = self
view = webView
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("loaded")
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
// Check for OAuth Callback
if let url = navigationAction.request.url, url.scheme == "oauthkeychainapp" {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
self.dismiss(animated: true, completion: nil)
decisionHandler(.cancel)
return
}
// Restrict URL's a user can access
if let host = navigationAction.request.url?.host {
if host.contains("spotify") {
decisionHandler(.allow)
return
} else {
// open link outside of our app
UIApplication.shared.open(navigationAction.request.url!)
decisionHandler(.cancel)
return
}
}
decisionHandler(.cancel)
}
}

You aren't doing anything to change the state of your application. Because of this initAuthFlow is being called again, Spotify I assume has a valid session for you, so the controller is dismissed and the cycle repeats.
In the success closure of your oauthSwift.authorize call you should put the tokens into the KeyChain or somewhere secure and ensure initAuthFlow is only called when that state is invalid.

Related

Error Domain=WebKitErrorDomain Code=102 "Frame load interrupted" iOS WKwebview WKnavigationdelegate

I´m working on an app that will show a website. But I'm running into errors when loading the website in app. I´ts also working perfectly fine on android.
The error:
WebPageProxy::didFailProvisionalLoadForFrame: frameID = 3, domain =
WebKitErrorDomain, code = 102 Error Domain=WebKitErrorDomain Code=102
"Frame load interrupted"
UserInfo={_WKRecoveryAttempterErrorKey=<WKReloadFrameErrorRecoveryAttempter:
0x600001922120>, NSErrorFailingURLStringKey=https://site.site/login,
NSErrorFailingURLKey=https://site.site/login,
NSLocalizedDescription=Frame load interrupted} Failed Provisinal
Navigation
My code:
// ViewController.swift
import UIKit
import WebKit
import SafariServices
import PushNotifications
class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {
let pushNotifications = PushNotifications.shared
var webView: WKWebView!
var manifest = WebAppManifest.shared
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage){
if let objStr = message.body as? String {
var arr = [" "," "]
if objStr.contains(";") {
arr = objStr.components(separatedBy: ";")
}
let tokenProvider = BeamsTokenProvider(authURL: "https://site.site/beams/token") { () -> (AuthData) in
let headers : [String: String] = [:]
var queryParams : [String: String] = [:]
if objStr.contains(";") {
queryParams = ["api_token":arr[1]]
}
return AuthData(headers: headers, queryParams: queryParams)
}
if objStr.contains(";") {
self.pushNotifications.setUserId(arr[0], tokenProvider: tokenProvider, completion: { error in
guard error == nil else {
print(error.debugDescription)
return
}
print("Succesfully authenticated with Pusher Beams")
})
} else {
self.pushNotifications.setUserId(objStr, tokenProvider: tokenProvider, completion: { error in
guard error == nil else {
print(error.debugDescription)
return
}
print("Succesfully authenticated with Pusher Beams")
})
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
let contentcontroller = WKUserContentController()
contentcontroller.add(self, name: "callbackHandler")
let config = WKWebViewConfiguration()
config.userContentController = contentcontroller
// Set-up the UI
self.view.backgroundColor = UIColor(fromHex: manifest.theme_color)
// Creates the web view engine
webView = WKWebView()
view.addSubview(webView)
webView.navigationDelegate = self
// Display attribute
var guide: AnyObject = self.view.safeAreaLayoutGuide
if manifest.display == "fullscreen" {
guide = self.view
webView.scrollView.contentInsetAdjustmentBehavior = .always
}
// Make the Web View take the whole screen
webView.translatesAutoresizingMaskIntoConstraints = false
webView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
webView.rightAnchor.constraint(equalTo: guide.rightAnchor).isActive = true
webView.leftAnchor.constraint(equalTo: guide.leftAnchor).isActive = true
webView.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true
// It will enable navigation gestures on the web view
webView.allowsBackForwardNavigationGestures = true
let url = URL(string: "https://" + manifest.origin + manifest.start_url)!
print(pushNotifications.getDeviceInterests())
webView.load(URLRequest(url: url))
}
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
get {
switch manifest.orientation {
case "landscape":
return UIInterfaceOrientationMask.landscape
case "portrait":
return UIInterfaceOrientationMask.portrait
default:
return UIInterfaceOrientationMask.all
}
}
set { self.supportedInterfaceOrientations = newValue }
}
override var prefersStatusBarHidden: Bool {
return manifest.display == "fullscreen"
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return UIColor(fromHex: manifest.theme_color).isDark() ? .lightContent : .darkContent
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
view.setNeedsLayout()
}
// MARK: loadWebPage function
func loadWebPage(url: URL) {
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
components?.query = nil
// If already has a query then append a param
// otherwise create a new one
if let query = url.query {
// If isFromMobile param already exists jsut reassign the existing query
if query.contains("source=TWA&platform=iOS") {
components?.query = query
} else {
components?.query = query + "&source=TWA&platform=iOS"
}
} else {
components?.query = "source=TWA&platform=iOS"
}
print(components!.url!)
let customRequest = URLRequest(url: components!.url!)
webView!.load(customRequest)
}
// MARK: NavigationAction handler
// Defines if it should navigate to a new URL
// Logic to check if the destination URL is in the scope
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
print(navigationAction.request.url?.absoluteURL)
if let host = navigationAction.request.url?.host,
let path = navigationAction.request.url?.path{
if host.contains(manifest.origin) &&
path.starts(with: manifest.scope){
let query = navigationAction.request.url?.query
if query != nil{
print("two")
// MARK: Pusher clear state
if path.contains("logout") || path.contains("login") {
pushNotifications.clearAllState {
print("Cleared all state!")
}
}
decisionHandler(.allow)
} else {
print("one")
loadWebPage(url: navigationAction.request.url!)
decisionHandler(.cancel)
}
return
} else {
print("wrong")
// Destination URL is out of the scope
if navigationAction.request.url?.scheme == "http" ||
navigationAction.request.url?.scheme == "https" {
// Opens an In-App browser
decisionHandler(.cancel)
let safariVC = SFSafariViewController(url: navigationAction.request.url!)
safariVC.preferredBarTintColor = UIColor(fromHex: manifest.theme_color)
safariVC.preferredControlTintColor =
UIColor(fromHex: manifest.theme_color).isDark() ? UIColor.white : UIColor.black
present(safariVC, animated: true)
} else {
// It looks like a different protocol
// We ask the OS to open it
UIApplication.shared.open(navigationAction.request.url!)
}
}
} else {
decisionHandler(.cancel)
}
}
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void) {
print("error")
if let response = navigationResponse.response as? HTTPURLResponse {
if response.statusCode >= 400 {
print("400 error")
handleError()
}
}
decisionHandler(.allow)
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print(error, "Failed Navigation")
handleError()
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
print(error, "Failed Provisinal Navigation")
handleError()
}
// Error handling in case the content of the PWA can't be loaded
func handleError() {
webView.loadHTMLString("<h1>:(</h1>", baseURL: nil)
let alert = UIAlertController(title: "Error", message: "There was a problem loading the App from the Internet. Please check your connection and try again", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: { (action) in
exit(100)
}))
present(alert, animated: true)
}
}
I have already made multiple apps of this type of but never had this error pop up. Any suggestion on how to fix this?

WKWebView: Completion handler passed to -[WebWidgetVC webView:decidePolicyForNavigationAction:decisionHandler:] was not called

I'm using swift in my project. i have WebWidgetVC (which is UIViewController) and inside of that UIViewController i have a WKWebView. i want for example if the url contain "https" denied the WKWebView and if the url contain "http" the WKWebView allowed. this is my codes:
import UIKit
import WebKit
class WebWidgetVC: BaseViewController {
var webView: WKWebView!
var widgetUrl: String?
var widget: Widget?
private var moreInfoView: WidgetInfoView!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
if let wrappedUrl = widgetUrl, let url = URL(string: wrappedUrl) {
let preference = WKPreferences()
preference.javaScriptEnabled = true
preference.javaScriptCanOpenWindowsAutomatically = false
preference.setValue(false, forKey: "allowFileAccessFromFileURLs")
let configuration = WKWebViewConfiguration()
configuration.preferences = preference
configuration.setValue(false, forKey: "allowUniversalAccessFromFileURLs")
configuration.websiteDataStore = WKWebsiteDataStore.default()
webView = WKWebView(frame: CGRect.zero, configuration: configuration)
webView.uiDelegate = self
webView.navigationDelegate = self
webView.load(URLRequest(url: url))
webView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(webView)
NSLayoutConstraint.activate([
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
webView.topAnchor.constraint(equalTo: view.topAnchor),
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
view.sendSubviewToBack(webView)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setNeedsStatusBarAppearanceUpdate()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
if #available(iOS 13.0, *) {
return .darkContent
} else {
return .default
}
}
#IBAction func showMoreInfo(_ sender: UIButton) {
guard let widget = widget else {
return
}
moreInfoView = WidgetInfoView(frame: view.frame)
view.addSubview(moreInfoView)
moreInfoView.activeReceiptView(widget: widget)
}
#IBAction func dismissVC(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}
// MARK: - Safari webkit delegate
extension WebWidgetVC: WKNavigationDelegate, WKUIDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
let request = navigationAction.request
let urlScheme = request.url?.scheme
if urlScheme == "http" {
decisionHandler(.allow)
} else if urlScheme == "https" {
decisionHandler(.cancel)
}
}
}
when program calling decisionHandler(.allow), getting this error:
Completion handler passed to -[WebWidgetVC webView:decidePolicyForNavigationAction:decisionHandler:] was not called
how can i fix this problem?
Updated
i put some breakpoints inside decidePolicyFor function and find out that after executing decisionHandler(.allow) code, this function called again.

How to get JS event handler with URL in swift

class FeedBackFormViewController: UIViewController, WKUIDelegate, WKScriptMessageHandler {
#IBOutlet weak var webViewShowing: UIView!
var formWebView: WKWebView!
private let fileString = UserSingleton.shared.feedbackFormLink
override func viewDidLoad() {
super.viewDidLoad()
setupJSFile()
formWebView.navigationDelegate = self
previewFiles()
}
// show files in web view
private func previewFiles() {
if let fileString = fileString, fileString != "" {
let url = URL(string: fileString)
let myRequest = URLRequest(url: url!)
UserSingleton.shared.showHUD()
formWebView.load(myRequest)
}else {
Alerts.shared.show(alert: .error, message: "no file found", type: .error)
}
}
private func setupJSFile() {
let config = WKWebViewConfiguration()
let js = "document.addEventListener('submit', function(){ window.webkit.messageHandlers.clickListener.postMessage('My hovercraft is full of eels!'); })"
let script = WKUserScript(source: js, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
config.userContentController.addUserScript(script)
config.userContentController.add(self, name: "submit")
formWebView = WKWebView(frame: UIScreen.main.bounds, configuration: config)
webViewShowing.addSubview(formWebView)
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.name)
}
#IBAction func dismissFeedbackFormVC(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
}
extension FeedBackFormViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!){
webView.evaluateJavaScript("document.readyState") { (result, error) in
if let result = result {
print(result)
}
}
}
}
only call wk navigation when the web view is loaded and I click anywhere no trigger call in userContentController any event
You'd need to add this script for execution, just append it at the end of the func setupJSFile:
formWebView.configuration.userContentController.addUserScript(script)
also, you'd need to change your JS script to
document.addEventListener('click', function(){ window.webkit.messageHandlers['iosListener'].postMessage('click clack!'); })

IOS WKWebview Cache Clearing

I have made a very simple WKWebview IOS app that embeds my Wordpress website ...
import UIKit
import WebKit
class ViewController: UIViewController {
private lazy var url = URL(string: "http://www.myblog.com")!
private weak var webView: WKWebView!
init (url: URL, configuration: WKWebViewConfiguration) {
super.init(nibName: nil, bundle: nil)
self.url = url
navigationItem.title = ""
}
required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
override func viewDidLoad() {
super.viewDidLoad()
initWebView()
webView.loadPage(address: url)
}
private func initWebView() {
let webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
view.addSubview(webView)
self.webView = webView
webView.navigationDelegate = self
webView.uiDelegate = self
webView.translatesAutoresizingMaskIntoConstraints = false
webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
webView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
webView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
webView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
}
}
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
guard let host = webView.url?.host else { return }
navigationItem.title = host
}
}
extension ViewController: WKUIDelegate {
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
guard navigationAction.targetFrame == nil,
let url = navigationAction.request.url else { return nil }
let vc = ViewController(url: url, configuration: configuration)
if let navigationController = navigationController {
navigationController.pushViewController(vc, animated: false)
return vc.webView
}
present(vc, animated: true, completion: nil)
return nil
}
}
extension WKWebView {
func loadPage(address url: URL) { load(URLRequest(url: url)) }
func loadPage(address urlString: String) {
guard let url = URL(string: urlString) else { return }
loadPage(address: url)
}
}
There is a caching plugin on the actual website and I would like for whenever the app loads on a users device - for the app to pull in a fresh copy of the url. Is this possible?
Can anyone advise where to start or how i can adjust my current code to get started?
Thank you!
Push notifications has nothing to do with the WKWebview.
First you need to handle events in the backend/wordpress. From the mobile side, you need the following:
1- Generating a P12 or P8 certificate and put it on the server to trust APN
2- Register for push notifications in AppDelegate class.
3- Handle receiving a push notification in AppDelegate class too.

WKWebView evaluateJavaScript not returning html

I am trying to parse the html returned from a WKWebView load() with evaluateJavaScript but it never prints anything. Am I doing this right? Any other ways? didFinish does print.
import UIKit
import WebKit
class MyWebViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView = WKWebView(frame: self.view.frame)
webView.navigationDelegate = self
let url = NSURL (string: "https://google.com");
let request = NSURLRequest(url: url! as URL)
webView.load(request as URLRequest)
self.view.addSubview(webView)
self.view.sendSubview(toBack: webView)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("document.documentElement.outerHTML.toString()", completionHandler: { (html: AnyObject?, error: NSError?) in
print(html!)
} as? (Any?, Error?) -> Void)
print("didFinish")
}
}
Using evaluateJavaScript with a WKWebView is a bit tricky.
Since I think this answer would be useful to many people, rather than address your specific question with a short code snippet and a comment that you need to implement WKScriptMessageHandler, I'm going to post a full, complete example that you can use to see how everything works together.
To use this, create a "Single View Application" iOS project in Xcode and paste this over the default ViewController.swift file.
//
// WebViewController.swift
// WKWebViewExample
//
// Created by par on 4/2/17.
// Copyright © 2017 par. All rights reserved. MIT License.
//
import UIKit
import WebKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let webViewController = WebViewController()
// install the WebViewController as a child view controller
addChildViewController(webViewController)
let webViewControllerView = webViewController.view!
view.addSubview(webViewControllerView)
webViewControllerView.translatesAutoresizingMaskIntoConstraints = false
webViewControllerView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
webViewControllerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
webViewControllerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
webViewControllerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
webViewController.didMove(toParentViewController: self)
}
}
class WebViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {
private var webView: WKWebView!
private var webViewContentIsLoaded = false
init() {
super.init(nibName: nil, bundle: nil)
self.webView = {
let contentController = WKUserContentController()
contentController.add(self, name: "WebViewControllerMessageHandler")
let configuration = WKWebViewConfiguration()
configuration.userContentController = contentController
let webView = WKWebView(frame: .zero, configuration: configuration)
webView.scrollView.bounces = false
webView.navigationDelegate = self
return webView
}()
}
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(webView)
webView.translatesAutoresizingMaskIntoConstraints = false
webView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
webView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
webView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if !webViewContentIsLoaded {
let url = URL(string: "https://stackoverflow.com")!
let request = URLRequest(url: url)
webView.load(request)
webViewContentIsLoaded = true
}
}
private func evaluateJavascript(_ javascript: String, sourceURL: String? = nil, completion: ((_ error: String?) -> Void)? = nil) {
var javascript = javascript
// Adding a sourceURL comment makes the javascript source visible when debugging the simulator via Safari in Mac OS
if let sourceURL = sourceURL {
javascript = "//# sourceURL=\(sourceURL).js\n" + javascript
}
webView.evaluateJavaScript(javascript) { _, error in
completion?(error?.localizedDescription)
}
}
// MARK: - WKNavigationDelegate
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// This must be valid javascript! Critically don't forget to terminate statements with either a newline or semicolon!
let javascript =
"var outerHTML = document.documentElement.outerHTML.toString()\n" +
"var message = {\"type\": \"outerHTML\", \"outerHTML\": outerHTML }\n" +
"window.webkit.messageHandlers.WebViewControllerMessageHandler.postMessage(message)\n"
evaluateJavascript(javascript, sourceURL: "getOuterHMTL")
}
// MARK: - WKScriptMessageHandler
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
guard let body = message.body as? [String: Any] else {
print("could not convert message body to dictionary: \(message.body)")
return
}
guard let type = body["type"] as? String else {
print("could not convert body[\"type\"] to string: \(body)")
return
}
switch type {
case "outerHTML":
guard let outerHTML = body["outerHTML"] as? String else {
print("could not convert body[\"outerHTML\"] to string: \(body)")
return
}
print("outerHTML is \(outerHTML)")
default:
print("unknown message type \(type)")
return
}
}
}
I know it has been a while since this was answered and I found that this didn't really work for me. I used the below instead.
I could not get the evaluateJavaScript to work until i added the setTimeout() function. For what it is worth here is my code below.
webView.evaluateJavaScript("setTimeout(function(){
// Do something here
},10);") { (result1, error) in
if error == nil {
print(result1 ?? "")
}
}

Resources