Fork me on GitHub

OC与JavaScript交互

简单介绍

在我们平时的开发中,可能都会使用一下UIWebView或者WKWebview有时候需要一些简单的交互,如:Web想调用相机扫描二维码,扫描成功后APP端需给Web端做一定的反馈。下面以UIWebView为例简单模拟一个场景,Web端需要调起APP端扫描,同时扫描到内容后APP端把扫描的结果反馈给Web端

OC 调用 Web 的方法,实际是使用UIWebView的如下方法

1
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;

此方法给Web传递一段需要执行的JavaScript代码,而且是同步执行,建议不要直接使用[ ]调用

1
[self.webView stringByEvaluatingJavaScriptFromString:javaScriptParameter];

而是使用下面的方法

1
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

Web端

Web端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body{
margin-top: 50px;
}
</style>
<title>测试网页</title>
</head>
<body>
<a href="idhong://liangdahong?method=scan&callMethod=openCamera">扫描二维码做网页跳转</a>
<p></p>
<a href="idhong://liangdahong?method=scan&callMethod=codingSearch">扫描二维码codingSearch搜索</a>
<script type="text/javascript">
function openCamera(str){
alert("Web 提示 \n 扫描成功(" + str + ")准备跳转界面");
window.location.href = str;
}
function codingSearch(str){
window.location.href = "http://www.coding.so/s?kw=" + str;
}
</script>
</body>
</html>

我们可以抽奖一个html文件保存如上h5代码,放入demo中。

APP端

  • 我们创建demo,使用UIWebView价值刚才的html文件
  • 实现如下协议
1
2
3
4
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
- (void)webViewDidStartLoad:(UIWebView *) webView;
- (void)webViewDidFinishLoad:(UIWebView *) webView;
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;
  • 我们主要是如下方法里面操作
1
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
  • 加载成功以后界面显示如下:

  • 当点击 扫描二维码codingSearch搜索时会调用下面的方法
1
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;

同时可以在方法里面做相关的操作,如果是指定的操作就调起相关功能,如:调起扫描等。当扫描成功以后使用

1
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;

反馈给Web端,当然这里的方法名等协议需要两端商量确定好即可。

  • 推荐使用WebViewJavascriptBridge

  • APP内加载H5

  • 解析URL中的数据信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    // <a href="idhong://liangdahong?method=scan&callMethod=openCamera">扫描二维码做网页跳转</a>
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    // 获取URL
    NSURL *url = [request URL];
    // url.scheme 获取协议
    // url.host 主机地址
    // url.query 参数
    // 1 判断是否为自定义的协议 idhong://liangdahong?method=scan&callMethod=openCamera
    if ([url.scheme isEqualToString:@"idhong"] && [url.host isEqualToString:@"liangdahong"]) {
    // 2 获取参数
    NSMutableDictionary *mutableDictionary = [@{} mutableCopy];
    [[url.query componentsSeparatedByString:@"&"] enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    NSArray *arr = [obj componentsSeparatedByString:@"="];
    if (arr.count == 2) {
    mutableDictionary[arr[0]] = arr[1];
    }
    }];
    // 3 获取JS调用OC的方法的方法名
    NSString *method = mutableDictionary[@"method"];
    // 4 获取OC回调的JS的方法的方法名
    NSString *callMethod = mutableDictionary[@"callMethod"];
    // 5 调用定义好的协议和相关方法
    // 6 如果是调用扫描功能
    if ([method isEqualToString:@"scan"]) {
    BMScanVC *vc = [BMScanVC new];
    vc.block = ^(NSString *scan) {
    // 7 构建OC回调到js的 JavaScriptFromString
    NSString *javaScriptParameter = [NSString stringWithFormat:@"%@(\"%@\")", callMethod, scan];
    // 8 回调JS
    [self.webView stringByEvaluatingJavaScriptFromString:javaScriptParameter];
    };
    [self.navigationController pushViewController:vc animated:YES];
    }
    return NO;
    }
    return YES;
    }

OC和JavaScript交互时使用的JS函数

  • 给图片添加点击事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1.JS
function addImageCick(){
var objs = document.getElementsByTagName("img");
for(var i=0;i<objs.length;i++){
objs[i].onclick=function() {
document.location="myweb:imageClick:"+this.src;
};
};
return objs.length;
};

// 2. 点击事件、同时传图片编号
function imageClick(i, url){
alert(i + "\n" + url);
}
function addImageCick(){
var imgs = document.getElementsByTagName("img");
for (var i=0;i<imgs.length;i++){
imgs[i].setAttribute("onClick","imageClick("+i+", this.src)");
}
}
  • 获取图片的size data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function getImageData(i){
var imgs = document.getElementsByTagName("img");
var img=imgs[i];
var canvas=document.createElement("canvas");
var context=canvas.getContext("2d");
canvas.width=img.width; canvas.height=img.height;
context.drawImage(img,0,0,img.width,img.height);
return canvas.toDataURL("image/png")
}

function getImageRect(i){
var imgs = document.getElementsByTagName("img");
var rect;
rect = imgs[i].getBoundingClientRect().left+"::";
rect = rect+imgs[i].getBoundingClientRect().top+"::";
rect = rect+imgs[i].width+"::";
rect = rect+imgs[i].height;
return rect;
}
  • 获取所有图片
1
2
3
4
5
6
7
8
9
function getAllImageUrl(){
var imgs = document.getElementsByTagName("img");
var urlArray = [];
for (var i=0;i<imgs.length;i++){
var src = imgs[i].src;
urlArray.push(src);
}
return urlArray.toString();
}

最后的话

- END -
关注微信公众号,发现更多精彩

文章作者:梁大红

特别声明:若无特殊声明均为原创,转载请注明,侵权请联系

版权声明:署名-非商业性使用-禁止演绎 4.0 国际