uiwebview_uiwebview适配ios13 - 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

     

    展开全文
  • 前两天我写了一套关于JS与OC交互的三种方法的文章,但是发现自己对UIWebView理解的还是比较浅,一直认为只能简单的当一个webView来使用,具体很多细节都忽略,如果想看我之前UIWebView的JS交互,请点击下面的连接 ...


    前两天我写了一套关于JS与OC交互的三种方法的文章,但是发现自己对UIWebView理解的还是比较浅,一直认为只能简单的当一个webView来使用,具体很多细节都忽略,如果想看我之前UIWebView的JS交互,请点击下面的连接

    开始今天的内容吧,事不宜迟

    一、UIWebView的基础使用

    - (void)viewDidLoad {
        [super viewDidLoad];
        //    1、创建UIWebView:
    
        CGRect bouds = [UIScreen mainScreen].bounds;
        UIWebView* webView = [[UIWebView alloc]initWithFrame:bouds];
    
        //    2、加载在线资源http内容
    
        NSURL* url = [NSURL URLWithString:@"http://www.baidu.com"];//创建URL
        NSURLRequest* request = [NSURLRequest requestWithURL:url];//创建
        [webView loadRequest:request];//加载
    
        //    2、 加载本地文件的方法:
    
        /**
         *
         //第一种方法:
    
         NSString* path = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];//mobile是根目录,name是文件名称,html是文件类型
         [webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]]; //加载本地文件
    
    
         //第二种方法:
    
         NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
    
         NSString *filePath = [resourcePath stringByAppendingPathComponent:@"mobile.html"];
    
         NSString *htmlstring=[[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    
         [webView loadHTMLString:htmlstring baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
    
         */
    
        //    3、导航
    
        //    UIWebView类内部会管理浏览器的导航动作,通过goForward和goBack方法你可以控制前进与后退动作:
    
        [webView goBack];
        [webView goForward];
    
        //    4、UIWebViewDelegate委托代理
    
        webView.delegate = self;
    
        //    5、显示网页视图UIWebView:
    
        [self.view addSubview:webView];
    }
    
    # pragma mark - UIWebView 的代理方法
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;//当网页视图被指示载入内容而得到通知。应当返回YES,这样会进行加载
    - (void)webViewDidStartLoad:(UIWebView *)webView { //当网页视图已经开始加载一个请求后,得到通知。
        //    [webView stopLoading];//取消载入内容
    }
    - (void)webViewDidFinishLoad:(UIWebView *)webView;//当网页视图结束加载一个请求之后,得到通知。
    - (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error {
        //    [webView reload];//重载
    }//当在请求加载中发生错误时,得到通知。会提供一个NSSError对象,以标识所发生错误类型。

    以上是IOS中UIWebView的基础使用要点详解,接下来一些UIWebView的常用注意点算是比较细节的部分。


    二、IOS中UIWebView常用注意点:
    1、与UIWebView进行交互,调用web页面中的需要传参的函数时,参数需要带单引号,或者双引号(双引号要进行转义在转义字符前加\),传递json字符串时不需要加单引号或双引号:

    -(void)webViewDidFinishLoad:(UIWebView *)webView
    
    {
        NSString *sendJsStr=[NSString stringWithFormat:@"openFile(\"%@\")", jsDocPathStr];
        [webView stringByEvaluatingJavaScriptFromString:sendJsStr];
    
    }

    2、在该代理方法中判断与webView的交互,可通过html里定义的协议实现:

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

    3、只有在webView加载完毕之后在能够调用对应页面中的js方法。(对应方法如第1条).详情请参考我另外一文章: [JS交互含Demo](http://www.jianshu.com/p/5c2b5d4952c9)

    4、为webView添加背景图片:

    webView.backgroundColor=[UIColor clearColor];
    //这句话很重要,webView是否是不透明的,no为透明 在webView下添加个imageView展示图片就可以了
    webView.opaque=NO;

    5、获取webView页面内容信息:

    NSString *docStr=[webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.textContent"];
    //获取web页面内容信息,此处获取的是个son字符串
    
    SBJsonParser *parserJson=[[[SBJsonParser alloc]init]autorelease];
    
    NSDictionary *contentDic=[parserJson objectWithString:docStr];
    //将json字符串转化为字典

    6、将文件下载到本地址然后再用webView打开(打开HTML5):

    NSString *path = [[[[NSBundle mainBundle] resourcePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"Documents"];
    NSString *resourceDocPath = [[NSString alloc] initWithString:path];
    
    self.filePath = [resourceDocPath stringByAppendingPathComponent:[NSString stringWithFormat:@"maydoc%@",docType]];
    
    NSData *attachmentData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:theUrl]];
    [attachmentData writeToFile:filePath atomically:YES];
    
    NSURL *url = [NSURL fileURLWithPath:filePath];
    NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
    
    [attachmentWebView loadRequest:requestObj];
    //删除指定目录下的文件
    
    NSFileManager *magngerDoc=[NSFileManager defaultManager];
    
    [magngerDoc removeItemAtPath:filePath error:nil];

    8、处理webView展示txt文档乱码问题:

    if ([theType isEqualToString:@".txt"]) {
    
        //txt分带编码和不带编码两种,带编码的如UTF-8格式txt,不带编码的如ANSI格式txt
    
        //不带的,可以依次尝试GBK和GB18030编码
    
        NSString* aStr = [[NSString alloc] initWithData:attachmentData encoding:NSUTF8StringEncoding];
        if (!aStr)
        {
    
            //用GBK进行编码
            aStr=[[NSString alloc] initWithData:attachmentData encoding:0x80000632];
    
        }
    
        if (!aStr)
        {
    
            //用GBK编码不行,再用GB18030编码
            aStr=[[NSString alloc] initWithData:attachmentData encoding:0x80000631];
    
        }
    
        //通过html语言进行排版
    
        NSString* responseStr = [NSString stringWithFormat:
                                 @"%@",aStr];
        [attachmentWebView loadHTMLString:responseStr baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
    
        return;
    }

    9、使用webView加载本地或网络文件整个流程:

    9.1、Loading a local PDF file into the web view

    - (void)viewDidLoad {
    
        [super viewDidLoad];
    
        //从本地加载
    
        NSString *thePath = [[NSBundle mainBundle] pathForResource:@"iPhone_User_Guide" ofType:@"pdf"];
    
        if (thePath) {
    
            NSData *pdfData = [NSData dataWithContentsOfFile:thePath];
    
            [(UIWebView *)self.view loadData:pdfData MIMEType:@"application/pdf"
    
                            textEncodingName:@"utf-8" baseURL:nil];
    
        }
        //从网络加载
    
        [self.myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.apple.com/"]]];
    
    }

    9.2、The web-view delegate managing network loading

    - (void)webViewDidStartLoad:(UIWebView *)webView
    
    {
    
        // starting the load, show the activity indicator in the status bar
    
        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    
    }
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView
    
    {
    
        // finished loading, hide the activity indicator in the status bar
    
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    
    }
    
    - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
    
    {
    
        // load error, hide the activity indicator in the status bar
    
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    
        // report the error inside the webview
    
        NSString* errorString = [NSString stringWithFormat:@"An error occurred:%@",error.localizedDescription];
        [self.myWebView loadHTMLString:errorString baseURL:nil];
    
    }

    9.3、Stopping a load request when the web view is to disappear

    - (void)viewWillDisappear:(BOOL)animated {
    
        if ( [self.myWebView loading] ) {
    
            [self.myWebView stopLoading];
    
        }
    
        self.myWebView.delegate = nil;    // disconnect the delegate as the webview is hidden
    
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    
    }

    10、查找webView中的scrollview:

    - (void) addScrollViewListener {
    
        UIScrollView* currentScrollView;
    
        for (UIView* subView in self.webView.subviews) {
    
            if ([subView isKindOfClass:[UIScrollView class]]) {
    
                currentScrollView = (UIScrollView*)subView;
    
                currentScrollView.delegate = self;
    
            }
    
        }

    11、去掉webView的阴影,做成类似scrollView:

    - (void)clearBackgroundWithColor:(UIColor*)color {
        // 去掉webview的阴影
        self.backgroundColor = color;
        for (UIView* subView in [self subviews])
        {
            if ([subView isKindOfClass:[UIScrollView class]]) {
                for (UIView* shadowView in [subView subviews])
                {
                    if ([shadowView isKindOfClass:[UIImageView class]]) {
                        [shadowView setHidden:YES];
                    }
                }
            }
        }
    }

    12、取消长按webView上的链接弹出actionSheet的问题:

    -(void)webViewDidFinishLoad:(UIWebView *)webView {
        [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout = 'none';"];
    }

    13、取消webView上的超级链接加载问题:

    -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
        if (navigationType==UIWebViewNavigationTypeLinkClicked) {
            return NO;
        } else {
            return YES;
        }
    }

    14、在使用webView进行新浪微博分享时,webView会自动保存登陆的cookie导致项目中的分享模块有些问题,删除 webView的cookie的方法:

    -(void)deleteCookieForDominPathStr:(NSString *)thePath
    
    {
        //删除本地cookie,thePath为cookie路径通过打印cookie可知道其路径
    
        for(NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
    
            if([[cookie domain] isEqualToString:thePath]) {
    
                [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
    
            }
    
        }
    
    }

    15、在UIWebView中使用flashScrollIndicators

    使用UIScrollView时,我们可以使用flashScrollIndicators方法显示滚动标识然后消失,告知用户此页面可以滚动,后面还有更多内容。UIWebView内部依赖于UIScrollView,但是其没有flashScrollIndicators方法,但可以通过其他途径使用此方法,如下所示。

    for (id subView in [webView subviews]){
    
        if ([subView respondsToSelector:@selector(flashScrollIndicators)]){
            [subView flashScrollIndicators];
        }
    }

    上述代码片段可以到webViewDidFinishLoad回调中使用,加载完网页内容后flash显示滚动标识。

    16、根据内容获取UIWebView的高度:

    有时候需要根据不同的内容调整UIWebView的高度,以使UIWebView刚好装下所有内容,不用拖动,后面也不会留白。有两种方式可根据加载内容获取UIWebView的合适高度,但都需要在网页内容加载完成后才可以,即需要在webViewDidFinishLoad回调中使用

    ①.使用sizeThatFits方法。

    - (void)webViewDidFinishLoad:(UIWebView *)webView
    
    {
    
        CGRect frame = webView.frame;
    
        frame.size.height = 1;
    
        webView.frame = frame;
    
        CGSize fittingSize = [webView sizeThatFits:CGSizeZero];
    
        frame.size = fittingSize;
    
        webView.frame = frame;
    
    }

    sizeThatFits方法有个问题,如果当前UIView的大小比刚好合适的大小还大,则返回当前的大小,不会返回最合适的大小值,所以使用sizeThatFits前,先将UIWebView的高度设为最小,即1,然后再使用sizeThatFits就会返回刚好合适的大小。

    ②、使用JavaScript

    - (void)webViewDidFinishLoad:(UIWebView *)webView
    
    {
        CGRect frame = webView.frame;
    
        NSString *fitHeight = [webview stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"];
    
        frame.size.height = [fitHeight floatValue];
    
        webView.frame = frame;
    }

    总结:

    首先 对IOS开发中的UIWebView控件的基本使用进行初步的详解,提到了创建、设置属性、设置背景、怎么样加载网页内容等一系列的基础点,然后阐述使用UIWebView控件时常用用注意点,经常需要用到的地方,需要注意的地方,使得对开发ios APP混合模式的桥梁---UIWebView控件更加的了解、熟悉。UIWebView既能够加载服务器提供的URI,又能够加载本地的资源文件,还能够加载服务器返回的网页界面代码,可想而知UIWebView是多么强大的一控件桥梁,以后在开发中使用到的地方会越来越多。

    展开全文
  • 随说 : 最近有个需求,是将公司的一个内网的页面嵌套在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

    2020-05-10 09:47:54
    什么是UIWebView UIWebView是iOS内置的浏览器控件 系统自带的Safari浏览器就是通过UIWebView实现的 UIWebView不但能加载远程的网页资源,还能加载绝大部分的常见文件 html\htm pdf,doc,ppt,txt mp4 UIWebView...
  • UIWebView体系结构(六)UIWebView

    千次阅读 2013-06-06 12:23:32
    UIWebView的实际成员变量都由UIWebViewInternal保存,UIWebViewInternal的声明如下: @interface UIWebViewInternal : NSObject { UIScrollView *scroller; UIWebBrowserView *browserView; ...
  • 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...
  • 现在工程属于电商类APP,混合开发,缓存出现问题,在网上找了demo,吧URL换成 我工程的URL后离线加载不了缓存数据,页面直接就是白屏,在网上也找方法了,还是不行!请问这是为什么,大神们
  • iOS 检测UIWebView还是否存在

    千次阅读 2020-05-09 17:47:14
    3.如果觉得终端不好看可以输入下面命令生成一个txt文本搜索关键词UIWebView看哪个隐藏的或者第三方还存在 grep -r UIWebView . >> xxx.txt 4这个会在你项目中出现一个t x t文件打开搜索 Binary file ./...
  • iOS 获取UIWebView上面的按钮点击事件

    万次阅读 2014-06-06 15:27:13
    在网上看到很多文章都说iOS的UIWebView比较耗内存,在我的项目中,最开始我也是用UIWebView来加载网页的。刚开始加载的是自己拼接成的Html,后来在Html中加入一个按钮,点击之后用当前的UIWebView去加载网络上的网页...
  • iOS UIWebView上架被拒完全解法办法

    千次阅读 2020-05-19 21:26:02
    一下子看到重点提示是UIWebView被弃用了,我们使用了被弃用的API,那么问题来了,怎么彻底清除项目中的UIWebView的代码呢?这就是接下来我要分享给大家的内容。 正文 首先,正常操作就是全局搜索UIWebView,将使用...
  • iOS 查找工程内UIWebView

    千次阅读 2020-05-07 19:30:55
    自从2020年5月1号,苹果强制要求使用xcode11,废弃UIWebView,最近提审包收到邮件说有UIWebView,要求更换掉才能提。 5月1号前都是警告⚠️说UiWebView需要更新成wk,现在强制要改了,生成不了构建版本,工程是...
  • iOS之UIWebView图文混排技术

    千次阅读 2019-03-07 11:30:17
    摘要今天小编跟我讲,有一个同学要利用UIWebView进行图文混排,其实图文混排的几种方式,我在之前的博客里面已经讲过,在这里就不再讲述了,如果大家需要看,请参考之前的那篇博文 iOS中不同形式的图文混排技术的实现总结...
  • IOS开发中因为引入cocos2dx,导致代码审核不通过无法提交( Apple will stop accepting submissions of apps that use UIWebView APIs )。该问题的解决方案有两种:1)升级Cocos2dx的版本,在查看Cocoas官网及Cocoas...
  • 苹果禁止使用UIWebView应用上架,这里面包含两层含义和两个时间点 时间点: 2020.4 和 2020.12 含义: 新应用的IPA 和 应用升级IPA 解读: 2020年4月30日之后(也就是五月份之前), 禁止新应用使用UIWebView 2020年12月30...
  • iOS开发之WKWebView代替UIWebView

    千次阅读 2019-06-24 11:18:40
    前言 Xcode8发布以后,编译器开始不支持IOS7,...支持到IOS8,第一个要改的自然是用WKWebView替换原来的UIWebView。WKWebView有很多明显优势: 更多的支持HTML5的特性 官方宣称的高达60fps的滚动刷新率以...
  • UIWebview 禁止点击事件

    千次阅读 2016-06-24 16:29:15
    用的UIWebView 来load联通的登录网址。 在登录界面我们就会发现有许多点击事件,但是我不想用操作这些点击事件,只想让他点击“登录按钮即可”,如下图所示: 这个时候怎么我们可以在UIWebview的代理方法里面进行...
  • IOS已经废弃了UIWebView接口,改用WKwebview。如果项目中使用了UIWebView将在审核失败,并提示ITMS-90809. 如何解决: 打开mac终端,cd到导出的Xcode路径处。 复制grep -r UIWebView . 回车。 便可查看工程中引用...
  • iOS13发布了,据说苹果开始拒绝使用UIWebView的api应用了。 有点慌,由于项目自17年开始就一直用的UIWebView,但UIWebView性能实在是太差了,进几个网页内存就飙升,并且退出页面VC销毁了但内存还无法降下来,首次...
  • 开发App的过程中,常常会遇到在App内部加载网页,通常用UIWebView加载。这个自iOS2开始使用的网页加载器一直是开发的心病:加载速度慢,占用内存多,优化困难。如果加载网页多,还可能因为过量占用内存而给系统kill...
1 2 3 4 5 ... 20
收藏数 19,674
精华内容 7,869
关键字:

uiwebview