成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

讓 Flutter 在鴻蒙系統(tǒng)上跑起來(lái)

系統(tǒng)
鴻蒙系統(tǒng)(HarmonyOS)是華為推出的一款面向未來(lái)、面向全場(chǎng)景的分布式操作系統(tǒng)。在傳統(tǒng)單設(shè)備系統(tǒng)能力的基礎(chǔ)上,鴻蒙提出了基于同一套系統(tǒng)能力、適配多種終端形態(tài)的分布式理念。

前言

鴻蒙系統(tǒng)(HarmonyOS)是華為推出的一款面向未來(lái)、面向全場(chǎng)景的分布式操作系統(tǒng)。在傳統(tǒng)單設(shè)備系統(tǒng)能力的基礎(chǔ)上,鴻蒙提出了基于同一套系統(tǒng)能力、適配多種終端形態(tài)的分布式理念。自 2020 年 9 月 HarmonyOS 2.0 發(fā)布以來(lái),華為加快了鴻蒙系統(tǒng)大規(guī)模落地的步伐,預(yù)計(jì) 2021 年底,鴻蒙系統(tǒng)會(huì)覆蓋包括手機(jī)、平板、智能穿戴、智慧屏、車機(jī)在內(nèi)數(shù)億臺(tái)終端設(shè)備。對(duì)移動(dòng)應(yīng)用而言, 新的系統(tǒng)理念、新的交互形式,也意味著新的機(jī)遇 。如果能夠利用好鴻蒙的開發(fā)生態(tài)及其特性能力,可以讓應(yīng)用覆蓋更多的交互場(chǎng)景和設(shè)備類型,從而帶來(lái)新的增長(zhǎng)點(diǎn)。

與面臨的機(jī)遇相比,適配鴻蒙系統(tǒng)帶來(lái)的挑戰(zhàn)同樣巨大。當(dāng)前手機(jī)端,盡管鴻蒙系統(tǒng)仍然支持安卓 APK 安裝及運(yùn)行,但長(zhǎng)期來(lái)看,華為勢(shì)必會(huì)拋棄 AOSP,逐步發(fā)展出自己的生態(tài),這意味著現(xiàn)有安卓應(yīng)用在鴻蒙設(shè)備上將會(huì)逐漸變成“二等公民”。然而,如果在 iOS 及 Android 之外再重新開發(fā)和維護(hù)一套鴻蒙應(yīng)用,在如今業(yè)界越來(lái)越注重開發(fā)迭代效率的環(huán)境下,所帶來(lái)的開發(fā)成本也是難以估量的。因此,通過打造一套合適的跨端框架,以相對(duì)低的成本移植應(yīng)用到鴻蒙平臺(tái),并利用好該系統(tǒng)的特性能力,就成為了一個(gè)非常重要的選項(xiàng)。

在現(xiàn)有的眾多跨端框架當(dāng)中,F(xiàn)lutter 以其自渲染能力帶來(lái)的多端高度一致性,在新系統(tǒng)的適配上有著突出的優(yōu)勢(shì)。雖然Flutter 官方 并沒有適配鴻蒙的計(jì)劃 ,但經(jīng)過一段時(shí)間的探索和實(shí)踐,美團(tuán)外賣 MTFlutter 團(tuán)隊(duì)成功實(shí)現(xiàn)了 Flutter 對(duì)于鴻蒙系統(tǒng)的原生支持。

這里也要提前說(shuō)明一下,因?yàn)轼櫭上到y(tǒng)目前還處于Beta版本,所以這套適配方案還沒有在實(shí)際業(yè)務(wù)中上線,屬于技術(shù)層面比較前期的探索。接下來(lái)本文會(huì)通過原理和部分實(shí)現(xiàn)細(xì)節(jié)的介紹,分享我們?cè)谝浦埠烷_發(fā)過程中的一些經(jīng)驗(yàn)。希望能對(duì)大家有所啟發(fā)或者幫助。

背景知識(shí)和基礎(chǔ)概念介紹

在適配開始之前,我們要明確好先做哪些事情。先來(lái)回顧一下 Flutter 的三層結(jié)構(gòu):

在 Flutter 的架構(gòu)設(shè)計(jì)中,最上層為 框架層 ,使用 Dart 語(yǔ)言開發(fā),面向 Flutter 業(yè)務(wù)的開發(fā)者;中間層為 引擎層 ,使用 C/C++ 開發(fā),實(shí)現(xiàn)了 Flutter 的渲染管線和 Dart 運(yùn)行時(shí)等基礎(chǔ)能力;最下層為 嵌入層 ,負(fù)責(zé)與平臺(tái)相關(guān)的能力實(shí)現(xiàn)。顯然我們要做的是將嵌入層移植到鴻蒙上,確切地說(shuō),我們要 通過鴻蒙原生提供的平臺(tái)能力,重新實(shí)現(xiàn)一遍 Flutter 嵌入層 。

對(duì)于 Flutter 嵌入層的適配,F(xiàn)lutter 官方有一份不算詳細(xì)的 指南 ,實(shí)際操作起來(lái)成本很高。由于鴻蒙的業(yè)務(wù)開發(fā)語(yǔ)言仍然可用 Java,在很多基礎(chǔ)概念上與 Android 也有相似之處(如下表所示),我們可以從 Android 的實(shí)現(xiàn)入手,完成對(duì)鴻蒙的移植。

Flutter 在鴻蒙上的適配

如前文所述,要完成 Flutter 在新系統(tǒng)上的移植,我們需要完整實(shí)現(xiàn) Flutter 嵌入層要求的所有子模塊,而從能力支持角度, 渲染 、 交互 以及 其他必要的原生平臺(tái)能力 是保證 Flutter 應(yīng)用能夠運(yùn)行起來(lái)的最基本的要素,需要優(yōu)先支持。接下來(lái)會(huì)依次進(jìn)行介紹。

1. 渲染流程打通

我們?cè)賮?lái)回顧一下 Flutter 的圖像渲染流程。如圖所示,設(shè)備發(fā)起 垂直同步 (VSync)信號(hào)之后,先經(jīng)過 UI 線程的渲染管線(Animate/Build/Layout/Paint),再經(jīng)過 Raster 線程的組合和柵格化,最終通過 OpenGL 或 Vulkan 將圖像 上屏 。這個(gè)流程的大部分工作都由框架層和引擎層完成,對(duì)于鴻蒙的適配,我們主要關(guān)注的是與設(shè)備自身能力相關(guān)的問題,即:

(1) 如何監(jiān)聽設(shè)備的 VSync 信號(hào)并通知 Flutter 引擎? (2) OpenGL/Vulkan 用于上屏的窗口對(duì)象從何而來(lái)?

VSync 信號(hào)的監(jiān)聽及傳遞

在 Flutter 引擎的 Android 實(shí)現(xiàn)中,設(shè)備的 VSync 信號(hào)通過 Choreographer 觸發(fā),它產(chǎn)生及消費(fèi)流程如下圖所示:

Flutter 框架注冊(cè) VSync 回調(diào)之后,通過 C++ 側(cè)的 VsyncWaiter 類等待 VSync 信號(hào),后者通過 JNI 等一系列調(diào)用,最終 Java 側(cè)的 VsyncWaiter 類調(diào)用 Android SDK 的 Choreographer.postFrameCallback 方法,再通過 JNI 一層層傳回 Flutter 引擎消費(fèi)掉此回調(diào)。Java 側(cè)的 VsyncWaiter 核心代碼如下:

  1. @Override 
  2. public void asyncWaitForVsync(long cookie) { 
  3.   Choreographer.getInstance() 
  4.       .postFrameCallback( 
  5.         new Choreographer.FrameCallback() { 
  6.           @Override 
  7.           public void doFrame(long frameTimeNanos) { 
  8.             float fps = windowManager.getDefaultDisplay().getRefreshRate(); 
  9.             long refreshPeriodNanos = (long) (1000000000.0 / fps); 
  10.             FlutterJNI.nativeOnVsync( 
  11.               frameTimeNanos, frameTimeNanos + refreshPeriodNanos, cookie); 
  12.           } 
  13.         }); 

在整個(gè)流程中,除了來(lái)自 Android SDK 的 Choreographer 以外,大多數(shù)邏輯幾乎都由 C++ 和 Java 的基礎(chǔ) SDK 實(shí)現(xiàn),可以直接在鴻蒙上復(fù)用,問題是鴻蒙目前的 API 文檔中尚沒有開放類似 Choreographer 的能力。所以現(xiàn)階段我們可以借用鴻蒙提供的類似 iOS Grand Central Dispatch 的線程 API,模擬出 VSync 的信號(hào)觸發(fā)與回調(diào):

  1. @Override 
  2. public void asyncWaitForVsync(long cookie) { 
  3.   // 模擬每秒 60 幀的屏幕刷新間隔:向主線程發(fā)送一個(gè)異步任務(wù), 16ms 后調(diào)用 
  4.   applicationContext.getUITaskDispatcher().delayDispatch(() -> { 
  5.     float fps = 60// 設(shè)備刷新幀率,HarmonyOS 未暴露獲取幀率 API,先寫死 60 幀 
  6.     long refreshPeriodNanos = (long) (1000000000.0 / fps); 
  7.     long frameTimeNanos = System.nanoTime(); 
  8.     FlutterJNI.nativeOnVsync(frameTimeNanos, frameTimeNanos + refreshPeriodNanos, cookie); 
  9.   }, 16); 
  10. }; 

渲染窗口的構(gòu)建及傳遞

在這一部分,我們需要在鴻蒙系統(tǒng)上構(gòu)建平臺(tái)容器,為 Flutter 引擎的圖形渲染提供用于上屏的窗口對(duì)象。同樣,我們參考 Flutter for Android 的實(shí)現(xiàn),看一下 Android 系統(tǒng)是怎么做的:

Flutter 在 Android 上支持 Vulkan 和 OpenGL 兩種渲染引擎,篇幅原因我們只關(guān)注 OpenGL。拋開復(fù)雜的注冊(cè)及調(diào)用細(xì)節(jié),本質(zhì)上整個(gè)流程主要做了三件事:

  1. 創(chuàng)建了一個(gè) 視圖對(duì)象 ,提供可用于直接繪制的 Surface,將它通過 JNI 傳遞給原生側(cè);
  2. 在原生側(cè)獲取 Surface 關(guān)聯(lián)的 本地窗口對(duì)象 ,并交給 Flutter 的平臺(tái)容器;
  3. 將本地窗口對(duì)象轉(zhuǎn)換為 OpenGL ES 可識(shí)別的 繪圖表面(EGLSurface) ,用于 Flutter 引擎的渲染上屏。

接下來(lái)我們用鴻蒙提供的平臺(tái)能力實(shí)現(xiàn)這三點(diǎn)。

a. 可用于直接繪制的視圖對(duì)象

鴻蒙系統(tǒng)的 UI 框架 提供了很多常用視圖組件(Component) ,比如按鈕、文字、圖片、列表等,但我們需要拋開這些上層組件,獲得直接繪制的能力。借助官方 媒體播放器開發(fā)指導(dǎo) 文檔,可以發(fā)現(xiàn)鴻蒙提供了 SurfaceProvider 類,它管理的 Surface 對(duì)象可以用于視頻解碼后的展示。而 Flutter 渲染與視頻上屏從原理上是類似的,因此我們可以借用 SurfaceProvider 實(shí)現(xiàn) Surface 的管理和創(chuàng)建:

  1. // 創(chuàng)建一個(gè)用于管理 Surface 的容器組件 
  2. SurfaceProvider surfaceProvider = new SurfaceProvider(context); 
  3. // 注冊(cè)視圖創(chuàng)建回調(diào) 
  4. surfaceProvider.getSurfaceOps().get().addCallback(surfaceCallback); 
  5.  
  6. // ... 在 surfaceCallback 中 
  7. @Override 
  8. public void surfaceCreated(SurfaceOps surfaceOps) { 
  9.   Surface surface = surfaceOps.getSurface(); 
  10.   // ...將 surface 通過 JNI 交給 Native 側(cè) 
  11.   FlutterJNI.onSurfaceCreated(surface); 

b. 與 Surface 關(guān)聯(lián)的本地窗口對(duì)象

鴻蒙目前開放的 Native API 并不多,在官方文檔中我們可以比較容易地找到 Native_layer API 。根據(jù)文檔的說(shuō)明,Native API 中的 NativeLayer 對(duì)象剛好對(duì)應(yīng)了 Java 側(cè)的 Surface 類,借助 GetNativeLayer 方法,我們實(shí)現(xiàn)了兩者之間的轉(zhuǎn)化:

  1. // platform_view_android_jni_impl.cc 
  2. static void SurfaceCreated(JNIEnv* env, jobject jcaller, jlong shell_holder, jobject jsurface) { 
  3.   fml::jni::ScopedJavaLocalFrame scoped_local_reference_frame(env); 
  4.   // 通過鴻蒙 Native API 獲取本地窗口對(duì)象 NativeLayer 
  5.   auto window = fml::MakeRefCounted<AndroidNativeWindow>( 
  6.       GetNativeLayer(env, jsurface)); 
  7.   ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyCreated(std::move(window)); 

c. 與本地窗口對(duì)象關(guān)聯(lián)的 EGLSurface

在 Android 的 AOSP 實(shí)現(xiàn) 中,EGLSurface 可通過 EGL 庫(kù)的 eglCreateWindowSurface 方法從本地窗口對(duì)象 ANativeWindow 創(chuàng)建而來(lái)。對(duì)于鴻蒙而言,雖然我們沒有從公開文檔找到類似的說(shuō)明,但是 鴻蒙標(biāo)準(zhǔn)庫(kù) 默認(rèn)支持了 OpenGL ES,而且鴻蒙 SDK 中也附帶了 EGL 相關(guān)的庫(kù)及頭文件,我們有理由相信在鴻蒙系統(tǒng)上,EGLSurface 也可以通過此方法從前一步生成的 NativeLayer 轉(zhuǎn)化而來(lái),在之后的驗(yàn)證中我們也確認(rèn)了這一點(diǎn):

  1. // window->handle() 即為之前得到的 NativeLayer 
  2. EGLSurface surface = eglCreateWindowSurface( 
  3.       display, config_, reinterpret_cast<EGLNativeWindowType>(window->handle()), 
  4.       attribs); 
  5. //...交給 Flutter 渲染管線 

2. 交互能力實(shí)現(xiàn)

交互能力是支撐 Flutter 應(yīng)用能夠正常運(yùn)行的另一個(gè)基本要求。在 Flutter 中,交互包含了各種觸摸事件、鼠標(biāo)事件、鍵盤錄入事件的傳遞及消費(fèi)。以觸摸事件為例,F(xiàn)lutter 事件傳遞的整個(gè)流程如下圖所示:

iOS/Android 的原生容器通過觸摸事件的回調(diào) API 接收到事件之后,會(huì)將其打包傳遞至引擎層,后者將事件傳發(fā)給 Flutter 框架層,并完成事件的消費(fèi)、分發(fā)和邏輯處理。同樣,整個(gè)流程的大部分工作已經(jīng)由 Flutter 統(tǒng)一,我們要做的僅僅是在原生容器上 監(jiān)聽 用戶的輸入,并 封裝 成指定格式交給引擎層而已。

在鴻蒙系統(tǒng)上,我們可以借助平臺(tái)提供的 多模輸入 API ,實(shí)現(xiàn)多種類型事件的監(jiān)聽:

  1. flutterComponent.setTouchEventListener(touchEventListener); // 觸摸及鼠標(biāo)事件 
  2. flutterComponent.setKeyEventListener(keyEventListener); // 鍵盤錄入事件 
  3. flutterComponent.setSpeechEventListener(speechEventListener); // 語(yǔ)音錄入事件 

對(duì)于事件的封裝處理,可以復(fù)用 Android 已有邏輯,只需要關(guān)注鴻蒙與 Android 在事件處理上的對(duì)應(yīng)關(guān)系即可,比如觸摸事件的部分對(duì)應(yīng)關(guān)系:

3. 其他必要的平臺(tái)能力

為了保證 Flutter 應(yīng)用能夠正常運(yùn)行,除了最基本的渲染和交互外,我們的嵌入層還要提供資源管理、事件循環(huán)、生命周期同步等平臺(tái)能力。對(duì)于這些能力 Flutter 大多都在嵌入層的公共部分有抽象類聲明,只需要使用鴻蒙 API 重新實(shí)現(xiàn)一遍即可。

比如資源管理,引擎提供了 AssetResolver 聲明,我們可以使用鴻蒙 Rawfile API 來(lái)實(shí)現(xiàn):

  1. class HAPAssetMapping : public fml::Mapping { 
  2.  public
  3.   HAPAssetMapping(RawFile* asset) : asset_(asset) {} 
  4.   ~HAPAssetMapping() override { CloseRawFile(asset_); } 
  5.  
  6.   size_t GetSize() const override { return GetRawFileSize(asset_); } 
  7.  
  8.   const uint8_t* GetMapping() const override { 
  9.     return reinterpret_cast<const uint8_t*>(GetRawFileBuffer(asset_)); 
  10.   } 
  11.  
  12.  private
  13.   RawFile* const asset_; 
  14.  
  15.   FML_DISALLOW_COPY_AND_ASSIGN(HAPAssetMapping); 
  16. }; 

對(duì)于事件循環(huán),引擎提供了 MessageLoopImpl 抽象類,我們可以使用鴻蒙 Native_EventHandler API 實(shí)現(xiàn):

// runner_ 為鴻蒙 EventRunnerNativeImplement 的實(shí)例
void MessageLoopHarmony::Run() {
  FML_DCHECK(runner_ == GetEventRunnerNativeObjForThread());
  int result = ::EventRunnerRun(runner_);
  FML_DCHECK(result == 0);
}

void MessageLoopHarmony::Terminate() {
  int result = ::EventRunnerStop(runner_);
  FML_DCHECK(result == 0);
}

對(duì)于生命周期的同步,鴻蒙的 Page Ability 提供了完整的生命周期回調(diào)(如下圖所示),我們只需要在對(duì)應(yīng)的時(shí)機(jī)將狀態(tài)上報(bào)給引擎即可。

當(dāng)以上這些能力都準(zhǔn)備好之后,我們就可以成功把 Flutter 應(yīng)用跑起來(lái)了。以下是通過 DevEco Studio 運(yùn)行官方 flutter gallery 應(yīng)用的截圖,截圖中 Flutter 引擎已經(jīng)使用鴻蒙系統(tǒng)的平臺(tái)能力進(jìn)行了重寫:

借由鴻蒙的多設(shè)備支持能力,此應(yīng)用甚至可在 TV、車機(jī)、手表、平板等設(shè)備上運(yùn)行:

總結(jié)和展望

通過上述的構(gòu)建和適配工作,我們以極小的開發(fā)成本實(shí)現(xiàn)了 Flutter 在鴻蒙系統(tǒng)上的移植,基于 Flutter 開發(fā)的上層業(yè)務(wù)幾乎不做任何修改就可以在鴻蒙系統(tǒng)上原生運(yùn)行,為迎接鴻蒙系統(tǒng)后續(xù)的大規(guī)模推廣也提前做好了技術(shù)儲(chǔ)備。

當(dāng)然,故事到這里并沒有結(jié)束。在最基本的運(yùn)行和交互能力之上,我們更需要關(guān)注 Flutter 與鴻蒙自身生態(tài)的結(jié)合:如何優(yōu)雅地適配鴻蒙的分布式技術(shù)?如何用 Flutter 實(shí)現(xiàn)設(shè)備之間的快速連接、資源共享?現(xiàn)有的眾多 Flutter 插件如何應(yīng)用到鴻蒙系統(tǒng)上?未來(lái) MTFlutter 團(tuán)隊(duì)將在這些方面做更深入的探索,因?yàn)榻鉀Q好這些問題,才是真正能讓應(yīng)用覆蓋用戶生活的全場(chǎng)景的關(guān)鍵。

責(zé)任編輯:張燕妮 來(lái)源: 美團(tuán)技術(shù)團(tuán)隊(duì)
相關(guān)推薦

2011-05-04 11:26:47

優(yōu)化

2009-04-29 14:40:17

2021-01-12 11:12:58

大數(shù)據(jù)智慧交通

2021-11-10 10:00:48

鴻蒙HarmonyOS應(yīng)用

2017-11-17 15:25:02

Java線程安全

2022-01-10 10:23:07

瀏覽器Vitenode

2010-07-13 09:31:08

RubyRuby on Rai

2023-03-02 23:09:53

Node.jsC++JS

2022-12-06 09:03:44

代碼fork系統(tǒng)

2023-08-03 09:02:32

LangChain開發(fā)GLM

2024-05-27 09:01:22

2015-08-04 17:46:19

戴爾anycloud云計(jì)算

2019-09-03 08:00:00

電腦硬盤程序

2012-05-15 13:29:20

HTML5

2020-04-06 09:05:07

谷歌機(jī)器狗人工智能

2023-01-31 07:42:29

代碼JDKMaven

2014-04-18 17:12:00

樂跑手環(huán)

2019-03-21 15:00:47

Python程序代碼

2019-09-08 23:00:19

GitHub代碼開發(fā)者
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产高清在线视频 | 亚洲精品成人网 | 久久天天躁狠狠躁夜夜躁2014 | 欧美日韩一区二区三区不卡视频 | 日韩中文字幕免费 | 久久aⅴ乱码一区二区三区 亚洲欧美综合精品另类天天更新 | 91干b| a级在线观看 | 欧美激情久久久 | 日韩一二区在线 | 亚洲 成人 在线 | 亚洲成人动漫在线观看 | 日韩精品无码一区二区三区 | 久久成人免费 | 久久草在线视频 | 欧美日韩在线精品 | 欧美成视频在线观看 | 在线不卡| 蜜臀av日日欢夜夜爽一区 | 在线观看国产www | 罗宾被扒开腿做同人网站 | 亚洲第一成年免费网站 | 在线观看中文字幕dvd播放 | 美女一级毛片 | 99视频在线免费观看 | 久久久综合色 | 亚洲精品一区在线观看 | 极品销魂美女一区二区 | 国产区在线免费观看 | 欧美一区二区三区在线播放 | 天天爱爱网 | 中文字幕一区二区三区四区 | 欧美精品啪啪 | 国产精品精品视频一区二区三区 | 亚洲成人在线免费 | 精品福利在线视频 | 久久伦理中文字幕 | 国产99视频精品免费播放照片 | 男人的天堂在线视频 | 成人福利在线观看 | 免费一区 |