如何从 objective-C 的 WKWebView 获取所选文本



我有一个WKWebView。

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

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

谢谢

这是我如何做到这一点的。不是一个完美的解决方案,但足够好。

一般解释

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

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

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

- (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 将检测选择更改,并通过名为"newSelectionDetection"的消息发送新选择

- (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的女儿类中,我只是覆盖了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行,这解决了我有时遇到的奇怪的选择行为。

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
}

只需要计算简单的js脚本

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

使用evaluateJavaScript方法

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

}];

斯威夫特版本

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

}

最新更新