簡介
愛奇藝開播助手項目,又稱"直播機",該項目目標是通過一個移動平臺爲主播提供多樣化的直播內容。現階段所涵蓋的直播內容包括:遊戲直播,美女攝像直播,小劇場直播,其中游戲直播相對主播數量最多,3種推流模式所涉及的推流SDK基本一致,推流邏輯存在部分差異。
該項目的Android端和iOS端架構類似,主要由APP、SDK和so三層構成,APP層負責界面展示和交互,由各端Native代碼實現,so層負責封裝核心的推流、播放等功能,由於更接近底層硬件,使用C實現,而中間的SDK層負責調用這些so庫的功能。
由於雙端的業務幾乎完全一樣,雙端爲了提高代碼的複用率,我們試圖接入一套跨平臺的框架同時開發兩端的APP。
爲什麼選擇Flutter
移動端跨平臺一直是開發者老生常談的話題,爲了儘可能的增加代碼複用,降低開發成本,各大科技巨頭都有自己的跨平臺框架,比如Facebook的React-Native、阿里的Weex、Cordova等。這些跨平臺框架各有優劣,Google也“不甘寂寞”,在2018年Google開發者大會上重點介紹了自己的跨平臺框架Flutter。
和RN和Weex將javascript轉化爲原生控件渲染不同,Flutter完全掙脫了原生控件的“束縛”,如圖1所示,Flutter使用了分層架構,分爲Framework和Engine兩個部分,其中Framework層提供各種基礎組件庫,包括各種Widget,動畫等,Engine層則完全由C和C++實現,使用Skia進行渲染(對!就是chrome用的那個圖形渲染框架),官方宣稱可以達到原生app的渲染性能。
下圖是和RN、Weex之間的對比:
可以看到目前Flutter從各個方面都已經不遜於前兩位,而且在Google新操作系統Fuchsia(被認爲是Android的繼任者)也使用Flutter作爲其UI框架,今後的發展不可限量。
除了渲染性能之外,Flutter還有一個非常誘人的特性:HotReload,在debug下的Flutter工程可以快速熱重載到真機上,修改完代碼後Ctrl+S就能實時展現在真機界面上,不需要重新安裝apk包,想想就興奮!
如果你對HotReload原理感興趣,可以移步Flutter官網進一步瞭解 HotReload。
總體來看,Flutter有性能好、開發效率高、跨平臺和可無縫接入原有工程等優勢,所以我們嘗試使用Flutter進行開播助手的改造實踐。
開播助手Android端接入
下面詳細介紹一下Android和iOS是如何接入的。
在Android中添加Flutter組件
目前開播助手中使用了Flutter的Fragment和View兩種方式,如下面兩段代碼所示:
使用Flutter.createFragment()和Flutter.createView()兩個方法,這兩個方法可以返回Flutter創建的供Android使用的Fragment和View,接下來和原生的Fragment和View使用方法就是一模一樣了。(是不是很簡單!)
- 使用Flutter Fragment
Flutter.createFragment("settings")
- 使用Flutter View
Flutter.createView(getActivity(), getLifecycle(), "settings");
當然爲了告訴Flutter需要使用哪個界面,使用了路由的機制,創建fragment或view的時候需要傳入一個路由的字符串,在Flutter工程中也需要使用此字符串,代碼如下:
void main() { runApp(_widgetForRoute(window.defaultRouteName));}
Widget _widgetForRoute(String route) {
switch (route) {case 'settings':return MaterialApp(home:
SettingsPage()); .... }}
在Flutter工程的入口處匹配傳入的字符串,來決定實例化哪個頁面返回。
使用Module接入
開發過程中我們可以使用Moudle依賴來接入,只需要在setting.gradle中添加以下代碼即可:
setBinding(new Binding([gradle: this]))
evaluate(new File(settingsDir.parentFile,'flutter_liveshow/.android/include_flutter.groovy'))
使用aar接入
Android使用aar接入Flutter十分的簡單,只用下面兩步就可以順利的將使用Flutter開發的界面接入原生的工程。
使用gradle工具打aar資源包
如果要Android可以使用Flutter的工程,可以將Flutter工程打成aar的包,如下圖所示,進入工程中的.android/目錄,使用./gradlew Flutter:assembleRelease即可。
將aar包加入工程並依賴
如下圖所示,首先將打好的release包放入libs目錄下:
目前最新版本的Flutter在集成時需要將sdk中的icudtl.dat文件放入資源目錄中一起打包,否則會出錯,官方正在修復此問題,相信不久就能解決。
開播助手iOS端接入
Podfile接入Flutter
flutter_application_path = '../flutter_liveshow/'
eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)
eval(string [, binding [, filename [,lineno]]]) → obj
Evaluates the Ruby expression(s) in string. If binding is given, which must be a Binding object, the evaluation is performed in its context. If the optional filename and lineno parameters are present, they will be used when reporting syntax errors.
添加完成後執行pod install。這段代碼實際就是在Podfile中加入一段Flutter所需要的腳本。如果基於Flutter master channel
開發,生成的podhelper.rb中會增加post_install
hooks,如果項目中也使用該hooks,需要手動合併。所幸這個文件只有在修改Flutter plugin依賴並運行Flutter package get之後纔會重新生成。
Dart代碼編譯設置
“TARGET APP -> Build Phases -> New Run Script Phase” 新增script phase填入下方代碼:
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
“Build Settings -> Add User-Defined Setting” 新增 FLUTTER_ROOT 字段。
接入Host App
- AppDelegate.swift
import Flutter
import FlutterPluginRegistrant // Only if you have Flutter Plugins.
@UIApplicationMainclass AppDelegate: FlutterAppDelegate {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
GeneratedPluginRegistrant.register(with: self);
......}
- 在App中接入Flutter開發的頁面
let flutterViewController = FlutterViewController()
flutterViewController.setInitialRoute("settings")
navigationController?.pushViewController(flutterViewController, animated: true)
敲黑板,劃重點
實際效果和今後的計劃
目前已經接入了使用Flutter開發的設置頁面和搜索節目單結果界面,具體兩端的效果如下圖所示:
經過實際接入發現使用Flutter開發的界面的流暢度和原生開發的界面幾乎沒有區別,可以說是完全無縫的體驗,使用Flutter開發部分獨立性較強的頁面還是沒有任何問題的。
Flutter目前還處於推廣階段,考慮到其各種優秀的特性,以後一定會發展的越來越好。開播助手後面還準備將更多頁面接入Flutter,先從部分列表頁開始,並且維護一個Flutter的組件庫,供今後頁面開發使用,提高兩端代碼複用率,逐步實現一套代碼雙端運行的目的。
轉載自公衆號“愛奇藝技術產品團隊”:https://mp.weixin.qq.com/s/f4j3_NGxjAjqNmecc5XrjA