iOS下JS与OC互相调用(二)--WKWebView 拦截URL

在第一篇文章 iOS下JS与OC互相调用(一)中讲述了使用UIWebView拦截URL的方式来处理JS与OC交互。 由于UIWebView比较耗内存,性能上不太好,而苹果在iOS 8中推出了WKWebView。 同样的用WKWebView也可以拦截URL,做JS 与OC交互。关于WKWebView与UIWebView的对比,大家请自动百度或者google。

WKWebView 拦截URL

WKWebView 与 UIWebView 拦截URL 的处理方式基本一样。除了代理方法和WKWebView的使用不太一样,关于WKWebView更详尽的讲解和用法,还是自行搜索学习,本文重点还是讲解如何实现JS 与OC 互相调用,WKWebView 是iOS 8 推出的WebKit.framework中的控件,只有app 不需要兼容iOS 7及以下的时候才可以使用。感谢Haley_Wong大神提供资源.

1.创建WKWebView,加载本地HTML。 WKWebView的创建有几点不同:

1.初始化多了个configuration参数,当然这个参数我们也可以不传,直接使用默认的设置就好。

2.WKWebView的代理有两个navigationDelegate和UIDelegate。我们要拦截URL,就要通过navigationDelegate的一个代理方法来实现。如果在HTML中要使用alert等弹窗,就必须得实现UIDelegate的相应代理方法。

3.在iOS 9之前,WKWebView加载本地HTML会有一些问题。(不能加载本地HTML,或者部分CSS/本地图片加载不了等) 我这里创建WKWebView的示例代码是这样的:

WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    configuration.userContentController = [WKUserContentController new];

    WKPreferences *preferences = [WKPreferences new];
    preferences.javaScriptCanOpenWindowsAutomatically = YES;
    preferences.minimumFontSize = 30.0;
    configuration.preferences = preferences;

    self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];

    NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:nil];
    NSURL *fileURL = [NSURL fileURLWithPath:urlStr];
    [self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL];

    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];

2.拦截URL

使用WKNavigationDelegate中的代理方法,拦截自定义的URL来实现JS调用OC方法。

#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSURL *URL = navigationAction.request.URL;
    NSString *scheme = [URL scheme];
    if ([scheme isEqualToString:@"haleyaction"]) {
        [self handleCustomAction:URL];
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

需要注意的是:

1.如果实现了这个代理方法,就必须得调用decisionHandler这个block,否则会导致app 崩溃。block参数是个枚举类型,WKNavigationActionPolicyCancel代表取消加载,相当于UIWebView的代理方法return NO的情况;WKNavigationActionPolicyAllow代表允许加载,相当于UIWebView的代理方法中 return YES的情况。

2.其他的关于为什么要统一设置scheme,在上一篇中讲过。

关于如何区分执行不同的OC 方法,也与UIWebView的处理方式一样,通过URL 的host 来区分执行不同的方法:

#pragma mark - private method
- (void)handleCustomAction:(NSURL *)URL
{
    NSString *host = [URL host];
    if ([host isEqualToString:@"scanClick"]) {
        NSLog(@"扫一扫");
    } else if ([host isEqualToString:@"shareClick"]) {
        [self share:URL];
    } else if ([host isEqualToString:@"getLocation"]) {
        [self getLocation];
    } else if ([host isEqualToString:@"setColor"]) {
        [self changeBGColor:URL];
    } else if ([host isEqualToString:@"payAction"]) {
        [self payAction:URL];
    } else if ([host isEqualToString:@"shake"]) {
        [self shakeAction];
    } else if ([host isEqualToString:@"goBack"]) {
        [self goBack];
    }
}

3.OC 调用 JS 方法

JS 调用OC 方法后,有的操作可能需要将结果返回给JS。这时候就是OC 调用JS 方法的场景。
WKWebView 提供了一个新的方法evaluateJavaScript:completionHandler:,实现OC 调用JS 等场景。

- (void)getLocation
{
    // 获取位置信息

    // 将结果返回给js
    NSString *jsStr = [NSString stringWithFormat:@"setLocation(‘%@‘)",@"广东省深圳市"];
    [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        NSLog(@"%@----%@",result, error);
    }];
}

evaluateJavaScript:completionHandler:没有返回值,JS 执行成功还是失败会在completionHandler 中返回。所以使用这个API 就可以避免执行耗时的JS,或者alert 导致界面卡住的问题。

4.WKWebView中使用弹窗

在上面提到,如果在WKWebView中使用alert、confirm 等弹窗,就得实现WKWebView的WKUIDelegate中相应的代理方法。
例如,我在JS中要显示alert 弹窗,就必须实现如下代理方法,否则alert 并不会弹出。

#pragma mark - WKUIDelegate
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }]];

    [self presentViewController:alert animated:YES completion:nil];
}

其中completionHandler这个block 一定得调用,至于在哪里调用,倒是无所谓,我们也可以写在方法实现的第一行,或者最后一行。

demo地址:https://github.com/domanc/JS-OC-URL.git

时间: 2024-12-17 15:24:28

iOS下JS与OC互相调用(二)--WKWebView 拦截URL的相关文章

iOS下JS与OC互相调用(一)--UIWebView 拦截URL

http://blog.csdn.net/u011619283/article/details/52135977 最近准备把之前用UIWebView实现的JS与原生相互调用功能,用WKWebView来替换.顺便搜索整理了一下JS 与OC 交互的方式,非常之多啊.目前我已知的JS 与 OC 交互的处理方式: * 1.在JS 中做一次URL跳转,然后在OC中拦截跳转.(这里分为UIWebView 和 WKWebView两种,去年因为还要兼容iOS 6,所以没办法只能采用UIWebView来做.) *

转--iOS下JS与原生OC互相调用

iOS下JS与原生OC互相调用 引言 一直听说WKWebView比UIWebView强大许多,可是一直没有使用到,今天花了点时间看写了个例子,对其API的使用有所了解,为了日后能少走弯路,也为了让大家更容易学习上手,这里写下这篇文章来记录如何使用以及需要注意的地方. 温馨提示:本人在学习使用过程中,确实有此体会,WKWebView的确比UIWebView强大很多,与JS交互的能力显示增强,在加载速度上有所提升. WKWebView新特性 性能.稳定性.功能大幅度提升 允许JavaScript的N

iOS下JS和原生交互,函数互调

现在越来越多的APP都是H5和原生混合开发,这样确实方便快捷,但是H5的部分总避免不了很多与原生的交互,原生调JS函数还比较简单,原生的API函数stringByEvaluatingJavaScriptFromString就可以完成需求,但是JS调原生的函数,系统没有提供API,所以很多人公司都采用标记位的形式完成,我们公司的也不例外,项目开发了很久,原生和JS交互一直是我负责,我们项目这块也要大量的交互操作,随便版本迭代,问题也越来越多,然后就想了很多办法去解决这个问题. 一,我原本的方案,拦

iOS开发——图形编程OC篇&(二)CALayer自定义图层

一.第一种方式 1.简单说明 以前想要在view中画东西,需要自定义view,创建一个类与之关联,让这个类继承自UIView,然后重写它的DrawRect:方法,然后在该方法中画图. 绘制图形的步骤: (1)获取上下文 (2)绘制图形 (3)渲染图形 如果在layer上画东西,与上面的过程类似. 代码示例: 新建一个类,让该类继承自CALayer YYMylayer.m文件 1 // 2 // YYMylayer.m 3 // 05-自定义layer(1) 4 // 5 // Created b

iOS开发——动画编程OC篇&(二)核心动画

核心动画 一.简单介绍 CAPropertyAnimation的子类 属性解析: fromValue:keyPath相应属性的初始值 toValue:keyPath相应属性的结束值 随着动画的进行,在长度为duration的持续时间内,keyPath相应属性的值从fromValue渐渐地变为toValue 如果fillMode=kCAFillModeForwards和removedOnComletion=NO,那么在动画执行完毕后,图层会保持显示动画执行后的状态.但在实质上,图层的属性值还是动画

iOS开发——网络编程OC篇&(二)XMPP实现用户登录与注销

登录: 步骤: * 在AppDelegate实现登录 1. 初始化XMPPStream 2. 连接到服务器[传一个JID] 3. 连接到服务成功后,再发送密码授权 4. 授权成功后,发送"在线" 消息 一:导入框架,根据上一篇文章的说明去导入相应的库与文件 二:定义一个XMPP的成员变量 1 @interface AppDelegate ()<XMPPStreamDelegate>{ 2 XMPPStream *_xmppStream; 3 } 三:按步骤在代理方法中声明四

iOS开发——图形编程OC篇&amp;(二)Quartz 2D自定义控件

Quartz2D(自定义UIImageView控件) 一.实现思路 Quartz2D最大的用途在于自定义View(自定义UI控件),当系统的View不能满足我们使用需求的时候,自定义View. 使用Quartz2D自定义View,可以从模仿系统的ImageView的使用开始. 需求驱动开发:模仿系统的imageview的使用过程 1.创建 2.设置图片 3.设置frame 4.把创建的自定义的view添加到界面上(在自定义的View中,需要一个image属性接收image图片参数->5). 5.

iOS开发——数据持久化OC篇&amp;(二)属性列表

属性列表 属性列表文件是一种XML文件,Foundation框架中的数组和字典等都可以于属性列表文件相互转换. NSArray类常用读写属性列表文件的方法: +arrayWithContentsOfFile:类级构造方法,用于从属性列表文件中读取数据,创建NSArray对象. -initWithContentsOfFile:实例构造方法,用于从属性列表文件中读取数据,创建NSArray对象. -writeToFile:atomically:该方法把NSArray对象写入到属性列表文件中,第一个参

UIWebView的应用和其中的JS与OC间传值

现在有很多的应用已经采用了WebView和html语言结合的开发模式.html5一直很火因为一份代码可以在多个平台上运用啊,效果各不相同都很美观,也越来越有一些公司直接招后台程序员和html5程序员,做完的产品再安卓也能用iOS也能用,不用再招双份的工程师了.应用程序一进去就全是UIWebView,里面发个请求到自己用html5做的页面,这就是一个应用!当然今天的主要不是说html5,是说html语言中JS代码和OC代码之间的传值. 先举例一个简单的用法: 我在模仿网易彩票做到设置页面的 常见问