文章插圖

文章插圖
背景
隨著華為Harmony OS2.0的發布 , 各大廠商紛紛搶先與華為展開合作 。優酷作為國內領先的長視頻在線視聽平臺 , 與華為公司長期以來保持緊密的合作 , 共同為消費者帶來優質的影音娛樂體驗 。因此 , 優酷技術團隊也在第一時間投入對鴻蒙系統以及鴻蒙開發者SDK的研究 。優酷技術團隊經過多輪的頭腦風暴 , 利用鴻蒙的某些新特性展開鴻蒙應用開發的嘗試 。
鴻蒙OS支持應用以Ability為單位進行部署 。Ability分為兩種類型:FA(Feature Ability)和PA(Particle Ability) 。FA/PA是應用的基本組成單元 , 能夠實現特定的業務功能 。FA有UI界面 , 而PA無UI界面 。
每種類型為開發者提供了不同的模板 , 以便實現不同的業務功能 。
鴻蒙OS的應用軟件包以APP Pack(Application Package)形式發布 , 它是由一個或多個HAP(HarmonyOS Ability Package)以及描述每個HAP屬性的pack.info組成 。HAP是Ability的部署包 , HarmonyOS應用代碼圍繞Ability組件展開 。
當前 , 包含有鴻蒙FA/PA的優酷鴻蒙版已經在華為鴻蒙應用市場上架 , 鴻蒙混合包在應用市場上會顯示為“含HarmonyOS服務” 。如果App是100% Pure鴻蒙App , 其Icon右下角會有HMOS字樣 。
在手機桌面上的優酷Icon輕輕上滑,會彈出一個鴻蒙卡片 , 向用戶推薦最近的熱劇 , 點擊卡片能快速拉起半屏落地頁顯示更多信息 , 點擊落地頁則跳轉到優酷客戶端的相應落頁面 。
點擊卡片上的圖釘按鈕 , 還可以將這個FA卡片固定在桌面上 。
這個桌面Widget與iOS桌面Widget的區別在于 , 它不依賴于優酷主客即可運作 。即使優酷主客不被啟動 , 卡片的數據也能夠更新 。
鴻蒙卡片的開發模式
在鴻蒙系統上 , 觸摸優酷主客的應用圖標向上滑動 , 可以喚起優酷的鴻蒙卡片 。實現這一點需要卡片的實現代碼與優酷主客做混合打包 , 一起提交到應用市場 。
而如果要實現服務中心免安裝使用 , 則需要卡片的獨立包總大小要小于10M 。這一體積限制使得很多Native 庫都無法引入 , 否則無法將體積控制在紅線之內 。
最終 , 優酷鴻蒙卡片的代碼放在一個工程中 , 方便跟優酷主客進行混合打包 。同時 , 優酷鴻蒙卡片的代碼僅依賴極少數的二、三方庫(例如JSON解析、圖片緩存等) , 以減小體積 。
卡片樣式
鴻蒙系統提供4中大小不同的卡片 , 根據占用桌面圖標數量的不同 , 分別是: 1×2、2×2、2×4、4×4 。優酷卡片實現了其中兩種: 2×2和2×4 , 其中2×2的卡片是必選項 。
下圖顯示了兩種不同樣式的卡片 , 以及不同的出現場景 。
跟Android的應用微件類似 , 鴻蒙的卡片也需要在一個配置文件中聲明 。在一個鴻蒙應用中 , 每個模塊都有自己的配置文件 , 位于該模塊的代碼main目錄下 , 名字為config.json 。
在配置文件中 , 每個模塊有一個abilities屬性 , 其值是一個數組 , 數組的每一個對象都定義了一個Ability ??ㄆ投x在其中一個Ability中:
{..."formsEnabled": true,"forms": [{"landscapeLayouts": ["$layout:youku_widget_2_2","$layout:youku_widget_2_4"],"isDefault": true,"defaultDimension": "2*2","name": "youku_widget","description": "$string:yk_widget_description","colorMode": "auto","type": "Java","supportDimensions": ["2*2","2*4"],"portraitLayouts": ["$layout:youku_widget_2_2","$layout:youku_widget_2_4"],"updateEnabled": true,"updateDuration": 1}],...}鴻蒙系統中 , 卡片用Form來表示 。上述聲明中 , formsEnabled用于指示這個Ability是用于定義卡片的 。forms數組用來定義一系列的卡片 。通常多個卡片可以定義在一個數組元素中 。其中landscapeLayouts、portraitLayouts、supportDimensions用于定義卡片的布局文件和大小 , updateEnabled、updateDuration用于控制卡片的數據更新 , updateDuration的單位是半小時 。【json卡片代碼大全 json卡片代碼生成器下載】生命周期
在鴻蒙系統上 , 卡片的生命周期比普通的Page Ability要簡單很多 , 只有三個相關的回調:
/** * 創建卡片時的回調 。* 在intent中 , 存有創建卡片的一些重要參數 , 可以通過Intent.getXXXParam()方法獲取 。* AbilitySlice.PARAM_FORM_IDENTITY_KEY: long類型 , 用于唯一標識一個卡片 * AbilitySlice.PARAM_FORM_NAME_KEY: String類型 , 卡片名稱 , 即在config.json中定義的name屬性 * AbilitySlice.PARAM_FORM_DIMENSION_KEY: int類型 , 卡片大小標識 , * 取值范圍是1-4 , 分別表示1x2、2x2、2x4、4x4 */protected ProviderFormInfo onCreateForm(Intent intent)/** * 更新卡片時的回調 。* 這里的formId就是onCreateForm中的AbilitySlice.PARAM_FORM_IDENTITY_KEY參數 。*/protected void onUpdateForm(long formId)/** * 刪除卡片時的回調 。* 這里的formId就是onCreateForm中的AbilitySlice.PARAM_FORM_IDENTITY_KEY參數 。*/protected void onDeleteForm(long formId)傳輸卡片內容卡片的創建和顯示通常由桌面(或者服務中心、搜索)發起 , 而決定顯示內容的是優酷卡片這個模塊 , 內容提供方和顯示方不在同一個進程 , 甚至由不同開發者開發 。在Android上也是一樣的情況 。
在這種情況下 , 一般都是內容提供方通過遠程View的方式將內容渲染到內容顯示方的 , 鴻蒙系統上這個跨進程的數據傳輸行為是由ComponentProvider來實現的 。
創建ComponentProvider有兩種方式:
// 第一種: 在onCreateForm()時 , 先創建一個卡片對應的ProviderFormInfo實例 。// 再通過ProviderFormInfo的實例拿到向它傳輸數據的ComponentProvider 。ProviderFormInfo form = new ProviderFormInfo(layoutId, context);ComponentProvider cp = form.getComponentProvider();// 第二種: 在onUpdateForm()時 , 直接創建出一個ComponentProvider 。ComponentProvider cp = new ComponentProvider(layoutId, context);需要注意的問題 1其中設置IntentAgent時需要注意 , 通常一個布局中會有多個View來覆蓋根布局的矩形區域 。如果設置了IntentAgent的View沒有覆蓋滿根布局 , 則未覆蓋區域被點擊時 , 系統也會響應點擊 , 默認調起這個卡片所屬的Ability , 傳入的Intent只包含formId 。
針對這個默認調起的Ability , 一般有兩種方式解決:一是確保設置了IntentAgent的View覆蓋滿根布局;二是Ability提供兜底方案 , 例如頁面做成透明 , 并且自動退出 。
需要注意的問題 2
在創建IntentAgent時 , 需要提供一個IntentAgentInfo實例 。這個IntentAgentInfo創建時的第一個參數是一個int類型的請求代碼 , 這個代碼必須保持各個卡片的不同點擊區都不一樣 。否則后設置的IntentAgent會覆蓋先前設置的同一請求代碼的IntentAgent 。
需要注意的問題 3
如果是跟優酷主客混合打包 , 卡片的布局文件中 , View的id必須跟主客中所有的id不同 , 否則系統會無法正確更新布局文件中對應的View 。
打開中轉頁
由于系統的限制 , 點擊卡片打開的頁面必須是純鴻蒙應用中的頁面 , 無法直接打開Android應用頁面 。優酷卡片的點擊 , 目的是打開優酷主客的播放頁 。
在這里我們做了分類:
當用戶未安裝優酷主客時 , 顯示一個中轉頁 , 提供下載按鈕供用戶跳轉到華為應用市場去下載優酷主客 , 當用戶安裝完優酷主客回來時 , 下載按鈕變成選集列表 , 對單集視頻則變成播放按鈕;當用戶已安裝優酷主客時 , 中轉頁自動打開優酷主客的播放頁 , 并退出 。數據請求
在優酷主客中 , 網絡數據的請求都是通過統一的網絡庫訪問的 。由于優酷鴻蒙卡片并未集成網絡庫 , 優酷鴻蒙卡片必須使用其他方式請求網絡接口 。
要實現在鴻蒙上發起數據請求 , 有兩個方案:
一是針對每個數據請求接口 , 封裝一個新的HTTP Open API接口 , 客戶端可以通過HTTP(S)直接訪問;二是客戶端通過H5頁面里的JS版Network庫發起數據請求 。
考慮到將來在鴻蒙系統上有可能實現更多其他的需求 , 且第一種方案有安全性的風險 , 所以最終我們采用了第二種方案 。
前端業務使用的JS版本的網絡庫 , 其使用方式是通過JS中的Promise機制來實現異步回調 , 但是這種方式在Java中并不好實現對應的調用結構 。所以這里需要有一層封裝 , 將網絡請求結果通過簡單回調來通知請求方 。相應的在Java側需要對WebView注冊全局的JS對象 , 實現JS對象的回調方法 , 打通JS -> Java的調用通路 。
這個方案在紙面上看著還不錯 , 但是在實際使用中會發現有嚴重的性能瓶頸 。WebView本身是一個很重的控件 , 在進程中首次創建的時候會比較耗時 , 有很多的so加載、初始化等工作 。加載HTML是一個網絡請求 , 耗時在百毫秒級 , 而加載并解析完HTML以后 , 還要再加載JS版本的網絡庫 , 又是一次網絡訪問 。等JS網絡庫加載并解釋執行后 , 才可以正常服務調用方 。
要在這個過程中進行優化 , 這里有主動權的地方就是加載HTML和JS網絡庫這兩個文件 。在鴻蒙系統中 , WebView可以通過設置WebAgent來實現特定URL的劫持 , 將其轉化為讀取本地資源中的HTML和JS文件 。
public class LoadAgent extends WebAgent {// ...@Overridepublic ResourceResponse processResourceRequest(WebView webView, ResourceRequest request) {// mInterceptor用于識別HTML和JS網絡庫的URL , 并返回本地資源中的HTML和JS 。ResourceResponse response = mInterceptor.intercept(request);if (response != null) {return response;}return super.processResourceRequest(webView, request);}}這可以將兩個百毫秒級的串行操作縮減為毫秒級 , 大大減少JS版本的網絡庫的初始化時間 。數據緩存
從網絡請求返回的卡片數據 , 除了用于即時渲染卡片之外 , 還會被保存一份到本地存儲中 。如果下一次發起網絡請求的時候 , 無法正常訪問網絡(例如手機重啟后一時連不上網絡) , 則可以使用緩存中的卡片數據先渲染一下 , 使用戶不至于完全看不到內容 。這就需要有一套卡片數據的緩存管理能力 。
針對卡片數據的特點 , 我們使用了兩個數據庫表來存儲卡片的緩存數據 。根據卡片大小不同 , 請求中會提供不同的參數給服務端 。反過來說 , 同樣大小的卡片發出請求的參數是相同的 , 也就是說同樣大小的卡片請求得到的數據是相同的 。所以有一個表用來存儲不同大小的卡片數據 , 每個卡片大小對應一條記錄 , 包括唯一標識、卡片大小、請求返回的數據、時間戳等 。
系統不限制用戶向桌面添加卡片的數量 , 同時在服務中心也可以有已經添加到桌面的卡片 。所以同樣的卡片數據是可以被顯示在多個卡片上的 。數據庫需要有一個表來記錄每一個卡片的信息 , 包括卡片的唯一標識、卡片大小、數據表中對應的記錄等 。
// StoreConfig最常見的作用是配置數據庫名字 。也可以配置存儲模式、加密等高級需求 。StoreConfig config = StoreConfig.newDefaultConfig(DB_NAME_FORM_STORE);// RdbOpenCallback用于定義創建數據庫、升級數據庫結構版本等時機的回調 。RdbOpenCallback callback = new FormStoreOpenCallback(context);DatabaseHelper helper = new DatabaseHelper(context);// RdbStore是數據庫的封裝類 , 最終的增刪改查操作都通過它來進行 。RdbStore store = helper.getRdbStore(config, CURRENT_VERSION, callback);具體的增刪改查操作就不一一列舉了 。數據更新
前面聲明卡片一節提到了config.json中 , updateEnabled、updateDuration定義了卡片的數據更新機制 。
其中updateEnabled用于指定是否通過系統來自動更新卡片數據 , 如果希望由應用自身觸發數據更新 , 這個可以設置為false 。優酷卡片的場景是希望系統能夠自動更新卡片數據的 , 所以設為了true 。
在updateEnabled設為true的情況下 , updateDuration才有意義 。updateDuration用于指定更新的時間間隔 。鴻蒙系統還支持固定時間更新 , 通過指定scheduledUpateTime來設置更新時間 。updateDuration和scheduledUpateTime只能選擇其中一種方式 。
優酷卡片選擇了用updateDuration指定更新間隔 。為了避免將來使用卡片的用戶多了 , 對服務端產生過大的壓力 , 更新間隔被控制在4小時 , 這樣用戶在上午、下午、晚上等不同時段去看卡片時 , 內容都會有更新 。
但是有些情況下 , 優酷卡片自身的邏輯也會更新卡片數據 , 所以為了避免兩種更新策略沖突而導致更密集的更新 , 或者長時間不更新 , updateDuration被指定為1 , 即每半小時系統就會調用一次onUpdateForm() 。在onUpdateForm()中 , 會判斷上一次實際發生更新的時間 , 使更新間隔保持在4小時左右 。
容錯處理
考慮到一些極端情況 , 例如用戶安裝優酷后 , 在沒有網絡的情況下就添加了桌面卡片 。此時卡片的數據請求是沒有返回的 , 同時由于剛安裝 , 也沒有緩存數據 , 所以卡片展示不出任何數據 , 只有灰色的打底圖作為背景 。此時如果點擊卡片 , 也沒有任何視頻信息 , 也就無法跳轉到某個特定視頻的播放頁 , 只能顯示一個加載失敗的提示 , 等用戶網絡恢復后 , 通過刷新得到有效數據 。
現在優酷鴻蒙版的桌面卡片已經隨著鴻蒙系統的發布 , 正式上線了 。在鴻蒙系統的手機上 , 從華為應用市場安裝的優酷主客就已經附帶了優酷卡片的能力 。
由于這是一個全新的開發技術棧 , 早期發布的應用肯定會有一些改進空間 。從現在看來主要有以下一些方面:
性能由于數據請求和埋點用到了JS庫 , 并且在WebView中運行 , 這使得運行時效率比Java要低 , 還要處理WebView與外界的交互 , 對性能有較大影響 。雖然已經有了一些措施來減少這方面的影響 , 但是后續還是需要繼續挖掘潛力監控后續還需要補足JS側崩潰等信息收集的能力 。線上配置能力優酷主客可以通過各種遠程配置平臺下發各種配置信息 。而鴻蒙上由于體積限制無法自帶相關的庫 。今后需要考慮使用其他方式實現遠程配置能力 。
最后 , 10月20日將上線《優酷鴻蒙開發實踐》系列技術文章第二篇 , 為大家介紹如何實現Android/鴻蒙混合打包的流程 。感謝關注 , 我們下篇技術實踐再見 。
- 異地戀卡片20個字 異地戀送女友賀卡內容撩妹套路
- 最大公約數的算法C語言 求最大公約數c++語言代碼
- c++游戲代碼大全 最簡單的c++游戲代碼
- 前端代碼混淆壓縮 js代碼混淆原理
- 安卓短信發送 安卓讀取短信代碼
- matlab求最大值最小值 matlab求函數最大值代碼
- 鮮花卡片留言 給女伴侶送花卡片留言撩妹套路
- 怎么自己編寫游戲代碼 自己做游戲代碼
- C語言代碼示例 c++代碼示例
- 遺傳算法經典實例matlab代碼 遺傳算法matlab程序案例詳解
