hi I'm implementing simple WKWebView appplication and I want to be able to ask user for input via prompt dialogue, I tried to use solution mentioned here
but I'm not sure how should it work when implemented - should this just add extension to WKWebView for triggering e.g. regular alert()
from javascript or I should pass some different instructions in js to trigger this native alert?
so my question is: 1) how this should work when implemented 2) what am I missing in implementation
here's my controller code (giving whole controller, as I dont know what could be important here)
thanks in advance!
import UIKit
import WebKit
class ViewController:
UIViewController
, WKNavigationDelegate
, UIScrollViewDelegate
, WKUIDelegate
{
@IBOutlet var webView: WKWebView!
let getUrlAtDocumentStartScript = "GetUrlAtDocumentStart"
let getUrlAtDocumentEndScript = "GetUrlAtDocumentEnd"
override func loadView() {
self.webView = WKWebView()
self.webView.navigationDelegate = self
//for prompt
self.webView?.uiDelegate = self
view = webView
}
override func viewWillAppear(_ animated: Bool) {//white status bar
super.viewWillAppear(animated)
webView.isOpaque = false //removes white flash on WKWebView load
webView.backgroundColor = UIColor(red: 41/255, green: 45/255, blue: 91/255, alpha: 1)
UIApplication.shared.statusBarStyle = .lightContent
do {
let paid = Bundle.main.infoDictionary?["paid"] as? Bool;
var fileName = "none"
if(paid!){
fileName = "index-ios-wvd-inlined--paid"
} else {
fileName = "index-ios-wvd-inlined"
}
guard let filePath = Bundle.main.path(forResource: fileName, ofType: "html")
else {
print ("File reading error")
return
}
let contents = try String(contentsOfFile: filePath, encoding: .utf8)
let baseUrl = URL(fileURLWithPath: filePath)
webView.loadHTMLString(contents as String, baseURL: baseUrl)
}
catch {
print ("File HTML error")
}
}
override var preferredStatusBarStyle : UIStatusBarStyle {//white status bar
return .lightContent
}
override func viewDidLoad() {
webView.scrollView.bounces = false;
super.viewDidLoad()
webView.scrollView.delegate = self //disable zoom
//for haptics
let config = WKWebViewConfiguration()
config.addScript(script: WKUserScript.getUrlScript(scriptName: getUrlAtDocumentStartScript), scriptHandlerName:getUrlAtDocumentStartScript, scriptMessageHandler: self, injectionTime: .atDocumentStart)
config.addScript(script: WKUserScript.getUrlScript(scriptName: getUrlAtDocumentEndScript), scriptHandlerName:getUrlAtDocumentEndScript, scriptMessageHandler: self, injectionTime: .atDocumentEnd)
webView = WKWebView(frame: UIScreen.main.bounds, configuration: config)
webView.navigationDelegate = self
view.addSubview(webView)
}
//disable zoom
func viewForZooming(in: UIScrollView) -> UIView? {
return nil;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tapped(i:Int) {
print("Triggering haptic #\(i)")
switch i {
case 1:
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.error)
case 2:
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.success)
case 3:
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.warning)
case 4:
let generator = UIImpactFeedbackGenerator(style: .light)
generator.impactOccurred()
case 5:
let generator = UIImpactFeedbackGenerator(style: .medium)
generator.impactOccurred()
case 6:
let generator = UIImpactFeedbackGenerator(style: .heavy)
generator.impactOccurred()
default:
let generator = UISelectionFeedbackGenerator()
generator.selectionChanged()
}
}
//alert/prompt/confirm dialogs
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping () -> Void) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
completionHandler()
}))
present(alertController, animated: true, completion: nil)
}
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping (Bool) -> Void) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
completionHandler(true)
}))
alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
completionHandler(false)
}))
present(alertController, animated: true, completion: nil)
}
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping (String?) -> Void) {
let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .actionSheet)
alertController.addTextField { (textField) in
textField.text = defaultText
}
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
if let text = alertController.textFields?.first?.text {
completionHandler(text)
} else {
completionHandler(defaultText)
}
}))
alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
completionHandler(nil)
}))
present(alertController, animated: true, completion: nil)
}
}
//sending scripts commands to JS and back
extension ViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
switch message.name {
case getUrlAtDocumentStartScript:
tapped(i: message.body as! Int)
//print("start: \(message.body)")
case getUrlAtDocumentEndScript:
tapped(i: message.body as! Int)
//print("tapped: \(message.body)")
default:
break;
}
}
}
extension WKUserScript {
class func getUrlScript(scriptName: String) -> String {
return "webkit.messageHandlers.\(scriptName).postMessage(1)"
}
}
extension WKWebView {
func loadUrl(string: String) {
if let url = URL(string: string) {
load(URLRequest(url: url))
}
}
}
extension WKWebViewConfiguration {
func addScript(script: String, scriptHandlerName:String, scriptMessageHandler: WKScriptMessageHandler, injectionTime:WKUserScriptInjectionTime) {
let userScript = WKUserScript(source: script, injectionTime: injectionTime, forMainFrameOnly: false)
userContentController.addUserScript(userScript)
userContentController.add(scriptMessageHandler, name: scriptHandlerName)
}
}