為了更好的閱讀體驗,建議閱讀原文
想和我一起全面了解新聞類App的開發(fā)境钟,點我學習
據相關數據顯示锦担,截至2017年底,中國手機新聞客戶端用戶規(guī)模達到6.36億人慨削,移動App已經成為新聞和內容傳播的最重要途徑之一洞渔。而伴隨著行業(yè)的競爭和發(fā)展套媚,App中的內容頁在提升App品質、提升使用時長及提升用戶黏性等方面磁椒,扮演著更為重要的角色堤瘤,同時也面臨著更大的挑戰(zhàn)。
- 內容頁在呈現上越來越豐富衷快。新聞資訊作為內容頁的主體宙橱,逐漸增加了更多的文字樣式姨俩、內容形式蘸拔、富媒體、以及廣告环葵、投票等更為豐富的元素调窍。
- 內容頁需要更多擴展區(qū)域來提高使用時長及用戶黏性。在資訊主體之外张遭,各個App逐漸打造了例如關注模塊邓萨、推薦閱讀模塊、評論模塊菊卷、運營模塊等越來越多的擴展閱讀區(qū)域缔恳。
- 短視頻、直播的爭奪越來越激烈歉甚。越來越多的新聞App都將視頻作為獨立的模塊和獨立的內容頁進行展示纸泄。
- 同質化產品競爭激烈聘裁。要求更快的迭代速度衡便、更優(yōu)質的用戶體驗镣陕、更小的實現成本茁彭。
所以理肺,新聞類App內容頁架構的設計和技術的優(yōu)化,也要配合產品形態(tài)的發(fā)展年枕,在越來越復雜的需求挑戰(zhàn)下熏兄,擁有快速響應的能力和穩(wěn)定優(yōu)質的體驗摩桶。
本文結合分析目前主流(DAU)新聞類App如今日頭條硝清、騰訊新聞芦拿、天天快報蔗崎、一點資訊等
內容頁技術方案的選擇缓苛,一起探索新聞類App內容頁的技術實現和優(yōu)化他嫡。
—— 幾十行代碼完成新聞類App多種形式內容頁
HybridPageKit :一個針對新聞類App高性能钢属、易擴展淆党、組件化的通用內容頁實現框架染乌。
基于ReusableNestingScrollview荷憋、WKWebViewExtension勒庄、以及本文中關于內容頁架構和性能的探索实蔽。
想和我一起全面了解新聞類App的開發(fā)局装,點我學習
1. 概念定義
結合目前主流的內容頁實現方式铐尚,我們把內容頁分為上下兩個部分塑径,為了方便后續(xù)的閱讀先簡單定義下關鍵的名詞统舀。
- 上部分通常用WebView實現誉简。常規(guī)包括標題 + 作者(關注)+ 資訊內容闷串,我們稱為
WebView內容區(qū)
烹吵。 - 下半部分主要是平行于WebView的各種擴展內容肋拔,常規(guī)包括點贊打賞凉蜂、廣告推廣窿吩、相關推薦纫雁,熱門評論等等轧邪,我們稱為
Native擴展區(qū)
。 - WebView中每個復雜UI呈現曾棕、擴展區(qū)中每個獨立模塊翘地,我們都稱為一個
模塊
或組件
衙耕。
完整來看橙喘,整個內容頁右側(右滑)普遍為評論頁厅瞎。無論是之前流行的ScrollView右滑還是近期流行的Push新頁面和簸,這兩種方式實現起來都比較簡單且較為獨立锁保,故本文暫時忽略右側(右滑)評論的部分爽柒。
2. 目錄
- 技術方案選擇 -
1.WebView類型選擇
不同于微博浩村,新聞類App的內容以段落性的文字為主穴亏,配合段落間的圖片嗓化、富媒體等刺覆。同時為了滿足跨平臺的一致呈現谦屑、PC網頁的文章轉載氢橙、不同平臺文章的抓取悍手,以及注重閱讀而非交互等原因坦康,使用WebView加載渲染本地的HTML字符串數據已經成為了新聞類App通用的方案滞欠。
1. UIWebView VS WKWebView
-
穩(wěn)定性:
UIWebView較多的WebCore筛璧、JavaScriptCore Crash隧哮,以及系統(tǒng)性的內存泄露導致OOM沮翔,對整個App的穩(wěn)定性都是極大的隱患采蚀。反觀WKWebView榆鼠,基于獨立進程妆够,不會占用App的內存計算神妹,同時也不會導致主App Crash鸵荠。所以在系統(tǒng)級的穩(wěn)定性上蛹找,WKWebView有著極大的優(yōu)勢庸疾。
-
加載速度:
WKWebView通過JIT大幅優(yōu)化了JS的執(zhí)行速度届慈,但是對于新聞類App內容頁的使用場景來說拧篮,簡單的進入串绩、退出頁面礁凡,且單純的加載渲染HTML字符串顷牌,WKWebView比UIWebView慢了很多(Benchmark)罪裹。
-
兼容性:
NSURLProtocol的無法使用状共、長按MenuItems Bug(before iOS11)峡继、iOS8不能刪除Cache碾牌、設置Cookies及UA舶吗、POST參數裤翩、異步執(zhí)行JS...這一系列的問題踊赠,成為了穩(wěn)定項目替換WKWebView最大的挑戰(zhàn)筐带。
-
擴展性:
WKWebView具有更加豐富的接口伦籍、更多HTML和CSS的支持帖鸦、以及更加友好的JS交互作儿。同時Api的持續(xù)更新和社區(qū)的活躍攻锰,從長遠使用的角度看有著極大的優(yōu)勢娶吞。
2. 修復妒蛇、擴展WKWebView
通過以上的分析材部,WkWebView從系統(tǒng)級的穩(wěn)定性乐导、性能以及后續(xù)擴展性都有很大的優(yōu)勢物臂。通過WKWebViewExtension擴展修復原生WKWebView棵磷,結合HybridPageKit中WKWebView的回收復用邏輯仪媒,極大程度上解決了原生WKWebView的問題算吩,起到了很好的效果偎巢。
-
修復擴展的問題:
通過逐階段分析耗時压昼,在內容頁的使用場景下窍霞,WKWebView從alloc到準備開始渲染這段時間但金,有著極大的優(yōu)化空間傲绣。在瀏覽內容頁這種場景下秃诵,HybridPageKit中通過WKWebView的復用回收以及資源緩存菠净,極大降低了WKWebView加載渲染HTML的時間毅往,使之低于原生UIWebView攀唯。
通過私有方法的擴展和代碼優(yōu)化侯嘀,在WKWebViewExtension中支持了URLProtocol戒幔、修復了MenuItems的bug诗茎、支持iOS8清理緩存王污、擴展安全的JS執(zhí)行方法玉掸、以及擴展NavigationDelegate以兼容JSBridge邏輯等司浪。
-
無需解決的問題:
對于新聞類App內容頁的使用場景啊易,一些WKWebView的問題并沒有必要形成通用的解決方案以兼容代碼租谈。比如POST請求不能帶參數割去、Javascript異步執(zhí)行等問題呻逆,都可以通過代碼的重構來進行解決咖城。尤其不推薦卡主Runloop從而同步JS的方式宜雀。
-
遺留問題:
目前辐董,在使用WKWebView的過程中简烘,唯一未解決的問題就是可靠夸研、全面的白屏檢測方案亥至,從而支持WKWebView在任何情況下的Crash進行重載絮供。諸如系統(tǒng)Crash回調壤靶、WebView Title監(jiān)聽贮乳、ContentSize監(jiān)聽向拆、甚至屏幕隨機取色值等方法都不能滿足全部的白屏場景。
2. WebView內容區(qū)與Native擴展區(qū)的銜接
對于目前的主流App來說颈将,單純的WebView已經無法滿足復雜的呈現和邏輯晴圾。如何在頁面中合理的處理WebView與擴展區(qū)中的多種View協(xié)同滾動疑务,靈活擴展知允,并且支持下拉刷新、上拉加載等操作涤垫,不同的新聞類App也有不同的技術方案蝠猬。
1. 結合TableView
-
實現原理:
由于擴展區(qū)中列表類型的模塊較多(例如相關文章榆芦、評論等),最簡單的實現即Native擴展區(qū)的模塊拆分到Cell的粒度,整體使用TableView實現。對于擴展區(qū)和WebView的銜接森爽,如上圖一般有兩種實現方案:TableView根據WebView的Inset(或Div占位)插入到WebView中 & WebView作為TableView的Header咐鹤。
-
優(yōu)點:
這種方法相對簡單雕旨,容易實現內容頁各個模塊的布局凡涩,同時基于TableView的刷新邏輯,也能動態(tài)的處理各個模塊的更新育韩、插入刪除筋讨,并且支持家在更多等悉罕。和WebView的結合滾動也較為流暢壁袄。
-
不足:
這種方式將Native擴展區(qū)的模塊粒度都區(qū)分到Cell的層級嗜逻,列表類型模塊只能通過Cell或者以Section的模式進行管理令哟,同時也無法跨頁面的整體復用UI及業(yè)務邏輯。UI的布局依賴TableView模式蛙卤,靈活性較差颤难。隨著組件類型的增多行嗤,非同質性的View也沒有充分利用TableView的復用。
同時無論使用哪種方式和WebView銜接栈雳,都影響了WebView、TableView的獨立渲染展示蛀骇,增加了維護的困難擅憔。并且Header與Inset對于頭部區(qū)域的擴展雕欺,如下拉刷新等,實現都較為困難。
2. ScrollView嵌套
-
實現原理:
這種實現用一個ScrollView作為Container沟蔑,將WebView及擴展區(qū)的組件分別作為SubView狱杰。全部SubView禁止?jié)L動仿畸,內容頁的全部滾動都發(fā)生在Container上簿晓。對于SubView中的滾動視圖,如果ContentSize小于屏幕高度谒臼,則作為普通View,否則設置為屏幕高度劫樟,通過offset和Frame的計算叠艳,動態(tài)的調整視圖相對Container的Frame以及自身的ContentOffset附较,實現滾動效果。
-
優(yōu)點:
這種方式完全獨立每個模塊的實現早像,使UI和業(yè)務邏輯一一對應卢鹦。對WebView的渲染沒有干擾冀自,模塊的加載和布局靈活管理搀玖、復用巷怜,模塊業(yè)務邏輯獨立內聚。添加刪除模塊答渔、實現上拉下拉等操作簡單。極大的提高了靈活性和復用的可能务豺。
-
不足:
由于這種方式需要對SubView中的滾動視圖進行計算、模塊動態(tài)更新時整體布局也需手動刷新等,極大的提高的實現的復雜度。
基于ReusableNestingScrollview舞骆,在HybridPageKit中督禽,封裝了以上ScrollView嵌套邏輯猖凛。這樣就隱藏了復雜的實現邏輯和邊界條件赂蠢,充分的保留了靈活性的特點。同時對于內容頁的使用場景辨泳,精簡了嵌套滾動的使用虱岂,擴展上拉加載更多及下拉刷新邏輯玖院,使整個方案實現簡單、靈活擴展第岖。
3. WebView內復雜UI键袱、復雜交互模塊的展示
隨著核心的WebView內容區(qū)逐漸支持復雜的呈現方式,單純的H5基礎渲染已經滿足不了現有的需求,比如視頻的交互、音樂的續(xù)播、以及各種地圖轩拨、投票等組件爸邢。同時Web中復雜的UI和邏輯也極大降低了WebView的渲染速度,增加了開發(fā)和維護的成本。
1. 復雜UI及邏輯實現困難
- 為了滿足更好的交互體驗,資訊內容中富媒體內容逐漸增多,如視頻的續(xù)播、小窗播放媒咳、音樂懸浮播放射富、內容中插入地圖赠群、投票等冬三。同時隨著產品功能的迭代匠襟,例如圖片類型的簡單模塊忽舟,也增加了點擊全屏状您、長按保存、二維碼識別先改、雙擊擴大等交互岛抄。這些復雜的UI和邏輯導致CSS和JS增多扰付,Native和Web的通信增加曙咽,以及大量運用LocalStorage等瀏覽器存儲,增加了客戶端開發(fā)和維護的成本睬魂。
2. 簡單圖片的展示耗時
- 對于內容WebView中的圖片,最簡單的作法闲延,就是后臺直接下發(fā)Img標簽,依靠WebView自身的下載與渲染互婿。但是這種方式靈活度較低猜绣、客戶端無法合理的控制下載時機、無法做自定義的緩存以及裁剪等怕篷。
- 對于簡單Img標簽的升級叠荠,即后臺數據單獨下發(fā)圖片數據,客戶端根據需求自定義選擇下載時機及緩存策略。Html模板中先用占位圖占位炭玫,Native下載成功后替換標簽的Src進行展示践图。這種方式雖然解決了靈活性的問題扣讼,但是也帶來了整個流程的復雜性蒸健,以及多次IPC間的通信延遲。
- 為了兼顧靈活性,以及縮短圖片的Loading時間诫硕,我們在單獨處理圖片的同時休偶,替換內容WebView中全部圖片為Native垮媒,減少不必要的流程及通信毁嗦,極大提高了加載的速度药版。
3. Native化全部非文字類組件
為了減少實現復雜UI、復雜交互模塊的開發(fā)、維護成本、減少模塊在Web和Native間的邏輯流程斑匪,提高Web中模塊的加載展示速度,在HybridPageKit中將Web中全部非文字類模塊全部Native化锡溯。
-
頁面模板使用空div占位:
結合后臺的模板與數據谆奥,全部模板中全部非文字類的組件魄懂,映射成統(tǒng)一Class的Div褐荷,通多唯一的id與數據綁定捉邢。組件默認實現占位圖邏輯,對于同步數據同時設置組件的Size商膊,異步數據則先設置為0伏伐。替換后WebView對模板進行渲染。
-
渲染完成通過JS獲取位置:
WebView渲染成功回調晕拆,通過JS獲取全部統(tǒng)一class對應WebView的Frame藐翎,以及對應的唯一Id。
-
在相應位置粘貼NativeView:
在進行以上兩個步驟的同時实幕,進行下載圖片數據吝镣、NativeView創(chuàng)建、初始化昆庇、異步數據拉取等工作赤惊。在JS回調全部位置時,根據位置及ID凰锡,粘貼Native組件未舟。
調整字體大小,組件異步數據拉鹊辔:對于異步的變化裕膀,在復用邏輯之后,下文將結合一并說明勇哗。
4. 內容頁全部組件的滾動復用
在Native化全部非文字類組件之后昼扛,面對文章中圖片、富媒體數量的增多欲诺,以及Native擴展區(qū)元素的增加抄谐,沒有復用回收的內容頁從滾動性能及內存兩個兩個方面都面臨著挑戰(zhàn)。同時扰法,為了更好的提升用戶體驗蛹含,需要對各個組件滾動時的位置進行計算,從而區(qū)分不同的區(qū)域進行諸如預處理浦箱、延遲釋放等邏輯。
1. 主流滾動復用框架
-
繼承特殊ScrollView:
目前流行的框架如alibab的LazyScrollView咽安,對于實現復用回收機制,都需要繼承相應的ScrollView蓬推,這種方式對于WKWebView來說,是無法實現的募逞。
-
繼承特殊Model:
由于滾動復用需要保存View對應的數據信息,大部分開源框架需要繼承特殊數據Model馋评,生成對應必要的參數或方法,對于支持多種類型組件的通用框架來說留特,繼承的實現方式不易于擴展和維護玛瘸。
-
View滾動狀態(tài)簡單:
滾動時位置的計算糊渊,最簡單的方式就是根據屏幕的高度計算是否進入屏幕,對于預加載的需求贺喝,絕大部分開源框架也是只是在屏幕區(qū)域的上下增加了Buffer躏鱼,仍然不能區(qū)分具體的狀態(tài)殷绍,如進入buffer主到、進入屏幕等,無法滿足復雜的業(yè)務邏輯畔师。
2. WebView中組件的滾動復用
-
無需繼承:
在ReusableNestingScrollview中茉唉,為了兼容WebView度陆、ScrollView等一切滾動視圖中子View的復用回收,我們通過scrollView delegate的擴展分發(fā)趾诗,擴展handler單獨處理子View的復用回收恃泪,這樣就在無需繼承的前提下贝乎,支持所有滾動視圖中子View的復用回收叽粹。
-
數據驅動:
由于View需要不斷的復用回收虫几,所以數據、狀態(tài)但校、位置状囱、對應的View類型都存儲在對應的Model中倘是,不但實現了數據驅動易于動態(tài)擴展辨绊,同時優(yōu)化了復用的邏輯,也緩存住了Frame等關鍵信息優(yōu)化了渲染布局邏輯门坷。
-
面向協(xié)議:
由于滾動復用的模塊對應的View及數據Model種類眾多默蚌,在不動態(tài)擴展NSObject绸吸、UIView的情況下设江,無法做到通用的邏輯公用叉存。所以為了更好的支持擴展歼捏、更靈活的實現方式笨篷,ReusableNestingScrollview中面向通過擴展數據Protocol率翅,使得任何Model輕松實現復用回收對應邏輯冕臭。
-
更加豐富的狀態(tài):
在ReusableNestingScrollview中,為了滿足更復雜的需求,如視頻預加載及自動播放念颈、Gif預加載及自動播放等榴芳,我們擴展了組件在滾動過程中的狀態(tài)跺撼,增加自定義workRange歉井,使組件在滾動過程中的狀態(tài)變?yōu)?種哩至,即None、prepare區(qū)域及Visible區(qū)域卢佣,更加全面準確的記錄狀態(tài)切換虚茶,更加靈活的支持業(yè)務場景嘹叫。同時通過3種狀態(tài)擴展為二級緩存,對View在不同級別的緩存設置不同的策略待笑。
綜上暮蹂,通過ReusableNestingScrollview只需將模塊對應Model擴展增加協(xié)議仰泻,滾動視圖擴展Delegate集侯,就可實現任何滾動視圖中子View的回收復用功能。
3. 內容頁中全部組件的滾動復用
在解決了內容WebView中非文字類組件的Native化浓体、滾動復用之后命浴,我們將實現思想運用到包含Native擴展區(qū)的生闲,內容頁整體架構中月幌。如果從內容頁的維度去看扯躺,內容WebView也可以算作一個組件录语,它和擴展區(qū)的各種組件一起作為Container的子View钦无,也可以運用上面提到的ReusableNestingScrollview進行實現和管理。
所以整個內容頁就是從兩個維度鳄虱、運用ReusableNestingScrollview中的實現方法兩次實現滾動復用回收拙已、數據驅動倍踪、組件自管理以及組件狀態(tài)切換邏輯建车。
5. 組件異步拉取與動態(tài)調整
面對復雜的需求缤至、以及按需加載康谆、異步拉取等優(yōu)化體驗的策略沃暗,在HybridPageKit中也針對相應的場景做了高效的處理孽锥。
1. WebView字體大小調整
當WebView中字體大小調整時忱叭,需要同時調整全部Native組件的位置今艺。我們監(jiān)聽WebView的ContenSize變化虚缎,當變化發(fā)生時实牡,重新執(zhí)行獲取組件位置的JS語句獲得全部組件的新位置创坞√庹牵基于滾動復用的邏輯,只需要對在屏幕中的組件View的位置進行調整却嗡,其余只需要重新對組件對應Model的Frame進行賦值铐望,極大提升了效率正蛙。在此基礎上跟畅,要動態(tài)的檢測ContenSize是否小于屏幕高度,高度小于一屏幕時奸攻,要同時調整Native擴展區(qū)組件的位置睹耐。
2. WebView中組件異步拉取數據渲染
對于異步拉取數據的組件硝训,由于初始化時占位Div的高度為0窖梁,當數據獲取成功纵刘,并渲染好組件后荸哟,需要首先執(zhí)行JS動態(tài)修改對應占位Div的大小鞍历,之后按照以上的邏輯劣砍,重新賦值Native組件位置。
3. Native擴展區(qū)組件異步拉取數據渲染
Native擴展區(qū)中的組件不同于WebView中的組件爵政,不依賴WebView自身渲染钾挟。所以當動態(tài)調整大小時饱岸,之需調整全部Native擴展區(qū)組件數據Model中保存的Frame信息,同時調整在屏幕中的組件位置即可汤锨。
—— 幾十行代碼完成新聞類App多種形式內容頁
HybridPageKit :一個針對新聞類App高性能闲礼、易擴展柬泽、組件化的通用內容頁實現框架锨并。
基于ReusableNestingScrollview第煮、WKWebViewExtension包警、以及本文中關于內容頁架構和性能的探索害晦。
想和我一起全面了解新聞類App的開發(fā)篱瞎,點我學習
- 內容頁組件化架構 -
在實現了以上技術關鍵點的基礎上,如何合理的設計內容頁通用的架構牵素,快速響應內容頁的各種需求調整笆呆,使整體架構易擴展、易維護询筏,同時有較高的性能及較小的內存占用嫌套,成為了整個內容頁架構實現的重點踱讨。在HybridPageKit中痹筛,我們圍繞靈活復用帚稠、高內聚低耦合翁锡、易于實現擴展三個重點的方向馆衔,設計實現了基于組件化的內容頁整體架構角溃。
1. 組件化解耦及組件通信
為了滿足內容頁業(yè)務的相對獨立减细,支持快速響應迭代及組件整體復用未蝌,內容頁整體的結構應滿足通用性萧吠、易于擴展纸型、以及高內聚低耦合的特點狰腌。所以在ReusableNestingScrollview的支持下琼腔,采用組件化的方式實現全部內容頁業(yè)務模塊丹莲。
1. 組件化解耦
為了達到組件的高內聚圾笨、與內容頁的低耦合擂达,在HybridPageKit中拆分業(yè)務邏輯為獨立的組件化的處理單元板鬓,每個處理單元通過MVC模式實現俭令。其中Model作為組件的數據抄腔,只需要在實現解析邏輯同時赫蛇,實現對應delegate即可悟耘。Controller只需要實現組件間通信的delegate暂幼,選擇性的實現例如controller生命周期旺嬉、webview關鍵回調鹰服、以及滾動復用相關的方法即可悲酷。通過組件的自管理及復用设易,組件可以集成統(tǒng)一的上報邏輯顿肺、業(yè)務邏輯到自己的Controller中屠尊,并且在不同類型的頁面靈活復用托享。
2. 組件通信
為了更好的實現組件化的結構闰围,組件的Controller需要在內容頁初始化時進行注冊羡榴。內容頁在每個關鍵的生命周期或業(yè)務節(jié)點校仑,采用中心化通信肤视,廣播執(zhí)行相應的方法邢滑,組件的Controller按需實現處理即可困后。對于新增摇予、刪除功能侧戴,只需擴展delegate中的方法积仗,內容頁中觸發(fā)方法寂曹、組件中實現方法即可隆圆。
2. 組件及WebView的復用管理
1. WebView & 組件View全局復用
為了提高WKWebView渲染速度渺氧,通過建立全局WKWebView復用回收池來復用WKWebView阶女。除了基本的線程安全、復用狀態(tài)管理等哩治,在進入回收池前要load特殊Url以維護整個backFowardList秃踩。組件的View也是通過全局的復用回收池進行管理,使得相同的組件View可以靈活的出現在內容頁业筏、列表頁等App內各個頁面憔杨,極大的減少了開發(fā)成本,提高運行效率蒜胖。
2. 自動回收 & 內存管理
WebView及組件View實現自動回收邏輯,每次在申請新View時檢測活動隊列中View的SuperView是否為nil台谢,是則自動回收防止內存泄露寻狂,同時增加View最大數量閾值、內存告警自動釋放邏輯等朋沮。
3. 內容頁整體架構
1. 易于擴展業(yè)務節(jié)點 & 組件類型
對于增加關鍵的業(yè)務節(jié)點用于組件業(yè)務處理蛇券,我們只需擴展delegate中的方法,在相關組件中實現樊拓。內容頁Controller中在相應位置纠亚,通過統(tǒng)一函數觸發(fā)廣播代理方法即可。對于增加組件來說筋夏,只需創(chuàng)建組件完全獨立的MVC代碼蒂胞,實現數據解析Model并實現滾動復用delegate,在組件Controller中實現delegate中需要的方法等待調用条篷,以及初始化時在內容頁注冊即可骗随。刪除組件完全無需操作內容頁蛤织,刪除獨立的MVC結構并停止注冊即可。
2. 易于擴展內容頁類型
為了實現內容頁擴展區(qū)的靈活復用鸿染,在HybridPageKit中也擴展了非WebView類型的內容頁指蚜。就像文中之前提到的,如果將WebView看做一個整體作為一個組件牡昆,基于ReusableNestingScrollview的位置動態(tài)管理姚炕,完全可以替換成普通的View(類似Banner視頻內容頁)摊欠,或者可擴展收起的View(問題回答頁面)甚至tableView等丢烘。所以整個App內各種類型的內容頁只需要簡單的配置,便可進行實現和組件復用些椒。
3. 內容頁架構
結合ReusableNestingScrollview播瞳、WKWebViewExtension以及組件化的設計思路,HybridPageKit整體的架構如下:
通過繼承特殊的內容頁Controller并進行簡單的配置免糕,即可生成不同類型的內容頁整體架構赢乓。框架內集成基本的Mustache解析和渲染石窑。結合后臺數據牌芋,只需實現對應頁面中組件MVC邏輯即可。其中Model只需實現對應Protocol松逊,Controller在內容頁中注冊躺屁,實現對應Protocol即可。
—— 幾十行代碼完成新聞類App多種形式內容頁
HybridPageKit :一個針對新聞類App高性能经宏、易擴展犀暑、組件化的通用內容頁實現框架。
基于ReusableNestingScrollview烁兰、WKWebViewExtension耐亏、以及本文中關于內容頁架構和性能的探索。
- 首屏加載速度優(yōu)化 -
新聞類App內容頁沪斟,在Native的頁面框架下广辰,基于WebView進行加載和渲染。所以主之,從優(yōu)化的角度就延伸出兩個維度轨域,即從Web的維度優(yōu)化,以及從Native的維度優(yōu)化杀餐。
1. Web維度的優(yōu)化
-
WKWebView的復用 :
通過WKWebView的復用干发,極大的縮短了WebView從創(chuàng)建到渲染結束的時間。
-
利用HTTP緩存 :
對于內容WebView中必要的CSS以及JS史翘,以及必要的基礎Icon枉长,可以通過設置HTTP緩存冀续,依靠瀏覽器自身緩存提高效率。同時通過資源md5校驗以保證刷新資源必峰。
-
減少資源請求并發(fā) :
通過Native化全部非文字類的內容洪唐,Web頁面只加載最近本的Html內容,減少了業(yè)務邏輯的資源請求和并發(fā)吼蚁。
-
減少Dom & Javascript復雜度 :
通過Native化全部非文字類的內容凭需,極大的減少了Dom的復雜度、CSS的復雜度以及過多的JS業(yè)務邏輯肝匆。
-
其它Web優(yōu)化通用方法 :
精簡Javascript粒蜈,使用iconFont,CSS & Javascript文件壓縮等
2. Native維度的優(yōu)化
-
數據模板分離旗国,資源并行加載 :
基于后臺數據以及Native化組件枯怖,內容頁Html中模板與數據分離,使得全部資源如圖片視頻等都可以通過Native在合適的時機異步并行加載能曾。不依賴與Web的渲染度硝。
-
預加載數據,延遲加載組件:
對于內容頁關鍵內容(Webview)的拉取,大部分App都放到了列表頁中進行寿冕。進入內容頁時直接從Cache中取出內容模板蕊程,直接交給WebView渲染⊥粘基于ReusableNestingScrollview擴展豐富的狀態(tài)及二級緩存藻茂,在頁面滾動的過程中各個組件也可以精確的實現按需加載、預加載等邏輯曙蒸。
-
Native化非文字UI捌治,及組件化實現負載均衡 :
WebView中非文字類UI Native化,極大的縮短了展示所需的流程纽窟,減少了進程間通信肖油,減少了I/O及圖片編解碼邏輯,提高了類似圖片類的UI展示速度臂港。
組件的解耦與自管理森枪,以及廣播delegate的實現,為組件的按需加載审孽、按優(yōu)先級加載提供了基礎县袱。對于內容頁的各個組件來說,在內容頁展示之前大部分是不需要初始化佑力、數據拉取以及渲染的式散。組件化之后的組件可以根據業(yè)務優(yōu)先級,在不同的關鍵生命周期回調中實現業(yè)務邏輯打颤,以減輕內容頁創(chuàng)建暴拄、模板拼接以及WebView渲染的壓力漓滔。簡單的舉例,由于內容WebView幾乎都大于一屏乖篷,擴展區(qū)中的全部組件都可以在WebView渲染結束后進行View創(chuàng)建响驴、網絡拉取和渲染等,這樣即不影響用戶的使用撕蔼,同時極大的釋放了渲染結束前的網絡豁鲤、IPC及CPU壓力,提高首屏展示速度鲸沮。
-
組件的滾動復用 & 全局復用 & Model緩存Frame:
基于ReusableNestingScrollview擴展數據Model琳骡,緩存對應View的Frame信息,結合View的滾動復用诉探,極大的減少了UI布局的邏輯和計算日熬。頁面內組件的滾動復用及頁面間的組件復用棍厌,也同時減少了組件View的初始化耗時肾胯。
-
其它通用方法:
基于App的技術實現和業(yè)務邏輯的優(yōu)化,如異步執(zhí)行業(yè)務邏輯耘纱、 圖片編解碼優(yōu)化及資源緩存敬肚,DNS緩存等。
3. 整體優(yōu)化方法
綜上束析,從一個內容頁在列表上的點擊艳馒,到WebView渲染結束,最后到用戶的滾動操作员寇,按照時間的順序弄慰,全部的優(yōu)化策略如下圖:
—— 幾十行代碼完成新聞類App多種形式內容頁
HybridPageKit :一個針對新聞類App高性能、易擴展蝶锋、組件化的通用內容頁實現框架陆爽。
基于ReusableNestingScrollview、WKWebViewExtension扳缕、以及本文中關于內容頁架構和性能的探索慌闭。
想和我一起全面了解新聞類App的開發(fā),點我學習
- 拾遺及Tips -
對于新聞類App內容頁的完整的解決方案躯舔,還有一些基本的技術點驴剔,比如模板引擎及模板拼接的模塊、JSApi注入及管理的模塊等等粥庄,由于篇幅所限丧失,暫且不做深入的展開。
新聞類App的內容頁惜互,除去基本的渲染HTML數據外布讹,同時也需要支持服務于活動科侈、運營的臨時H5頁面。這些頁面為了和Native進行交互炒事,在自定義JSApi注入臀栈、JSBridge的選擇、后臺下發(fā)domain黑白名單挠乳、以及相關的安全性考慮也是整個實現中重要的一環(huán)权薯。同時由于WKWebView支持復用回收,加載本地Html類型的WebView應該與加載H5的WebView在不同的回收復用池分開管理睡扬。
對于內容頁圖片的管理盟蚣,絕大多數App都將之納入了App統(tǒng)一的圖片管理體系中。無論使用哪個開源圖片庫卖怜,在緩存策略上屎开,盡量將內容頁圖片的緩存策略與其他的有所區(qū)分,或者使用
LRU + FIFO
的緩存策略马靠,避免進入內容頁大量圖片占用緩存空間奄抽,導致列表圖片釋放。同時從使用的角度來說甩鳄,重復進入同一篇文章的場景也不會頻繁的出現逞度。由于各個App的數據接口和技術選型不同,在HybridPageKit中只簡單的實現了基于Mustache的模板拼接妙啃,主要是由于它的logic-less档泽、多終端集成的方便以及開源社區(qū)的活躍。對于這部分邏輯揖赴,需要根據后臺數據的格式及業(yè)務需求自定義的擴展馆匿。
內容頁整體的實現和優(yōu)化,依賴整個App的技術實現和結構燥滑,在實現和優(yōu)化的過程中渐北,還有許多權衡和妥協(xié),以及許多通用的突倍、細節(jié)的優(yōu)化腔稀,這里就不一一贅述。
- 寫在最后 -
文章全部的探索及分析的實現羽历,除對應業(yè)務邏輯外焊虏,應用封裝成三個框架:HybridPageKit、ReusableNestingScrollview以及WKWebViewExtension秕磷。最終可以通過幾十行代碼诵闭,完成新聞類App多種形式的、高性能、易擴展疏尿、組件化的內容頁實現瘟芝。
有任何疑問,歡迎提交 issue褥琐, 或者直接修改提交 PR!
—— 幾十行代碼完成新聞類App多種形式內容頁
HybridPageKit :一個針對新聞類App高性能锌俱、易擴展、組件化的通用內容頁實現框架敌呈。
基于ReusableNestingScrollview贸宏、WKWebViewExtension、以及本文中關于內容頁架構和性能的探索磕洪。
想和我一起全面了解新聞類App的開發(fā)吭练,點我學習