真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯網站制作重慶分公司

flutter原生混合,flutter原生混合開發(fā)

iOS與Flutter混合開發(fā)

在現有iOS項目中導入Flutter, 需要在Podfile文件中加入

創(chuàng)新互聯專注于崗巴企業(yè)網站建設,響應式網站,商城建設。崗巴網站建設公司,為崗巴等地區(qū)提供建站服務。全流程按需策劃,專業(yè)設計,全程項目跟蹤,創(chuàng)新互聯專業(yè)和態(tài)度為您提供的服務

flutter_application_path = '/Users/../flutter_app_module'

load File.join(flutter_application_path,'.ios','Flutter','podhelper.rb')

并對target添加:

install_flutter_engine_pod

install_all_flutter_pods(flutter_application_path)

從上我們可以看到導入Flutter需要依賴Flutter項目中的'.ios'文件夾下的'podhelper.rb'文件,所以在pod install之前,請確認.ios文件夾存在

也許你一開始存在這個文件,但是在執(zhí)行flutter clean之后,這個文件不見了,不用驚慌, .ios文件夾基本可以通過以下幾種方式生成,自行選擇:

1.?flutter run

2. flutter pub get

3. flutter create .

.ios文件夾生成之后,回到原生項目pod install即可。

友情提示:

在生成.ios的時候,項目中不要存在其他的內層項目(如下截圖),那可能會導致你無法生成.ios或者生成的.ios不包含podhelper.rb這個文件,而最終導致你pod install失敗。

愉快的開始coding......

Flutter與原生通信概述

flutter與原生通信主要有三種方式:MethodChannel、EventChannel、BasicMessageChannel,這三種方式均各有適用的場景:MethodChannel用于native與flutter的方法調用,EventChannel用于native單向的向flutter發(fā)送廣播消息,BasicMessageChannel用于native與flutter之間的消息互發(fā)。

MethodChannel用于雙方之間的方法互調,使用步驟是:

1.創(chuàng)建一個MethodChannel對象,傳入MethodChannel名稱。

2.使用setMethodHandle對對方調用自己的方法進行監(jiān)聽,通過回調中的MethodCall對象方法名判斷、獲取方法參數,并且返回調用結果。

3.使用invokeMethod來調用對方的方法,可傳入方法名,方法參數,以及監(jiān)聽對方的回調結果。

以下是示例:

需要注意的是,MethodChannel的名稱需要雙方保持一致,否則就不是同一個MethodChannel了。另外這里的方法調用并不是像Java里面反射那樣去先找到class示例對象再解析到相應的方法,而是將雙方互發(fā)的消息包裝成了MethodCall對象,拿到這個對象后通過MethodCall里面的方法名去判斷要做什么操作,并不是直接就調用了自身(native或flutter)相對應的方法。具體要做什么操作、調用什么方法還是得自己去調用和實現。

EventChannel適用于native向flutter發(fā)送廣播消息,只是單向的消息發(fā)送,native發(fā),flutter收,返過來flutter并不能向native發(fā)送消息。例如native可將定位數據不斷的報給flutter,或者錄像數據等等,所有基于原生能力產生的數據都可以通過EventChannel進行發(fā)送。

步驟:

1.創(chuàng)建一個EventChannel對象,傳入EventChannel名稱。

2.flutter端調用receiveBroadcastStream進行廣播消息注冊,傳入arguments參數即為廣播名稱,此參數是告訴native端你要接受的廣播類型,判別是什么廣播發(fā)送的數據。

2.native調用setStreamHandler方法進行廣播消息監(jiān)聽,onListen回調里會有一個arguments參數,這里及為flutter注冊的廣播類型,若flutter端沒有注冊,則native端不會收到這個回調,也就無法進行消息發(fā)送。收到flutter端的廣播注冊后,根據arguments可判斷廣播類型,然后根據EventChannel.EventSink來進行消息發(fā)送,EventSink.success()即可將消息發(fā)送給flutter端。

3.flutter進行廣播注冊會返回一個streamSubscription類型的對象,該對象可以進行消息的停止,native可在onCancel回調里面收到。

示例如下:

BasicMessageChannel就是比較常用的消息互發(fā),使用步驟如下:

1.創(chuàng)建BasicMessageChannel對象,傳入BasicMessageChannel名稱。還需傳入編解碼方式(可以自己實現),系統提供了一些列的編解碼方式,后續(xù)會介紹到。

2.使用setMessageHandler方法進行消息監(jiān)聽,也可進行回復。

3.使用send方法進行消息發(fā)送。

無論哪種方式的消息傳遞,最終都是將自定義數據轉化為二進制數據進行傳遞,flutter提供的編解碼方式分為MethodCodec和MessageCodec兩種,EventChannel和MethodChannel使用的就是MethodCodec,BasicMessageChannel使用的是MessageCodec。MethodCodec其實就是在MessageCodec的基礎上將數據包裝了一下,使其轉化為MethodCall對象方便使用。

MethodCodec源碼:

MethodCodec提供了兩種方式:JSONMethodCodec和StandardMethodCodec,前一種就是JSON和MethodCall對象之間的互轉,后一種則是根據傳入的數據基本類型(String,Integer等)來進行互轉。

MessageCodec則提供了四種方式,如下圖,具體就不詳細講述了,看看名字就知道是怎么回事,可以直接去看源碼。最常用和默認的就是StandardMessageCodec方式。

從上面的使用方式可以看出,每一種Channel在創(chuàng)建的時候都需要傳遞一個BinaryMessenger,這個接口可以在FlutterEngine里面拿到,因此需要在FlutterActivity里面實現configFlutterEngine方法里面重寫這個方法。FlutterActivity在attach FlutterEngine之后就會調用這個configFlutterEngine方法,通過flutterEngine.getPlugins().add(FlutterPlugin)方法可以FlutterPlugin的回調方法里進行數據的初始化和銷毀工作。如下圖

這個回調方法里的FlutterPluginBinding提供了一些我們可能會用到的對象,如下:

Flutter浪潮下的音視頻研發(fā)探索

文/陳爐軍

整理/LiveVideoStack

大家好,我是阿里巴巴閑魚事業(yè)部的陳爐軍,本次分享的主題是Flutter浪潮下的音視頻研發(fā)探索,主要內容是針對閑魚APP在當下流行的跨平臺框架Flutter的大規(guī)模實踐,介紹其在音視頻領域碰到的一些困難以及解決方案。

分享內容主要分為四個方面,首先會對Flutter有一個簡單介紹以及選擇Flutter作為跨平臺框架的原因,其次會介紹Flutter中與音視頻關系非常大的外接紋理概念,以及對它做出的一些優(yōu)化。之后會對閑魚在音視頻實踐過程中碰到的一些Flutter問題提出了一些解決方案——TPM音視頻框架。最后是閑魚Flutter多媒體開源組件的介紹。

Flutter

Flutter是一個跨平臺框架,以往的做法是將音頻、視頻和網絡這些模塊都下沉到C++層或者ARM層,在其上封裝成一個音視頻的SDK,供UI層的PC、iOS和Android調用。

而Flutter做為一個UI層的跨平臺框架,顧名思義就是在UI層也實現了一個跨平臺開發(fā)??梢灶A想的是未Flutter發(fā)展的好的話,會逐漸變?yōu)橐粋€從底層到UI層的一個全鏈路的跨平臺開發(fā),技術人員分別負責SDK和UI層的開發(fā)。

在Flutter之前已經有很多跨平臺UI解決方案,那為什么選擇Flutter呢?

我們主要考慮性能和跨平臺的能力。

以往的跨平臺方案比如Weex,ReactNative,Cordova等等因為架構的原因無法滿足性能要求,尤其是在音視頻這種性能要求幾乎苛刻的場景。

而諸如Xamarin等,雖然性能可以和原生App一致,但是大部分邏輯還是需要分平臺實現。

我們可以看一下,為什么Flutter可以實現高性能:

原生的native組件渲染以IOS為例,蘋果的UIKit通過調用平臺自己的繪制框架QuaztCore來實現UI的繪制,圖形繪制也是調用底層的API,比如OpenGL、Metal等。

而Flutter也是和原生API邏輯一致,也是通過調用底層的繪制框架層SKIA實現UI層。這樣相當于Flutter他自己實現了一套UI框架,提供了一種性能超越原生API的跨平臺可能性。

但是我們說一個框架最終性能怎樣,其實取決于設計者和開發(fā)者。至于現在到底是一個什么狀況:

在閑魚的實踐中,我們發(fā)現在正常的開發(fā)沒有特意的去優(yōu)化UI代碼的情況下,在一些低端機上,Flutter界面的流暢性是比Native界面要好的。

雖然現在閑魚某些場景下會有卡頓閃退等情況,但是這是一個新事物發(fā)展過程中的必然問題,我們相信未來性能肯定不會成為限制Flutter發(fā)展的瓶頸的。

在閑魚實踐Flutter的過程中,混合棧和音視頻是其中比較難解決的兩個問題,混合棧是指一個APP在Flutter過程中不可能一口氣將所有業(yè)務全部重寫為Flutter,所以這是一個逐步迭代的過程,這期間原生native界面與Flutter界面共存的狀態(tài)就稱之為混合棧。閑魚在混合棧上也有一些比較好的輸出,例如FlutterBoost。

外接紋理

在講音視頻之前需要簡要介紹一下外接紋理的概念,我們將它稱之為是Flutter和Frame之間的橋梁。

Flutter渲染一幀屏幕數據首先要做的是,GPU發(fā)出的VC信號在Flutter的UI線程,通過AOT編譯的機器碼結合當前Dart Runtime,生成Layer Tree UI樹,Layer Tree上每一個葉子節(jié)點都代表了當前屏幕上所需要渲染的每一個元素,包含了這些元素渲染所需要的內容。將Layer Tree拋給GPU線程,在GPU線程內調用Skia去完成整個UI的渲染過程。Layer Tree中有PictureLayer和TextureLayer兩個比較重要的節(jié)點。PictureLayer主要負責屏幕圖片的渲染,Flutter內部實現了一套圖片解碼邏輯,在IO線程將圖片讀取或者從網絡上拉取之后,通過解碼能夠在IO線程上加載出紋理,交給GPU線程將圖片渲染到屏幕上。但是由于音視頻場景下系統API太過繁多,業(yè)務場景過于復雜。Flutter沒有一套邏輯去實現跨平臺的音視頻組件,所以說Flutter提出了一種讓第三方開發(fā)者來實現音視頻組件的方式,而這些音視頻組件的視頻渲染出口,就是TextureLayer。

在整個Layer Tree渲染的過程中,TextureLayer的數據紋理需要由外部第三方開發(fā)者來指定,可以把視頻數據和播放器數據送到TextureLayer里,由Flutter將這些數據渲染出來。

TextureLayer渲染過程:首先判斷Layer是否已經初始化,如果沒有就創(chuàng)建一個Texture,然后將Texture Attach到一個SufaceTexture上。

這個SufaceTexture是音視頻的native代碼可以獲取到的對象,通過這個對象創(chuàng)建的Suface,我們可以將視頻數據、攝像頭數據解碼放到Suface中,然后Flutter端通過監(jiān)聽SufaceTexture的數據更新就可以順利把剛才創(chuàng)建的數據更新到它的紋理中,然后再將紋理交給SKIA渲染到屏幕上。

然而我們如果需要用Flutter實現美顏,濾鏡,人臉貼圖等等功能,就需要將視頻數據讀取出來,更新到紋理中,再將GPU紋理經過美顏濾鏡處理后生成一個處理后的紋理。按Flutter提供的現有能力,必須先將紋理中的數據從GPU讀出到CPU中,生成Bitmap后再寫入Surface中,這樣在Flutter中才能順利的更新到視頻數據,這樣做對系統性能的消耗很大。

通過對Flutter渲染過程分析,我們知道Flutter底層需要渲染的數據就是GPU紋理,而我們經過美顏濾鏡處理完成以后的結果也是GPU紋理,如果可以將它直接交給Flutter渲染,那就可以避免GPU-CPU-GPU這樣的無用循環(huán)。這樣的方法是可行的,但是需要一個條件,就是OpenGL上下文共享。

OpenGL

在說上下文之前,得提到一個和上線文息息相關的概念:線程。

Flutter引擎啟動后會啟動四個線程:

第一個線程是UI線程,這是Flutter自己定義的UI線程,主要負責GPU發(fā)出的VSync信號時候用當前Dart編譯的機器碼和當前運行環(huán)境創(chuàng)建出Layer Tree。

還有就是IO線程和GPU線程。和大部分OpenGL處理解決方案中一樣,Flutter也采取一個線程責資源加載,一部分負責資源渲染這種思路。

兩個線程之間紋理共享有兩種方式。一種是EGLImage(IOS是 CVOpenGLESTextureCache)。一種是OpenGL Share Context。Flutter通過Share Context來實現紋理共享,將IO線程的Context和GPU線程的Context進行Share,放到同一個Share Group下面,這樣兩個線程下資源是互相可見可以共享的。

Platform線程是主線程,Flutter中有一個很奇怪的設定,GPU線程和主線程共用一個Context。并且在主線程也有很多OpenGL 操作。

這樣的設計會給音視頻開發(fā)帶來很多問題,后面會詳細說。

音視頻端美顏處理完成的OpenGL紋理能夠讓Flutter直接使用的條件就是Flutter的上下文需要和平臺音視頻相關的OpenGL上下文處在一個Share Group下面。

由于Flutter主線程的Context就是GPU的Context,所以在音視頻端主線程中有一些OpenGL操作的話,很有可能使Flutter整個OpenGL被破壞掉。所以需要將所有的OpenGL操作都限制在子線程中。

通過上述這兩個條件的處理,我們就可以在沒有增加GPU消耗的前提下實現美顏和濾鏡等等功能。

TPM

在經過demo驗證之后,我們將這個方案應用到閑魚音視頻組件中,但改造過程中發(fā)現了一些問題。

上圖是攝像頭采集數據轉換為紋理的一段代碼,其中有兩個操作:首先是切進程,將后面的OpenGL操作都切到cameraQueue中。然后是設置一次上下文。然后這種限制條件或者說是潛規(guī)則往往在開發(fā)過程中容易被忽略的。而這個條件一旦忽略后果就是出現一些莫名其妙的詭異問題極難排查。因此我們就希望能抽象出一套框架,由框架本身實現線程的切換、上下文和模塊生命周期等的管理,開發(fā)者接入框架以后只需要安心實現自己的算法,而不需要關心這些潛規(guī)則還有其他一些重復的邏輯操作。

在引入Flutter之前閑魚的音視頻架構與大部分音視頻邏輯一樣采用分層架構:

1:底層是一些獨立模塊

2:SDK層是對底層模塊的封裝

3:最上層是UI層。

引入Flutter之后,通過分析各個模塊的使用場景,我們可以得出一個假設或者說是抽象:音視頻應用在終端上可以歸納為視頻幀解碼之后視頻數據幀在各個模塊之間流動的過程,基于這種假設去做Flutter音視頻框架的抽象。

咸魚Flutter多媒體開源組件

整個Flutter音視頻框架抽象分為管線和數據的抽象、模塊的抽象、線程統一管理和上下文同一管理四部分。

管線,其實就是視頻幀流動的管道。數據,音視頻中涉及到的數據包括紋理、Bit Map以及時間戳等。結合現有的應用場景我們定義了管線流通數據以Texture為主數據,同時可以選擇性的添加Bit Map等作為輔助數據。這樣的數據定義方式,避免重復的創(chuàng)建和銷毀紋理帶來的性能開銷以及多線程訪問紋理帶來的一些問題。也滿足一些特殊模塊對特殊數據的需求。同時也設計了紋理池來管理管線中的紋理數據。

模塊:如果把管線和數據比喻成血管和血液,那框架音視頻的場景就可以比喻成器官,我們根據模塊所在管線的位置抽象出采集、處理和輸出三個基類。這三個基類里實現了剛才說的線程切換,上下文切換,格式轉換等等共同邏輯,各個功能模塊通過集成自這些基類,可以避免很多重復勞動。

線程:每一個模塊初始化的時候,初始化函數就會去線程管理的模塊去獲取自己的線程,線程管理模塊可以決定給初始化函數分配新的線程或者已經分配過其他模塊的線程。

這樣有三個好處:

一是可以根據需要去決定一個線程可以掛載多少模塊,做到線程間的負載均衡。第二,多線程并發(fā)式能夠保證模塊內的OpenGL操作是在當前線程內而不會跑到主線程去,徹底避免Flutter的OpenGL 環(huán)境被破壞。第三,多線程并行可以充分利用CPU多核架構,提升處理速度。

從Flutter端修改Flutter引擎將Context取出后,根據Context創(chuàng)建上下文的統一管理模塊,每一個模塊在初始化的時候會獲取它的線程,獲取之后會調用上下文管理模塊獲取自己的上下文。這樣可以保證每一個模塊的上下文都是與Flutter的上下文進行Share的,每個模塊之間資源都是共享可見的,Flutter和音視頻native之間也是互相共享可見的。

基于上述框架如果要實現一個簡單的場景,比如畫面實時預覽和濾鏡處理功能,

1:需要選擇功能模塊,功能模塊包括攝像頭模塊、濾鏡處理模塊和Flutter畫面渲染模塊,

2:需要配置模塊參數,比如采集分辨率、濾鏡參數和前后攝像頭設置等,

3:在創(chuàng)建視頻管線后使用已配置的參數創(chuàng)建模塊

4:最后管線搭載模塊,開啟管線就可以實現這樣簡單的功能。

上圖為整個功能實現的代碼和結構圖。

結合上述音視頻框架,閑魚實現了Flutter多媒體開源組件。

組要包含四個基本組件分別是:

1:視頻圖像拍攝組件

2:播放器組件

3:視頻圖像編輯組件

4:相冊選擇組件

現在這些組件正在走內部開源流程。預計9月份,相冊和播放器會實現開源。

后續(xù)展望和規(guī)劃

1:實現開頭所說的從底層SDK到UI的全鏈路的跨端開發(fā)。目前底層框架層和模塊層都是各個平臺各自實現,反而是Flutter的UI端進行了跨平臺的統一,所以后續(xù)會將底層也按照音視頻常用做法把邏輯下沉到C++層,盡可能的實現全鏈路跨平臺。

2:第二部分內容為開源共建,閑魚開源的內容不僅包括拍攝、編輯組件,還包括了很多底層模塊,希望有開發(fā)者在基于Flutter開發(fā)音視頻應用時可以充分利用閑魚開源出的音視頻模塊能力,搭建APP框架,開發(fā)者只要去負責實現特殊需求模塊就可以,盡可能的減少重復勞動。

flutter屬于原生開發(fā)嗎

Flutter只是 谷歌的移動 UI 框架,在Android開發(fā)中,你可以理解為 嵌套在activity里面的一個view即可。

目前有純flutter開發(fā),還有 flutter,原生混合開發(fā) 兩種模式。。

Flutter(六)Android與Flutter混合開發(fā)(Hybird)

如果我們目前的項目是Android的,但是接下來我們希望部分頁面可以使用Flutter進行開發(fā),甚至我們希望在Native頁面中嵌入FlutterUI組件,那么我們該如何實現呢?

假設你現在Android項目的目錄的結構是這樣的

這時候如果你想創(chuàng)建一個Flutter模塊,使得Android模塊和Flutter模塊之間可以進行交互,我們可以通過Android Studio新建一個Flutter Module,具體過程是:File — New — New Module ,之后選擇Flutter Module,指定Project Location的路徑為

也就是說,最終你的項目結構會是這樣的

接下來在Android Module的 build.gradle 文件中添加flutter依賴

先創(chuàng)建一個Flutter頁面

這里比較重要的是 window.defaultRouteName 這個字段,這個字段可以接收從Native傳遞過來的參數 (下文我們會介紹原生傳遞參數的方法),也就是說通過這個字段我們就可以進行Flutter頁面的路由的分發(fā)

我們可以直接在Android的 MainActivity 中啟動一個 FlutterActivity ,這里的 initialRoute 方法中傳遞的參數就對應Flutter層的 window.defaultRouteName

注意:需要在 AndroidManifest.xml 注冊 FlutterActivity

自己創(chuàng)建一個 FlutterAppActivity 繼承自 FlutterActivity

在 MainActivity 中啟動 FlutterAppActivity (另外別忘了在 AndroidManifest.xml 中注冊 FlutterAppActivity )

兩種啟動方式的區(qū)別

如果單純只是想打開一個Flutter頁面,兩種方式實際上基本沒有太大區(qū)別,第一種方式也許還會更簡單一點。但是,在Flutter開發(fā)中,我們往往還需要開發(fā)一些Native插件供Flutter調用,如果使用復寫 FlutterActivity 的方式更有利于我們在 FlutterActivity 中注冊我們的Native插件,所以實際開發(fā)中一般推薦使用第二種方式

擴展思考

initialRoute 從名稱上看起來是Flutter提供給我們進行Native與Flutter交互的路由跳轉的,但是實際上他就是一個字符串,我們不僅僅可以傳遞一個路由名稱,有時候我們也可以通過這個參數傳遞一串JSON數據,然后在Flutter端進行解析,這樣我們就可以通過這個參數做更多的事情

activity_main.xml

FrameLayout 用于承載Flutter組件

MainActivity.java

使用 FragmentManager 將 FlutterFragment 添加到 FrameLayout 容器中

運行結果

上半部分是原生的TextView,下半部分是Flutter的Text組件

本節(jié)主要介紹了Native和Flutter之間的頁面跳轉,以及同一個頁面中Native與Flutter組件的組合。接下來會介紹如何編寫Android插件與Flutter進行數據交互

Flutter/IOS混和開發(fā)情況下,項目內首個Flutter頁面導航無返回問題

在Flutter內部機制中,默認使用自動管理導航機制,該機制在Flutter與原生混和開發(fā)情況下,Flutter頁面不一定作為項目的首頁面,所以出現需要在首個Flutter頁面使用導航返回的需求。

Flutter的AppBar中定義有屬性:

該屬性默認為YES,即默認為自動管理導航欄,該情況下其會在非第一個Flutter頁面創(chuàng)建導航返回按鈕,我們在AppBar中將其設置為false:

并且手動添加導航返回按鈕:

完成


新聞名稱:flutter原生混合,flutter原生混合開發(fā)
文章來源:http://weahome.cn/article/hopgde.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部