试过给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
网友评论