Javascript WKWebView自定义长按菜单工作正常,但存在一些主要问题
当用户长按链接时,警报控制器将显示以下选项:Javascript WKWebView自定义长按菜单工作正常,但存在一些主要问题,javascript,ios,objective-c,wkwebview,Javascript,Ios,Objective C,Wkwebview,当用户长按链接时,警报控制器将显示以下选项: 打开 在新选项卡中打开 抄袭 目前存在两个问题: 如果用户在WKWebView完成导航之前长按,则会显示默认(Safari)警报控制器 如果用户在弹出动画以某种方式出现后抬起手指,WKWebView会将其注册为点击,并在屏幕上仍显示警报控制器时导航到该链接 这一机制分为三个部分 首先, WKWebView完成导航后,将向页面注入javascript,以禁用默认警报控制器 - (void)webView:(WKWebView *)webView d
- 打开
- 在新选项卡中打开
- 抄袭
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
[_webView evaluateJavaScript:@"document.body.style.webkitTouchCallout='none';"
completionHandler:^(id result, NSError *error){
NSLog(@"Javascript: {%@, %@}", result, error.description);
}];
}
第二,
将UILongPressGestureRecognitor添加到WKWebView并实现,以便它根据触摸的位置查找元素的属性
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (void)longPress:(UILongPressGestureRecognizer *)longPressGestureRecognizer
{
if (longPressGestureRecognizer.state == UIGestureRecognizerStateBegan) {
_shouldCancelNavigation = YES;
CGPoint touchLocation = [longPressGestureRecognizer locationInView:_webView];
NSString *javascript = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Javascript" ofType:@"js"]
encoding:NSUTF8StringEncoding
error:nil];
[_webView evaluateJavaScript:javascript
completionHandler:^(id result, NSError *error){
NSLog(@"Javascript: {%@, %@}", result, error.description);
}];
[_webView evaluateJavaScript:[NSString stringWithFormat:@"MyAppGetHTMLElementsAtPoint(%f,%f);", touchLocation.x, touchLocation.y]
completionHandler:^(id result, NSError *error){
NSLog(@"Javascript: {%@, %@}", result, error.description);
NSString *tags = (NSString *)result;
if ([tags containsString:@",A,"]) {
[_webView evaluateJavaScript:[NSString stringWithFormat:@"MyAppGetHREFAttributeAtPoint(%f,%f);", touchLocation.x, touchLocation.y]
completionHandler:^(id result, NSError *error){
NSLog(@"Javascript: {%@, %@}", result, error.description);
NSString *urlString = (NSString *)result;
[_delegate webView:self didLongPressAtTouchLocation:touchLocation URL:[NSURL URLWithString:urlString]];
}];
return;
}
if ([tags containsString:@",IMG,"]) {
[_webView evaluateJavaScript:[NSString stringWithFormat:@"MyAppGetSRCAttributeAtPoint(%f,%f);", touchLocation.x, touchLocation.y]
completionHandler:^(id result, NSError *error){
NSLog(@"Javascript: {%@, %@}", result, error.description);
NSString *urlString = (NSString *)result;
[_delegate webView:self didLongPressAtTouchLocation:touchLocation imageWithSourceURL:[NSURL URLWithString:urlString]];
}];
return;
}
}];
}
}
最后,
表示警报控制器的委托方法在主ViewController上实现
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
[_webView evaluateJavaScript:@"document.body.style.webkitTouchCallout='none';"
completionHandler:^(id result, NSError *error){
NSLog(@"Javascript: {%@, %@}", result, error.description);
}];
}
我对第二个问题的解决方案是添加一个布尔值shouldCancelNavigation,该值在显示警报控制器时为YES,在解除警报控制器时为NO
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
if (_shouldCancelNavigation) {
decisionHandler(WKNavigationActionPolicyCancel);
}
else {
decisionHandler(WKNavigationActionPolicyAllow);
}
}
有趣的是,网上有很多链接不需要决策的例子。他们只是发生了,我没有办法阻止他们
例如:
资料来源:
资料来源2:
编辑:
这解决了第二个问题,但我不确定它是否会在其他地方损坏某些东西
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if ([otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
otherGestureRecognizer.enabled = NO;
otherGestureRecognizer.enabled = YES;
}
return YES;
}
编辑2:
它确实造成了一个问题。。。您不能再选择文本,因为上面的代码会重置内部长按手势识别器
编辑3:
如果我完全删除我的实现(全部3个步骤),并让默认警报控制器在每次我长按链接时启动,第二个问题就会得到解决
苹果的alert控制器有一点在你抬起手指后会阻止WKWebView导航。如果我没说错的话,在第二部分:
- (void)longPress:(UILongPressGestureRecognizer *)longPressGestureRecognizer
{
if (longPressGestureRecognizer.state == UIGestureRecognizerStateBegan) {
//Rest of your code ...
}
}
您正在注入javascript以禁用系统对话框。现在,在新闻结束后,WKWebview已经收到从web链接触发的事件。既然为时已晚,为什么不尝试检查LongPressGestureRecognitzer的条件。状态
等于UIGestureRecognitzerStateEnded
因此它改为下面的代码
if (longPressGestureRecognizer.state == UIGestureRecognizerStateEnded) {
//Rest of your code ...
}
我还没有测试这段代码。如果它能工作,我会更高兴。这个答案可以解决第二个问题,但我不确定它对App Store是否安全。 首先,您需要断开内部长按手势识别器,以便在用户抬起手指时它们不会触发
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if ([otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
if (otherGestureRecognizer.state == UIGestureRecognizerStateBegan) {
// Warning: This will break how WKWebView handles selection of text.
[otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer];
}
}
return YES;
}
用户完成与自定义长按菜单的交互后,此代码将修复损坏的WKWebView:
[_webView removeGestureRecognizer:_longPressGestureRecognizer]; // This code will remove the dependency and recover the lost functionality.
_longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
_longPressGestureRecognizer.numberOfTouchesRequired = 1;
_longPressGestureRecognizer.delegate = self;
[_webView addGestureRecognizer:_longPressGestureRecognizer];
这就是一种黑客行为。我在页面加载完成时注入javascript以禁用系统对话框,而不是在手势识别器阶段开始时。而且,这是问题的第一部分。