Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 97色婷婷成人综合在线观看,精品久久久久久国产91,日韩电影中文字幕在线观看

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          WKWebView適配(實(shí)戰(zhàn)篇)

          、Cookie適配

          1.現(xiàn)狀

          WKWebView適配中最麻煩的就是cookie同步問(wèn)題

          WKWebView采用了獨(dú)立存儲(chǔ)控件,因此和以往的UIWebView并不互通

          雖然iOS11以后,iOS開放了WKHTTPCookieStore讓開發(fā)者去同步,但是還是需要考慮低版本的 同步問(wèn)題,本章節(jié)從各個(gè)角度切入考慮cookie同步問(wèn)題

          2.同步cookie(NSHTTPCookieStorage->WKHTTPCookieStore)

          iOS11+

          可以直接使用WKHTTPCookieStore遍歷方式設(shè)值,可以在創(chuàng)建wkwebview時(shí)候就同步也可以是請(qǐng)求時(shí)候

          // iOS11同步 HTTPCookieStorag到WKHTTPCookieStore
          WKHTTPCookieStore *cookieStore = self.wkWebView.configuration.websiteDataStore.httpCookieStore;
          
          - (void)syncCookiesToWKCookieStore:(WKHTTPCookieStore *)cookieStore  API_AVAILABLE(ios(11.0)){
              NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
              if (cookies.count == 0) return;
              for (NSHTTPCookie *cookie in cookies) {
                  [cookieStore setCookie:cookie completionHandler:^{
                      if ([cookies.lastObject isEqual:cookie]) {
                          [self wkwebviewSetCookieSuccess];
                      }
                  }];
              }
          }

          同步cookie可以在初始化wkwebview的時(shí)候,也可以在請(qǐng)求的時(shí)候。初始化時(shí)候同步可以確保發(fā)起html頁(yè)面請(qǐng)求的時(shí)候帶上cookie

          例如:請(qǐng)求在線頁(yè)面時(shí)候要通過(guò)cookie來(lái)認(rèn)證身份,如果不是初始化時(shí)同步,可能請(qǐng)求頁(yè)面時(shí)就是401了

          iOS11-

          通過(guò)前端執(zhí)行js注入cookie,在請(qǐng)求時(shí)候執(zhí)行

          //wkwebview執(zhí)行JS
          - (void)injectCookiesLT11 {
              WKUserScript * cookieScript = [[WKUserScript alloc] initWithSource:[self cookieString] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
              [self.wkWebView.configuration.userContentController addUserScript:cookieScript];
          }
          //遍歷NSHTTPCookieStorage,拼裝JS并執(zhí)行
          - (NSString *)cookieString {
              NSMutableString *script = [NSMutableString string];
              [script appendString:@"var cookieNames = document.cookie.split('; ').map(function(cookie) { return cookie.split('=')[0] } );\n"];
              for (NSHTTPCookie *cookie in NSHTTPCookieStorage.sharedHTTPCookieStorage.cookies) {
                  // Skip cookies that will break our script
                  if ([cookie.value rangeOfString:@"'"].location != NSNotFound) {
                      continue;
                  }
                  [script appendFormat:@"if (cookieNames.indexOf('%@') == -1) { document.cookie='%@'; };\n", cookie.name, [self formatCookie:cookie]];
              }
              return script;
          }
          //Format cookie的js方法
          - (NSString *)formatCookie:(NSHTTPCookie *)cookie {
              NSString *string = [NSString stringWithFormat:@"%@=%@;domain=%@;path=%@",
                                  cookie.name,
                                  cookie.value,
                                  cookie.domain,
                                  cookie.path ?: @"/"];
              if (cookie.secure) {
                  string = [string stringByAppendingString:@";secure=true"];
              }
              return string;
          }

          但是上面方法執(zhí)行js,也無(wú)法保證第一個(gè)頁(yè)面請(qǐng)求帶有cookie

          所以請(qǐng)求時(shí)候創(chuàng)建request需要設(shè)置cookie,并且loadRequest

          -(void)injectRequestCookieLT11:(NSMutableURLRequest*)mutableRequest {
              // iOS11以下,手動(dòng)同步所有cookie
              NSArray *cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage.cookies;
              NSMutableArray *mutableCookies = @[].mutableCopy;
              for (NSHTTPCookie *cookie in cookies) {
                  [mutableCookies addObject:cookie];
              }
              // Cookies數(shù)組轉(zhuǎn)換為requestHeaderFields
              NSDictionary *requestHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:(NSArray *)mutableCookies];
              // 設(shè)置請(qǐng)求頭
              mutableRequest.allHTTPHeaderFields = requestHeaderFields;
          }

          3.反向同步cookie(WKHTTPCookieStore->NSHTTPCookieStorage)

          wkwebview產(chǎn)生的cookie也可能在某些場(chǎng)景需要同步給NSHTTPCookieStorage

          iOS11+可以直接用WKHTTPCookieStore去同步,

          iOS11-可以采用js端獲取,觸發(fā)bridge同步給NSHTTPCookieStorage

          但是js同步方式無(wú)法同步httpOnly,所以真的遇到了,還是要結(jié)合服務(wù)器等方式去做這個(gè)同步。

          二、JS和Native通信

          1.Native調(diào)用JS

          將代碼準(zhǔn)備完畢后調(diào)用API即可,回調(diào)函數(shù)可以接收js執(zhí)行結(jié)果或者錯(cuò)誤信息,So Easy。

          [self.wkWebView evaluateJavaScript:jsCode completionHandler:^(id object, NSError *error){}];

          2.注入JS

          其實(shí)就是提前注入一些JS方法,可以提供給JS端調(diào)用。

          比如有的框架會(huì)將bridge直接通過(guò)這種方式注入到WK的執(zhí)行環(huán)境中,而不是從前端引入JS,這種好處就是假設(shè)前端的JS是在線加載,JS服務(wù)器掛了或者網(wǎng)絡(luò)問(wèn)題,這樣前端頁(yè)面就失去了Naitve的Bridge通信能力了。

          -(instancetype)initWithSource:(NSString *)source injectionTime:(WKUserScriptInjectionTime)injectionTime forMainFrameOnly:(BOOL)forMainFrameOnly;
          
          //WKUserScriptInjectionTime說(shuō)明
          typedef NS_ENUM(NSInteger, WKUserScriptInjectionTime) {
              WKUserScriptInjectionTimeAtDocumentStart, /**文檔開始時(shí)候就注入**/
              WKUserScriptInjectionTimeAtDocumentEnd /**文檔加載完成時(shí)注入**/
          } API_AVAILABLE(macos(10.10), ios(8.0));

          3.JS調(diào)用Native

          3-1.準(zhǔn)備代理類

          代理類要實(shí)現(xiàn)WKScriptMessageHandler

          @interface WeakScriptMessageDelegate : NSObject<WKScriptMessageHandler>
            @property (nonatomic, weak) id<WKScriptMessageHandler> scriptDelegate;
            - (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;
          @end

          WKScriptMessageHandler就一個(gè)方法

          @implementation WeakScriptMessageDelegate
          - (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate {
              self = [super init];
              if (self) {
                  _scriptDelegate = scriptDelegate;
              }
              return self;
          }
          
          - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
              [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
          }

          3-2.設(shè)置代理類

          合適時(shí)機(jī)(一般初始化)設(shè)置代理類,并且指定name

          NSString* MessageHandlerName = @"bridge";
          [config.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:MessageHandlerName];

          3-3.bridge的使用(JS端)

          執(zhí)行完上面語(yǔ)句后就會(huì)在JS端注入了一個(gè)對(duì)象"window.webkit.messageHandlers.bridge"

          //JS端發(fā)送消息,參數(shù)最好選用String,比較通用
          window.webkit.messageHandlers.bridge.postMessage("type");

          3-4.Native端消息的接收

          然后native端可以通過(guò)WKScriptMessage的body屬性中獲得傳入的值

          - (void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
              if ([message.name isEqualToString:HistoryBridageName]) {
                
              } else if ([message.name isEqualToString:MessageHandlerName]) {
                  [self jsToNativeImpl:message.body];
              }
          }

          3-5.思考題

          這里我們?yōu)槭裁匆褂肳eakScriptMessageDelegate,并且再設(shè)置個(gè)delegate指向self(controller),為什么不直接指向?

          提示:可以參考NSTimer的循環(huán)引用問(wèn)題

          3-6.完整的示例

          -(void)_defaultConfig{
             WKWebViewConfiguration* config = [WKWebViewConfiguration new];
             …… ……
             …… ……
             WKUserContentController* userController = [[WKUserContentController alloc] init];
             config.userContentController = userController;
             [self injectHistoryBridge:config];
             …… ……
             …… ……     
          }
          
          -(void)injectHistoryBridge:(WKWebViewConfiguration*)config{
              [config.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:HistoryBridageName];
              NSString *_jsSource = [NSString stringWithFormat:
                                     @"(function(history) {\n"
                                     "  function notify(type) {\n"
                                     "    setTimeout(function() {\n"
                                     "      window.webkit.messageHandlers.%@.postMessage(type)\n"
                                     "    }, 0)\n"
                                     "  }\n"
                                     "  function shim(f) {\n"
                                     "    return function pushState() {\n"
                                     "      notify('other')\n"
                                     "      return f.apply(history, arguments)\n"
                                     "    }\n"
                                     "  }\n"
                                     "  history.pushState = shim(history.pushState)\n"
                                     "  history.replaceState = shim(history.replaceState)\n"
                                     "  window.addEventListener('popstate', function() {\n"
                                     "    notify('backforward')\n"
                                     "  })\n"
                                     "})(window.history)\n", HistoryBridageName
                                     ];
              WKUserScript *script = [[WKUserScript alloc] initWithSource:_jsSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
              [config.userContentController addUserScript:script];
          }

          3-7.其它問(wèn)題

          在iOS8 beta5前,JS和Native這樣通信設(shè)置是不行的,所以可以采用生命周期中做URL的攔截去解析數(shù)據(jù)來(lái)達(dá)到效果,這里不做贅述,可以自行參考網(wǎng)上類似UIWebview的橋接原理文章

          三、實(shí)戰(zhàn)技巧

          1.UserAgent的設(shè)置

          添加UA

          實(shí)際過(guò)程中最好只是原有UA上做添加操作,全部替換可能導(dǎo)致服務(wù)器的拒絕(安全策略)

          日志中紅線部分是整個(gè)模擬器的UA,綠色部門是UA中的ApplicationName部分

          iOS9上,WKWebview提供了API可以設(shè)置ua中的ApplicationName

          config.applicationNameForUserAgent = [NSString stringWithFormat:@"%@ %@", config.applicationNameForUserAgent, @"arleneConfig"];

          全部替換UA

          iOS9以上直接可以指定wkwebview的customUserAgent,iOS9以下的話,設(shè)置NSUserDefaults

          if (@available(iOS 9.0, *)) {
             self.wkWebView.customUserAgent = @"Hello My UserAgent";
          }else{
             [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent":@"Hello My UserAgent"}];
             [[NSUserDefaults standardUserDefaults] synchronize];
          }

          2.監(jiān)聽進(jìn)度和頁(yè)面的title變化

          wkwebview可以監(jiān)控頁(yè)面加載進(jìn)度,類似瀏覽器中打開頁(yè)面中的進(jìn)度條的顯示

          頁(yè)面切換的時(shí)候也會(huì)自動(dòng)更新頁(yè)面中設(shè)置的title,可以在實(shí)際項(xiàng)目中動(dòng)態(tài)切換容器的title,比如根據(jù)切換的title設(shè)置navigationItem.title

          原理直接通過(guò)KVO方式監(jiān)聽值的變化,然后在回調(diào)中處理相關(guān)邏輯

          //kvo 加載進(jìn)度
          [self.webView addObserver:self
                        forKeyPath:@"estimatedProgress"
                        options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
                        context:nil];
          //kvo title
          [self.webView addObserver:self
                        forKeyPath:@"title"
                        options:NSKeyValueObservingOptionNew
                        context:nil];
          
          /** KVO 監(jiān)聽具體回調(diào)**/
          - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
              if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) {
                  ALLOGF(@"Progress--->%@",[NSNumber numberWithDouble:self.webView.estimatedProgress]);
              }else if([keyPath isEqualToString:@"title"]
                       && object == self.webview){
                  self.navigationItem.title = self.webView.title;
              }else{
                  [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
              }
          }
          
          /**銷毀時(shí)候記得移除**/
          [self.webView removeObserver:self
                     forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
          [self.webView removeObserver:self
           					forKeyPath:NSStringFromSelector(@selector(title))];
          
          

          3.Bridge通信實(shí)戰(zhàn)

          下面介紹自己實(shí)現(xiàn)的bridge通信框架,前端無(wú)需關(guān)心所在容器,框架層做適配。

          import {WebBridge} from 'XXX'
          /**
          * 方法: WebBridge.call(taskName,options,callback)
          * 參數(shù)說(shuō)明: 
          *	taskName String task的名字,用于Native處理分發(fā)任務(wù)的標(biāo)識(shí)
          * options  Object 傳遞的其它參數(shù)
          * callback function 回調(diào)函數(shù)
          *.         回調(diào)參數(shù)
          *					 json object native返回的內(nèi)容
          **/
          WebBridge.call("Alert",{"content":"彈框內(nèi)容","btn":"btn內(nèi)容"},function(json){
          	 console.log("call back is here",JSON.stringify(json));
          });

          上面調(diào)用了Native的Alert控件,然后返回調(diào)用結(jié)果。

          調(diào)用到的Native代碼如下:

          //AlertTask.m
          #import "AlertTask.h"
          #import <lib-base/ALBaseConstants.h>
          @interface AlertTask (){}
          @property (nonatomic,weak) ArleneWebViewController* mCtrl;
          @end
          
          @implementation AlertTask
          -(instancetype)initWithContext:(ArleneWebViewController*)controller{
              self = [super init];
              self.mCtrl = controller;
              return self;
          }
          -(NSString*)taskName{
              return @"Alert";
          }
          -(void)doTask:(NSDictionary*)params{
              ALShowAlert(@"Title",@"message");//彈出Alert
              NSMutableDictionary* callback = [ArleneTaskUtils basicCallback:params];//獲取callback
              [callback addEntriesFromDictionary:params];
              [self.mCtrl callJS:callback];//執(zhí)行回調(diào)
          }
          @end
          
          

          關(guān)于我

          期待與要求上進(jìn)的您進(jìn)一步溝通

          微信號(hào):maako127

          可以加入我的公眾號(hào)(二碼前端說(shuō)),定期更新前端相關(guān)技術(shù)干貨

          年做了大量的 HTML5 項(xiàng)目,遇到了很多坑。在這個(gè)過(guò)程中學(xué)到了一些之前不具備的知識(shí),所以這篇文章就簡(jiǎn)單分享一下這方面的話題。

          傳統(tǒng)的MPA

          首先,說(shuō)一個(gè)比較古老的東西,叫做 MPA。

          MPA 的全稱是 Multi-page Application,意思是整個(gè)應(yīng)用(站點(diǎn))由多個(gè)完整的 html 構(gòu)成。用戶在頁(yè)面 1 點(diǎn)擊跳轉(zhuǎn),需要向服務(wù)端請(qǐng)求頁(yè)面 2,請(qǐng)求成功后渲染。而用戶返回時(shí),相當(dāng)于是點(diǎn)擊了瀏覽器的返回,頁(yè)面退回到之前的歷史記錄,并重新加載出來(lái)。

          在這樣的模式下,頁(yè)面間切換慢、不流暢的問(wèn)題比較突出,尤其是在移動(dòng)端。

          同時(shí),它還產(chǎn)生了幾個(gè)小問(wèn)題:

          • 跳轉(zhuǎn)動(dòng)畫:頁(yè)面間的跳轉(zhuǎn)無(wú)法實(shí)現(xiàn)轉(zhuǎn)場(chǎng)動(dòng)畫效果。
          • 如果前一個(gè)頁(yè)比較長(zhǎng),用戶滑動(dòng)到頁(yè)面比較靠下方的位置后點(diǎn)擊,返回時(shí),頁(yè)面無(wú)法默認(rèn)停留在原位置。
          • iOS 右滑返回產(chǎn)生問(wèn)題,從頁(yè)面 1 跳轉(zhuǎn)到頁(yè)面 2,再?gòu)捻?yè)面 2 跳轉(zhuǎn)到頁(yè)面 3,右滑返回,會(huì)直接回到頁(yè)面 1 前的頁(yè)。

          SPA

          隨著對(duì)移動(dòng)端體驗(yàn)需求的提高以及技術(shù)的進(jìn)步,另一種模式 SPA(Single-page Application)逐漸成為主流。

          SPA 簡(jiǎn)單來(lái)說(shuō),就是原來(lái)在 MPA 中的多個(gè) html,現(xiàn)在被放在了一個(gè) html 中,并被分成若干個(gè)片段。跳轉(zhuǎn)、返回的本質(zhì)變成了分段的「隱藏」與「顯示」。跳轉(zhuǎn)不需要反復(fù)對(duì)服務(wù)端進(jìn)行請(qǐng)求,從而使得頁(yè)面與頁(yè)面之間切換更加快速流暢。

          在這樣的機(jī)制下,跳轉(zhuǎn)與返回完全由代碼控制,所以可以通過(guò)代碼定義頁(yè)面轉(zhuǎn)場(chǎng)的效果、返回。

          在設(shè)計(jì)轉(zhuǎn)場(chǎng)動(dòng)畫時(shí),我們需要留意的是導(dǎo)航欄是 Native 的還是 HTML5 的。如果導(dǎo)航欄是 Native 的,那 HTML5 頁(yè)面不包括導(dǎo)航欄,它相當(dāng)于是網(wǎng)頁(yè)外的元素,不在轉(zhuǎn)場(chǎng)效果的設(shè)計(jì)范圍內(nèi)。

          WebView

          說(shuō) HTML5 的跳轉(zhuǎn),就不得不說(shuō) WebView。簡(jiǎn)單來(lái)說(shuō),WebView 是在 App 中用于顯示 web 內(nèi)容的容器。上文提到的 MPA 和 SPA,都裝在了這個(gè)叫做 WebView 的容器中。

          用戶點(diǎn)擊頁(yè)面中的元素進(jìn)行跳轉(zhuǎn),除了前面的兩種方式外,還有第三種:新打開 WebView 的方式。在這樣的方式下,跳轉(zhuǎn)的本質(zhì)是 HTML5「告訴」Native,由 Native 執(zhí)行打開新 WebView,并在新 WebView 中加載頁(yè)面。

          因?yàn)?Native 的機(jī)制,打開新 WebView 的同時(shí),之前的 WebView 會(huì)被自然、完整地保留。所以這時(shí),之前的幾個(gè)問(wèn)題就變?yōu)椋?/p>

          • 跳轉(zhuǎn)動(dòng)畫:頁(yè)面間的跳轉(zhuǎn)動(dòng)畫由 WebView 之間的跳轉(zhuǎn)動(dòng)畫來(lái)決定。
          • 返回后頁(yè)面停留在原位置:完美支持。
          • iOS 右滑返回:完美支持。

          不過(guò)需要注意的地方是,打開新 WebView 是一個(gè)資源消耗比較大的操作。如果我們?cè)谠O(shè)計(jì)一個(gè)流程時(shí),需要比較多的連續(xù)使用這種方式,需要和研發(fā)同學(xué)進(jìn)行充分的溝通。

          比較特殊的Replace

          前述的三種跳轉(zhuǎn),都會(huì)產(chǎn)生歷史記錄。MPA、SPA 的歷史記錄是在 HTML5 中產(chǎn)生,新開 WebView 中的記錄是在 Native 中產(chǎn)生。

          在 MPA 或 SPA 中,如果跳轉(zhuǎn)時(shí)使用 Replace 方法,它會(huì)用新頁(yè)面替換之前的頁(yè)面,歷史記錄中沒(méi)有之前頁(yè)面的記錄。

          這是一種特殊的跳轉(zhuǎn)方式,在設(shè)計(jì)一些不可逆的流程時(shí)可考慮使用。

          多頁(yè)面回退

          了解了上述的幾種機(jī)制后,我們來(lái)看一個(gè)小的應(yīng)用場(chǎng)景──多頁(yè)面回退。

          我們?cè)趯?shí)際業(yè)務(wù)中,經(jīng)常會(huì)有這樣的需求。假設(shè)我們有 1、2、3 三個(gè)頁(yè)組成的一個(gè)流程,在頁(yè)面 3 上有個(gè)「完成」按鈕點(diǎn)擊回到頁(yè)面 1。在不同的交互模式下,實(shí)現(xiàn)這樣的跳轉(zhuǎn)有著不同的機(jī)制。

          1. SPA模式下的正常跳轉(zhuǎn)

          這種模式是 3 個(gè)頁(yè)面都在一個(gè) WebView 中。點(diǎn)擊頁(yè)面 3 中的「完成」按鈕,回退 -2 ,即回退 2 步歷史記錄,到頁(yè)面 1。

          2. 新打開WebView

          打開新 WebView 又分三種方式。

          如果我們把 3 個(gè)頁(yè)面,拆分到 2 個(gè) WebView 中,如下圖,點(diǎn)擊完成按鈕,即關(guān)閉自身所在的 WebView。

          同樣是打開新的 WebView,如果我們按如下圖的方法拆分會(huì)稍微復(fù)雜。這時(shí)點(diǎn)擊完成按鈕,首先關(guān)閉自身所在的 WebView,當(dāng)頁(yè)面 2「意識(shí)」到自己重新被展現(xiàn)時(shí),自動(dòng)退回 1 步到頁(yè)面 1。

          每次打開新的 WebView,這時(shí)點(diǎn)擊完成,回退的本質(zhì)是 HTML5「告訴」Native 關(guān)閉多個(gè) WebView。需要特別注意的是,HTML5 中實(shí)現(xiàn)這種方式不是天然具備的,它需要 Native 具有一次關(guān)閉多個(gè) WebView 的能力。所以我們?cè)谠O(shè)計(jì)方案時(shí),需要了解清楚自家的 Native 是否有這樣的能力。

          總結(jié)

          以上,簡(jiǎn)單說(shuō)了幾種 HTML5 的跳轉(zhuǎn)方式。這些跳轉(zhuǎn)方式,沒(méi)有絕對(duì)的對(duì)與錯(cuò),我們?cè)谠O(shè)計(jì)方案時(shí),需要根據(jù)實(shí)際的業(yè)務(wù)需求與技術(shù)的限制,來(lái)整體考慮解決方案。

          根據(jù)個(gè)人經(jīng)驗(yàn),也有幾點(diǎn)小帖士分享給大家:

          • 前后邏輯交織不復(fù)雜的單個(gè)頁(yè)面,可以考慮使用新 WebView 打開跳轉(zhuǎn)。
          • 如果是一個(gè)任務(wù)型的流程,可以考慮將一個(gè)任務(wù)流包在一個(gè) WebView 中,在任務(wù)內(nèi)使用 SPA 跳轉(zhuǎn)。不同的任務(wù)使用不同的 WebView。保持任務(wù)之間的關(guān)系清晰明了。
          • 設(shè)計(jì)上需要著重表現(xiàn)頁(yè)面間轉(zhuǎn)場(chǎng)動(dòng)畫的效果,優(yōu)先考慮使用 SPA 跳轉(zhuǎn)。
          • 為防止流程過(guò)于復(fù)雜,盡量不要自定義關(guān)閉、返回的行為。保持關(guān)閉為默認(rèn)的關(guān)閉行為,保持返回為默認(rèn)的返回行為。

          N 在 0.37 版本中加入了WebView功能,所以想要在使用WebView,版本必須>=0.37,發(fā)送的 message 只能是字符串,所以需要將其他格式的數(shù)據(jù)轉(zhuǎn)換成字符串,在接收到后再轉(zhuǎn)換回去,其實(shí)直接用JSON.stringify和JSON.parse就可以加載html source屬性用于指定加載的 html,可以加載在線的頁(yè)面,也可以加載本地的頁(yè)面,代碼如下:

          注意 ??在 RN 中可以加載 WebView,但是無(wú)法調(diào)試,也不能使用 alert 來(lái)驗(yàn)證代碼 js 代碼是否運(yùn)行成功,只能通過(guò)往 html 寫入東西(innerHTML)來(lái)驗(yàn)證 js 是否運(yùn)行成功。

          WebView 與 html 的通信

          webview 發(fā)送信息到 html。WebView 給 html 發(fā)送信息需要使用postMessage,而 html 接收 RN 發(fā)過(guò)來(lái)的信息需要監(jiān)聽message事件,代碼如下:

          這里需要注意一點(diǎn),postMessage需要在 webview 加載完成之后再去 post,如果放在commponentWillMount里由于頁(yè)面沒(méi)有加載完成就 post 信息,會(huì)導(dǎo)致 html 端無(wú)法監(jiān)聽到 message 事件。html 發(fā)送信息到 webview。

          RN 中 debug webview 和安卓開發(fā)中看起來(lái)是差不多的,連接好設(shè)備后,在 chrome 中輸入chrome://inspect。就可以看到安卓設(shè)備上正在運(yùn)行的 webview 了,點(diǎn)擊inspect就會(huì)開啟一個(gè)調(diào)試頁(yè)面,就可以進(jìn)行 debug 了,RN 似乎默認(rèn)開啟了 debug 調(diào)試,直接就可以看到 webview 中輸出的信息。


          主站蜘蛛池模板: 在线电影一区二区| 久久一本一区二区三区| 国产成人综合精品一区| 色欲综合一区二区三区| 白丝爆浆18禁一区二区三区| 亚洲国产成人一区二区三区 | 日本免费一区二区三区| 亚洲国产精品一区二区九九| 国产免费伦精品一区二区三区 | 日韩欧美一区二区三区免费观看| 中文字幕日本精品一区二区三区| 国产萌白酱在线一区二区| 激情内射亚洲一区二区三区爱妻 | 亚洲中文字幕无码一区二区三区 | 中文字幕一区二区三匹| 女人和拘做受全程看视频日本综合a一区二区视频 | 久久精品一区二区三区不卡| 亚洲国产精品一区二区第四页 | 中文字幕一区二区视频| 无码精品久久一区二区三区| 精品一区二区三区在线观看l | 日本精品高清一区二区| 91视频国产一区| 无码av免费一区二区三区| 亚洲欧美日韩国产精品一区| 韩国福利影视一区二区三区| 国产精品第一区第27页| 制服丝袜一区在线| 成人区人妻精品一区二区不卡网站| 3d动漫精品啪啪一区二区中文 | 狠狠色婷婷久久一区二区| 国产精品揄拍一区二区| 精品一区二区三区免费视频| 亚洲a∨无码一区二区| 亚洲乱码一区二区三区在线观看| 国产日产久久高清欧美一区| 午夜视频在线观看一区二区| 国产成人无码一区二区三区| 国产一区二区三区不卡在线看 | 亚洲熟妇av一区| 在线观看国产区亚洲一区成人|