uiwebview_uiwebviewdelegate - CSDN
  • UIWebView

    2019-06-25 20:15:30
    UIWebView *view = [[UIWebView alloc] initWithFrame:kScreenBounds]; [view setUserInteractionEnabled:YES]; [view setScalesPageToFit:YES]; [self.view addSubview:view]; ...

            UIWebView *view = [[UIWebView alloc] initWithFrame:kScreenBounds];

            [view setUserInteractionEnabled:YES];

            [view setScalesPageToFit:YES];

            [self.view addSubview:view];

            

            NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];

            [view loadRequest:[NSURLRequest requestWithURL:url]];

     

     

    //2.加载本地文件资源
       /* NSURL *url = [NSURL fileURLWithPath:filePath];
      NSURLRequest *request = [NSURLRequest requestWithURL:url];
      [webView loadRequest:request];*/
      //3.读入一个HTML,直接写入一个HTML代码
      //NSString *htmlPath = [[[NSBundle mainBundle]bundlePath]stringByAppendingString:@"webapp/loadar.html"];
      //NSString *htmlString = [NSString stringWithContentsOfURL:htmlPath encoding:NSUTF8StringEncoding error:NULL];
      //[webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:htmlPath]];
      
      opaqueView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
      activityIndicatorView = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
      [activityIndicatorView setCenter:opaqueView.center];
      [activityIndicatorView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhite];
      [opaqueView setBackgroundColor:[UIColor blackColor]];
      [opaqueView setAlpha:0.6];
      [self.view addSubview:opaqueView];
      [opaqueView addSubview:activityIndicatorView];

    转载于:https://www.cnblogs.com/tom2015010203/p/5358653.html

    展开全文
  • 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的实际成员变量都由UIWebViewInternal保存,UIWebViewInternal的声明如下: @interface UIWebViewInternal : NSObject { UIScrollView *scroller; UIWebBrowserView *browserView; ...

    UIWebView的实际成员变量都由UIWebViewInternal保存,UIWebViewInternal的声明如下:

    @interface UIWebViewInternal : NSObject
    {
        UIScrollView *scroller;
        UIWebBrowserView *browserView;
        UICheckeredPatternView *checkeredPatternView;
        id <UIWebViewDelegate> delegate;
        unsigned int scalesPageToFit:1;
        unsigned int isLoading:1;
        unsigned int hasOverriddenOrientationChangeEventHandling:1;
        unsigned int drawsCheckeredPattern:1;
        unsigned int webSelectionEnabled:1;
        unsigned int drawInWebThread:1;
        unsigned int inRotation:1;
        NSURLRequest *request;
        int clickedAlertButtonIndex;
        UIWebViewWebViewDelegate *webViewDelegate;
        UIWebPDFViewHandler *pdfHandler;
    }
    
    @end
    其中scroller指向_UIWebViewScrollView的实例。

    UIWebViewWebViewDelegate的声明为:(代码很长,点此跳过)

    @interface UIWebViewWebViewDelegate : NSObject
    {
        UIWebView *uiWebView;
    }
    
    - (void)_clearUIWebView;
    - (void)webView:(id)arg1 didChangeLocationWithinPageForFrame:(id)arg2;
    - (BOOL)webView:(id)arg1 resource:(id)arg2 canAuthenticateAgainstProtectionSpace:(id)arg3 forDataSource:(id)arg4;
    - (void)webView:(id)arg1 resource:(id)arg2 didCancelAuthenticationChallenge:(id)arg3 fromDataSource:(id)arg4;
    - (void)webView:(id)arg1 resource:(id)arg2 didReceiveAuthenticationChallenge:(id)arg3 fromDataSource:(id)arg4;
    - (void)webView:(id)arg1 resource:(id)arg2 didFailLoadingWithError:(id)arg3 fromDataSource:(id)arg4;
    - (void)webView:(id)arg1 resource:(id)arg2 didFinishLoadingFromDataSource:(id)arg3;
    - (id)webView:(id)arg1 identifierForInitialRequest:(id)arg2 fromDataSource:(id)arg3;
    - (void)webView:(id)arg1 decidePolicyForGeolocationRequestFromOrigin:(id)arg2 frame:(id)arg3 listener:(id)arg4;
    - (id)webView:(id)arg1 runJavaScriptTextInputPanelWithPrompt:(id)arg2 defaultText:(id)arg3 initiatedByFrame:(id)arg4;
    - (BOOL)webView:(id)arg1 runJavaScriptConfirmPanelWithMessage:(id)arg2 initiatedByFrame:(id)arg3;
    - (void)webView:(id)arg1 runJavaScriptAlertPanelWithMessage:(id)arg2 initiatedByFrame:(id)arg3;
    - (void)webViewClose:(id)arg1;
    - (void)webView:(id)arg1 didFirstLayoutInFrame:(id)arg2;
    - (void)webView:(id)arg1 didFailLoadWithError:(id)arg2 forFrame:(id)arg3;
    - (void)webView:(id)arg1 didFinishLoadForFrame:(id)arg2;
    - (void)webView:(id)arg1 decidePolicyForMIMEType:(id)arg2 request:(id)arg3 frame:(id)arg4 decisionListener:(id)arg5;
    - (void)webView:(id)arg1 didFailProvisionalLoadWithError:(id)arg2 forFrame:(id)arg3;
    - (void)webView:(id)arg1 didReceiveServerRedirectForProvisionalLoadForFrame:(id)arg2;
    - (void)webView:(id)arg1 didClearWindowObject:(id)arg2 forFrame:(id)arg3;
    - (id)webView:(id)arg1 resource:(id)arg2 willSendRequest:(id)arg3 redirectResponse:(id)arg4 fromDataSource:(id)arg5;
    - (id)webView:(id)arg1 connectionPropertiesForResource:(id)arg2 dataSource:(id)arg3;
    - (void)webViewSupportedOrientationsUpdated:(id)arg1;
    - (void)webView:(id)arg1 didReceiveTitle:(id)arg2 forFrame:(id)arg3;
    - (void)webView:(id)arg1 didCommitLoadForFrame:(id)arg2;
    - (void)webView:(id)arg1 didStartProvisionalLoadForFrame:(id)arg2;
    - (void)webView:(id)arg1 printFrameView:(id)arg2;
    - (void)webView:(id)arg1 exceededApplicationCacheOriginQuotaForSecurityOrigin:(id)arg2 totalSpaceNeeded:(unsigned int)arg3;
    - (void)webView:(id)arg1 frame:(id)arg2 exceededDatabaseQuotaForSecurityOrigin:(id)arg3 database:(id)arg4;
    - (void)webView:(id)arg1 unableToImplementPolicyWithError:(id)arg2 frame:(id)arg3;
    - (void)webView:(id)arg1 decidePolicyForNavigationAction:(id)arg2 request:(id)arg3 frame:(id)arg4 decisionListener:(id)arg5;
    - (void)webView:(id)arg1 decidePolicyForNewWindowAction:(id)arg2 request:(id)arg3 newFrameName:(id)arg4 decisionListener:(id)arg5;
    - (id)webView:(id)arg1 createWebViewWithRequest:(id)arg2;
    - (id)initWithUIWebView:(id)arg1;
    
    @end

    它负责接收很多来自WebView的通知,并转发给UIWebView。如第一节概貌中提到,它实现了多个WebView的delegate。

    UIWebView的non-public declaration为: (代码很长,点此跳过

    @interface UIWebView : UIView <NSCoding, UIScrollViewDelegate>
    {
        UIWebViewInternal *_internal;
    }
    
    + (void)_updatePersistentStoragePaths;
    + (void)_fixPathsForSandboxDirectoryChange;
    + (id)_relativePathFromAbsolutePath:(id)arg1 removingPathComponents:(unsigned int)arg2;
    - (void)_addShortcut:(id)arg1;
    - (void)_define:(id)arg1;
    - (void)selectAll:(id)arg1;
    - (void)select:(id)arg1;
    - (void)copy:(id)arg1;
    - (BOOL)canPerformAction:(SEL)arg1 withSender:(id)arg2;
    - (void)configureWithSettings:(id)arg1;
    - (unsigned int)_audioSessionCategoryOverride;
    - (void)_setAudioSessionCategoryOverride:(unsigned int)arg1;
    - (BOOL)_alwaysDispatchesScrollEvents;
    - (void)_setAlwaysDispatchesScrollEvents:(BOOL)arg1;
    - (unsigned int)_pageCount;
    - (void)_setGapBetweenPages:(float)arg1;
    - (float)_gapBetweenPages;
    - (void)_setPageLength:(float)arg1;
    - (float)_pageLength;
    - (void)_setPaginationBehavesLikeColumns:(BOOL)arg1;
    - (BOOL)_paginationBehavesLikeColumns;
    - (void)_setPaginationMode:(int)arg1;
    - (int)_paginationMode;
    - (void)_setDrawInWebThread:(BOOL)arg1;
    - (void)_setWebSelectionEnabled:(BOOL)arg1;
    - (void)_setDrawsCheckeredPattern:(BOOL)arg1;
    - (void)_setOverridesOrientationChangeEventHandling:(BOOL)arg1;
    - (id)_pdfViewHandler;
    - (id)_scrollView;
    - (id)_documentView;
    - (id)_browserView;
    - (id)_initWithWebView:(id)arg1;
    - (struct CGImage *)newSnapshotWithRect:(struct CGRect)arg1;
    - (struct CGImage *)createSnapshotWithRect:(struct CGRect)arg1;
    - (void)webView:(id)arg1 didChangeLocationWithinPageForFrame:(id)arg2;
    - (BOOL)webView:(id)arg1 resource:(id)arg2 canAuthenticateAgainstProtectionSpace:(id)arg3 forDataSource:(id)arg4;
    - (void)webView:(id)arg1 resource:(id)arg2 didCancelAuthenticationChallenge:(id)arg3 fromDataSource:(id)arg4;
    - (void)webView:(id)arg1 resource:(id)arg2 didReceiveAuthenticationChallenge:(id)arg3 fromDataSource:(id)arg4;
    - (void)webView:(id)arg1 resource:(id)arg2 didFailLoadingWithError:(id)arg3 fromDataSource:(id)arg4;
    - (void)webView:(id)arg1 resource:(id)arg2 didFinishLoadingFromDataSource:(id)arg3;
    - (id)webView:(id)arg1 identifierForInitialRequest:(id)arg2 fromDataSource:(id)arg3;
    - (void)webView:(id)arg1 decidePolicyForGeolocationRequestFromOrigin:(id)arg2 frame:(id)arg3 listener:(id)arg4;
    - (id)webView:(id)arg1 runJavaScriptTextInputPanelWithPrompt:(id)arg2 defaultText:(id)arg3 initiatedByFrame:(id)arg4;
    - (BOOL)webView:(id)arg1 runJavaScriptConfirmPanelWithMessage:(id)arg2 initiatedByFrame:(id)arg3;
    - (void)webView:(id)arg1 runJavaScriptAlertPanelWithMessage:(id)arg2 initiatedByFrame:(id)arg3;
    - (id)_makeAlertView;
    - (void)webViewClose:(id)arg1;
    - (void)alertView:(id)arg1 didDismissWithButtonIndex:(int)arg2;
    - (void)webView:(id)arg1 didFirstLayoutInFrame:(id)arg2;
    - (void)webView:(id)arg1 didFailLoadWithError:(id)arg2 forFrame:(id)arg3;
    - (void)webView:(id)arg1 didFinishLoadForFrame:(id)arg2;
    - (void)webView:(id)arg1 didFailProvisionalLoadWithError:(id)arg2 forFrame:(id)arg3;
    - (void)webView:(id)arg1 didReceiveServerRedirectForProvisionalLoadForFrame:(id)arg2;
    - (void)webView:(id)arg1 didClearWindowObject:(id)arg2 forFrame:(id)arg3;
    - (id)webView:(id)arg1 resource:(id)arg2 willSendRequest:(id)arg3 redirectResponse:(id)arg4 fromDataSource:(id)arg5;
    - (id)webView:(id)arg1 connectionPropertiesForResource:(id)arg2 dataSource:(id)arg3;
    - (void)webView:(id)arg1 didReceiveTitle:(id)arg2 forFrame:(id)arg3;
    - (void)webView:(id)arg1 didCommitLoadForFrame:(id)arg2;
    - (void)webView:(id)arg1 didStartProvisionalLoadForFrame:(id)arg2;
    - (void)_updateRequest;
    - (void)webViewSupportedOrientationsUpdated:(id)arg1;
    - (void)webView:(id)arg1 printFrameView:(id)arg2;
    - (void)webView:(id)arg1 exceededApplicationCacheOriginQuotaForSecurityOrigin:(id)arg2 totalSpaceNeeded:(unsigned int)arg3;
    - (void)webView:(id)arg1 frame:(id)arg2 exceededDatabaseQuotaForSecurityOrigin:(id)arg3 database:(id)arg4;
    - (void)webView:(id)arg1 unableToImplementPolicyWithError:(id)arg2 frame:(id)arg3;
    - (void)webView:(id)arg1 decidePolicyForMIMEType:(id)arg2 request:(id)arg3 frame:(id)arg4 decisionListener:(id)arg5;
    - (void)webView:(id)arg1 decidePolicyForNavigationAction:(id)arg2 request:(id)arg3 frame:(id)arg4 decisionListener:(id)arg5;
    - (void)webView:(id)arg1 decidePolicyForNewWindowAction:(id)arg2 request:(id)arg3 newFrameName:(id)arg4 decisionListener:(id)arg5;
    - (void)_reportError:(id)arg1;
    - (void)scrollViewWasRemoved:(id)arg1;
    - (void)scrollViewDidScrollToTop:(id)arg1;
    - (void)scrollViewDidEndDecelerating:(id)arg1;
    - (void)scrollViewDidEndDragging:(id)arg1 willDecelerate:(BOOL)arg2;
    - (void)_didCompleteScrolling;
    - (void)scrollViewWillBeginDragging:(id)arg1;
    - (void)scrollViewDidEndZooming:(id)arg1 withView:(id)arg2 atScale:(float)arg3;
    - (void)scrollViewDidZoom:(id)arg1;
    - (void)scrollViewWillBeginZooming:(id)arg1 withView:(id)arg2;
    - (id)viewForZoomingInScrollView:(id)arg1;
    - (void)restoreStateFromHistoryItem:(id)arg1 forWebView:(id)arg2;
    - (void)saveStateToHistoryItem:(id)arg1 forWebView:(id)arg2;
    - (void)webViewMainFrameDidFailLoad:(id)arg1 withError:(id)arg2;
    - (void)webViewMainFrameDidFinishLoad:(id)arg1;
    - (void)webViewMainFrameDidCommitLoad:(id)arg1;
    - (void)webViewMainFrameDidFirstVisuallyNonEmptyLayoutInFrame:(id)arg1;
    - (void)_updateScrollerViewForInputView:(id)arg1;
    - (void)view:(id)arg1 didSetFrame:(struct CGRect)arg2 oldFrame:(struct CGRect)arg3;
    - (BOOL)_appliesExclusiveTouchToSubviewTree;
    - (void)setBackgroundColor:(id)arg1;
    - (void)setOpaque:(BOOL)arg1;
    - (void)_updateOpaqueAndBackgroundColor;
    - (void)setBounds:(struct CGRect)arg1;
    - (void)setFrame:(struct CGRect)arg1;
    - (void)_frameOrBoundsChanged;
    - (void)_rescaleDocument;
    - (void)_finishRotation;
    - (void)_beginRotation;
    - (struct CGSize)sizeThatFits:(struct CGSize)arg1;
    - (void)_updateCheckeredPattern;
    @property(nonatomic) BOOL suppressesIncrementalRendering;
    @property(readonly, nonatomic, getter=canGoForward) BOOL canGoForward;
    @property(readonly, nonatomic, getter=canGoBack) BOOL canGoBack;
    - (void)goForward;
    - (void)goBack;
    - (void)stopLoading;
    - (void)reload;
    @property(readonly, nonatomic) NSURLRequest *request;
    - (void)loadData:(id)arg1 MIMEType:(id)arg2 textEncodingName:(id)arg3 baseURL:(id)arg4;
    - (void)loadHTMLString:(id)arg1 baseURL:(id)arg2;
    - (void)loadRequest:(id)arg1;
    @property(readonly, nonatomic) UIScrollView *scrollView;
    @property(nonatomic) id <UIWebViewDelegate> delegate;
    @property(readonly, nonatomic, getter=isLoading) BOOL loading;
    @property(nonatomic) BOOL scalesPageToFit;
    @property(nonatomic) BOOL mediaPlaybackAllowsAirPlay;
    @property(nonatomic) BOOL mediaPlaybackRequiresUserAction;
    @property(nonatomic) BOOL allowsInlineMediaPlayback;
    @property(nonatomic) unsigned int dataDetectorTypes;
    @property(nonatomic) BOOL detectsPhoneNumbers;
    - (id)stringByEvaluatingJavaScriptFromString:(id)arg1;
    - (void)dealloc;
    - (void)encodeWithCoder:(id)arg1;
    - (void)_populateArchivedSubviews:(id)arg1;
    - (id)initWithCoder:(id)arg1;
    - (id)initWithFrame:(struct CGRect)arg1;
    - (id)_initWithFrame:(struct CGRect)arg1 enableReachability:(BOOL)arg2;
    - (void)_webViewCommonInitWithWebView:(id)arg1 scalesPageToFit:(BOOL)arg2 shouldEnableReachability:(BOOL)arg3;
    - (void)_updateViewSettings;
    - (void)_setRichTextReaderViewportSettings;
    - (void)_setScalesPageToFitViewportSettings;
    - (void)_didRotate:(id)arg1;
    @property(nonatomic) BOOL keyboardDisplayRequiresUserAction;
    - (void)decodeRestorableStateWithCoder:(id)arg1;
    - (void)encodeRestorableStateWithCoder:(id)arg1;
    - (BOOL)isElementAccessibilityExposedToInterfaceBuilder;
    - (Class)_printFormatterClass;
    
    @end

    从函数名看其主要作用,只列non-public API:

    • 选择/全选/复制网页内容
    • 维护设置项
    • 设置是否在WebThread渲染页面
    • 设置是否允许选择网页内容
    • 提供截图的接口(newSnapshotWithRect)
    • 在UIWebDocumentView传过来的回调通知中做进一步处理
    • 展示alertView,包括由js alert发起的对话框
    • 响应UIScrollViewDelegate的回调,传递消息给UIWebBrowserView
    • 处理旋转屏幕的逻辑
    • 序列化/反序列化

    有一些API虽然名字看懂了,但没办法猜出意义,后面做反编译研究时再详细说吧。这个系列都是浅探。


    下一篇:UIWebView体系结构(七)WebView

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




    展开全文
  • 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...

    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.

    自从2020开始,每次上传包,都会有ITMS-90809: Deprecated API Usage UIWebView,可以自己进行检查

     1.打开终端,cd + 把项目的工程文件所在文件夹拖入终端(即 得到项目的工程文件所在的路径)

     2.输入以下命令(注意最后有个点号,而且点号和 UIWebView 之间必须有一个空格):

    grep -r UIWebView .

     3.以上操作都正确的话,会马上出现工程中带有 UIWebView 的文件的列表(包括在工程中无法搜索到的 .a 文件中对UIWebView 的引用)

     

    注:引用AFNetWorking可以直接把AFNetWorking 里面的 UIWebView+AFNetworking 扩展删掉就可以了,没影响的。

    展开全文
  • 苹果2020年4月份停止接受使用UIWebview api 的app 第一步 全局搜索UIWebview ,将相关代码删除或者替换 但是第一步不能检测到.a 文件或者一些没有添加到项目目录中的文件中是否使用UIWebview api 现在就需要第二步...
  • 现在工程属于电商类APP,混合开发,缓存出现问题,在网上找了demo,吧URL换成 我工程的URL后离线加载不了缓存数据,页面直接就是白屏,在网上也找方法了,还是不行!请问这是为什么,大神们
  • 3.如果觉得终端不好看可以输入下面命令生成一个txt文本搜索关键词UIWebView看哪个隐藏的或者第三方还存在 grep -r UIWebView . >> xxx.txt 4这个会在你项目中出现一个t x t文件打开搜索 Binary file ./...
  • 在网上看到很多文章都说iOS的UIWebView比较耗内存,在我的项目中,最开始我也是用UIWebView来加载网页的。刚开始加载的是自己拼接成的Html,后来在Html中加入一个按钮,点击之后用当前的UIWebView去加载网络上的网页...
  • iOS UIWebView键盘处理

    2014-08-21 00:15:51
    +----------...键盘出现时UIWebView里面的Content内容向上移动,以至聚焦的文本框超出了UIWebView的可视区域。如何在键盘弹出时禁止UIWebView里面的Content向上移动。无法在UIWebView中获取到坐标,来计算c
  • 一下子看到重点提示是UIWebView被弃用了,我们使用了被弃用的API,那么问题来了,怎么彻底清除项目中的UIWebView的代码呢?这就是接下来我要分享给大家的内容。 正文 首先,正常操作就是全局搜索UIWebView,将使用...
  • iOS 查找工程内UIWebView

    2020-05-07 19:30:55
    自从2020年5月1号,苹果强制要求使用xcode11,废弃UIWebView,最近提审包收到邮件说有UIWebView,要求更换掉才能提。 5月1号前都是警告⚠️说UiWebView需要更新成wk,现在强制要改了,生成不了构建版本,工程是...
  • 摘要今天小编跟我讲,有一个同学要利用UIWebView进行图文混排,其实图文混排的几种方式,我在之前的博客里面已经讲过,在这里就不再讲述了,如果大家需要看,请参考之前的那篇博文 iOS中不同形式的图文混排技术的实现总结...
  • 苹果禁止使用UIWebView应用上架,这里面包含两层含义和两个时间点 时间点: 2020.4 和 2020.12 含义: 新应用的IPA 和 应用升级IPA 解读: 2020年4月30日之后(也就是五月份之前), 禁止新应用使用UIWebView 2020年12月30...
  • UIWebView开发中,经常会使用 alert() 函数来调试脚本。但在某种情况下,alert() 函数是无效的,同时导致 App 停止响应。 比如你在 UIWebView 中调用 native 方法弹出一个模式窗口(比如展现一个模式菜单),然后...
  • iOS13发布了,据说苹果开始拒绝使用UIWebView的api应用了。 有点慌,由于项目自17年开始就一直用的UIWebView,但UIWebView性能实在是太差了,进几个网页内存就飙升,并且退出页面VC销毁了但内存还无法降下来,首次...
  • IOS已经废弃了UIWebView接口,改用WKwebview。如果项目中使用了UIWebView将在审核失败,并提示ITMS-90809. 如何解决: 打开mac终端,cd到导出的Xcode路径处。 复制grep -r UIWebView . 回车。 便可查看工程中引用...
  • 开发App的过程中,常常会遇到在App内部加载网页,通常用 UIWebView 加载。这个自iOS2开始使用的网页加载器一直是开发的心病:加载速度慢,占用内存多,优化困难。如果加载网页多,还可能因为过量占用内存而给系统...
  • UIWebView 是用来加载加载网页数据。
  • 代码中有包含UIWebView的代码,需要去掉。否则上传苹果审核的时候会上传失败。 删除UIWebView总结: Unity版本不能用2018.4.19国内版本,4.12和4.23测试可行。 检测库中包含的UIWebView最好是到xcode源工程目录...
1 2 3 4 5 ... 20
收藏数 19,757
精华内容 7,902
关键字:

uiwebview