【问题标题】:How do I get the selected text from a WKWebView from objective-C如何从 Objective-C 的 WKWebView 中获取选定的文本
【发布时间】:2018-11-23 13:51:08
【问题描述】:

我有一个 WKWebView。

当用户右键单击它时,我可以在我的 Objective-C 方法中自定义一个上下文菜单。只有当用户在 WKWebView 中选择了一些文本时,我才想添加一个菜单项。当然,我稍后需要检索选定的文本来处理它。

如何从 Objective-c 的 WKWebView 中检索选择,确保它只是文本并获取该文本?

谢谢

【问题讨论】:

    标签: macos cocoa webkit


    【解决方案1】:

    这是我设法做到这一点的方法。不是一个完美的解决方案,但已经足够好了。

    一般说明

    似乎在 WKWebView 中发生的任何事情都必须在 Javascript 中进行管理。 Apple 提供了一个框架,用于在 Javascript 世界和 Objective-C(或 Swift)世界之间交换信息。该框架基于一些从 Javascript 世界发送并通过可安装在 WKWebView 中的消息处理程序在 Objective-C(或 Swift)世界中捕获的消息。

    第一步 - 安装消息处理程序

    在 Objective-C(或 Swift)世界中,定义一个负责接收来自 Javascript 世界的消息的对象。我为此使用了我的视图控制器。下面的代码将视图控制器安装为“用户内容控制器”,它将接收可以从 Javascipts 发送的名为“newSelectionDetected”的事件

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        //  Add self as scriptMessageHandler of the webView
        WKUserContentController *controller = self.webView.configuration.userContentController ;
        [controller addScriptMessageHandler:self
                                       name:@"newSelectionDetected"] ;
        ... the rest will come further down...
    

    第二步 - 在视图中安装 Javascript

    此 Javascript 将检测选择更改,并通过名为“newSelectionDetected”的消息发送新选择

    - (void)    viewDidLoad
    {
        ...See first part up there...
    
        NSURL       *scriptURL      = .. URL to file DetectSelection.js...
        NSString    *scriptString   = [NSString stringWithContentsOfURL:scriptURL
                                                               encoding:NSUTF8StringEncoding
                                                                  error:NULL] ;
    
        WKUserScript    *script = [[WKUserScript alloc] initWithSource:scriptString
                                                         injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
                                                      forMainFrameOnly:YES] ;
        [controller addUserScript:script] ;
    }
    

    和 Javascript :

    function getSelectionAndSendMessage()
    {
        var txt = document.getSelection().toString() ;
        window.webkit.messageHandlers.newSelectionDetected.postMessage(txt) ;
    }
    document.onmouseup = getSelectionAndSendMessage ;
    document.onkeyup   = getSelectionAndSendMessage ;
    document.oncontextmenu  = getSelectionAndSendMessage ;
    

    第三步 - 接收和处理事件

    现在,每当我们在 WKWebView 中按下鼠标或按键时,选择(可能为空)将被捕获并通过消息发送到 Objective-C 世界。

    我们只需要视图控制器中的处理程序来处理该消息

    - (void)    userContentController:(WKUserContentController*)userContentController
              didReceiveScriptMessage:(WKScriptMessage*)message
    {
        // A new selected text has been received
        if ([message.body isKindOfClass:[NSString class]])
        {
            ...Do whatever you want with message.body which is an NSString...
        }
    }
    

    我创建了一个继承自 WKWebView 的类,并且有一个 NSString 属性“selectedText”。所以我在这个处理程序中所做的就是将接收到的 NSString 存储在这个属性中。

    第四步 - 更新上下文菜单

    在我的 WKWebView 子类中,如果 selectedText 不为空,我只需重写 willOpenMenu:WithEvent: 方法以添加菜单项。

    - (void)    willOpenMenu:(NSMenu*)menu withEvent:(NSEvent*)event
    {
        if ([self.selectedText length]>0)
        {
            NSMenuItem  *item   = [[NSMenuItem alloc] initWithTitle:@"That works !!!"
                                                             action:@selector(myAction:)
                                                      keyEquivalent:@""] ;
            item.target = self ;
            [menu addItem:item] ;
        }
    }
    
    - (IBAction)    myAction:(id)sender
    {
        NSLog(@"tadaaaa !!!") ;
    }
    

    现在为什么不理想?好吧,如果您的网页已经设置了 onmouseup 或 onkeyup,我会覆盖它。

    但正如我所说,对我来说已经足够了。

    编辑:我在 javascript 中添加了 document.oncontextmenu 行,解决了我有时遇到的奇怪选择行为。

    【讨论】:

    • 我需要这样做,但我似乎无法在我的处理程序中获取文本;它是零。您能否详细说明您的 selectedText 属性是如何设置的,因为我怀疑在调用处理程序时它已经消失了?
    • @slashlos,好吧,在处理程序中(userContentController:didReceiveScriptMessage,我只是设置了视图的一个属性,在其头文件中声明为强,因此只要视图本身存在,它就会存在。当 willOpenMenu:withEvent 被调用时,该属性仍然存在。
    • @slashlos,如果您的消息中出现 nil 正文,则可能表明您的 Javascript 中有问题。是否调用了 userContentController:didReceiveScriptMessage 处理程序?你检查过消息和正文了吗?
    • 我在我的设置中发现了我的问题。我将发布我的问题 - 以您的出色工作作为开始,我需要什么,谢谢!
    【解决方案2】:

    Swift 5 翻译

    webView.configuration.userContentController.add(self, name: "newSelectionDetected")
    let scriptString = """
        function getSelectionAndSendMessage()
        {
            var txt = document.getSelection().toString() ;
            window.webkit.messageHandlers.newSelectionDetected.postMessage(txt);
        }
        document.onmouseup = getSelectionAndSendMessage;
        document.onkeyup = getSelectionAndSendMessage;
        document.oncontextmenu = getSelectionAndSendMessage;
    """
    let script = WKUserScript(source: scriptString, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
    webView.configuration.userContentController.addUserScript(script)
    
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        // Use message.body here
    }
    

    【讨论】:

      【解决方案3】:

      只需要评估简单的js脚本

      NSString *script = @"window.getSelection().toString()";
      

      使用evaluateJavaScript方法

      [wkWebView evaluateJavaScript:script completionHandler:^(NSString *selectedString, NSError *error) {
          
      }];
      

      Swift 版本

      let script = "window.getSelection().toString()"
      wkWebView.evaluateJavaScript(script) { selectedString, error in
              
      }
      

      【讨论】:

        猜你喜欢
        • 2017-06-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-01
        • 1970-01-01
        相关资源
        最近更新 更多