iOS中UIWebView的一个需求:获得js图片请求完成的回调时机

不久之前,项目中用到了UIWebView加载js的功能,之前使用webView都是简单使用,没考虑很多与js交互的地方,虽然现在项目完成了,但是回头看看这方面的知识还是有些茫然,在此记录一点,然后后续如果有用更多的话再来进行补充。

需求

封装个view,提供给开发者使用,暴露两个方法以供调用:

1、是调用initWithXXX进行初始化位置等等参数配置;

2、调用loadH5PageWithSuccessBlock:failureBlock:让view中的webView加载H5页面显示出来即可。

其主要实现就是webView加载一个URL的过程,给开发者一个加载失败和完成的回调。

 

UIWebView的代理方法

1、首先实现的是UIWebView的shouldStartLoadWithRequest:navigationType:代理方法 

注:对于返回的是unicode编码的字符串,用 stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding 进行返回UTF8编码的字符串。

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    
    NSLog(@"URL : %@", [request.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]);
    
    // click event
    if ([request.URL.host isEqualToString:@"call_close"])
    {// notify click close
        if (self.gh_clickCloseBlock) {
            self.gh_clickCloseBlock(webView, request.URL.absoluteString);
        }
        [self stopTimer:self.loadStatusCheckTimer];
        return NO;
    }
    
    if ([request.URL.host isEqualToString:@"on_click"])
    {
        NSString *URL_String = [request.URL.path substringFromIndex:1];
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:URL_String]];
        
        // notify click content
        if (self.gh_clickBlock) {
            self.gh_clickBlock(webView, URL_String);
        }
        return NO;
    }
    
    return YES;
}

如果上述回调中返回YES,那么webView会进行加载html页面,执行 webViewDidStartLoad: 回调。

每次在页面中的点击都可能会“截获”该URL,并会再次调用上述回调,那么通过URL的scheme和host就可以判断是什么动作事件,

例如:

如果是host为“call_close”,则可以做一些关闭的操作:移除view,停止定时器等,并添加关闭页面的block回调给开发者。

如果是host为“on_click”,则可以添加点击页面内容的block回调给开发者。

 

2、开始加载的回调

- (void)webViewDidStartLoad:(UIWebView *)webView {
    NSLog(@"start, %d", webView.loading);
}

 

3、如果加载失败的话会调用 didFailLoadWithError:

页面加载超时等失败的时机回调给开发者,但是对于请求中HTTP的状态码error的时候并不能判断出来,

对于这部分具体可以用NSURLConnection判断response的statusCode,如果是400以上即可回调失败,如果是成功响应再允许webView加载这个URL,

我们可以只要response,不需要receiveData,所以在得到response之后将connection cancel掉。

参考相关:http://stackoverflow.com/questions/1061364/how-do-i-get-the-last-http-status-code-from-a-uiwebview

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
    NSLog(@"failure : %@", error.description);
    
    // page加载失败的callBack
    if (self.gh_loadFailBlock) {
        self.gh_loadFailBlock(webView, error.code);
    }
}

 

4、page加载完成的回调,启动定时器进行检查,不断获取js中关于image的加载状态,以便获取回调时机。

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    NSLog(@"finish, %d", webView.loading);
    
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
    [webView stringByEvaluatingJavaScriptFromString:@"document.body.style.webkitTouchCallout='none';"];
    
    if(!injectedPageLoadedJS)
    {
        injectedPageLoadedJS = YES;
        [self stopTimer:self.loadStatusCheckTimer];
        self.loadStatusCheckTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(checkLoadStatus:) userInfo:nil repeats:YES];
    }
}

加载html的时候,我们的js会执行对url进行请求的操作,其中会有请求image资源,但是在webView这里,当html这个page加载完成时就会调用finish回调,如果加载H5页面的成功回调写在这里,可能会出现js还没有成功请求到图片资源渲染到页面上,你已经回调开发者加载成功。所以期间从finish到image异步请求完成,中间有段时间需要等待。

解决方式是在页面加载完成finish之后,通过NSTimer不断地去获取js加载image状态的返回值,直到获取成功的返回值,做出给开发者的block。

与js简单交互

和前端协商将js中标示image异步请求成功的变量定为window.__loadImageStatus__; 这样js在拿到image请求成功的回调之后,会将此变量赋值为imgLoaded,这个js的值可以通过webView的stringByEvaluatingJavaScriptFromString:方法的返回值拿到。 

何时去取到这个值,需要在webView加载完html页面时finish回调之后取,可以添加一个定时器,每隔0.5s中通过stringByEvaluatingJavaScriptFromString:拿到返回值,判断是否是imgLoaded,如果是,说明此时图片异步加载成功,图片已经展示,在此可以作为给开发者的成功回调。

 

- (void)checkLoadStatus:(NSTimer *)timer {
    
    NSString *evalString = [_webH5View stringByEvaluatingJavaScriptFromString:@"window.__loadImageStatus__;"];
    NSLog(@"+++++js 返回的status值:%@", evalString);
    
    if([evalString isEqualToString:@"imgLoaded"])
    {
        //Web page has finished. Shut down the timer.
        [self stopTimer:timer];
        injectedPageLoadedJS = NO;
        
        NSLog(@"成功获取到imgLoaded,js将image load 完成的回调值发给");// 成功回调
        if (self.gh_loadAdSuccessBlock) {
            self.gh_loadAdSuccessBlock(_webH5View, _request.URL.absoluteString);
        }
        
        self.count = 0;
    }
    
    else {
        
        if (self.count > 10) {
            [self stopTimer:timer];
            
        } else {
            self.count += 1;
        }
    }
}

 

注:最好添加一个计数器,当10次(也就是5s)还没有获取到js关于image加载成功的返回值,就可以将timer等相关对象移除,避免长时间等待,影响交互体验。

转载于:https://www.cnblogs.com/--yy/p/5065440.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值