Webkit callAsyncJavaScript 不等待 SwiftUI 中的异步等待函数调用

问题描述 投票:0回答:1

我在 SwiftUI 中使用 WebKit 来更新我的 indexedDB,但由于某种原因,webkit 模块的 callAsyncJavaScript 函数没有等待等待响应,有人可以帮忙吗?我应该实施哪些更改或方法才能实现此任务的正确功能?我是 SwiftUI 新手,想要访问 indexedDB。

这里是示例代码供参考。

swiftcode.swift -

import SwiftUI
import WebKit

struct IndexedDBView: UIViewRepresentable {
    var jsCode: String

    class Coordinator: NSObject, WKNavigationDelegate {
        var webView: WKWebView?
        var jsCode: String

        init(jsCode: String) {
            self.jsCode = jsCode
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            self.webView = webView
            webView.callAsyncJavaScript(jsCode, in: nil, in: .page) { result in
                switch result {
                case let .failure(error):
                    debugPrint("failure \(error)")
                case let .success(result):
                    print(result)
                }
            }
        }
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(jsCode: jsCode)
    }

    func makeUIView(context: Context) -> WKWebView {
        let webViewConfiguration = WKWebViewConfiguration()
        let webView = WKWebView(frame: .zero, configuration: webViewConfiguration)
        webView.navigationDelegate = context.coordinator
        return webView
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        if let htmlPath = Bundle.main.path(forResource: "abcd", ofType: "html") {
            let htmlURL = URL(fileURLWithPath: htmlPath)
            uiView.loadFileURL(htmlURL, allowingReadAccessTo: htmlURL)
        }
    }
}

abcd.html -

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/crypto-js.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/idb@8/build/umd.js"></script>
    <script src="yourScript.js"></script>
    <script src="sample.js"></script>
</head>
<body>
    <div id="updateMe">Initial content</div>
</body>
</html>

sample.js -

const getKeyForEncryptAndDecrypt = (userId) => {
    if (userId) {
        let first = '';
        let second = '';
        for (let index = 0; index < userId.length; index += 2) {
          first += userId[index];
          second = userId[index + 1] + second;
        }
        const key = first + second;
        return key;
      }
      return '';
};

    const handleSetPassAndTicketWithDB = async () => {
        var decryptkey = getKeyForEncryptAndDecrypt('9953425561');
        var myIndexDB = IndexDB(objectStoreKeys.myPassHistory);
        let pass = await myIndexDB.get('twqwa', decryptkey);
        var divElement = document.getElementById('updateMe');
        if (divElement) {
            divElement.innerHTML = 'IndexedDB updated with key: ' + JSON.stringify(pass);
        }
        return pass;
    };

这是我在 swiftui 代码中调用 IndexedDBView 的方式 -

IndexedDBView(jsCode: "handleSetPassAndTicketWithDB();")

在屏幕上,我显示为“未定义”。

IndexDB 函数包含一个异步等待函数的对象,并写入 yourscript.js 文件中。

javascript ios swift webkit indexeddb
1个回答
0
投票
  • handleSetPassAndTicketWithDB 函数在sample.js 文件中定义,该文件在abcd.html 文件中加载。但是,当您使用 webView.callAsyncJavaScript(jsCode, in: nil, in: .page) 从 SwiftUI 调用此函数时,找不到该函数,因为它不在全局范围内。

  • 要解决此问题,您需要将handleSetPassAndTicketWithDB函数设置为全局函数。您可以通过将函数附加到 example.js 文件中的 window 对象来完成此操作。

    window.handleSetPassAndTicketWithDB = async () => {
      var decryptkey = getKeyForEncryptAndDecrypt('9953425561');
      var myIndexDB = IndexDB(objectStoreKeys.myPassHistory);
      let pass = await myIndexDB.get('twqwa', decryptkey);
      var divElement = document.getElementById('updateMe');
      if (divElement) {
         divElement.innerHTML = 'IndexedDB updated with key: ' + JSON.stringify(pass);
      }
      return pass;
    };
    
  • 您的sample.js 文件中未定义IndexDB 函数。使用前需要先定义它。

    window.IndexDB = async (objectStoreKey) => {
      const dbName = 'myDatabase';
      const dbVersion = 1;
      const dbRequest = indexedDB.open(dbName, dbVersion);
    
      dbRequest.onupgradeneeded = (event) => {
          const db = event.target.result;
          if (!db.objectStoreNames.contains(objectStoreKey)) {
              db.createObjectStore(objectStoreKey);
          }
      };
    
      const db = await dbRequest;
    
      return {
          get: async (key, decryptkey) => {
              const transaction = db.transaction(objectStoreKey, 'readonly');
              const objectStore = transaction.objectStore(objectStoreKey);
              const request = objectStore.get(key);
              const result = await request;
              if (result) {
                  const decrypted = CryptoJS.AES.decrypt(result, decryptkey);
                  return decrypted.toString(CryptoJS.enc.Utf8);
              }
              return null;
          },
      };
    };
    
© www.soinside.com 2019 - 2024. All rights reserved.