Как заставить invokeUndefinedMethodFromWebScript работать в Swift

Я пытаюсь заставить интерфейс Javascript-Swift работать с WKWebView, и у кого-то, похоже, он работает здесь.

Однако я не могу заставить его работать в Swift (я новичок в Swift и новее в Obj-C). Я попробовал следующий код в ViewController.swift с WKWebView, добавленным в Main.storyboard и подключенным:

import WebKit

class ViewController: NSViewController, WKUIDelegate {
    @IBOutlet weak var wkWebView: WKWebView!
    override func viewDidLoad() {
        super.viewDidLoad()
        let url = URL(string: "http://127.0.0.1:8080")
        let request = URLRequest(url: url!)
        wkWebView!.configuration.preferences.javaScriptEnabled = true
        wkWebView!.load(request)
    }
}

extension WKWebView {
    open override func invokeUndefinedMethod(fromWebScript name: String!, withArguments arguments: [Any]!) -> Any! {
        return "Hello From Swift"
    }
}

и на стороне HTML:

<html>
  <body>
    <p>Hello World</p>
    <input type=text id='i'/>
    <input type=button value='Submit' onclick='document.getElementById(\"i\").value = window.external.MY_ObjectiveCFunction();'>
  </body>
</html>

Но когда я нажимаю кнопку «Отправить», ничего не происходит. Если я использую document.getElementById("i") = "hello", он работает. @ctrlspace, похоже, как-то заработал (см. ссылку выше).

Любые идеи?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
699
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы нашли старую статью, написанную для древнего WebView macOS, а не для WKWebView.

Вы используете WKScriptMessageHandler для взаимодействия между JavaScript и Swift при использовании WKWebView.

ViewController.swift:

import WebKit

class ViewController: NSViewController, WKUIDelegate {
    @IBOutlet weak var wkWebView: WKWebView!
    override func viewDidLoad() {
        super.viewDidLoad()
        let url = Bundle.main.url(forResource: "index", withExtension: "html")! //Simplified for testing
        let request = URLRequest(url: url)
        wkWebView.configuration.preferences.javaScriptEnabled = true
        wkWebView.configuration.userContentController.add(self, name: "mySwiftMessage") //<-
        wkWebView.load(request)
    }

    //...
}

extension ViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        switch message.name {
        case "mySwiftMessage":
            if let callbackName = message.body as? String {
                message.webView?.evaluateJavaScript("\(callbackName)('Hello From Swift');", completionHandler: nil)
            }
        default:
            break
        }
    }
}

индекс.html:

<html>
    <body>
        <script>
            function myCallback(value) {
                document.getElementById("i").value = value;
            }
        </script>
        <p>Hello World</p>
        <input type=text id='i'/>
        <input type=button value='Submit' onclick='window.webkit.messageHandlers.mySwiftMessage.postMessage("myCallback");'>
    </body>
</html>

ДОБАВЛЕНИЕ

Чтобы WKWebView работал на более ранних версиях iOS, чем 11, вам просто нужно программно создать его экземпляр:

import WebKit

class ViewController: UIViewController, WKUIDelegate {

    var wkWebView: WKWebView! //<- NOT an IBOutlet

    override func viewDidLoad() {
        super.viewDidLoad()
        let webConfig = WKWebViewConfiguration()
        webConfig.preferences.javaScriptEnabled = true
        webConfig.userContentController.add(self, name: "mySwiftMessage")
        wkWebView = WKWebView(frame: self.view.bounds, configuration: webConfig)
        view.addSubview(wkWebView)
        //You may need to add some constraints...
        //And create a better `index.html` for iOS...
        let url = Bundle.main.url(forResource: "index", withExtension: "html")!
        let request = URLRequest(url: url)
        wkWebView.load(request)
    }

    //...
}

Спасибо за полностью работающее решение. Я также хотел бы, чтобы UIWebView поддерживал iOS 9.0+, поскольку WKWebView предназначен только для iOS11+. Является ли это возможным?

arun 19.01.2019 09:34

Я не смог найти такого элегантного решения для UIWebView. Кажется, доступны только обходные пути (например, загрузка пользовательского URL-адреса)

arun 19.01.2019 09:40

Вы ошибаетесь с доступностью WKWebView, которая доступна с iOS 8. Просто вы не можете использовать раскадровку для WKWebView до iOS 11. Вам просто нужно создать экземпляр WKWebView программно.

OOPer 19.01.2019 11:12

Отлично .. Это тоже сработало .. Хотел бы я проголосовать за вас более одного раза .. Огромное спасибо !!

arun 19.01.2019 11:23

Другие вопросы по теме