一、在閱讀過無數關於WebView的文章後,纔有此文的出現。某種意義上,此文的初衷並不是技術分享,而是對抄襲的不滿。但願閱讀此文的你是乾乾淨淨的。
二、選擇WebView做爲第一篇技術文章的緣由,是由於網絡上衆多對於第二代webview引擎的介紹不盡人意,且關於JS交互極爲模糊,作事不應是作完整嗎?假若你想琢磨,可在源碼中一窺究竟。
三、若是你有更加高明的思路,請Email:xorshine@icloud.com,或者在github上說明。
四、GSWebView下載地址 GSWebView文檔
javascript
iOS8以前閉源的UIWebView與以後開源的WKWebView,在開發中爲了支持iOS8如下的系統,難免要費些功夫。不多見到一個框架能如GSWebView通常將二者的用法簡化。java
GSWebView內部是對UIWebView與WKWebView的封裝,可是,它被設計成具備良好的代碼體驗。沒有過多的類讓人耳目眩暈。假若你使用過UIWebView,那麼,使用GSWebView則更加容易,你能很清楚的看出GSWebView是基本符合UIWebView的使用習慣。git
使用GSWebView能從根本上解決開發者對於兩代web引擎封裝的困惑。github
假若你仔細觀察過UIWebView的內存佔用和內存泄漏,你會認爲蘋果的工程師在此處開了小差,而這個小差很難被接受。當你對比WKWebView時,你會感受到它對於內存佔用優化上的作出的努力。web
UIWebView | WKWebView | 備註 | |
---|---|---|---|
iOS 版本 | 8.4 | 8.4 | ——— |
iPhone | 6 | 6 | 真機測試 |
測試網頁 | 天貓首頁 | 天貓首頁 | ——— |
內存佔用峯值 | 132.2MB | 8.4MB | ——— |
加載耗時 | 3.1s | 2.6s | mach_absolute_time(); |
FPS | 無明顯差別 | 無明顯差別 | Instruments (core animation) |
測試次數 | 2 | 2 | ——— |
注:該項測試或許存在很大的主觀性,當我加載天貓首頁時,這個結果出乎意料,差異大到使人難以接受。objective-c
無數的類堆積的時候,究竟是OOP仍是POP,當你看到WKWebView時,GSWebView纔會成爲你的真愛,WKWebView的設計......哎,但性能好纔是真的好!網絡
引入WebKit與JavaScriptCore庫,就可開始使用GSWebView。app
熟悉的屬性、方法框架
@property (nonatomic, readonly, strong) UIScrollView *scrollView; @property (nonatomic, readonly) BOOL canGoBack; @property (nonatomic, readonly) BOOL canGoForward; - (void)reload; - (void)stopLoading; - (void)goBack; - (void)goForward; //......and so on
形神皆似的協議方法post
#prama mark - GSWebViewDelegate - (BOOL)gswebView:(GSWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(GSWebViewNavigationType)navigationType; - (void)gswebViewDidStartLoad:(GSWebView *)webView; - (void)gswebViewDidFinishLoad:(GSWebView *)webView; - (void)gswebView:(GSWebView *)webView didFailLoadWithError:(NSError *)error;
GSWebView定義了兩套協議GSWebViewDelegate和GSWebViewJavaScript,GSWebViewDelegate定義了加載狀態,GSWebViewJavaScript則只定義了JS交互。
當你把方法名就這麼一傳,連參數都不要,回調天然完成,絲滑般天然......
#prama mark - GSWebViewJavaScript /** 交互協議 */ @protocol GSWebViewJavaScript <NSObject> @optional /** 調用OC方法 - (NSArray<NSString *>*)gswebViewRegisterObjCMethodNameForJavaScriptInteraction { return @[@"getCurrentUserId"]; } - (void)getCurrentUserId:(NSString *)Id { NSLong@(@"JS調用到OC%@",Id); } */ - (NSArray<NSString *>*)gswebViewRegisterObjCMethodNameForJavaScriptInteraction;
改動並不是是爲了增長複雜度,而是GSWebView內部的WKWebView必須經過Apple.Inc指定的方法
Adding a scriptMessageHandler adds a function window.webkit.messageHandlers.<name>.postMessage(<messageBody>) for all frames.
EXAMPLE:
JS調用客戶端getConsultationInfo:方法,客戶端獲取到id實現該方法,蘋果要求必須這樣作:
//獲取客戶端iOS版本 var version = (navigator.appVersion).match(/OS (\\d+)_(\\d+)_?(\\d+)?/); version = parseInt(ver[1], 10); if(version >= 7.0 && version < 8.0){ getConsultationInfo(id); }else if(version>=8.0){ window.webkit.messageHandlers.getConsultationInfo.postMessage(id) }
這不是貧僧的錯,要怪就怪......
若是以前使用了UIWebView,現在使用GSWebView,在服務端對JS源碼作出改動後,必需要考慮客戶端老版本的兼容狀況。當改動服務端的JS代碼,勢必致使老版本中的UIWebView交互失效。在下有個建議:
當GSWebView加載成功,咱們調用服務端預先寫好的方法 function shouldUseLatestWebView(isBool);
NSString * shouldUseLatestWebView; if (IS_IOS_8) { shouldUseLatestWebView = [NSString stringWithFormat:@"shouldUseLatestWebView('%@')", @"1"]; }else{ shouldUseLatestWebView = [NSString stringWithFormat:@"shouldUseLatestWebView('%@')", @"0"]; } [self.webview excuteJavaScript:jsGetCurrentUserId completionHandler:^(id _Nonnull params, NSError * _Nonnull error) { if (error) { NSLog(@"注入JS方法shouldUseLatestWebView出錯:%@",[error localizedDescription]); } }];
服務端用一個全局變量保存isBool的值,當isBool爲字符串1時,說明須要使用的是第二代WebView,服務端必須使用最新的交互方式代碼,若是爲字符串0或者空,則依舊使用原來的代碼交互:
//一個全局的變量 var isBool = ""; function shouldUseLatestWebView(isBool){ isBool = isBool; } if(isBool == "0" || isBool == ""){ getConsultationInfo(id); }else if(isBool == "1"){ window.webkit.messageHandlers.getConsultationInfo.postMessage(id); }
如此一來,就能夠作到老版本的兼容。
大膽的批評GSWebView!
畢竟,代碼體驗與用戶體驗,都一樣,重要。
本做品採用採用知識共享署名-非商業性使用-禁止演繹 3.0 中國大陸許可協議進行許可
*