Air*_*ène 6 macos cocoa webkit
我有一个 WKWebView。
当用户右键单击它时,我可以在我的 Objective-c 方法中自定义上下文菜单。只有当用户在 WKWebView 中选择了一些文本时,我才想添加一个菜单项。当然,我稍后需要检索选定的文本来处理它。
如何从objective-c的WKWebView中检索选择,确保它只是文本并获取该文本?
谢谢
这是我如何做到这一点的。不是一个完美的解决方案,但足够好。
一般说明
似乎 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...
Run Code Online (Sandbox Code Playgroud)
第二步 - 在视图中安装 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] ;
}
Run Code Online (Sandbox Code Playgroud)
和 Javascript :
function getSelectionAndSendMessage()
{
var txt = document.getSelection().toString() ;
window.webkit.messageHandlers.newSelectionDetected.postMessage(txt) ;
}
document.onmouseup = getSelectionAndSendMessage ;
document.onkeyup = getSelectionAndSendMessage ;
document.oncontextmenu = getSelectionAndSendMessage ;
Run Code Online (Sandbox Code Playgroud)
第三步——接收和处理事件
现在,每当我们在 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...
}
}
Run Code Online (Sandbox Code Playgroud)
我创建了一个继承自 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 !!!") ;
}
Run Code Online (Sandbox Code Playgroud)
现在为什么不理想?好吧,如果您的网页已经设置了 onmouseup 或 onkeyup,我会覆盖它。
但正如我所说,对我来说已经足够了。
编辑:我在 javascript 中添加了 document.oncontextmenu 行,解决了我有时遇到的奇怪选择行为。
斯威夫特 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)
Run Code Online (Sandbox Code Playgroud)
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
// Use message.body here
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2667 次 |
| 最近记录: |