美文网首页iOS常用
iOS WKWebView 长按保存图片

iOS WKWebView 长按保存图片

作者: 跳跳跳跳跳跳跳 | 来源:发表于2020-11-03 16:25 被阅读0次

试过给WKWebView添加长按手势,然后再通过转换坐标在web内获取图片资源,失败了,转换出来的坐标有误差,无法得到正确的图片。
然后就试了以下的方法:
原理大概就是注入JS的touch事件,然后在touch事件中捕获坐标回传给OC,在OC中判定是否为长按事件,如果是,则通过回传的JS坐标调用JS中的elementFromPoint获取图片url,最后根据个人的需求做相应的操作。

//注入触摸事件
//新增时间判定,如果end与start事件间隔大于0.7则阻止后续touch事件传递
- (void)injectionJS{
    NSString *js = @"\
    var startTimestamp = 0;\
    var endTimestamp = 0;\
    document.ontouchstart=function(event){\
    startTimestamp = Date.parse(new Date());\
    x=event.targetTouches[0].clientX;\
    y=event.targetTouches[0].clientY;\
    window.webkit.messageHandlers.TheData.postMessage('thewebview:touch:start:\'+x+\':\'+y);\
    };\
    document.ontouchmove=function(event){\
    x=event.targetTouches[0].clientX;\
    y=event.targetTouches[0].clientY;\
    window.webkit.messageHandlers.TheData.postMessage('thewebview:touch:move:\'+x+\':\'+y);\
    };\
    document.ontouchcancel=function(event){\
    window.webkit.messageHandlers.TheData.postMessage('thewebview:touch:cancel');\
    ;};\
    document.ontouchend=function(event){\
    endTimestamp = Date.parse(new Date());\
    if (endTimestamp - startTimestamp > 0.7) {\
    event.preventDefault();\
    }\
    window.webkit.messageHandlers.TheData.postMessage('thewebview:touch:end');\
    };";
    [self.wkWebView evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) {
        
    }];
}

在web加载完成之后调用injectionJS,注入代码

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    [self injectionJS];
}

到这里JS代码算注入完成了,接下来处理JS的回调:

先申明三个属性

@property (nonatomic,strong) WKWebView *wkWebView;
@property (nonatomic, strong) CXWebViewScriptHandler *scriptHandler;
@property (nonatomic, strong)NSArray *components;

然后在viewDidLoad中初始化这三个属性:

self.scriptHandler = [CXWebViewScriptHandler new];
CX_WS(self);
self.scriptHandler.scriptCallback = ^(WKUserContentController *userContentController, WKScriptMessage *scriptMessage) {
            [weakself receiveScriptMessage:scriptMessage userContentController:userContentController];
};
        
WKWebViewConfiguration *configuration =[[WKWebViewConfiguration alloc] init];
self.wkWebView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];  
self.wkWebView.backgroundColor = [UIColor whiteColor];
self.wkWebView.navigationDelegate = self;
[[self.wkWebView configuration].userContentController addScriptMessageHandler:self.scriptHandler name:@"TheData"];
self.wkWebView.UIDelegate = self;
//禁止3Dtouch事件
self.wkWebView.allowsLinkPreview = NO;
[self.view addSubview:self.wkWebView];
[self.wkWebView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.progress.mas_bottom);
        make.left.right.equalTo(self.view);
        if (@available(iOS 11.0, *)) {
                make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom).offset(-h);
            } else {
                make.bottom.equalTo(self.view.mas_bottomMargin).offset(-h);
        }
 }];
- (void)receiveScriptMessage:(WKScriptMessage *)message userContentController:(WKUserContentController *)userContentController {
   if ([message.name isEqualToString:@"TheData"]) {
        [self handleJSEvent:message.body];
    }
}
///js执行代码
- (void)handleJSEvent:(NSString *)str{
    _components = nil;
    _components = [str componentsSeparatedByString:@":"];
    if ([_components count] > 1 && [(NSString *)[_components objectAtIndex:0]
                                   isEqualToString:@"thewebview"]) {
        if([(NSString *)[_components objectAtIndex:1] isEqualToString:@"touch"]) {
            if ([(NSString *)[_components objectAtIndex:2] isEqualToString:@"start"]) {
                //长按
                [self performSelector:@selector(handleLongPress) withObject:nil afterDelay:0.7];
                NSLog(@"start");
            }else if ([(NSString *)[_components objectAtIndex:2] isEqualToString:@"move"]) {
                [NSObject cancelPreviousPerformRequestsWithTarget:self];
            }else if ([(NSString*)[_components objectAtIndex:2] isEqualToString:@"cancel"]) {
                [NSObject cancelPreviousPerformRequestsWithTarget:self];
            }else if ([(NSString*)[_components objectAtIndex:2] isEqualToString:@"end"]) {
                [NSObject cancelPreviousPerformRequestsWithTarget:self];
                NSLog(@"end");
            }
        }
    }
}
- (void)handleLongPress {
    if (_components.count == 3) {
        return;
    }
    float ptX = [[_components objectAtIndex:3] floatValue];
    float ptY = [[_components objectAtIndex:4] floatValue];
    [self.wkWebView evaluateJavaScript:[NSString stringWithFormat:@"document.elementFromPoint(%f, %f).tagName", ptX, ptY] completionHandler:^(id _Nullable response, NSError * _Nullable error) {
        NSString * tagName = response;
        NSLog(@"tagName %@", tagName);
        if ([tagName isEqualToString:@"IMG"]) {
            [self.wkWebView evaluateJavaScript:[NSString stringWithFormat:@"document.elementFromPoint(%f, %f).src", ptX, ptY] completionHandler:^(id _Nullable response, NSError * _Nullable error) {
                NSString * imgURL = response;
                if (imgURL == nil || imgURL.length == 0) {
                    return;
                }
                NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:imgURL]];
                UIImage *image = [UIImage imageWithData:data];
                if (!image) {
                    return;
                }
                //拿到图片后自行做相应的处理
                NSArray *handles = @[];
                NSString *qrCode = [image detecteQRCode];
                if (qrCode) {
                    handles = @[NSLocalizedString(@"recognizeQRCode", nil), NSLocalizedString(@"saveToAlbum", nil)];
                }else {
                    handles = @[NSLocalizedString(@"saveToAlbum", nil)];
                }
                [XCAlertView AlertViewWithTitle:nil message:nil cancelTitle:nil acitons:handles style:XCAlertStyle_Sheet inView:self itemblock:^(NSInteger itemIndex) {
                    if (itemIndex == 0) {
                        //拥有识别与保存两个选项
                        if (handles.count == 2) {
                            WebViewController *vc = [[WebViewController alloc] initWithUrlStr:qrCode withLocalFile:nil withTitle:nil withFunction:YES];
                            [self.navigationController pushViewController:vc animated:YES];
                        }else {
                            UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
                        }
                    }else if (itemIndex == 1) {
                        if (handles.count == 2) {
                            UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
                        }else {

                        }
                    }
                }];
            }];
        }
    }];
}

关于CXWebViewScriptHandler类,只是用来解决循环引用的问题

@interface CXWebViewScriptHandler : NSObject
@property (nonatomic, copy) void(^scriptCallback)(WKUserContentController *userContentController, WKScriptMessage *scriptMessage);
@end

@implementation CXWebViewScriptHandler
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
    if (self.scriptCallback) {
        self.scriptCallback(userContentController, message);
    }
}
@end

相关文章

网友评论

    本文标题:iOS WKWebView 长按保存图片

    本文链接:https://www.haomeiwen.com/subject/ibqjektx.html