美文网首页
iOS OC与JS交互(一)-- UIWebView

iOS OC与JS交互(一)-- UIWebView

作者: 淡定的笨鸟 | 来源:发表于2019-05-09 16:25 被阅读0次

UIWebView实现OC调用JS有两种方式
1、stringByEvaluatingJavaScriptFromString
2、JavaScriptCore
JS调用OC也有两种方式
1、request的url拦截
2、JavaScriptCore
其实从这里就可以看出JavaScriptCore很棒。

UIWebViewDemo

先写html

使用url拦截的方式需要提前定义好url的规则,这里的简单的定义个规则lfjstooc:///methodName/para1/para2(规则可以是各种各样的,只要你能拦截下来就行),先看一下我们预先写好的html文件

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
                <title>UIWebView中OC与JS交互</title>
                </head>
    
    <style type="text/css">
        .button {
            background: #f5be14;
            margin: 10px;
            text-align: center;
            width: 300px;
            height: 44px;
            line-height: 44px;
            margin: 10px auto;
            border-radius: 5px;
        }
    #setImage {
        width: 200px;
        height: 200px;
        margin: 0 auto;
    }
    </style>
    
    <body>
        
        <div class="button" onclick="firstClick()">今晚打老虎</div>
        <div class="button" onclick="secondClick()">请用力的点我</div>
        <div class="button" onclick="thirdClick()">弹我弹我</div>
        <div class="button" onclick="forthClick()">选择图片</div>
        <div id="setImage"></div>
    </body>
    
    <script type="text/javascript">
        
        var prefixStandard = "LFJSToOC://";
        
        function getText(index) {
            return document.getElementsByClassName("button")[0].innerText;
        }
    
    function firstClick() {
        var action = "firstClick";
        var token = getText(0);
        setUrl(action, token);
    }
    
    function secondClick() {
        var action = "secondClick";
        var token = getText(1);
        setUrl(action, token);
    }
    
    function thirdClick() {
        var action = "thirdClick";
        var token = getText(2);
        setUrl(action, token);
    }
    
    function forthClick() {
        var action = "forthClick";
        var token = getText(3);
        setUrl(action, token);
    }
    
    function setUrl(action, token) {
        var url = prefixStandard + "/" + action + "/" + token;
        loadUrl(url);
    }
    
    function loadUrl(url) {
        window.location.href = url;
    }
    
    function showImageOnDiv(imageStr) {
        var imgDiv = document.getElementById("setImage");
        imgDiv.innerHTML = "<image style='width:200px;' src='data:image/png;base64,"+imageStr+"'>";
    }
    
        </script>
    
</html>

这里实现的效果是这样的


HTML的效果

我们想要做的是,点击不同的按钮,在源生弹窗显示按钮上的字。

UIWebView

1、UIWebView初始化

self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-HOME_INDICATOR_HEIGHT)];
self.webView.delegate = self;
self.webView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.webView];
    
//这里在加载本地的html文件
NSURL *url = [[NSBundle mainBundle] URLForResource:@"UIWebView.html" withExtension:nil];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
[self.webView loadRequest:request];

2、实现代理
UIWebView的主要四个代理如下,

//加载所有webview的请求数据,以及控制是否要加载,所以JS调用的拦截在这里实现。
/*
JS的UIWebViewNavigationType对应如下样式,可以根据业务需求更细致的判断。
typedef NS_ENUM(NSInteger, UIWebViewNavigationType) {
    UIWebViewNavigationTypeLinkClicked,        点击
 UIWebViewNavigationTypeFormSubmitted,      提交
 UIWebViewNavigationTypeBackForward,        返回
 UIWebViewNavigationTypeReload,             刷新
 UIWebViewNavigationTypeFormResubmitted,    重复提交
 UIWebViewNavigationTypeOther               其他
} API_UNAVAILABLE(tvos);
*/
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType API_DEPRECATED("No longer supported.", ios(2.0, 12.0));
//开始加载
- (void)webViewDidStartLoad:(UIWebView *)webView API_DEPRECATED("No longer supported.", ios(2.0, 12.0));
//加载完成
- (void)webViewDidFinishLoad:(UIWebView *)webView API_DEPRECATED("No longer supported.", ios(2.0, 12.0));
//加载失败
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error API_DEPRECATED("No longer supported.", ios(2.0, 12.0));
JS调OC

这里我们先用普通的方式"request拦截",我们都知道webView在调用一个Url之前会走- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType这个代理,我们看到有NSURLRequest这个类型的参数,而从这个request中可以获取到JS调用的url(lfjstooc:///methodName/para1/para2),于是我们的故事开始了。
1、request.URL.scheme
我们通过scheme路由发放响应

if ([request.URL.scheme.lowercaseString isEqualToString:@"lfjstooc"]) {
    return NO;//webview停止继续加载
}

2、request.URL.pathComponents
通过pathComponents获取函数名和参数

NSArray *arr = request.URL.pathComponents;
/*
(
    "/",
    secondClick,//方法名
    "this is the message"//一个NSString类型参数
)
*/

3、调用OC方法
当然调用OC方法可以有很多种,[self methodName]直接调也行,performSelector: withObject:这种方式也行,我这里用objc_msgSend

objc_msgSend(self, sel, arr[2]);

综上,我们- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType里面代码如下

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    //拦截JS的回调
    if ([request.URL.scheme.lowercaseString isEqualToString:@"lfjstooc"]) {
        NSArray *arr = request.URL.pathComponents;
        SEL sel = NULL;
        if (arr.count > 2) {//表示调用js调用的方法有参数
            sel = NSSelectorFromString([NSString stringWithFormat:@"%@:",arr[1]]);
        } else if(arr.count == 2) {//js调用OC,数组中至少得有两个元素
            sel = NSSelectorFromString(arr[1]);
        }
        objc_msgSend(self, sel, arr[2]);//调用对应的OC方法
        
        return NO;
    }
    
    return YES;
}
OC调JS

OC调JS我们选择用UIWebView的stringByEvaluatingJavaScriptFromString方法,比如调用js的docoument.title方法获取当前页面的标题。

NSString *title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
    self.title = title;

下面举一个点击html页面的按钮调用源生的系统相册选择图片,并把图片放到html页面的例子,代码如下
首先响应JS调用的源生相册

//第四个按钮点击事件,调用系统相册
- (void)forthClick:(NSString *)str {
    if (!self.imagePicker) {
        self.imagePicker = [[UIImagePickerController alloc] init];
    }
    self.imagePicker.delegate = self;
    self.imagePicker.allowsEditing = YES;
    self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    [self presentViewController:self.imagePicker animated:YES completion:nil];
}

其次实现照片选择完毕的系统代理- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info

#pragma mark -- UIImagePickerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
    NSLog(@"info---%@",info);
    UIImage *resultImage = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
    NSData *imgData = UIImageJPEGRepresentation(resultImage, 0.01);
    NSString *encodedImageStr = [imgData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    [self dismissViewControllerAnimated:YES completion:nil];
    NSString *imageString = [self clearImageString:encodedImageStr];
    
    NSString *jsFunctStr = [NSString stringWithFormat:@"showImageOnDiv('%@')",imageString];
    //OC调用JS
    [self.webView stringByEvaluatingJavaScriptFromString:jsFunctStr];
}

//清除base64串里面的东西
- (NSString *)clearImageString:(NSString *)str {
    NSString *temp = [str stringByReplacingOccurrencesOfString:@" " withString:@""];
    temp = [temp stringByReplacingOccurrencesOfString:@"\r" withString:@""];
    temp = [temp stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    return temp;
}

效果如下:


JS与OC交互-选择系统相册.gif

OK,以上就是UIWebView中OC与JS交互的内容,这种是比较简单的OC与JS交互,针对简单的业务使用起来很方便。

相关文章

网友评论

      本文标题:iOS OC与JS交互(一)-- UIWebView

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