Как работает API iOS 14 WKScriptMessageHandlerWithReply для связи с помощью JavaScript из iOS?

В iOS 14 представлен новый способ получения вызовов javascript и предоставления ответа с использованием WKScriptMessageHandlerWithReply вместо WKScriptMessageHandler (внутри представления WebKit). Однако документация практически отсутствует. Как это работает?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
4
0
3 027
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Я немного покопался в этом и обнаружил, что он использует обещания Javascript для обеспечения механизма обратного вызова (и ответ кода приложения обратно на javascript должен быть асинхронным).

Вот пример кода для иллюстрации:

Быстрый код:

import UIKit
import WebKit
import PureLayout

final class ViewController: UIViewController {

    var webView : WKWebView?
    let JavaScriptAPIObjectName = "namespaceWithinTheInjectedJSCode"
    
    override func viewDidLoad() {
        super.viewDidLoad()
                
        //-------
        
        guard let scriptPath = Bundle.main.path(forResource: "script", ofType: "js"),
              let scriptSource = try? String(contentsOfFile: scriptPath) else { return }

        let userScript = WKUserScript(source: scriptSource, injectionTime: .atDocumentEnd, forMainFrameOnly: true)

        let config = WKWebViewConfiguration()

        let userContentController = WKUserContentController()
        userContentController.addUserScript(userScript)
        
        // REQUIRES IOS14
        if #available(iOS 14, *){
            userContentController.addScriptMessageHandler(self, contentWorld: .page, name: JavaScriptAPIObjectName)
        }

        config.userContentController = userContentController
        
        webView = WKWebView(frame: .zero, configuration: config)
                
        if let webView = webView{
            view.addSubview(webView)
            webView.autoPinEdgesToSuperviewMargins() // using PureLayout for easy AutoLayout syntax

            if let htmlPath = Bundle.main.url(forResource: "page", withExtension: "html"){
                webView.loadFileURL( htmlPath, allowingReadAccessTo: htmlPath);
            }
        }
    }

    // need to deinit and remove webview stuff
    deinit {
        if let webView = webView{
            let ucc = webView.configuration.userContentController
            ucc.removeAllUserScripts()
            ucc.removeScriptMessageHandler(forName:JavaScriptAPIObjectName)
        }
    }
}

extension ViewController: WKScriptMessageHandlerWithReply {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage, replyHandler: @escaping (Any?, String?) -> Void) {
        if message.name == JavaScriptAPIObjectName, let messageBody = message.body as? String {
            print(messageBody)
            replyHandler( 2.2, nil ) // first var is success return val, second is err string if error
        }
    }
}

Это script.js, загруженный с помощью этого кода Swift и внедренный на веб-страницу:

function sampleMethodTheHTMLCanCall( inputInfo, successFunc, errorFunc ) {
    
    var promise = window.webkit.messageHandlers.namespaceWithinTheInjectedJSCode.postMessage( inputInfo );
    
    promise.then(
      function(result) {
        console.info(result); // "Stuff worked!"
        successFunc( result )
      },
      function(err) {
        console.info(err); // Error: "It broke"
        errorFunc( err )
      });
}

А вот пример HTML page.html, который может вызывать код приложения:

<html>
    <meta name = "viewport" content = "width=device-width" />
        <script>
            function handleInfoFromApp( fromApp ){
                document.getElementById("valToWrite").innerHTML = fromApp;
            }
            function handleError( err ){
            
            }
        </script>

    <h1 id = "valToWrite">Hello</h1>
    <button onclick = "sampleMethodTheHTMLCanCall( 'inputInfo', handleInfoFromApp, handleError )">Load Info from App</button>
    
</html>

В приведенном выше HTML-коде представлены функции, которые впоследствии будут вызываться кодом расширения приложения при успешном или неудачном выполнении запроса, инициированного javascript.

Этот ответ должен быть принят, на мой взгляд. Большое спасибо!!!!!

biomiker 17.02.2021 18:42

Эй, @Jason, я знаю, что это взрыв из прошлого, но мне интересно, не могли бы вы объяснить, почему вы добавили удаление скрипта в функцию deinit. Мне интересно, почему это должно произойти. Спасибо!

Xeaza 07.04.2023 17:49

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