WKWebView的使用

iOS8.0之后苹果推出了新框架Webkit,提供了WKWebView的组件,用来替换UIWebView。之前UIWebView 加载速度慢,占用内存大,如果加载的网页比较多,占用内存比较大可能还会导致项目crash。WKWebView在性能上有了很大的优化,占用内存小,允许JavaScript的Nitro库加载并使用,支持了更多的HTML5特性。

WKWebView的使用
自定义一个WKWebVC

声明两个属性

@property (nonatomic,strong) WKWebView *webView;
@property (nonatomic,copy) NSString *urlStr;

定义几个静态字符串 用来初始化注册js方法

static NSString * const JSHandlerNameShare = @"share";
static NSString * const JSHandlerNameHideNavBar = @"hideNavBar";
static NSString * const JSHandlerNameShowNavBar = @"showNavBar";
static NSString * const JSHandlerNameSetNavBarAlpha = @"setNavBarAlpha";

初始化WKWebView

- (WKWebView *)webView {
    if (!_webView) {
        WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
        //允许html内联播放
        config.allowsInlineMediaPlayback = YES;
        _webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
        _webView.backgroundColor = [UIColor whiteColor];
        _webView.navigationDelegate = self;
        _webView.UIDelegate = self;
        _webView.scrollView.delegate = self;

        //注册js方法
        [_webView.configuration.userContentController addScriptMessageHandler:self name:JSHandlerNameShare];
        [_webView.configuration.userContentController addScriptMessageHandler:self name:JSHandlerNameHideNavBar];
        [_webView.configuration.userContentController addScriptMessageHandler:self name:JSHandlerNameSetNavBarAlpha];

    }
    return _webView;
}

加载webView

- (void)setUrlStr:(NSString *)urlStr
{
    _urlStr = urlStr;
    NSURL *url = [NSURL URLWithString:urlStr];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:0 timeoutInterval:10.0];
    [self.webView loadRequest:request];
    [self.view addSubview:self.webView];
}

遵守相应的代理协议并实现相应的代理方法

WKNavigationDelegate 代理方法如下:

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
{
    //在此可以显示加载动画
    NSLog(@"页面开始加载时调用");
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    //停止加载动画
    NSLog(@"页面加载完毕");
}

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    //页面加载失败,添加失败页面,或者是添加重新加载按钮
    //重新加载需要重新赋值请求链接 重新loadRequest
    NSLog(@"页面加载失败");
}

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
{
    //内容返回后,加载动画停止
    NSLog(@"当内容返回的时候调用");
}

跳转前会调用以下这个方法,在跳转前可以进行判断跳转的链接,根据跟前端开发协商好的协议头和主机位判断是属于那种跳转,在这个方法中可以进行相应的操作。
- (void)webView:(WKWebView )webView decidePolicyForNavigationAction:(WKNavigationAction )navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

声明一个通知 用于监听是属于那种跳转

extern NSString * const WKJumpNotification;

为该属性赋值

NSString * const WKJumpNotification = @"WKJumpNotification";

在viewDidLoad 中添加通知

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jumpAction:) name:WKJumpNotification object:nil];

}

在请求链接跳转前进行如下监听

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    //可以在此进行判断是属于那种跳转类型
    //获取跳转链接
    NSURL *url = navigationAction.request.URL;
    //根据约定好的协议头进行判断
    if ([url.scheme isEqualToString:@"saga"]) {
        [[NSNotificationCenter defaultCenter] postNotificationName:WKJumpNotification object:nil userInfo:@{@"url":url}];
        //不允许跳转
        decisionHandler(WKNavigationActionPolicyCancel);
    } else {
        //允许页面跳转
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    NSLog(@"跳转前调用,决定是否跳转");
}

定义一个枚举判断是属于那种跳转

typedef enum {
    WKWebVCRequestTypeCustomerService = 1001,//客服列表
    WKWebVCRequestTypeProductDetail = 1002,//商品详情
    WKWebVCRequestTypeOrderDetail = 1003//订单详情

}WKWebVCRequestType;

通知方法的执行

- (void)jumpAction:(NSNotification *)notification
{
    NSDictionary *dict = notification.userInfo;
    id url = dict[@"url"];
    if (![url isKindOfClass:[NSURL class]]) {
        NSLog(@"参数不是请求URL");
        return;
    }
    NSURL *requestUrl = url;
    //根据主机位判断是属于那种跳转类型 这主机位事先跟web前端约定好
    WKWebVCRequestType type = requestUrl.host.intValue;
    switch (type) {
        case WKWebVCRequestTypeCustomerService:
            NSLog(@"跳转到客服列表");
            break;
        case WKWebVCRequestTypeProductDetail:
            NSLog(@"跳转到商品详情");
            break;
        case WKWebVCRequestTypeOrderDetail:
            NSLog(@"跳转到订单详情");
            break;

        default:
            break;
    }

}

WKUIDelegate 的相应代理方法的使用 处理web界面的三种提示框(警告框、确认框、输入框)

//弹出提示框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"温馨提示" message:message delegate:self cancelButtonTitle:@"确定" otherButtonTitles: nil];
    [alertView show];
    completionHandler();
}

//弹出确认框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"确认框" message:message delegate:self cancelButtonTitle:@"取消" otherButtonTitles: @"确定",nil];
    [alertView show];
}

//弹出输入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:prompt message:nil delegate:self cancelButtonTitle:@"取消" otherButtonTitles: @"确定",nil];
    [alertView show];
}

WKScriptMessageHandler 协议的使用,它能让网页通过JS把消息发送给OC

//网页通过JS把消息发送给OC
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    //判断网页是进行那种操作
    if ([message.name isEqualToString:JSHandlerNameShare]) { //分享

        if ([message.body isKindOfClass:[NSDictionary class]]) {
            //分享字典模型数据
            NSDictionary *dict = message.body;

        }

        NSLog(@"在此可以弹出分享面板");
    } else if ([message.name isEqualToString:JSHandlerNameHideNavBar]) {
        NSLog(@"隐藏导航栏");
    } else if ([message.name isEqualToString:JSHandlerNameShowNavBar]) {
        NSLog(@"显示导航栏");
    } else if ([message.name isEqualToString:JSHandlerNameSetNavBarAlpha]) {
        if ([message.body isKindOfClass:[NSDictionary class]]) {
            //根据模型字典中的数据设置导航栏的透明度
            NSDictionary *dict = message.body;
        }

        NSLog(@"设置导航栏的透明度");
    } else {

        NSLog(@"没有注册此操作");
    }

}

在开发中使用WKWebView遇到一些问题

  • (void)dealloc;中发现self没有被释放,原因是注册的js事件没有移除

为了释放self 我在viewWillDisAppear里进行了如下操作

- (void)viewWillDisappear:(BOOL)animated
{
    //移除之前注册的js回调,不然会导致webView无法正常释放。
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:JSHandlerNameShare];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:JSHandlerNameHideNavBar];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:JSHandlerNameShowNavBar];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:JSHandlerNameSetNavBarAlpha];
}

由于webView指定了UIScrollViewDelegate,所以要在dealloc中将webView的滚动代理赋值为nil,否则会导致crash

- (void)dealloc
{
    //需要将滚动的代理赋值为nil否则会导致crash
    _webView.scrollView.delegate = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

这是个人使用WKWebView的总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值