webview给前端页面传递数据_使用WebViewJavascriptBridge实现与UIWebView的深度交互

本文介绍了如何使用WebViewJavascriptBridge在Objective-C项目中与UIWebView进行深度交互,包括设置HTML、注册方法、调用JS方法、处理图片点击和放大功能,详细阐述了每个步骤和关键代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在做的项目遇到这么一个需求:网络加载一段HTML格式的只有body部分的文本,自己本地拼写完整的HTML,图片需带点击放大浏览功能(移动端实现)。

分析需求之后发现难点在如何与UIWebview进行交互,在查阅资料后,找到http://kittenyang.com/webview-javascript-bridge

KittenYang大神完美解决了我的问题,但过程中还是出了不少问题,这里就写下按照大神的思路写的具体实现过程

这里主要用了WebViewJavascriptBridge,SDWebImage,YYPhotoGroup这三个第三方库。

WebViewJavascriptBridge使用简介

HTML文本的标签中间添加如下代码

function setupWebViewJavascriptBridge(callback) {

if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }

if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }

window.WVJBCallbacks = [callback];

var WVJBIframe = document.createElement('iframe');

WVJBIframe.style.display = 'none';

WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';

document.documentElement.appendChild(WVJBIframe);

setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)}

setupWebViewJavascriptBridge(function(bridge) {

//方法名,传递的参数,回调

bridge.callHandler('testObjcCallback', 'Hello world', function(response)){

};

//方法名,收到的参数,回调方法

bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {

var message = data['foo']

console.log(message)

})

在OC端需实现

@property(strong,nonatomic) WebViewJavascriptBridge* bridge;

_bridge = [WebViewJavascriptBridge bridgeForWebView:webView];

//注册方法

[_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {

NSLog(@"testObjcCallback called: %@", data);

responseCallback(@"Response from testObjcCallback");

}];

//调用JS的方法并传参

[_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];

完成上面的步骤后就可以实现与UIWebView的JS交互,但是要实现需求中所提到的功能还需要更深层次的交互,还需要一定的前端知识。

流程设计

e6a01c74f026

流程图

功能实现

HTML文本处理

//获取本地HTML路径

NSString* HTMLPath = [[NSBundle mainBundle] pathForResource:@"HTMLDemo" ofType:@"html"];

//获取HTML字符串

NSMutableString* HTMLString = [NSMutableString stringWithContentsOfFile:HTMLPath encoding:NSUTF8StringEncoding error:nil];

//设定需要替换的字符串

NSRange range = [HTMLString rangeOfString:@"

mainviews

"];

//将字符串中的src标签都替换掉,防止加载HTML的时候预加载图片

NSString *replace = [self.HTMLBoday stringByReplacingOccurrencesOfString:@"src=" withString:@"esrc="];

//将字符串替换调

[HTMLString replaceOccurrencesOfString:@"

mainviews

" withString:replace options:NSCaseInsensitiveSearch range:range];

//根据正则表达式查找img标签

NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(]+esrc=\")(\\S+)\"" options:0 error:nil];

//给img标签添加点击事件

NSString *finalHTMLString = [regex stringByReplacingMatchesInString:HTMLString options:0 range:NSMakeRange(0, HTMLString.length) withTemplate:@"

//加载HTML

[self.webView loadHTMLString:finalHTMLString baseURL:[NSURL fileURLWithPath:HTMLPath]];

获取所有img的src

JS端

bridge.registerHandler('getImageUrlsArray', function(data, responseCallback) {

//获取所有img标签

var allImage = document.querySelectorAll("img");

//Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组

allImage = Array.prototype.slice.call(allImage, 0);

var imageUrlsArray = new Array();

allImage.forEach(function(image) {

//将所有图片的URL存入新数组

var esrc = image.getAttribute("esrc");

var newLength = imageUrlsArray.push(esrc);

});

//将URL数组回传OC端

responseCallback({'data':imageUrlsArray})

})

OC端

[self.bridge callHandler:@"getImageUrlsArray" data:nil responseCallback:^(id responseData) {

//拿到img的所有url并开始下载

[self demo_downloadImages:responseData[@"data"]];

}];

下载图片

SDWebImageManager *manager = [SDWebImageManager sharedManager];

//假如没有截取图片则不执行方法

if (imageUrlArray.count == 0) {

return;

}

//预防数组越界处理

for (NSUInteger i = 0; i < imageUrlArray.count; i++) {

[self.downloadImageArray addObject:[NSNull null]];

}

for (NSUInteger i = 0; i < imageUrlArray.count; i++) {

NSString *_url = imageUrlArray[i];

//SDWebImage下载图片

[manager downloadImageWithURL:[NSURL URLWithString:_url] options:SDWebImageHighPriority progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {

if (image) {

//拿到存储的key

NSString *key = [manager cacheKeyForURL:imageURL];

//将url转换成string

NSString *old = [imageURL absoluteString];

//根据key拿到本地存储路径

NSString *localCachePath = [manager.imageCache defaultCachePathForKey:key];

[self.downloadImageArray removeObjectAtIndex:i];

[self.downloadImageArray insertObject:localCachePath atIndex:i];

//将本地缓存图片的地址传到webView

[self.bridge callHandler:@"imagesDownloadComplete" data:@{@"old":old,@"new":localCachePath} responseCallback:^(id responseData) {

}];

}

}]; }

JS端加载图片

bridge.registerHandler('imagesDownloadComplete',function(data) {

//解析数据,拿到原来的url和本地存储地址

var oldUrl = data['old']

var localCachePath = data['new']

imagesDownloadComplete(oldUrl,localCachePath)

})

var errorNum = 0

function imagesDownloadComplete(pOldUrl, localCachePath) {

//获取所以得img标签

var allImage = document.querySelectorAll("img");

allImage = Array.prototype.slice.call(allImage, 0);

allImage.forEach(function(image) {

if (image.getAttribute("esrc") == pOldUrl || image.getAttribute("esrc") == decodeURIComponent(pOldUrl)) {

//加载本地图片地址

image.src = localCachePath;

//图片加载错误时再加载

image.onerror = function(){

if (errorNum < 5) {

errorNum ++;

this.src = localCachePath;

}

console.log('图片加载从错误重新加载')

}

}

});

}

点击放大图片

JS端

function onImageClick(picUrl){

setupWebViewJavascriptBridge(function(bridge) {

var allImage = document.querySelectorAll("img[esrc]");

allImage = Array.prototype.slice.call(allImage, 0);

var urls = new Array();

var index = -1;

var x = 0;

var y = 0;

var width = 0;

var height = 0;

allImage.forEach(function(image) {

var imgUrl = image.getAttribute("esrc");

var newLength = urls.push(imgUrl);

//获取

if(imgUrl == picUrl || imgUrl == decodeURIComponent(picUrl)){

index = newLength-1;

x = image.getBoundingClientRect().left;

y = image.getBoundingClientRect().top;

x = x + document.documentElement.scrollLeft;

y = y + document.documentElement.scrollTop;

width = image.width;

height = image.height;

console.log("x:"+x +";y:" + y+";width:"+image.width +";height:"+image.height);

}

});

console.log("检测到点击");

//将图片在图片数组中的index,frame回传给OC端

bridge.callHandler('imageDidClicked', {'index':index,'x':x,'y':y,'width':width,'height':height}, function(response) {

console.log("JS已经发出imgurl和index,同时收到回调,说明OC已经收到数据");

});

});

}

OC端

图片在UIWebView中的frame和本地存储地址都能拿到,怎么实现放大功能就看自己的喜好了,这里我使用了YYPhotoGroup这个第三方库。

[self.bridge registerHandler:@"imageDidClicked" handler:^(id data, WVJBResponseCallback responseCallback) {

NSInteger index = [[data objectForKey:@"index"] integerValue];

CGFloat originX = [[data objectForKey:@"x"] floatValue];

CGFloat originY = [[data objectForKey:@"y"] floatValue];

CGFloat width = [[data objectForKey:@"width"] floatValue];

CGFloat height = [[data objectForKey:@"height"] floatValue];

self.tappedImageView.frame = CGRectMake(originX, originY, width, height);

self.tappedImageView.image = [YYImage imageWithContentsOfFile:self.downloadImageArray[index]];

responseCallback(@"OC已经收到JS的imageDidClicked了");

//点击放大图片

YYPhotoGroupItem *item = [[YYPhotoGroupItem alloc]init];

item.thumbView = self.tappedImageView;

item.largeImageURL = [NSURL URLWithString:self.downloadImageArray[index]];

YYPhotoGroupView *view = [[YYPhotoGroupView alloc]initWithGroupItems:@[item]];

view.blurEffectBackground = NO;

[view presentFromImageView:self.tappedImageView toContainer:[UIApplication sharedApplication].keyWindow animated:YES completion:^{

}];

}];

效果图

e6a01c74f026

demo.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值