<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      iOS開發基礎146-深入解析WKWebView

      WKWebView是蘋果在iOS 8中引入的重要組件,它替代了UIWebView,為開發者提供了高性能、高穩定性的網頁顯示和交互能力。在本文中,我們將深入探討WKWebView的底層架構、關鍵特性、使用方法和高級功能。

      一、WKWebView的底層架構

      WKWebView基于WebKit框架,采用多進程架構,將頁面渲染和JavaScript執行放在獨立的Web進程中,這樣做的好處是主應用進程與Web內容進程隔離,能顯著提升應用的穩定性和安全性。其架構主要包括以下幾個部分:

      1. Web內容進程

      負責HTML解析、CSS解析、JavaScript執行、頁面渲染等操作。這些操作都是在獨立的進程中進行,防止網頁崩潰影響整個應用。

      2. 網絡進程

      負責網絡請求的管理和緩存數據的處理,從數據源獲取網頁內容,并傳輸給Web內容進程。

      3. UI進程

      主要負責與用戶的交互,如接收用戶輸入、發送消息給Web內容進程等。UI進程與Web內容進程通過IPC(進程間通信)進行信息的傳遞。

      如下圖所示是WKWebView的架構示意圖:

      +------------------+                +------------------+
      |                  | <------------> |                  |
      |      UI進程       |                |    Web內容進程     |
      |                  |    IPC 通信      |                  |
      +------------------+                +------------------+
               ^                                   ^
               |                                   |
               v                                   v
      +------------------+                +------------------+
      |                  |                |                  |
      |     WKWebView    |                |     頁面引擎      |
      |                  |                |                  |
      +------------------+                +------------------+
      

      二、WKWebView的基本使用

      1. 初始化WKWebView

      要使用WKWebView,首先需要進行基本初始化和配置工作。不同于UIWebView,初始化WKWebView時需指定其配置屬性。

      #import <WebKit/WebKit.h>
      
      @interface ViewController ()
      @property (nonatomic, strong) WKWebView *webView;
      @end
      
      @implementation ViewController
      
      - (void)viewDidLoad {
          [super viewDidLoad];
          
          // 創建配置對象
          WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
          
          // 初始化WKWebView
          self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
          
          // 設置內邊距
          [self.view addSubview:self.webView];
          
          // 加載一個網頁示例
          NSURL *url = [NSURL URLWithString:@"https://www.apple.com"];
          NSURLRequest *request = [NSURLRequest requestWithURL:url];
          [self.webView loadRequest:request];
      }
      
      @end
      

      2. 加載本地文件

      除了加載網絡資源外,WKWebView還可以加載本地文件:

      NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
      NSURL *baseURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
      NSString *htmlContent = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil];
      [self.webView loadHTMLString:htmlContent baseURL:baseURL];
      

      3. 導航控制

      WKWebView提供了豐富的導航控制方法,幫助我們處理網頁的前進、后退和刷新等操作:

      // 刷新當前頁面
      [self.webView reload];
      
      // 停止加載
      [self.webView stopLoading];
      
      // 后退到上一頁面
      [self.webView goBack];
      
      // 前進到下一頁面
      [self.webView goForward];
      

      4. 獲取網頁內容

      WKWebView的一個強大功能是可以直接執行JavaScript代碼并獲取返回值:

      [self.webView evaluateJavaScript:@"document.title" completionHandler:^(id result, NSError *error) {
          if (!error) {
              NSLog(@"Page title: %@", result);
          }
      }];
      

      三、WKWebView的代理與回調

      WKWebView提供了兩個主要的代理協議:WKNavigationDelegateWKUIDelegate,它們分別處理導航和用戶界面方面的回調。

      1. WKNavigationDelegate

      該協議管理網頁內容的加載過程,包括開始、完成、失敗等事件:

      @interface ViewController () <WKNavigationDelegate>
      @end
      
      @implementation ViewController
      
      - (void)viewDidLoad {
          [super viewDidLoad];
      
          // 設置導航代理
          self.webView.navigationDelegate = self;
          
          // 加載網頁
          NSURL *url = [NSURL URLWithString:@"https://www.apple.com"];
          NSURLRequest *request = [NSURLRequest requestWithURL:url];
          [self.webView loadRequest:request];
      }
      
      // 頁面開始加載
      - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
          NSLog(@"頁面開始加載");
      }
      
      // 內容開始返回
      - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
          NSLog(@"內容開始返回");
      }
      
      // 頁面加載完成
      - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
          NSLog(@"頁面加載完成");
      }
      
      // 頁面加載失敗
      - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
          NSLog(@"頁面加載失敗,錯誤: %@", error.localizedDescription);
      }
      @end
      

      2. WKUIDelegate

      該協議處理網頁中的UI事件,比如顯示JavaScript的alertconfirmprompt對話框:

      @interface ViewController () <WKUIDelegate>
      @end
      
      @implementation ViewController
      
      - (void)viewDidLoad {
          [super viewDidLoad];
      
          // 設置用戶界面代理
          self.webView.UIDelegate = self;
          
          // 加載網頁
          NSURL *url = [NSURL URLWithString:@"https://www.apple.com"];
          NSURLRequest *request = [NSURLRequest requestWithURL:url];
          [self.webView loadRequest:request];
      }
      
      // JavaScript alert框
      - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
          UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
          UIAlertAction *ok = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
              completionHandler();
          }];
          [alert addAction:ok];
          [self presentViewController:alert animated:YES completion:nil];
      }
      
      // JavaScript confirm框
      - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
          UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"確認" message:message preferredStyle:UIAlertControllerStyleAlert];
          UIAlertAction *ok = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
              completionHandler(YES);
          }];
          UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
              completionHandler(NO);
          }];
          [alert addAction:ok];
          [alert addAction:cancel];
          [self presentViewController:alert animated:YES completion:nil];
      }
      
      // JavaScript prompt框
      - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler {
          UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"輸入" message:prompt preferredStyle:UIAlertControllerStyleAlert];
          [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
              textField.text = defaultText;
          }];
          UIAlertAction *ok = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
              NSString *input = alert.textFields.firstObject.text;
              completionHandler(input);
          }];
          UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
              completionHandler(nil);
          }];
          [alert addAction:ok];
          [alert addAction:cancel];
          [self presentViewController:alert animated:YES completion:nil];
      }
      
      @end
      

      四、WKWebView的進階使用

      1. 與JavaScript交互

      通過WKScriptMessageHandler協議,WKWebView可以和網頁中的JavaScript進行雙向交互。

      前提配置

      需要在WKWebViewConfiguration中配置內容控制器WKUserContentController并注冊JavaScript消息處理器:

      @interface ViewController () <WKScriptMessageHandler>
      @end
      
      @implementation ViewController
      
      - (void)viewDidLoad {
          [super viewDidLoad];
      
          WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
          WKUserContentController *contentController = [[WKUserContentController alloc] init];
          [contentController addScriptMessageHandler:self name:@"nativeHandler"];
          config.userContentController = contentController;
      
          self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
          [self.view addSubview:self.webView];
      
          NSString *html = @"<html><body><button onclick=\"window.webkit.messageHandlers.nativeHandler.postMessage('Hello from JS!');\">Click Me</button></body></html>";
          [self.webView loadHTMLString:html baseURL:nil];
      }
      
      - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
          if ([message.name isEqualToString:@"nativeHandler"]) {
              NSLog(@"Received message from JS: %@", message.body);
          }
      }
      
      - (void)dealloc {
          [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"nativeHandler"];
      }
      
      @end
      

      這樣,當點擊網頁按鈕時,JavaScript會將消息發送到原生代碼并觸發userContentController:didReceiveScriptMessage:回調。

      2. Loading進度條

      通過監聽WKWebViewestimatedProgress屬性,我們可以實現網頁加載過程中的進度條顯示:

      @interface ViewController ()
      
      @property (nonatomic, strong) UIProgressView *progressView;
      
      @end
      
      @implementation ViewController
      
      - (void)viewDidLoad {
          [super viewDidLoad];
      
          // 初始化WKWebView
          self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
          [self.view addSubview:self.webView];
      
          // 初始化進度條
          self.progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
          self.progressView.frame = CGRectMake(0, 88, self.view.bounds.size.width, 2);
          [self.view addSubview:self.progressView];
      
          // 觀察estimatedProgress屬性
          [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
      
          // 加載網頁
          NSURL *url = [NSURL URLWithString:@"https://www.apple.com"];
          NSURLRequest *request = [NSURLRequest requestWithURL:url];
          [self.webView loadRequest:request];
      }
      
      - (void)dealloc {
          [self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
      }
      
      - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
          if ([keyPath isEqualToString:@"estimatedProgress"]) {
              self.progressView.progress = self.webView.estimatedProgress;
              if (self.webView.estimatedProgress >= 1.0) {
                  [UIView animateWithDuration:0.5 animations:^{
                      self.progressView.alpha = 0.0;
                  }];
              } else {
                  self.progressView.alpha = 1.0;
              }
          } else {
              [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
          }
      }
      
      @end
      

      3. 處理文件上傳

      WKWebView支持文件上傳,通過實現UIDocumentPickerViewController,我們可以定制上傳文件的操作:

      @interface ViewController () <WKUIDelegate, UIDocumentPickerDelegate>
      @end
      
      @implementation ViewController
      
      - (void)viewDidLoad {
          [super viewDidLoad];
      
          // 初始化WKWebView
          WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
          self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
          self.webView.UIDelegate = self;
          [self.view addSubview:self.webView];
      
          // 加載網頁
          NSURL *url = [NSURL URLWithString:@"https://example.com"];
          NSURLRequest *request = [NSURLRequest requestWithURL:url];
          [self.webView loadRequest:request];
      }
      
      - (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> * _Nullable URLs))completionHandler {
          UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen];
          documentPicker.delegate = self;
          documentPicker.completionHandler = ^(NSArray<NSURL *> * _Nonnull urls) {
              completionHandler(urls);
          };
          [self presentViewController:documentPicker animated:YES completion:nil];
      }
      
      @end
      

      五、WKWebView的性能優化

      由于WKWebView在實際使用中可能會面臨性能問題,以下是一些性能優化的建議:

      1. 緩存策略

      通過使用合適的緩存策略,你可以避免重復加載相同的資源,從而提高加載速度。如使用URLCache配置:

      NSURLCache *urlCache = [[NSURLCache alloc] initWithMemoryCapacity:1024 * 1024 * 10
                                                          diskCapacity:1024 * 1024 * 50
                                                              diskPath:@"wkwebview_cache"];
      [NSURLCache setSharedURLCache:urlCache];
      
      NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30];
      [self.webView loadRequest:request];
      

      2. 異步加載資源

      避免同步加載資源導致主線程阻塞,可以使用異步加載的方法來處理:

      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
          NSURL *url = [NSURL URLWithString:@"https://example.com/resource"];
          NSData *data = [NSData dataWithContentsOfURL:url];
          dispatch_async(dispatch_get_main_queue(), ^{
              [self.webView loadData:data MIMEType:@"text/html" characterEncodingName:@"UTF-8" baseURL:[NSURL URLWithString:@"https://example.com"]];
          });
      });
      

      3. 減少DOM操作

      在需要頻繁操作DOM時,盡量將多個操作合并為一次,以減少引擎的渲染負擔:

      function updateContent() {
          let container = document.getElementById('container');
          let fragment = document.createDocumentFragment();
      
          for (let i = 0; i < 1000; i++) {
              let div = document.createElement('div');
              div.textContent = `Item ${i}`;
              fragment.appendChild(div);
          }
      
          container.appendChild(fragment);
      }
      

      六、OC與JavaScript通信進階

      如果只是傳遞簡單的用戶信息數據,除了通過 WKScriptMessageHandler 的方式,還有以下幾種方法可以將數據從客戶端(Objective-C/Swift)傳遞給 JavaScript。

      1、通過 URL Scheme

      這種方法主要是在加載網頁的時候,將用戶信息作為查詢參數(query parameter)嵌入到 URL 中傳遞給頁面。這種方式適用于初始加載頁面的數據傳遞。

      // 構建用戶信息數據
      NSString *userInfo = @"userId=12345&userName=JohnDoe";
      NSString *urlString = [NSString stringWithFormat:@"https://example.com?%@", userInfo];
      NSURL *url = [NSURL URLWithString:urlString];
      NSURLRequest *request = [NSURLRequest requestWithURL:url];
      [self.webView loadRequest:request];
      

      在 JavaScript 中可以通過 window.location.search 獲取查詢參數。

      2、通過 evaluateJavaScript 執行 JavaScript

      evaluateJavaScript:completionHandler: 是一個簡單直接的方法,可以在客戶端執行任意 JavaScript 代碼并通過回調獲取執行結果。

      // 構建JavaScript代碼
      NSString *userId = @"12345";
      NSString *userName = @"JohnDoe";
      NSString *jsCode = [NSString stringWithFormat:@"setUserInfo('%@', '%@');", userId, userName];
      
      // 執行JavaScript代碼
      [self.webView evaluateJavaScript:jsCode completionHandler:^(id result, NSError *error) {
          if (error) {
              NSLog(@"Error: %@", error.localizedDescription);
          }
      }];
      

      在網頁中,需要定義對應的 JavaScript 函數來接收這些數據:

      <script>
      function setUserInfo(userId, userName) {
          console.log("User ID: " + userId);
          console.log("User Name: " + userName);
          // 其他業務邏輯
      }
      </script>
      

      3、通過 User Scripts

      如果你想在頁面加載的初始階段注入數據,可以使用 WKUserScript 來添加 JavaScript 預處理。

      // 構建JavaScript代碼
      NSString *userId = @"12345";
      NSString *userName = @"JohnDoe";
      NSString *scriptSource = [NSString stringWithFormat:@"window.userInfo = {userId: '%@', userName: '%@'};", userId, userName];
      
      // 創建用戶腳本
      WKUserScript *userScript = [[WKUserScript alloc] initWithSource:scriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
      
      // 添加用戶腳本到配置
      WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
      [config.userContentController addUserScript:userScript];
      
      // 創建并加載 WKWebView
      self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
      NSURL *url = [NSURL URLWithString:@"https://example.com"];
      NSURLRequest *request = [NSURLRequest requestWithURL:url];
      [self.webView loadRequest:request];
      

      通過上述方法,頁面在加載時就會自動注入用戶信息,網頁可以在任何地方直接訪問 window.userInfo

      4、通過 Document.cookie(不推薦)

      雖然不太推薦,但我們也可以通過設置 Document.cookie 將信息傳遞給網頁。以下是示例:

      NSString *userId = @"12345";
      NSString *userName = @"JohnDoe";
      NSString *cookieScript = [NSString stringWithFormat:@"document.cookie = 'userId=%@; path=/'; document.cookie = 'userName=%@; path=/';", userId, userName];
      [self.webView evaluateJavaScript:cookieScript completionHandler:^(id result, NSError *error) {
          if (error) {
              NSLog(@"Error: %@", error.localizedDescription);
          }
      }];
      

      在網頁中,可以通過 JavaScript 解析 document.cookie 獲取用戶信息。

      function getCookie(name) {
          let value = `; ${document.cookie}`;
          let parts = value.split(`; ${name}=`);
          if (parts.length === 2) return parts.pop().split(';').shift();
      }
      
      let userId = getCookie('userId');
      let userName = getCookie('userName');
      console.log("User ID: " + userId);
      console.log("User Name: " + userName);
      

      選擇

      以上方法各有優劣,根據實際使用場景選擇適合的方法:

      • 如果是初始加載時傳遞數據,用 URL Scheme 比較簡單直接。
      • 如果需要在頁面加載后隨時傳遞數據,evaluateJavaScript:completionHandler: 非常靈活。
      • 需要在頁面加載前就注入數據,WKUserScript 是一種好方法。
      • Document.cookie 方式雖然可以傳遞數據,但不推薦用于敏感信息。

      七、總結

      WKWebView提供了現代化的網頁視圖解決方案,具有高性能、高穩定性的優勢。通過理解其底層架構、掌握常用和進階的使用方法、如何與JavaScript進行交互和處理實際應用中的各種需求,你可以更好地實現復雜的網頁加載與交互功能,提升應用的用戶體驗和性能。

      posted @ 2024-08-03 18:28  Mr.陳  閱讀(985)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲综合一区无码精品| 永福县| 亚洲国产成人精品无色码| 国产精品三级爽片免费看| 91久久夜色精品国产网站| 国产成人综合久久亚洲精品| 久久综合97丁香色香蕉| 狠狠色综合tv久久久久久| 成人乱码一区二区三区四区 | 欧洲免费一区二区三区视频 | 中文字幕国产精品自拍| 女高中生自慰污污网站| 亚洲成在人线在线播放无码| 亚洲av无码片在线播放| 两个人免费完整高清视频| 在线播放深夜精品三级| 成人国产精品中文字幕| 亚洲熟女乱色一区二区三区| 精品人妻少妇一区二区三区| 亚洲偷自拍国综合| 亚洲精品国产无套在线观| 亚洲色欲在线播放一区二区三区| 97精品尹人久久大香线蕉| 亚洲乱人伦中文字幕无码| 九九热精彩视频在线免费| 成人亚欧欧美激情在线观看 | 亚洲精品国产字幕久久麻豆| 亚洲国产精品久久久久婷婷老年 | 国产精品免费看久久久| 亚洲va久久久噜噜噜久久狠狠| 久久国内精品一国内精品| 欧美日韩综合网| 国产成人av免费观看| 国产一区二区三区在线观看免费| 国产精品久久久国产盗摄| 天天做天天爱夜夜爽导航| 日本一卡2卡3卡四卡精品网站| 亚洲av永久无码一区二区三区| 午夜福利激情一区二区三区| 国产区成人精品视频| 夜夜夜高潮夜夜爽夜夜爰爰|