我在 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 文件中。
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;
},
};
};