uiwebview_uiwebview 友盟 - CSDN
精华内容
参与话题
  • 文章目录前言I、解决方案1.1 、 使用WKWebView替换UIWebView 前言 202012之后苹果将不再接受使用UIWebView的app。 I、解决方案 1.1 、 使用WKWebView替换UIWebView 1.1 移除/升级包含UIWebView的第三方SDK(grep ...


    前言

    202012之后苹果将不接受使用UIWebView

    I、解决方案

    1.1 、 使用WKWebView替换UIWebView

    1.1.1 移除/升级包含UIWebView的第三方SDK(grep -r "UIWebView" .

    ➜  retail git:(develop) grep -r "UIWebView" .
    Binary file ./retail.xcworkspace/xcuserdata/mac.xcuserdatad/UserInterfaceState.xcuserstate matches
    ./Pods/Pods.xcodeproj/project.pbxproj:		337C8A9592224E2629F71F4759AE0DF2 /* UIWebView+AFNetworking.h in Headers */ = {isa = PBXBuildFile; fileRef = 55098EA6EA9BE396074DA1E1980C154A /* UIWebView+AFNetworking.h */; settings = {ATTRIBUTES = (Project, ); }; };
    ./Pods/Pods.xcodeproj/project.pbxproj:		6326910744CB757A56F0D16A8892445E /* UIWebView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = F1F2113749BAA47EBE9F2FE1F43FDA51 /* UIWebView+AFNetworking.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
    
    

    在这里插入图片描述

    • NJKWebViewProgress
     ./Pods/NJKWebViewProgress/NJKWebViewProgress/NJKWebViewProgress.m:- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    

    AXWebViewController (0.7.2) 使用了NJKWebViewProgress
    iOS8.0以下使用了NJKWebViewProgress作为进度条, 因此对于上架审核没有影响。

    • ZBarSDK
    ./Pods/Headers/Private/ZBarSDK/ZBarHelpController.h:                              < UIWebViewDelegate,
    ./Pods/Headers/Private/ZBarSDK/ZBarHelpController.h:    UIWebView *webView;
    ./Pods/ZBarSDK/iphone/ZBarHelpController.m:    webView = [[UIWebView alloc]
    ./Pods/ZBarSDK/iphone/ZBarHelpController.m:- (void) webViewDidFinishLoad: (UIWebView*) view
    ./Pods/ZBarSDK/iphone/ZBarHelpController.m:- (BOOL)             webView: (UIWebView*) view
    ./Pods/ZBarSDK/iphone/ZBarHelpController.m:              navigationType: (UIWebViewNavigationType) nav
    
    
    pod 'LBXScan/LBXNative','~> 2.4.1' #系统原生API封装库
    pod 'LBXScan/LBXZXing','~> 2.4.1'
    #pod 'LBXScan/UI','~> 2.3'
    pod 'LBXScan/UI','~> 2.4.1'
    pod 'LBXZBarSDK','~> 1.3' 删除UIWebView
    
    

    1.1.2 移除/替换自己项目使用UIWebView API的代码

    自己是否用了该 API 只需要在 Xcode 中全局搜索即可

    II、升级包含UIWebView的第三方SDK的具体例子

        pod 'AFNetworking','~> 4.0.1'#2、 Migrate UIWebview to WKWebView #4441
      #4.x  iOS 9  macOS 10.10  watchOS 2.0  tvOS 9.0  Xcode 11+ is required.
    
    

    2.1 Installing AFNetworking 4.0.1 (was 3.2.1)正式移除了UIWebView分类

    • 新版本主要移除的类如下
      在这里插入图片描述

    处理afn的接口问题,老版本的post get formdata的请求形式在4.0都有了调整,因此需要更改工程中的相应的方法

    在这里插入图片描述

    • 例如
      在这里插入图片描述

    修改为:

    在这里插入图片描述

        [manager GET:urlStr parameters:params  headers:@{} progress:^(NSProgress * _Nonnull downloadProgress) {
    
    
    展开全文
  • UIWebView和WKWebView

    2019-05-03 00:25:29
    UIWebView 什么是UIWebView UIWebView是iOS内置的浏览器控件 系统自带的Safari浏览器就是通过UIWebView实现的 UIWebView不但能加载远程的网页资源,还能加载绝大部分的常见文件 html\htm pdf、doc、ppt、txt...

    UIWebView

    • 什么是UIWebView

           UIWebView是iOS内置的浏览器控件

          系统自带的Safari浏览器就是通过UIWebView实现的

    •  UIWebView不但能加载远程的网页资源,还能加载绝大部分的常见文件

            html\htm

            pdf、doc、ppt、txt

            mp4

            … …

    •  UIWebView常用的加载资源的方法

    - (void)loadRequest:(NSURLRequest *)request;

    • UIWebView控件自身存在内存泄漏的问题 

    UIWebView常用属性和方法

    •   重新加载(刷新)
    • - (void)reload;

    •  停止加载
    • - (void)stopLoading;

    • 回退
    • - (void)goBack;

    • 前进
    • - (void)goForward;

    • 需要进行检测的数据类型
    • @property(nonatomic) UIDataDetectorTypes dataDetectorTypes

    • 是否能回退
    • @property(nonatomic,readonly,getter=canGoBack) BOOL canGoBack;

    • 是否能前进
    • @property(nonatomic,readonly,getter=canGoForward) BOOL canGoForward;

    • 是否正在加载中
    • @property(nonatomic,readonly,getter=isLoading) BOOL loading;

    • 是否伸缩内容至适应屏幕当前尺寸
    • @property(nonatomic) BOOL scalesPageToFit;


    UIWebView常用属性和方法的代理监听

    • 成为UIWebView的代理,遵守UIWebViewDelegate协议,就能监听UIWebView的加载过程
    • 开始发送请求(加载数据)时调用这个方法

           - (void)webViewDidStartLoad:(UIWebView *)webView;

    • 请求完毕(加载数据完毕)时调用这个方法

            - (void)webViewDidFinishLoad:(UIWebView *)webView;

    • 请求错误时调用这个方法

           - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;

    • UIWebView在发送请求之前,都会调用这个方法,如果返回NO,代表停止加载请求,返回YES,代表允许加载请求

           - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:      (UIWebViewNavigationType)navigationType;


    UIWebView的基本使用

    #import "ViewController.h"
    
    @interface ViewController ()
    @property (weak, nonatomic) IBOutlet UIWebView *webView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self test5];
    }
    
    -(void)test1
    {
        NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
        //加载网页
        [self.webView loadRequest:[NSURLRequest requestWithURL:url]];
    }
    
    -(void)test2
    {
        NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
        //加载网页
        [self.webView loadRequest:[NSURLRequest requestWithURL:url]];
        
        self.webView.scrollView.contentInset = UIEdgeInsetsMake(40, 0, 0, 0);
    }
    
    //加载本地的文件
    -(void)test3
    {
        NSURL *url = [NSURL fileURLWithPath:@"/Users/Alan/Desktop/NSURLSession.pptx"];
        //加载网页
        [self.webView loadRequest:[NSURLRequest requestWithURL:url]];
    }
    
    -(void)test4
    {
        NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
        //加载网页
        [self.webView loadRequest:[NSURLRequest requestWithURL:url]];
        
        //设置时候自适应
        self.webView.scalesPageToFit = YES;
    }
    
    -(void)test5
    {
        NSURL *url = [[NSBundle mainBundle] URLForResource:@"text.html" withExtension:nil];
        
        //加载网页
        [self.webView loadRequest:[NSURLRequest requestWithURL:url]];
        
        //设置时候自适应
        self.webView.dataDetectorTypes = UIDataDetectorTypeAll;
    }
    @end

     


    UIWebView的小用例

    #import "ViewController.h"
    
    @interface ViewController ()<UIWebViewDelegate>
    @property (weak, nonatomic) IBOutlet UIWebView *webView;
    @property (weak, nonatomic) IBOutlet UIBarButtonItem *goBack;
    @property (weak, nonatomic) IBOutlet UIBarButtonItem *goForward;
    
    @end
    
    @implementation ViewController
    
    #pragma mark ----------------------
    #pragma mark Life Cycle
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        
        //加载网页
        [self.webView loadRequest:request];
        
        //设置代理
        self.webView.delegate = self;
    }
    
    #pragma mark ----------------------
    #pragma mark Events
    - (IBAction)goBackBtnClick:(id)sender
    {
        
        [self.webView goBack];
    }
    - (IBAction)goForwardBtnClick:(id)sender
    {
        [self.webView goForward];
        
    }
    - (IBAction)reloadBtnClick:(id)sender
    {
        [self.webView reload];
    }
    
    #pragma mark ----------------------
    #pragma mark UIWebViewDelegate
    
    //即将加载某个请求的时候调用(最先调用)
    -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    {
        NSLog(@"%@",request.URL.absoluteString);
        //简单的请求拦截处理
        NSString *strM = request.URL.absoluteString;
        if ([strM containsString:@"360"]) {
            return NO;
        }
        return YES;
    }
    
    //1.开始加载网页的时候调用
    -(void)webViewDidStartLoad:(UIWebView *)webView
    {
        NSLog(@"webViewDidStartLoad");
    }
    
    //2.加载完成的时候调用
    -(void)webViewDidFinishLoad:(UIWebView *)webView
    {
        NSLog(@"webViewDidFinishLoad");
        
        self.goBack.enabled = self.webView.canGoBack;
        self.goForward.enabled = self.webView.canGoForward;
    }
    
    //3.加载失败的时候调用
    -(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
    {
        NSLog(@"didFailLoadWithError");
    }
    
    @end

    WKWebView

    一、WKWebView涉及的一些类

          1)WKWebView:网页的渲染与展示

    注意: #import <WebKit/WebKit.h>
         //初始化
           _webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) configuration:config];
            // UI代理
            _webView.UIDelegate = self;
            // 导航代理
            _webView.navigationDelegate = self;
            // 是否允许手势左滑返回上一级, 类似导航控制的左滑返回
            _webView.allowsBackForwardNavigationGestures = YES;
            //可返回的页面列表, 存储已打开过的网页 
           WKBackForwardList * backForwardList = [_webView backForwardList];
    
            //        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.chinadaily.com.cn"]];
            //        [request addValue:[self readCurrentCookieWithDomain:@"http://www.chinadaily.com.cn"] forHTTPHeaderField:@"Cookie"];
            //        [_webView loadRequest:request];
            //页面后退
            [_webView goBack];
            //页面前进
             [_webView goForward];
            //刷新当前页面
            [_webView reload];
            
            NSString *path = [[NSBundle mainBundle] pathForResource:@"JStoOC.html" ofType:nil];
            NSString *htmlString = [[NSString alloc]initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
          //加载本地html文件
            [_webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
            
    

          2)WKWebViewConfiguration:为添加WKWebView配置信息

    //创建网页配置对象
            WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
            
            // 创建设置对象
            WKPreferences *preference = [[WKPreferences alloc]init];
            //最小字体大小 当将javaScriptEnabled属性设置为NO时,可以看到明显的效果
            preference.minimumFontSize = 0;
            //设置是否支持javaScript 默认是支持的
            preference.javaScriptEnabled = YES;
            // 在iOS上默认为NO,表示是否允许不经过用户交互由javaScript自动打开窗口
            preference.javaScriptCanOpenWindowsAutomatically = YES;
            config.preferences = preference;
            
            // 是使用h5的视频播放器在线播放, 还是使用原生播放器全屏播放
            config.allowsInlineMediaPlayback = YES;
            //设置视频是否需要用户手动播放  设置为NO则会允许自动播放
            config.requiresUserActionForMediaPlayback = YES;
            //设置是否允许画中画技术 在特定设备上有效
            config.allowsPictureInPictureMediaPlayback = YES;
            //设置请求的User-Agent信息中应用程序名称 iOS9后可用
            config.applicationNameForUserAgent = @"ChinaDailyForiPad";
             //自定义的WKScriptMessageHandler 是为了解决内存不释放的问题
            WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self];
            //这个类主要用来做native与JavaScript的交互管理
            WKUserContentController * wkUController = [[WKUserContentController alloc] init];
            //注册一个name为jsToOcNoPrams的js方法
            [wkUController addScriptMessageHandler:weakScriptMessageDelegate  name:@"jsToOcNoPrams"];
            [wkUController addScriptMessageHandler:weakScriptMessageDelegate  name:@"jsToOcWithPrams"]; 
           config.userContentController = wkUController;
            

            3)WKUserScript:用于进行JavaScript注入

       //以下代码适配文本大小,由UIWebView换为WKWebView后,会发现字体小了很多,这应该是WKWebView与html的兼容问题,解决办法是修改原网页,要么我们手动注入JS
            NSString *jSString = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
            //用于进行JavaScript注入
            WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
            [config.userContentController addUserScript:wkUScript];

            4)WKUserContentController:这个类主要用来做native与JavaScript的交互管理

    //这个类主要用来做native与JavaScript的交互管理
            WKUserContentController * wkUController = [[WKUserContentController alloc] init];
            //注册一个name为jsToOcNoPrams的js方法,设置处理接收JS方法的代理
            [wkUController addScriptMessageHandler:self  name:@"jsToOcNoPrams"];
            [wkUController addScriptMessageHandler:self  name:@"jsToOcWithPrams"];
            config.userContentController = wkUController;
           //用完记得移除
           //移除注册的js方法
            [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsToOcNoPrams"];
           [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsToOcWithPrams"];

            5)WKScriptMessageHandler:这个协议类专门用来处理监听JavaScript方法从而调用原生OC方法,和WKUserContentController搭配使用

    注意:遵守WKScriptMessageHandler协议,代理是由WKUserContentControl设置
    
       //通过接收JS传出消息的name进行捕捉的回调方法
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
        NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);
        //用message.body获得JS传出的参数体
        NSDictionary * parameter = message.body;
        //JS调用OC
        if([message.name isEqualToString:@"jsToOcNoPrams"]){
            UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js调用到了oc" message:@"不带参数" preferredStyle:UIAlertControllerStyleAlert];
            [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            }])];
            [self presentViewController:alertController animated:YES completion:nil];
            
        }else if([message.name isEqualToString:@"jsToOcWithPrams"]){
            UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js调用到了oc" message:parameter[@"params"] preferredStyle:UIAlertControllerStyleAlert];
            [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            }])];
            [self presentViewController:alertController animated:YES completion:nil];
        }
    }
    

    WKWebView涉及的代理方法

         1)WKNavigationDelegate :主要处理一些跳转、加载处理操作

        // 页面开始加载时调用
    - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
    }
        // 页面加载失败时调用
    - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
        [self.progressView setProgress:0.0f animated:NO];
    } 
        // 当内容开始返回时调用
    - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
    }
        // 页面加载完成之后调用
    - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
        [self getCookie];
    }
        //提交发生错误时调用
    - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
        [self.progressView setProgress:0.0f animated:NO];
    }  
       // 接收到服务器跳转请求即服务重定向时之后调用
    - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
    }
        // 根据WebView对于即将跳转的HTTP请求头信息和相关信息来决定是否跳转
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
        
        NSString * urlStr = navigationAction.request.URL.absoluteString;
        NSLog(@"发送跳转请求:%@",urlStr);
        //自己定义的协议头
        NSString *htmlHeadString = @"github://";
        if([urlStr hasPrefix:htmlHeadString]){
            UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"通过截取URL调用OC" message:@"你想前往我的Github主页?" preferredStyle:UIAlertControllerStyleAlert];
            [alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {   
            }])];
            [alertController addAction:([UIAlertAction actionWithTitle:@"打开" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                NSURL * url = [NSURL URLWithString:[urlStr stringByReplacingOccurrencesOfString:@"github://callName_?" withString:@""]];
                [[UIApplication sharedApplication] openURL:url];
            }])];
            [self presentViewController:alertController animated:YES completion:nil];
            decisionHandler(WKNavigationActionPolicyCancel);
        }else{
            decisionHandler(WKNavigationActionPolicyAllow);
        }
    }
        
        // 根据客户端受到的服务器响应头以及response相关信息来决定是否可以跳转
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
        NSString * urlStr = navigationResponse.response.URL.absoluteString;
        NSLog(@"当前跳转地址:%@",urlStr);
        //允许跳转
        decisionHandler(WKNavigationResponsePolicyAllow);
        //不允许跳转
        //decisionHandler(WKNavigationResponsePolicyCancel);
    } 
        //需要响应身份验证时调用 同样在block中需要传入用户身份凭证
    - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{
        //用户身份信息
        NSURLCredential * newCred = [[NSURLCredential alloc] initWithUser:@"user123" password:@"123" persistence:NSURLCredentialPersistenceNone];
        //为 challenge 的发送方提供 credential
        [challenge.sender useCredential:newCred forAuthenticationChallenge:challenge];
        completionHandler(NSURLSessionAuthChallengeUseCredential,newCred);
    }
        //进程被终止时调用
    - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{
    }
    

         2)WKNavigationDelegate :主要处理一些跳转、加载处理操作

    // 页面开始加载时调用
    - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
    }
        // 页面加载失败时调用
    - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
        [self.progressView setProgress:0.0f animated:NO];
    } 
        // 当内容开始返回时调用
    - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
    }
        // 页面加载完成之后调用
    - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
        [self getCookie];
    }
        //提交发生错误时调用
    - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
        [self.progressView setProgress:0.0f animated:NO];
    }  
       // 接收到服务器跳转请求即服务重定向时之后调用
    - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
    }
        // 根据WebView对于即将跳转的HTTP请求头信息和相关信息来决定是否跳转
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
        
        NSString * urlStr = navigationAction.request.URL.absoluteString;
        NSLog(@"发送跳转请求:%@",urlStr);
        //自己定义的协议头
        NSString *htmlHeadString = @"github://";
        if([urlStr hasPrefix:htmlHeadString]){
            UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"通过截取URL调用OC" message:@"你想前往我的Github主页?" preferredStyle:UIAlertControllerStyleAlert];
            [alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {   
            }])];
            [alertController addAction:([UIAlertAction actionWithTitle:@"打开" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                NSURL * url = [NSURL URLWithString:[urlStr stringByReplacingOccurrencesOfString:@"github://callName_?" withString:@""]];
                [[UIApplication sharedApplication] openURL:url];
            }])];
            [self presentViewController:alertController animated:YES completion:nil];
            decisionHandler(WKNavigationActionPolicyCancel);
        }else{
            decisionHandler(WKNavigationActionPolicyAllow);
        }
    }
        
        // 根据客户端受到的服务器响应头以及response相关信息来决定是否可以跳转
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
        NSString * urlStr = navigationResponse.response.URL.absoluteString;
        NSLog(@"当前跳转地址:%@",urlStr);
        //允许跳转
        decisionHandler(WKNavigationResponsePolicyAllow);
        //不允许跳转
        //decisionHandler(WKNavigationResponsePolicyCancel);
    } 
        //需要响应身份验证时调用 同样在block中需要传入用户身份凭证
    - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{
        //用户身份信息
        NSURLCredential * newCred = [[NSURLCredential alloc] initWithUser:@"user123" password:@"123" persistence:NSURLCredentialPersistenceNone];
        //为 challenge 的发送方提供 credential
        [challenge.sender useCredential:newCred forAuthenticationChallenge:challenge];
        completionHandler(NSURLSessionAuthChallengeUseCredential,newCred);
    }
        //进程被终止时调用
    - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{
    }
    

         3)WKUIDelegate :主要处理JS脚本,确认框,警告框等

    /**
         *  web界面中有弹出警告框时调用
         *
         *  @param webView           实现该代理的webview
         *  @param message           警告框中的内容
         *  @param completionHandler 警告框消失调用
         */
    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"HTML的弹出框" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
        [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completionHandler();
        }])];
        [self presentViewController:alertController animated:YES completion:nil];
    }
        // 确认框
        //JavaScript调用confirm方法后回调的方法 confirm是js中的确定框,需要在block中把用户选择的情况传递进去
    - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
        [alertController addAction:([UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            completionHandler(NO);
        }])];
        [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completionHandler(YES);
        }])];
        [self presentViewController:alertController animated:YES completion:nil];
    }
        // 输入框
        //JavaScript调用prompt方法后回调的方法 prompt是js中的输入框 需要在block中把用户输入的信息传入
    - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
        [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
            textField.text = defaultText;
        }];
        [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completionHandler(alertController.textFields[0].text?:@"");
        }])];
        [self presentViewController:alertController animated:YES completion:nil];
    }
        // 页面是弹出窗口 _blank 处理
    - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
        if (!navigationAction.targetFrame.isMainFrame) {
            [webView loadRequest:navigationAction.request];
        }
        return nil;
    }
    

    WKWebView网页内容加载进度条和title的实现

    //添加监测网页加载进度的观察者
        [self.webView addObserver:self
                       forKeyPath:@"estimatedProgress"
                          options:0
                          context:nil];
       //添加监测网页标题title的观察者
        [self.webView addObserver:self
                       forKeyPath:@"title"
                          options:NSKeyValueObservingOptionNew
                          context:nil];
    
       //kvo 监听进度 必须实现此方法
    -(void)observeValueForKeyPath:(NSString *)keyPath
                         ofObject:(id)object
                           change:(NSDictionary<NSKeyValueChangeKey,id> *)change
                          context:(void *)context{
        if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))]
            && object == _webView) {
           NSLog(@"网页加载进度 = %f",_webView.estimatedProgress);
            self.progressView.progress = _webView.estimatedProgress;
            if (_webView.estimatedProgress >= 1.0f) {
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    self.progressView.progress = 0;
                });
            } 
        }else if([keyPath isEqualToString:@"title"]
                 && object == _webView){
            self.navigationItem.title = _webView.title;
        }else{
            [super observeValueForKeyPath:keyPath
                                 ofObject:object
                                   change:change
                                  context:context];
        }
    }
        //移除观察者
        [_webView removeObserver:self
                      forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
        [_webView removeObserver:self
                      forKeyPath:NSStringFromSelector(@selector(title))];
    

    WKWebView的JS和OC的交互

    这个实现主要是依靠WKScriptMessageHandler协议类和WKUserContentController两个类:WKUserContentController对象负责注册JS方法,设置处理接收JS方法的代理,代理遵守WKScriptMessageHandler,实现捕捉到JS消息的回调方法,详情可以看第一步中对这两个类的介绍。

     1)JS调用OC

     //这个类主要用来做native与JavaScript的交互管理
            WKUserContentController * wkUController = [[WKUserContentController alloc] init];
            //注册一个name为jsToOcNoPrams的js方法,设置处理接收JS方法的代理
            [wkUController addScriptMessageHandler:self  name:@"jsToOcNoPrams"];
            [wkUController addScriptMessageHandler:self  name:@"jsToOcWithPrams"];
            config.userContentController = wkUController;
    
    注意:遵守WKScriptMessageHandler协议,代理是由WKUserContentControl设置
     //通过接收JS传出消息的name进行捕捉的回调方法  js调OC
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
        NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);
    }
    

    2)OC调用JS

    //OC调用JS  changeColor()是JS方法名,completionHandler是异步回调block
        NSString *jsString = [NSString stringWithFormat:@"changeColor('%@')", @"Js参数"];
        [_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) {
            NSLog(@"改变HTML的背景色");
        }];
        
        //改变字体大小 调用原生JS方法
        NSString *jsFont = [NSString stringWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'", arc4random()%99 + 100];
        [_webView evaluateJavaScript:jsFont completionHandler:nil];
    

    参考:https://www.jianshu.com/p/5cf0d241ae12

     

    展开全文
  • UIWebView加载网页中进入后台崩溃 网页中使用了OpenGL ES绘制,根据Apple的要求,这个不能在后台绘制的(An OpenGL ES application will be terminated if it attempts to execute OpenGL ES commands in the ...
    1. UIWebView加载网页中进入后台崩溃
      网页中使用了OpenGL ES绘制,根据Apple的要求,这个不能在后台绘制的(An OpenGL ES application will be terminated if it attempts to execute OpenGL ES commands in the background.),解决方案:
    • 就是网页提供绘制开始和停止的接口供原生在进入后台和切换到前台时使用,但是我们使用的是其他厂家提供的链接,没有此接口。
    • 在前后台切换时,停止和重新加载UIWebView,调用stopLoading但是还是会在后台绘制,并不能停止OpenGL ES的绘制,所以排除此方法。
    • 改用WKWebView,因为这是Apple的bug,所以使用最新的API去替换,但是其他厂家提供的链接不支持WKWebView
    • Apple Forum中有开发者指出这是Apple的bug,并提供了解决方法,在进入后台时调用webView:enableGL方法设置为NO,进入前天后,调用webView:enableGL方法设置为YES
    #import <objc/runtime.h>
    
    
    typedef void (*CallFuc)(id, SEL, BOOL);
    typedef BOOL (*GetFuc)(id, SEL);
    -(BOOL)webView:(UIWebView*)view enableGL:(BOOL)bEnable
    {
      BOOL bRet = NO;
      do
      {
      Ivar internalVar = class_getInstanceVariable([view class], "_internal");
      if (!internalVar)
      {
      NSLog(@"enable GL _internal invalid!");
      break;
      }
       
      UIWebViewInternal* internalObj = object_getIvar(view, internalVar);
      Ivar browserVar = class_getInstanceVariable(object_getClass(internalObj), "browserView");
      if (!browserVar)
      {
      NSLog(@"enable GL browserView invalid!");
      break;
      }
       
      id webbrowser = object_getIvar(internalObj, browserVar);
      Ivar webViewVar = class_getInstanceVariable(object_getClass(webbrowser), "_webView");
      if (!webViewVar)
      {
      NSLog(@"enable GL _webView invalid!");
      break;
      }
       
      id webView = object_getIvar(webbrowser, webViewVar);
      if (!webView)
      {
      NSLog(@"enable GL webView obj nil!");
      }
       
      if(object_getClass(webView) != NSClassFromString(@"WebView"))
      {
      NSLog(@"enable GL webView not WebView!");
      break;
      }
       
      SEL selector = NSSelectorFromString(@"_setWebGLEnabled:");
      IMP impSet = [webView methodForSelector:selector];
      CallFuc func = (CallFuc)impSet;
      func(webView, selector, bEnable);
       
      SEL selectorGet = NSSelectorFromString(@"_webGLEnabled");
      IMP impGet = [webView methodForSelector:selectorGet];
      GetFuc funcGet = (GetFuc)impGet;
      BOOL val = funcGet(webView, selector);
       
      bRet = (val == bEnable);
       
      }while(NO);
       
      return bRet;
    }
    • 上一个方法中能解决一定概率的崩溃问题,但是不能从根本上解决,还是存在一定概率的崩溃,所以改用进入后台时,加载空白页面,移除UIWebView,清除delegate,销毁UIWebView。为什么还需要销毁呢?

    因为只加载空白页的话,回到前台在加载之前的URL,那么加载出来之后点击返回的时候,会多了一层空白页,而不是返回上一个视图

    参考地址:https://stackoverflow.com/questions/34891639/uiwebview-update-in-background-ive-got-a-exc-bad-access

    展开全文
  • 随说 : 最近有个需求,是将公司的一个内网的页面嵌套在app中作为一个模块.这不是很简单的webView请求一下就行了么?其实内里大有乾坤.自己也将思路整理一遍 ... UIWebView *webView = [[UIWebView al

    随说 : 最近有个需求,是将公司的一个内网的页面嵌套在app中作为一个模块.这不是很简单的webView请求一下就行了么?其实内里大有乾坤.自己也将思路整理一遍

    UIWebView

    UIWebView的基本使用方法 :

    就这样就已经整整个baidu的页面展示到app上
    下面我们看一下webView的属性与方法

        UIWebView *webView = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.view = webView;
        NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [webView loadRequest:request];

    UIWebView的层级结构 :


    UIWebView的类继承关系

    UIWebView的属性 :

    // 代理属性 重点需要知道代理方法的使用
    @property (nullable, nonatomic, assign) id <UIWebViewDelegate> delegate;
    
    // 这个是webView内部的scrollView 只读,但是利用这个属性,设置scrollView的代理,就可以控制整个webView的滚动事件
    @property(nonatomic, readonly, strong) UIScrollView *scrollView;
    
    // webView的请求,这个属性一般在整个加载完成后才能拿到
    @property (nullable, nonatomic, readonly, strong) NSURLRequest *request;
    
    // A Boolean value indicating whether the receiver can move backward. (read-only)
    // If YES, able to move backward; otherwise, NO.
    // 如果这个属性为YES,才能后退
    @property (nonatomic, readonly, getter=canGoBack) BOOL canGoBack;
    
    // A Boolean value indicating whether the receiver can move forward. (read-only)
    // If YES, able to move forward; otherwise, NO.
    // 如果这个属性为YES,才能前进
    @property (nonatomic, readonly, getter=canGoForward) BOOL canGoForward;
    
    // A Boolean value indicating whether the receiver is done loading content. (read-only)
    // If YES, the receiver is still loading content; otherwise, NO.
    // 这个属性很好用,如果为YES证明webView还在加载数据,所有数据加载完毕后,webView就会为No
    @property (nonatomic, readonly, getter=isLoading) BOOL loading;
    
    //A Boolean value determining whether the webpage scales to fit the view and the user can change the scale.
    //If YES, the webpage is scaled to fit and the user can zoom in and zoom out. If NO, user zooming is disabled. The default value is NO.
    // YES代表网页可以缩放,NO代表不可以缩放
    @property (nonatomic) BOOL scalesPageToFit;
    
    // 设置某些数据变为链接形式,这个枚举可以设置如电话号,地址,邮箱等转化为链接
    @property (nonatomic) UIDataDetectorTypes dataDetectorTypes NS_AVAILABLE_IOS(3_0);
    
    // iPhone Safari defaults to NO. iPad Safari defaults to YES
    // 设置是否使用内联播放器播放视频
    @property (nonatomic) BOOL allowsInlineMediaPlayback NS_AVAILABLE_IOS(4_0); 
    
    // iPhone and iPad Safari both default to YES
    // 设置视频是否自动播放
    @property (nonatomic) BOOL mediaPlaybackRequiresUserAction NS_AVAILABLE_IOS(4_0); 
    
    // iPhone and iPad Safari both default to YES
    // 设置音频播放是否支持ari play功能
    @property (nonatomic) BOOL mediaPlaybackAllowsAirPlay NS_AVAILABLE_IOS(5_0); 
    
    // iPhone and iPad Safari both default to NO
    // 设置是否将数据加载入内存后渲染界面
    @property (nonatomic) BOOL suppressesIncrementalRendering NS_AVAILABLE_IOS(6_0); 
    
    // default is YES
    // 设置用户是否能打开keyboard交互
    @property (nonatomic) BOOL keyboardDisplayRequiresUserAction NS_AVAILABLE_IOS(6_0); 
    
    /* IOS7 */ 以后的新特性
    // 这个属性用来设置一种模式,当网页的大小超出view时,将网页以翻页的效果展示,枚举如下:
    @property (nonatomic) UIWebPaginationMode paginationMode NS_AVAILABLE_IOS(7_0);
    typedef NS_ENUM(NSInteger, UIWebPaginationMode) { 
    UIWebPaginationModeUnpaginated, //不使用翻页效果 
    UIWebPaginationModeLeftToRight, //将网页超出部分分页,从左向右进行翻页 
    UIWebPaginationModeTopToBottom, //将网页超出部分分页,从上向下进行翻页 
    UIWebPaginationModeBottomToTop, //将网页超出部分分页,从下向上进行翻页 
    UIWebPaginationModeRightToLeft //将网页超出部分分页,从右向左进行翻页 
    };
    
    // This property determines whether certain CSS properties regarding column- and page-breaking are honored or ignored. 
    // 这个属性决定CSS的属性分页是可用还是忽略。默认是UIWebPaginationBreakingModePage 
    @property (nonatomic) UIWebPaginationBreakingMode paginationBreakingMode NS_AVAILABLE_IOS(7_0);
    
    // 设置每一页的长度
    @property (nonatomic) CGFloat pageLength NS_AVAILABLE_IOS(7_0);
    
    // 设置每一页的间距
    @property (nonatomic) CGFloat gapBetweenPages NS_AVAILABLE_IOS(7_0);
    
    // 获取页数
    @property (nonatomic, readonly) NSUInteger pageCount NS_AVAILABLE_IOS(7_0);

    还有一些属性请详细翻苹果文档

    UIWebView的代理方法 :

    UIWebView的代理方法是用的最多的方法,并且一般来说,相对Web页面作处理都在这相应的4个方法中
    分别解释一下方法的调用情况

        // Sent before a web view begins loading a frame.请求发送前都会调用该方法,返回NO则不处理这个请求
        - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
    
        // Sent after a web view starts loading a frame. 请求发送之后开始接收响应之前会调用这个方法
        - (void)webViewDidStartLoad:(UIWebView *)webView;
    
        // Sent after a web view finishes loading a frame. 请求发送之后,并且服务器已经返回响应之后调用该方法
        - (void)webViewDidFinishLoad:(UIWebView *)webView;
    
        // Sent if a web view failed to load a frame. 网页请求失败则会调用该方法
        - (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error;

    UIWebView的对象方法

    // 加载Data数据创建一个webView
    - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL
    
    // 加载本地HTML创建一个webView
    - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
    
    // 加载一个请求创建一个webView
    - (void)loadRequest:(NSURLRequest *)request
    
    // 刷新网页
    - (void)reload;
    
    // 停止网页加载内容
    - (void)stopLoading;
    
    // 后退
    - (void)goBack;
    
    // 前进
    - (void)goForward;
    
    // 执行JS方法
    - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script






    WKWebView

    WKWebView的简介 :

    从文档中可以看到,这个是IOS8之后新增的一个类,也是苹果推崇的一个新的类


    WKWebView的类层级结构

    WKWebView的基本使用方法 :

    其实和UIWebView的用法没什么区别
    但是WKWebView相对于UIWebView强大了很多,内存的消耗相对少了,所提供的接口也丰富了。
    推荐使用
    多了一部操作就是需要包含webkit框架
    @import webkit

        WKWebView *webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.view = webView;
        NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [webView loadRequest:request];

    WKWebView的属性 :

    // UIWebView 中会自动保存Cookie,如果登录了一次下次再次进入的时候,会记住登录状态
    // 在WKWebView中,新增一个configuration属性,  configuration 让WKWebView知道登录状态,
    // configuration 可以通过已有的Cookie进行设置,也可以通过保存上一次的configuration进行设置
    // WKWebViewConfiguration类中也有一些相应的属性
    @property (nonatomic, readonly, copy) WKWebViewConfiguration *configuration;
    
    // The methods of the WKNavigationDelegate protocol help you track the progress of the web site's main frame navigations and decide load policy for main frame and subframe navigations.
    // WKWebView中,加入了网站导航的概念,这个对象决定主框架导航加载方法协议。
    @property (nullable, nonatomic, weak) id <WKNavigationDelegate> navigationDelegate;
    
    // The WKUIDelegate class provides methods for presenting native user interface 
    elements on behalf of a webpage.
    // WKWebView中,加入了网站窗口的概念,这个对象决了webView窗口的一些方法协议。
    @property (nullable, nonatomic, weak) id <WKUIDelegate> UIDelegate;
    
    A WKBackForwardList object is a list of webpages previously visited in a web view that can be reached by going back or forward.
    // WKWebView中,加入了网站列表的概念,这个WEBBackForwardList对象是以前在Web视图访问的网页,可以通过去后退或前进
    @property (nonatomic, readonly, strong) WKBackForwardList *backForwardList;

    还有很多方法,同样可以查文档看到

    WKWebView的代理方法 :

    有一些方法和UIWebView是基本一直的,但是因为返回了navigation,所能用到的属性多了很多,另外多了一些方法,将请求与相应的整个过程

    - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{
        NSLog(@"webViewWebContentProcessDidTerminate:  当Web视图的网页内容被终止时调用。");
    }
    
    
    - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
    {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        NSLog(@"webView:didFinishNavigation:  响应渲染完成后调用该方法   webView : %@  -- navigation : %@  \n\n",webView,navigation);
    }
    
    
    - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation
    {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
        NSLog(@"webView:didStartProvisionalNavigation:  开始请求  \n\n");
    }
    
    - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
        NSLog(@"webView:didCommitNavigation:   响应的内容到达主页面的时候响应,刚准备开始渲染页面应用 \n\n");
    }
    
    
    // error
    - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
        // 类似 UIWebView 的- webView:didFailLoadWithError:
    
        NSLog(@"webView:didFailProvisionalNavigation:withError: 启动时加载数据发生错误就会调用这个方法。  \n\n");
    }
    
    
    
    - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{
        NSLog(@"webView:didFailNavigation: 当一个正在提交的页面在跳转过程中出现错误时调用这个方法。  \n\n");
    }
    
    
    
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    
        NSLog(@"请求前会先进入这个方法  webView:decidePolicyForNavigationActiondecisionHandler: %@   \n\n  ",navigationAction.request);
    
        decisionHandler(WKNavigationActionPolicyAllow);
    
    }
    
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    
        NSLog(@"返回响应前先会调用这个方法  并且已经能接收到响应webView:decidePolicyForNavigationResponse:decisionHandler: Response?%@  \n\n",navigationResponse.response);
    
        decisionHandler(WKNavigationResponsePolicyAllow);
    }
    
    
    
    - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
    
        NSLog(@"webView:didReceiveServerRedirectForProvisionalNavigation: 重定向的时候就会调用  \n\n");
    }

    WKWebView的对象方法 :

    这些方法,基本上和UIWebView中的使用用法是一致的,所以

    // 这是加载网页最常用的一种方式,通过一个网页URL来加载一个WKWebView,这个URL可以是远程的也可以是本地的,例如我加载百度的主页
    - (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
    
    // 根据一个文件,加载一个WKWebView
    - (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL NS_AVAILABLE(10_11, 9_0);
    
    // 这个方法需要将html文件读取为字符串从而加载为WKWebView,其中baseURL是我们自己设置的一个路径,用于寻找html文件中引用的图片等素材。
    - (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
    
    // 这个方式使用的比较少,但也更加自由,其中data是文件数据,MIMEType是文件类型,characterEncodingName是编码类型,baseURL是素材资源路径
    - (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL NS_AVAILABLE(10_11, 9_0);

    基本使用

    下面会总结一些我在开发过程中遇到的坑,和解决问题的一些思路,不过在此之前我发现,如果要webView玩得好,有以下几点的只是也需要掌握好,因为我认为在H5崛起的今天,源生App和H5的交互之间会产生比较大改变,而且源生与H5之间的混编,越来越被重视.所以 :

    1. 源生技术,特别是有关于webView这一块的API要非常熟练,
    2. js语法, js的语法需要熟练,特别是操作document的几个常用js,标签需要用得滚瓜烂熟.
    3. 要非常了解网络请求 - 响应的机制,理解请求头,响应头,等等.HTTP的整套协议

    需求一 : 展示一个网页,但是需要隐藏一部分页面

    首先看看百度的页面,这是用Chrome浏览器打开的开发者模式
    基本界面组成如下,基本使用用法请详情百度,这里不作介绍


    假设现在想将这个Logo由网页开始加载就去掉


    百度的logo就是一个div套着一个image标签


    - (void)webViewDidFinishLoad:(UIWebView *)webView
    {
        // 在HTML标签都加载完成后,开始处理HTML标签,调用JS,操作document
        [webView stringByEvaluatingJavaScriptFromString:@"document.getElementById('plus-card').remove();"];
    }

    就这样, logo标签就被去掉了,思路就是等HTML加载完成后,操作JS从而操作document标签从而改变整个html页面的应用,下图是去掉整个Body主题内容后的结果


    另外还可以将一段函数封装到里面,执行函数,原理是通过stringByEvaluatingJavaScriptFromString将JS函数写进head标签中,然后再调用该函数

    // 自定义editMyLogo函数
    [webView stringByEvaluatingJavaScriptFromString:@"var script = document.createElement('script');"
         "script.type = 'text/javascript';"
         "script.text = \"function editMyLogo() { "
         "var logo = document.getElementById('logo');"
         "logo.innerHTML= logo.innerHTML + '这是我自己定义的名字';"
         "var imglist = logo.getElementsByTagName('IMG');"
         "for (i=0 ; i < imglist.length ; i++ ){"
         "imglist[i].src = 'http://pic.to8to.com/attch/day_160218/20160218_d968438a2434b62ba59dH7q5KEzTS6OH.png';"
         "}"
         "}\";"
         "document.getElementsByTagName('head')[0].appendChild(script);"];
    
        // 执行editMyLogo函数
        [webView stringByEvaluatingJavaScriptFromString:@"editMyLogo();"];

    效果如下 :


    有几点问题,这种操作是在webViewDidFinishLoad方法下进行的,webViewDidFinishLoad方法是webView的document已经渲染好后,再去处理这个这个页面.

    1. 你会发现有时候会出现一些闪屏现象,原因是渲染过后,内部处理JS代码后,页面会再渲染一次
    2. 资源浪费,假设这边的需求只需要显示10%的内容,却要加载100%的内容,不过这一方面还需要网页端作出很好的适配
    3. 某些时候,JS会失效,不知道什么原因,有些时候自定义加载的JS的方法并没有执行到.等于内容并没有屏蔽
    4. 等等..

    需求二 : 怎样处理403,404的情况 ?


    @property (nonatomic, assign) BOOL isPost; // 定义一个变量
    
    // 每一个请求开始发送前都会调用这个方法
    // 1, 定义一个全局变量currentRequest,用作保存当前的请求
    // 2, 将请求转换成data,然后处理data再将data作为请求数据再次请求
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    
        if (!_isPost) {
            NSHTTPURLResponse *response = nil;
            NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
            if (response.statusCode == 404) {
                // 这里处理 404 代码
            } else if (response.statusCode == 403) {
                // 这里处理 403 代码
            } else {
    
                _isPost = true;
                [webView loadData:data MIMEType:@"text/html" textEncodingName:@"NSUTF8StringEncoding" baseURL:[request URL]];
    
            }
            return NO;
        }else{
            NSLog(@"\n\n shouldStartLoadWithRequest请求准备 --  %@ \n\n ",request);
            _isPost = NO;
            return YES;
        }
    }

    需求一 : 进一步改进


    在处理HTML这里,将你想隐藏的页面,加上 display:none 属性,
    或者,将整段HTML标签去掉.




    展开全文
  • UIWebView到WKWebView

    千次阅读 2017-05-25 17:27:43
    8.0之前都是UIWebView,以后苹果官方鼓励用WKWebView,本人建议也是用WKWebView,因为除了功能更加强大,性能和内存都会好很多,网上也有兼容两者的三方比如IMYWebView等。1.UIWebView:@interface ...
  • WKWebView相对UIWebView的优劣势

    千次阅读 2018-08-01 17:28:44
    在开发过程中,iOS 中实现加载 web 页面主要有两种控件,UIWebView 和 WKWebview,两种控件对应具体的实现方法不同。WKWebView 是苹果在iOS 8中引入的新组件,目的是提供一个现代的支持最新Webkit功能的网页浏览控件...
  • UIWebView

    2019-06-20 05:49:13
    UIWebView 控件是做网络应用开发时使用的最多的一个控件,它实现了内置的浏览器(类似于 Safari),并且 UIWebView 继承自 UIView,可以将其像其它控件一样应用到需要的位置。 优点:简单,快速。 缺点:内存消耗大...
  • iOS开发 检测项目中是否包含UIWebView

    万次阅读 2020-04-26 09:12:58
    ITMS-90809: Deprecated API Usage - Apple will stop accepting submissions of apps that use UIWebView APIs . Seehttps://developer.apple.com/documentation/uikit/uiwebviewfor more information. 自从2020...
  • iOS 检测UIWebView还是否存在

    千次阅读 2020-05-09 17:47:14
    3.如果觉得终端不好看可以输入下面命令生成一个txt文本搜索关键词UIWebView看哪个隐藏的或者第三方还存在 grep -r UIWebView . >> xxx.txt 4这个会在你项目中出现一个t x t文件打开搜索 Binary file ./...
  • 现在工程属于电商类APP,混合开发,缓存出现问题,在网上找了demo,吧URL换成 我工程的URL后离线加载不了缓存数据,页面直接就是白屏,在网上也找方法了,还是不行!请问这是为什么,大神们
  • 苹果2020年4月份停止接受使用UIWebview api 的app 第一步 全局搜索UIWebview ,将相关代码删除或者替换 但是第一步不能检测到.a 文件或者一些没有添加到项目目录中的文件中是否使用UIWebview api 现在就需要第二步...
  • UIWebView 无缝切换到 WKWebView

    万次阅读 2015-07-09 10:17:49
    优点: 加载速度 比UIWebView提升差不多一倍的, 内存使用上面,反而还少了一半。  缺点: WKWebView 不支持缓存 和 NSURLProtocol 拦截了 我建议如果对缓存不高的页面可以使用,用户体验会提高很多。 由于项目...
  • ITMS-90809: Deprecated API Usage - Apple will stop accepting submissions of apps that use UIWebView APIs . See https://developer.apple.com/documentation/uikit/uiwebview for more information. 官方...
  • UIWebView获取网页的标题

    万次阅读 2011-11-24 20:45:48
    第一种办法: 直接解析请求到的网页的... 第二种办法: ...- (void)webViewDidFinishLoad:(UIWebView *)webView {  titleLabel.text = [webView stringByEvaluatingJavaScriptFromString:@"document.title"]; }
  • 修改UIWebView中字体的大小

    万次阅读 2014-04-11 14:16:26
    1、UIWebView设置字体大小,颜色,字体:1、UIWebView设置字体大小,颜色,字体: UIWebView无法通过自身的属性设置字体的一些属性,只能通过html代码进行设置,代码如下:UIWebView无法通过自身的属性设置字体的...
  • iOS 查找工程内UIWebView

    千次阅读 2020-05-07 19:30:55
    自从2020年5月1号,苹果强制要求使用xcode11,废弃UIWebView,最近提审包收到邮件说有UIWebView,要求更换掉才能提。 5月1号前都是警告⚠️说UiWebView需要更新成wk,现在强制要改了,生成不了构建版本,工程是...
  • ITMS-90809: Deprecated API Usage - New apps that use UIWebView are no longer accepted. Instead, use WKWebView for improved security and reliability. Learn more ...
  • UIWebView缓存基础知识

    万次阅读 2014-06-12 19:44:59
    第一. NSURLRequest的缓存设置 - (id)initWithURL:(NSURL *)URL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval; cachePolicy表示缓存策略 ...
  • [绍棠] 去除AFNetWorking中UIWebView分类

    千次阅读 2020-04-01 13:04:57
    从2020年4月开始,苹果将停止接受使用UIWebView API的应用,打包的时候会给一个这样的提示:ITMS-90809: Deprecated API Usage** - Apple will stop accepting submissions of new apps that use UIWebView APIs ...
  • iTunesConnect吃包 因为ipa包中包含uiwebview 5月1号以后iTunesConnect不允许上传的ipa包中屌用UIWebView,使用过后上传的ipa包都不会显示在活动里(我称呼这种骚操作为‘吃包’)。 已经把项目工程里面的有关...
1 2 3 4 5 ... 20
收藏数 19,682
精华内容 7,872
关键字:

uiwebview