首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Wkwebview更改ObservedObject值

用Wkwebview更改ObservedObject值
EN

Stack Overflow用户
提问于 2022-05-26 02:56:58
回答 2查看 310关注 0票数 1

我正在使用WkWebView作为我的应用程序。在加载视图时,我希望以本地方式显示得分,而不是在WkWebView中显示。我使用combine框架工作来创建一个ObservableObject,以便当分数在WkWebview中发生变化时,将我的分数显示给视图和其他视图。我使用window.onload获取最近的得分,并在页面第一次呈现时显示它。为此,我调用一个JS函数,该函数向带有score的本地webkit.messageHandlers.bridge.postMessage("0")发送一条消息,并将发送的分数分配给我的ObservedObject。问题在土著一方。UserContentController函数处理来自WkWebview的消息,它不断打印分数并将分数重新分配给my ObservedObject。好像被困在了一个循环里。我提供了下面代码的简化版本。已经被困在这个问题上几天了,似乎无法解决这个问题。

代码语言:javascript
复制
 //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的一面:

代码语言:javascript
复制
<!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>

编辑2:这就是控制台输出的内容。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-05-26 04:17:03

在这里,我看到通过更新Myscore来加载循环,这会导致updateUIView调用等等。

初始加载应放在makeUIView

代码语言:javascript
复制
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

    // make here initial loading !!!
    guard let path: String = Bundle.main.path(forResource: "index", ofType: "html") 
 else { return _wkwebview }

    let localHTMLUrl = URL(fileURLWithPath: path, isDirectory: false)
    _wkwebview.loadFileURL(localHTMLUrl, allowingReadAccessTo: localHTMLUrl)

    
    return _wkwebview
}

  func updateUIView(_ webView: WKWebView, context: Context) {
     // reload should be made here only if base url changed
     // externally
   }

用Xcode 13.4 / iOS 15.5测试

票数 2
EN

Stack Overflow用户

发布于 2022-05-26 12:46:01

score应该是@Binding,当它发生变化时会自动调用updateUIView。不幸的是,这是SwiftUI结构中许多无文档化的魔术行为之一。

FYI ObservableObject被设计为将组合管道分配给@Published。尝试并坚持数据的结构,并使用@State@Binding使您的值类型具有引用类型语义。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72386187

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档