本文做者:陸康、陳馳枻、聶帥前端
當前造車新勢力愈來愈火,汽車智能化成爲風口,不少手機應用但願拓展車機場景,雲音樂及旗下 Look 直播也在車機端場景進行了一些探索,下面分享過程當中的一些總結和心得體會java
當前車載接入方式主要有三種,第一種是以華爲 Hicar 爲表明的手機app擴展接入,第二種是提供對外的 OpenApi,車企自行研發應用進行接入,最後一種是最爲廣泛的車機獨立 app 接入。android
這種方式並不要求給車機提供獨立的車載版 apk,而是由手機端的應用接入 Hicar sdk,直接在原有的工程上開發。git
目前多家手機廠商採用的車聯方案都是基於 Android 系統自帶的 MediaSession 框架進行模板化開發,手機端的應用只須要根據廠商提供的模板準備數據,具體的UI展現由車機設備完成,開發者無需關心屏幕適配及UI風格統一的問題,具體的播控指令同步也是經過 MediaSession 框架完成的。github
該接入方式須要本身制定 Media Data Tree 的結構。由於 ViewTree 的展現是交給外部進行渲染的,咱們每每只能經過 onPlayFromMediaId 回調裏的 mediaId 和 extras 來獲取車機上點擊播放的媒體信息,mediaId能夠構形成例如 tab -> page -> listId -> songId 的層級關係,咱們就能夠知道播放的是具體來自哪一個頁面中哪一個歌單中的哪首歌了,這也是 Android 官方的 Universal Android Music Player Sample 中採用的實現方式。shell
這種車載接入方式有以下特色api
這種實現方式是服務端根據咱們的服務內容提供對應的 OpenAPI 接口。廠商能夠自行設計需求方案和視覺方案,根據不一樣的需求範圍去調用不一樣的接口來獲取數據並展現,可是最後通常須要經過咱們的審覈才能發佈。這種接入方式中的開發資源也是由廠商本身提供的,承載的平臺包括 Linux、Android 等多個系統環境。因爲這種方式不是本文的重點,就不在此贅訴了。性能優化
這種接入方式有如下特色markdown
能夠看出上述 OpenAPI 的實現方式仍是存在一些比較關鍵的問題,因此通常來講咱們會優先採用獨立 app 接入的方式,這是目前更爲廣泛的方式,也是本文主要描述的接入方式。這種方式與手機應用開發其實相似,但也有一些特色網絡
針對上文中提到的車載獨立 app 開發的一些特色,咱們在渠道分包、解耦車機依賴、語音操做接入、分辨率適配等方面進行了一系列探索,下面介紹幾個相關的方案設計
上面提到車機系統比較碎片化,要實現車機的方控、桌面 widget、儀表顯示等控制,通常有兩種狀況
考慮到上層業務代碼最好能不感知平臺差別,決定對渠道接入能力作一層封裝隔離 如上圖所示,將渠道依賴的能力抽象爲 EnvironmentDependency 接口,不一樣渠道依賴各自的車機 sdk 實現該接口,Mediasession 規範單獨實現一個通用類。業務層看到的是渠道無關的DependcyWrapper 代理實例,只需在各業務處理時機調用代理的對應方法便可,規避了業務層寫渠道相關的代碼。方控響應能力抽象爲 EventCallback 接口,業務實現後注入對應 dependcy 實例,由其適時觸發。 針對分渠道打包問題,採用 AGP 自帶的 productFlavors 方案,不一樣的渠道包含不一樣的源文件夾,隔離 sdk 依賴。
flavorDimensions "channel"
productFlavors {
//小鵬
xp {
dimension "channel"
buildConfigField("String", "channel", ""xp"")
}
//比亞迪
byd {
dimension "channel"
buildConfigField("String", "channel", ""byd"")
}
......
}
複製代碼
要作語音控制,首先須要思考以下問題
從對接經驗來看,目前提供車機語音開放能力的廠商並不廣泛,個別廠商即便提供,其接入和自定義流程也比較複雜,須要至關長的週期,因此應用本身集成三方sdk來實現是更合理的選擇,可是針對於一些須要支持車機自帶語音助手的廠商咱們也要提供出對應的方案 2. 語音控制如何喚起?(除了頁面點擊外,可否提供其餘快捷入口) 若是要實現特定短句喚起語音助手,就要求語音識別 sdk 在應用生命週期內長期收音,一直搶佔着 mic 焦點,致使車機系統自帶的語音助手沒法工做(有個別車機實現了多麥克風陣列,即系統收音使用單獨 mic 通道,但這種車機是極少數),所以,短句喚起方案是行不通的。那麼,可否藉助方控呢?方控廣泛能提供確認鍵的響應,若是應用業務自己不須要確認鍵(如應用爲直播業務,不須要暫停、恢復)則可直接使用確認鍵喚起語音助手,若是須要,也能夠設計某種點按方式喚起(好比長按或者雙擊,這能夠經過在業務層判斷按鍵事件的時間間隔作到),固然,對應的引導也須要跟上,好比在用戶首次進入時展現浮層加語音的引導 3. 如何從語音識別出的文字映射到對應操做?最方便的作法確定是客戶端直接判斷文字匹配性,好比識別到「下一首」就切換到下一個直播,可是這種作法容錯性較低,用戶稍微調整下說法就會失效,更加合理的作法是在語音轉文字環節後再加上語義識別環節,流程以下
解決了這些基本問題後,再來考慮下一個比較完善的語音助手的完整交互流程,助手喚起後,會首先進入詢問態並提示語音支持的操做類型,接着用戶輸入,若是輸入超時會提示助手即將關閉,正常輸入後進行請求解析,獲取結果後某些操做執行會直接關閉面板,而某些操做將直接在面板展現結果並回到詢問態,若沒法解析則直接提示並回到詢問態,因而可知客戶端上整個流程比較適合抽象爲一個狀態機
前置的視覺交互設計中,考慮到駕駛時的場景,經常使用的操做區域要儘可能放在靠近駕駛側的一邊,同時交互流程要儘量簡單,頁面跳轉層級不宜過多。除去主流的橫屏佈局以外,比亞迪、小鵬等車機屏幕也會存在豎屏的狀況。 常見的屏幕適配方案包括 smallestWidth 適配、頭條的修改 DisplayMetrics#density 方案、使用百分比佈局等。結合項目的實際狀況,咱們建議大部分的佈局都採用流式佈局,只須要在佈局中改變 recyclerView 的方向就能夠適配橫豎屏的切換,同時卡片佈局儘可能扁平化,ConstraintLayout 中的 Guideline、layout_constraintHeight_percent 等屬性都能幫助咱們很方便的實現百分比佈局,若是遇到比例特別奇怪的屏幕,頁面又不能使用流式佈局時,能夠考慮結合 sw 限定符的方案,讓視覺同窗給出佈局調整策略,單獨針對少許特殊的屏幕進行適配。 在進行視覺適配開發時,咱們的第一反應固然是讓廠商提供全部可能涉及的車機設備,然而這是不現實的,從咱們的對接經驗來看,測試車機是至關緊缺的,部分廠商甚至連車機都暫時沒法提供,只提供文檔,讓咱們自行適配後再內部測試。在這種狀況下,咱們只能模擬不一樣的分辨率設備。adb shell wm size 命令就是解決方法,其接受 總長度像素值x總寬度像素值 格式的參數,運行後便可調整成對應的長寬比,測試過程只須要在同一設備上運行不一樣參數的命令便可實現不一樣分辨率的模擬。
上面提到車機相比於手機,整體性能上要落後不少。在一開始,一方面因爲歷史包袱、組件複用等因素,另外一方面編寫代碼時也每每忽略了性能相關問題,使得 app 運行在車機上的體驗至關糟糕,安裝慢、啓動速度慢、卡頓丟幀等性能問題很明顯的就暴露了出來,因而咱們作了一系列針對性的優化
減少包體積包括代碼和資源兩方面,一般的作法以下:
多進程運行須要佔用更多的系統資源,在性能較弱的設備上,單app多進程的運行方式會給設備 CPU、內存等帶來更多壓力
和進程類似,線程過多在啓動中頻繁切換帶來了很大的開銷成本,主線程獲得執行的時間也會減小
啓動過程當中文件 IO 過多也會拖慢啓動速度,儘可能減小沒必要要的文件讀寫
爲了更快地展現界面或者執行某項具體功能,最好減小啓動流程中 Activity 的跳轉層級,每多一個 Activity 就會增長几百毫秒的耗時;在請求一些接口時,也要考慮到請求時機,是否能夠前置並行請求,或者合併請求,減小接口的 RT
下面分享一個性能優化的實例,在與某家車廠的合做過程當中,廠商反饋語音喚起階段從冷啓動到開始播放速度特別慢,將近 8s 之久。咱們在手機上測試是徹底沒有問題的,可是受限於車機的性能,在先後反覆數輪的溝通聯調下,咱們主要作了如下優化
最終將時間壓縮到 3s 內,咱們的優化過程從前期對耗時明顯部分着重優化,效果明顯,到後期分析啓動日誌,一點點摳細節,最終經過廠商方面的驗收。在開始着手優化前,須要量化好具體指標,明確好目標再着手進行,用數據來衡量優化效果能讓優化過程更加順暢
車載開發過程當中,還遇到了一些以前手機應用開發不常見的問題,印象深入,也在這裏分享下
車載場景,用戶主動下載及更新 app 的頻率相對手機來講要低不少,因此預裝是很重要的鋪量手段,但當咱們好不容易與某渠道談成預裝後,卻發現一個奇怪的問題,全部用 RN 實現的頁面進入進入或者預加載就會引發應用的 crash,崩潰堆棧提示的直接緣由是 libjsexcutor.so 這個 RN 依賴的 js 解析庫加載失敗了,因而初步看了下 RN 崩潰位置的源碼,發現 RN 的 so 庫都是經過 SoLoader 這個 facebook 的工具加載的(官方文檔說主要用來兼容 4.3 如下版本的 so 加載依賴問題),而應用中其餘業務 so 的都是正常工做的,因此就猜想 SoLoader 在應用預裝場景會存在問題,因而復現並重點查看 Soloader 相關的日誌 上圖爲問題渠道上的 RN 加載日誌,而下圖爲正常場景下的 RN 加載日誌 能夠看到二者的區別就在於問題渠道上,標紅處的 so 查找路徑沒有被添加(該路徑實際就是應用安裝後的 so 路徑的軟連接),而正常渠道上是在該路徑上找到了 RN 相關的 so 並進行了加載,順着該思路查看了下 SoLoader 的源碼,發現有以下邏輯 即判斷當前應用是系統應用後,就不將 app 默認 so 路徑加入查找路徑,致使 RN 相關用 Soloader 加載的庫都會失敗,定位到緣由後,再仔細過了下 SoLoader 加載 so 相關源碼,發現其提供了 setSystemLoadLibraryWrapper 的設置接口,能夠由上層來定義針對系統應用場景如何加載依賴的 so,因此咱們只要設置該場景用應用本來的 so 加載方式便可解決問題,以下代碼所示
SoLoader.setSystemLoadLibraryWrapper {
ReLinker.loadLibrary(context, it)
}
複製代碼
查看後果真發現部分規則比較特殊,猜想是測試車機原本是隻給廠商內部使用的,爲了防止流出後產生問題,對網絡環境作了識別,一旦發現非廠商公司內網就丟棄數據包,因而用以下命令清理規則,問題解決
iptables -F
iptables -X
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
複製代碼
javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException:
Could not validate certificate: Certificate not valid until Wed Dec 16
09:00:05 GMT+08:00 2015 (compared to Sun Oct 12 16:20:03 GMT+08:00 1980)
複製代碼
看起來是時間和證書有效期對不上,查看系統時間發現確實不對,原來該車機每次啓動後都會重置系統時間,而 SSL 客戶端的校驗過程是包含證書有效期校驗的,調整系統時間後便可解決問題 上述可見,測試車機會由於一些特殊設定而帶來一些奇怪的開發問題,不過比較好的一點是這些測試車機每每是已經 root 過的,因此命令權限足夠大,能夠進行深刻地分析。
參與車載應用從啓動到正式上架的全過程,技術以外,還有一些其餘的體會
本文介紹了目前車載開發的一些現狀,分享了一些開發過程的設計思路和遇到的典型問題,但願能對你們的應用上車有所幫助!
本文發佈自 網易雲音樂大前端團隊,文章未經受權禁止任何形式的轉載。咱們常年招收前端、iOS、Android,若是你準備換工做,又剛好喜歡雲音樂,那就加入咱們 grp.music-fe(at)corp.netease.com!