使用wkwebview更改观察值
我正在为我的应用使用wkwebview
。加载视图时,我想在本机上显示得分,而不是在wkwebview
中显示。我使用组合
框架工作来创建observableObject
,以便在wkwebview
中的分数更改时将我的分数显示给视图和其他视图。 。我使用window。我这样做是通过调用JS函数,该函数将消息发送到本机side
,并将已发送的分数分配给我的webkit.messagehandlers.bridge.postmessage(“ 0”)
obseved> obsevedObject < /代码>。问题在本地。
USERCONTENTCONTROLLER
函数,从wkwebview
中处理消息,不断打印出分数并将分数重新分配给我的obsevedObject
。它似乎被困在一个循环中。我提供了以下代码的简化版本。已经被困了几天了,似乎无法解决问题。
//Holds the score
class Myscore:ObservableObject{
@Published var score = "0"
}
//Wkwebview
struct WebView: UIViewRepresentable {
@ObservedObject var myScore : Myscore
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
var webView: WKWebView?
var myScore: Myscore
init(myScore:Myscore) {
self.myScore = myScore
super.init()
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.webView = webView
}
// receive message from wkwebview
func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
// This is where the issue occurs
var newscore = message.body as! String
myScore.score = newscore
print(myScore.score)
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(myScore:myScore)
}
func makeUIView(context: Context) -> WKWebView {
let coordinator = makeCoordinator()
let userContentController = WKUserContentController()
userContentController.add(coordinator, name: "bridge")
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
let _wkwebview = WKWebView(frame: .zero, configuration: configuration)
_wkwebview.navigationDelegate = coordinator
return _wkwebview
}
func updateUIView(_ webView: WKWebView, context: Context) {
guard let path: String = Bundle.main.path(forResource: "index", ofType: "html")
else { return }
let localHTMLUrl = URL(fileURLWithPath: path, isDirectory: false)
webView.loadFileURL(localHTMLUrl, allowingReadAccessTo: localHTMLUrl)
}
}
//Content View to display the Score
struct ContentView: View {
@StateObject var myScore = Myscore()
var body: some View {
VStack {
Text("Your Score is\( myScore.score)")
WebView(myScore: myScore)
}
}
}
在这里编辑是HTML侧:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, minimum-scale=1, viewport-fit=cover">
</head>
<body>
<button>click me</button>
<hr/>
<div id="log"></div>
<script>
window.onload = function () {
webkit.messageHandlers.bridge.postMessage("98 points")
}
</script>
</body>
</html>
I am using WkWebView
for my app. When the view is loaded I would like to display the score Natively and not in the WkWebView
. I used the combine
Frame work to create an ObservableObject
in order to display my score to the view and other views when the score changes in the WkWebview
. I use window.onload
to get the most recent score and display it when the page first renders. I do so by calling a JS function which sends a message to the Native side webkit.messageHandlers.bridge.postMessage("0")
with the score and assign the sent score to my ObservedObject
. The issue is on the Native side. The UserContentController
function, which handles the message from the WkWebview
, keeps printing out the score and reassigning the score to my ObservedObject
. It seems to be stuck in a loop. I provided a simplified version of the code below. Have been stuck on this for a few days now and cant seem to fix the issue.
//Holds the score
class Myscore:ObservableObject{
@Published var score = "0"
}
//Wkwebview
struct WebView: UIViewRepresentable {
@ObservedObject var myScore : Myscore
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
var webView: WKWebView?
var myScore: Myscore
init(myScore:Myscore) {
self.myScore = myScore
super.init()
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.webView = webView
}
// receive message from wkwebview
func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
// This is where the issue occurs
var newscore = message.body as! String
myScore.score = newscore
print(myScore.score)
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(myScore:myScore)
}
func makeUIView(context: Context) -> WKWebView {
let coordinator = makeCoordinator()
let userContentController = WKUserContentController()
userContentController.add(coordinator, name: "bridge")
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
let _wkwebview = WKWebView(frame: .zero, configuration: configuration)
_wkwebview.navigationDelegate = coordinator
return _wkwebview
}
func updateUIView(_ webView: WKWebView, context: Context) {
guard let path: String = Bundle.main.path(forResource: "index", ofType: "html")
else { return }
let localHTMLUrl = URL(fileURLWithPath: path, isDirectory: false)
webView.loadFileURL(localHTMLUrl, allowingReadAccessTo: localHTMLUrl)
}
}
//Content View to display the Score
struct ContentView: View {
@StateObject var myScore = Myscore()
var body: some View {
VStack {
Text("Your Score is\( myScore.score)")
WebView(myScore: myScore)
}
}
}
Edit here is the html side:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, minimum-scale=1, viewport-fit=cover">
</head>
<body>
<button>click me</button>
<hr/>
<div id="log"></div>
<script>
window.onload = function () {
webkit.messageHandlers.bridge.postMessage("98 points")
}
</script>
</body>
</html>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
等等来查看周期加载。
在这里,我可以
通过更新
myScore
进行updateUiview
调用 13.4 / iOS 15.5Here I see cycle loading by updating
Myscore
which result inupdateUIView
call and so forth...Initial loading should be placed into
makeUIView
Tested with Xcode 13.4 / iOS 15.5
得分
应为@binding
和updateUiview
将在更改时自动调用。不幸的是,这是Swiftui结构的众多无证件魔术行为之一。FYI
observableObject
旨在将组合管道分配给@published
。尝试坚持数据的结构,并使用@State
和@binding
以使您的值类型具有参考类型语义。score
should be@Binding
andupdateUIView
will be called automatically when it changes. Unfortunately this is one of the many undocumented magic behaviours of SwiftUI's structs.FYI
ObservableObject
is designed to assign a Combine pipeline to an@Published
. Try and stick to structs for your data and use@State
and@Binding
to make your value types have reference type semantics.