優酷鴻蒙開發實踐 | 鴻蒙卡片開發

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c7/c7c73a83994db10394f5998ded9b8b81.gif","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者:苧麻","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"“","attrs":{}},{"type":"text","text":"  如標題所述,我們將持續更新《優酷鴻蒙開發實踐》系列文章。本文爲系列首篇技術文章,後續文章包括:鴻蒙/Android混合打包技術實踐,多屏互動技術實踐等,歡迎持續關注【阿里巴巴移動技術】。”","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"背景","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"隨着華爲Harmony OS2.0的發佈,各大廠商紛紛搶先與華爲展開合作。優酷作爲國內領先的長視頻在線視聽平臺,與華爲公司長期以來保持緊密的合作,共同爲消費者帶來優質的影音娛樂體驗。因此,優酷技術團隊也在第一時間投入對鴻蒙系統以及鴻蒙開發者SDK的研究。優酷技術團隊經過多輪的頭腦風暴,利用鴻蒙的某些新特性展開鴻蒙應用開發的嘗試。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"鴻蒙OS支持應用以Ability爲單位進行部署。Ability分爲兩種類型:FA(Feature Ability)和PA(Particle Ability)。FA/PA是應用的基本組成單元,能夠實現特定的業務功能。FA有UI界面,而PA無UI界面。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每種類型爲開發者提供了不同的模板,以便實現不同的業務功能。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"鴻蒙OS的應用軟件包以APP Pack(Application Package)形式發佈,它是由一個或多個HAP(HarmonyOS Ability Package)以及描述每個HAP屬性的pack.info組成。HAP是Ability的部署包,HarmonyOS應用代碼圍繞Ability組件展開。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/93/93de4e3255890800716dfb4a5c198092.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"鴻蒙工程通過鴻蒙打包工具鏈打包後,其產物格式即爲HAP。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當前,包含有鴻蒙FA/PA的優酷鴻蒙版已經在華爲鴻蒙應用市場上架,鴻蒙混合包在應用市場上會顯示爲“含HarmonyOS服務”。如果App是100% Pure鴻蒙App,其Icon右下角會有HMOS字樣。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在手機桌面上的優酷Icon輕輕上滑,會彈出一個鴻蒙卡片,向用戶推薦最近的熱劇,點擊卡片能快速拉起半屏落地頁顯示更多信息,點擊落地頁則跳轉到優酷客戶端的相應落頁面。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"點擊卡片上的圖釘按鈕,還可以將這個FA卡片固定在桌面上。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b6/b629fcc0bed9b50d69c3e5fb1bbdc643.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/67/67e7259dab37467c14291e5cb916277f.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個FA是100%利用鴻蒙API編寫的,可以脫離優酷主客獨立運行。由於FA卡片有極其嚴格的體積限制,而使用native的庫體積則會過大。最終,我們的Widget 通過一個Webview,加載JS版本的前端網絡庫去請求優酷內部的網絡接口,獲取到數據後再使用鴻蒙的Native圖形圖像API去繪製Native界面。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個桌面Widget與iOS桌面Widget的區別在於,它不依賴於優酷主客即可運作。即使優酷主客不被啓動,卡片的數據也能夠更新。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"鴻蒙卡片的開發模式","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在鴻蒙系統上,觸摸優酷主客的應用圖標向上滑動,可以喚起優酷的鴻蒙卡片。實現這一點需要卡片的實現代碼與優酷主客做混合打包,一起提交到應用市場。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而如果要實現服務中心免安裝使用,則需要卡片的獨立包總大小要小於10M。這一體積限制使得很多Native 庫都無法引入,否則無法將體積控制在紅線之內。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最終,優酷鴻蒙卡片的代碼放在一個工程中,方便跟優酷主客進行混合打包。同時,優酷鴻蒙卡片的代碼僅依賴極少數的二、三方庫(例如JSON解析、圖片緩存等),以減小體積。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"卡片樣式","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"鴻蒙系統提供4中大小不同的卡片,根據佔用桌面圖標數量的不同,分別是: 1x2、2x2、2x4、4x4。優酷卡片實現了其中兩種: 2x2和2x4,其中2x2的卡片是必選項。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下圖顯示了兩種不同樣式的卡片,以及不同的出現場景。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/67/67bf1bdeae113a5c7690b05d4e3407e1.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"聲明卡片","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"跟Android的應用微件類似,鴻蒙的卡片也需要在一個配置文件中聲明。在一個鴻蒙應用中,每個模塊都有自己的配置文件,位於該模塊的代碼main目錄下,名字爲config.json。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在配置文件中,每個模塊有一個abilities屬性,其值是一個數組,數組的每一個對象都定義了一個Ability。卡片就定義在其中一個Ability中:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"{\n ...\n \"formsEnabled\": true,\n \"forms\": [\n {\n \"landscapeLayouts\": [\n \"$layout:youku_widget_2_2\",\n \"$layout:youku_widget_2_4\"\n ],\n \"isDefault\": true,\n \"defaultDimension\": \"2*2\",\n \"name\": \"youku_widget\",\n \"description\": \"$string:yk_widget_description\",\n \"colorMode\": \"auto\",\n \"type\": \"Java\",\n \"supportDimensions\": [\n \"2*2\",\n \"2*4\"\n ],\n \"portraitLayouts\": [\n \"$layout:youku_widget_2_2\",\n \"$layout:youku_widget_2_4\"\n ],\n \"updateEnabled\": true,\n \"updateDuration\": 1\n }\n ],\n ...\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"鴻蒙系統中,卡片用Form來表示。上述聲明中,formsEnabled用於指示這個Ability是用於定義卡片的。forms數組用來定義一系列的卡片。通常多個卡片可以定義在一個數組元素中。其中landscapeLayouts、portraitLayouts、supportDimensions用於定義卡片的佈局文件和大小,updateEnabled、updateDuration用於控制卡片的數據更新,updateDuration的單位是半小時。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"生命週期","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在鴻蒙系統上,卡片的生命週期比普通的Page Ability要簡單很多,只有三個相關的回調:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"/**\n * 創建卡片時的回調。\n * 在intent中,存有創建卡片的一些重要參數,可以通過Intent.getXXXParam()方法獲取。\n * AbilitySlice.PARAM_FORM_IDENTITY_KEY: long類型,用於唯一標識一個卡片\n * AbilitySlice.PARAM_FORM_NAME_KEY: String類型,卡片名稱,即在config.json中定義的name屬性\n * AbilitySlice.PARAM_FORM_DIMENSION_KEY: int類型,卡片大小標識,\n * 取值範圍是1-4,分別表示1x2、2x2、2x4、4x4\n */\nprotected ProviderFormInfo onCreateForm(Intent intent)\n\n/**\n * 更新卡片時的回調。\n * 這裏的formId就是onCreateForm中的AbilitySlice.PARAM_FORM_IDENTITY_KEY參數。\n */\nprotected void onUpdateForm(long formId)\n\n/**\n * 刪除卡片時的回調。\n * 這裏的formId就是onCreateForm中的AbilitySlice.PARAM_FORM_IDENTITY_KEY參數。\n */\nprotected void onDeleteForm(long formId)\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"傳輸卡片內容","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"卡片的創建和顯示通常由桌面(或者服務中心、搜索)發起,而決定顯示內容的是優酷卡片這個模塊,內容提供方和顯示方不在同一個進程,甚至由不同開發者開發。在Android上也是一樣的情況。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這種情況下,一般都是內容提供方通過遠程View的方式將內容渲染到內容顯示方的,鴻蒙系統上這個跨進程的數據傳輸行爲是由ComponentProvider來實現的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"創建ComponentProvider有兩種方式:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"// 第一種: 在onCreateForm()時,先創建一個卡片對應的ProviderFormInfo實例。\n// 再通過ProviderFormInfo的實例拿到向它傳輸數據的ComponentProvider。\nProviderFormInfo form = new ProviderFormInfo(layoutId, context);\nComponentProvider cp = form.getComponentProvider();\n\n// 第二種: 在onUpdateForm()時,直接創建出一個ComponentProvider。\nComponentProvider cp = new ComponentProvider(layoutId, context);\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"需要注意的問題 1","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中設置IntentAgent時需要注意,通常一個佈局中會有多個View來覆蓋根佈局的矩形區域。如果設置了IntentAgent的View沒有覆蓋滿根佈局,則未覆蓋區域被點擊時,系統也會響應點擊,默認調起這個卡片所屬的Ability,傳入的Intent只包含formId。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對這個默認調起的Ability,一般有兩種方式解決:一是確保設置了IntentAgent的View覆蓋滿根佈局;二是Ability提供兜底方案,例如頁面做成透明,並且自動退出。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"需要注意的問題 2","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在創建IntentAgent時,需要提供一個IntentAgentInfo實例。這個IntentAgentInfo創建時的第一個參數是一個int類型的請求代碼,這個代碼必須保持各個卡片的不同點擊區都不一樣。否則後設置的IntentAgent會覆蓋先前設置的同一請求代碼的IntentAgent。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"需要注意的問題 3","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果是跟優酷主客混合打包,卡片的佈局文件中,View的id必須跟主客中所有的id不同,否則系統會無法正確更新佈局文件中對應的View。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"打開中轉頁","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於系統的限制,點擊卡片打開的頁面必須是純鴻蒙應用中的頁面,無法直接打開Android應用頁面。優酷卡片的點擊,目的是打開優酷主客的播放頁。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這裏我們做了分類:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當用戶未安裝優酷主客時,顯示一箇中轉頁,提供下載按鈕供用戶跳轉到華爲應用市場去下載優酷主客,當用戶安裝完優酷主客回來時,下載按鈕變成選集列表,對單集視頻則變成播放按鈕;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當用戶已安裝優酷主客時,中轉頁自動打開優酷主客的播放頁,並退出。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"數據請求","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在優酷主客中,網絡數據的請求都是通過統一的網絡庫訪問的。由於優酷鴻蒙卡片並未集成網絡庫,優酷鴻蒙卡片必須使用其他方式請求網絡接口。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要實現在鴻蒙上發起數據請求,有兩個方案:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一是針對每個數據請求接口,封裝一個新的HTTP Open API接口,客戶端可以通過HTTP(S)直接訪問;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"二是客戶端通過H5頁面裏的JS版Network庫發起數據請求。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"考慮到將來在鴻蒙系統上有可能實現更多其他的需求,且第一種方案有安全性的風險,所以最終我們採用了第二種方案。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前端業務使用的JS版本的網絡庫,其使用方式是通過JS中的Promise機制來實現異步回調,但是這種方式在Java中並不好實現對應的調用結構。所以這裏需要有一層封裝,將網絡請求結果通過簡單回調來通知請求方。相應的在Java側需要對WebView註冊全局的JS對象,實現JS對象的回調方法,打通JS -> Java的調用通路。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個方案在紙面上看着還不錯,但是在實際使用中會發現有嚴重的性能瓶頸。WebView本身是一個很重的控件,在進程中首次創建的時候會比較耗時,有很多的so加載、初始化等工作。加載HTML是一個網絡請求,耗時在百毫秒級,而加載並解析完HTML以後,還要再加載JS版本的網絡庫,又是一次網絡訪問。等JS網絡庫加載並解釋執行後,纔可以正常服務調用方。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要在這個過程中進行優化,這裏有主動權的地方就是加載HTML和JS網絡庫這兩個文件。在鴻蒙系統中,WebView可以通過設置WebAgent來實現特定URL的劫持,將其轉化爲讀取本地資源中的HTML和JS文件。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"public class LoadAgent extends WebAgent {\n // ...\n\n @Override\n public ResourceResponse processResourceRequest(WebView webView, ResourceRequest request) {\n // mInterceptor用於識別HTML和JS網絡庫的URL,並返回本地資源中的HTML和JS。\n ResourceResponse response = mInterceptor.intercept(request);\n if (response != null) {\n return response;\n }\n return super.processResourceRequest(webView, request);\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這可以將兩個百毫秒級的串行操作縮減爲毫秒級,大大減少JS版本的網絡庫的初始化時間。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"數據緩存","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從網絡請求返回的卡片數據,除了用於即時渲染卡片之外,還會被保存一份到本地存儲中。如果下一次發起網絡請求的時候,無法正常訪問網絡(例如手機重啓後一時連不上網絡),則可以使用緩存中的卡片數據先渲染一下,使用戶不至於完全看不到內容。這就需要有一套卡片數據的緩存管理能力。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對卡片數據的特點,我們使用了兩個數據庫表來存儲卡片的緩存數據。根據卡片大小不同,請求中會提供不同的參數給服務端。反過來說,同樣大小的卡片發出請求的參數是相同的,也就是說同樣大小的卡片請求得到的數據是相同的。所以有一個表用來存儲不同大小的卡片數據,每個卡片大小對應一條記錄,包括唯一標識、卡片大小、請求返回的數據、時間戳等。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"系統不限制用戶向桌面添加卡片的數量,同時在服務中心也可以有已經添加到桌面的卡片。所以同樣的卡片數據是可以被顯示在多個卡片上的。數據庫需要有一個表來記錄每一個卡片的信息,包括卡片的唯一標識、卡片大小、數據表中對應的記錄等。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/75/75bc186af48a73fa8d45566c7564bdc1.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果在Android中實現過ContentProvider,一般都會比較熟悉SQLite數據庫。通常ContentProvider需要管理大量、不同類型且互相有關聯的數據,這種需求用SQLite來實現最合適了。這裏管理卡片數據的緩存也具有同樣的特徵,並且鴻蒙系統也提供了SQLite數據庫的使用接口。典型的數據庫初始化操作如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"// StoreConfig最常見的作用是配置數據庫名字。也可以配置存儲模式、加密等高級需求。\nStoreConfig config = StoreConfig.newDefaultConfig(DB_NAME_FORM_STORE);\n\n// RdbOpenCallback用於定義創建數據庫、升級數據庫結構版本等時機的回調。\nRdbOpenCallback callback = new FormStoreOpenCallback(context);\n\nDatabaseHelper helper = new DatabaseHelper(context);\n\n// RdbStore是數據庫的封裝類,最終的增刪改查操作都通過它來進行。\nRdbStore store = helper.getRdbStore(config, CURRENT_VERSION, callback);\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"具體的增刪改查操作就不一一列舉了。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"數據更新","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面聲明卡片一節提到了config.json中,updateEnabled、updateDuration定義了卡片的數據更新機制。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中updateEnabled用於指定是否通過系統來自動更新卡片數據,如果希望由應用自身觸發數據更新,這個可以設置爲false。優酷卡片的場景是希望系統能夠自動更新卡片數據的,所以設爲了true。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在updateEnabled設爲true的情況下,updateDuration纔有意義。updateDuration用於指定更新的時間間隔。鴻蒙系統還支持固定時間更新,通過指定scheduledUpateTime來設置更新時間。updateDuration和scheduledUpateTime只能選擇其中一種方式。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優酷卡片選擇了用updateDuration指定更新間隔。爲了避免將來使用卡片的用戶多了,對服務端產生過大的壓力,更新間隔被控制在4小時,這樣用戶在上午、下午、晚上等不同時段去看卡片時,內容都會有更新。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是有些情況下,優酷卡片自身的邏輯也會更新卡片數據,所以爲了避免兩種更新策略衝突而導致更密集的更新,或者長時間不更新,updateDuration被指定爲1,即每半小時系統就會調用一次onUpdateForm()。在onUpdateForm()中,會判斷上一次實際發生更新的時間,使更新間隔保持在4小時左右。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"容錯處理","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"考慮到一些極端情況,例如用戶安裝優酷後,在沒有網絡的情況下就添加了桌面卡片。此時卡片的數據請求是沒有返回的,同時由於剛安裝,也沒有緩存數據,所以卡片展示不出任何數據,只有灰色的打底圖作爲背景。此時如果點擊卡片,也沒有任何視頻信息,也就無法跳轉到某個特定視頻的播放頁,只能顯示一個加載失敗的提示,等用戶網絡恢復後,通過刷新得到有效數據。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6b/6bb240a0ff1f803a81b6b44da53dcb39.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"
空白卡片點擊卡片後的空白頁面
\"\"\"\"
"}}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"展望","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在優酷鴻蒙版的桌面卡片已經隨着鴻蒙系統的發佈,正式上線了。在鴻蒙系統的手機上,從華爲應用市場安裝的優酷主客就已經附帶了優酷卡片的能力。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於這是一個全新的開發技術棧,早期發佈的應用肯定會有一些改進空間。從現在看來主要有以下一些方面:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"性能","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":"none"},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"由於數據請求和埋點用到了JS庫,並且在WebView中運行,這使得運行時效率比Java要低,還要處理WebView與外界的交互,對性能有較大影響。雖然已經有了一些措施來減少這方面的影響,但是後續還是需要繼續挖掘潛力","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"監控","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":"none"},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"後續還需要補足JS側崩潰等信息收集的能力。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"線上配置能力","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":"none"},"content":[{"type":"paragraph","attrs":{"indent":0,"number":6,"align":null,"origin":null},"content":[{"type":"text","text":"優酷主客可以通過各種遠程配置平臺下發各種配置信息。而鴻蒙上由於體積限制無法自帶相關的庫。今後需要考慮使用其他方式實現遠程配置能力。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後,10月20日將上線《優酷鴻蒙開發實踐》系列技術文章第二篇,爲大家介紹如何實現Android/鴻蒙混合打包的流程。感謝關注,我們下篇技術實踐再見。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#FF7021","name":"orange"}},{"type":"strong","attrs":{}}],"text":"關注我們,每週 3 篇移動技術實踐&乾貨給你思考!","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章