FIDL:Flutter與原生通訊的新姿勢(shì)徽鼎,不局限于基礎(chǔ)數(shù)據(jù)類型

大家好!今天給大家安利一個(gè)自認(rèn)為比較重磅的Flutter開源項(xiàng)目酷麦。

Flutter的產(chǎn)品定義是一個(gè)高性能的跨平臺(tái)的移動(dòng)UI框架矿卑,能夠用一套代碼同時(shí)構(gòu)建出Android/iOS/Web/MacOS應(yīng)用。作為一套UI框架沃饶,它不具備一些系統(tǒng)的接口母廷,自然還是避免不了跟原生打交道轻黑。于是乎,它提出了名為platform channel的東西琴昆,用于flutter和原生靈活的交換數(shù)據(jù)氓鄙。以下為了描述方便,用Android代指原生业舍。

image

燃鵝抖拦,燃鵝,燃鵝舷暮,它只支持一些基礎(chǔ)的數(shù)據(jù)類型和數(shù)據(jù)結(jié)構(gòu)的傳輸态罪,例如bool/int/long/byte/char/String/byte[]/List/Map等。

因此下面,當(dāng)你想傳輸復(fù)雜點(diǎn)的數(shù)據(jù)复颈,你只能包裝成Map,類似這樣:

await _channel.invokeMethod('initUser',
    {'name': 'Oscar', 'age': 16, 'gender': 'MALE', 'country': 'China'});

然后再在Android層hard code沥割,解析出不同的key對(duì)應(yīng)的不同數(shù)據(jù)券膀。如果你是一個(gè)純fluter項(xiàng)目,且以后也沒(méi)有和原生打交道的打算驯遇,或者只是需要進(jìn)行簡(jiǎn)單的交互,那這種做法也無(wú)可厚非蓄髓。而當(dāng)你的項(xiàng)目已經(jīng)有很大的一部分原生代碼或者你需要使用第三方不支持flutter的lib庫(kù)的時(shí)候叉庐,就意味著你需要編寫大量向上面那樣的模板代碼』岷龋可見效率低下陡叠,且可維護(hù)性差。這時(shí)肢执,你會(huì)想枉阵,能傳輸對(duì)象就好了!

而當(dāng)你想傳輸對(duì)象時(shí):

image

抱歉预茄,沒(méi)門兴溜,只能給你一個(gè)尷尬又不是禮貌的危笑。當(dāng)然耻陕,也不是不可以拙徽,我們可以在原生上層把對(duì)象序列化成json對(duì)象,然后在flutter層再把json轉(zhuǎn)成flutter的對(duì)象诗宣,同樣效率很差膘怕。

FIDL是什么

學(xué)過(guò)Android的應(yīng)該都知道AIDL(Android Interface Defination Language),即Android接口定義語(yǔ)言召庞。Android中有一種高級(jí)的跨進(jìn)程通信方式——Binder岛心,但是想要使用Binder需要了解一些Binder的機(jī)制和API来破,需要編寫大量的模板代碼。Android為了解決這個(gè)問(wèn)題忘古,嘗試把使用Binder的方法做的小白一點(diǎn)徘禁。于是定義了AIDL,告訴開發(fā)者存皂,你的接口文件必須按照我規(guī)定的來(lái)寫晌坤,你要跨進(jìn)程傳輸?shù)膶?duì)象必須實(shí)現(xiàn)Parcelable接口。然后旦袋,Android給你生成了一個(gè)Service.Stub類骤菠,偷偷的在背后把對(duì)象的序列化、反序列化的工作都給做了疤孕。開發(fā)者使用這個(gè)Stub類就能輕松上手Binder這種高級(jí)的跨進(jìn)程通訊方法商乎。(??????我編的,差不多啦)

FIDL(Flutter Interface Defination Language)即Flutter接口定義語(yǔ)言祭阀,它的使命和AIDL很類似鹉戚,悄悄把對(duì)象的序列化、反序列化专控、自動(dòng)生成代碼這種“臟活累活”給做了抹凳。開發(fā)者在原生代碼中看到的類,能通過(guò)@FIDL注解標(biāo)記伦腐,自動(dòng)在Dart側(cè)生成和原生代碼中一樣的類赢底。FIDL是一面鏡子,把各種原生平臺(tái)的類影射到Dart中柏蘑,把Dart中的類影射到各個(gè)原生平臺(tái)幸冻。

少啰嗦,先看東西

image

1咳焚、首先是Java類:

public class User {
  String name;
  int age;
  String country;
  Gender gender;
}
enum Gender {
  MALE, FEMALE
}

2洽损、定義FIDL接口

@FIDL
public interface IUserService {
    void initUser(User user);
}

3、執(zhí)行幾個(gè)命令

4革半、Android側(cè)在合適的地方打開IUserServiceStub通道(IUserServiceStub是IUserService的實(shí)現(xiàn)類碑定,自動(dòng)生成的)

FidlChannel.openChannel(getFlutterEngine().getDartExecutor(), new IUserServiceStub() {
  @Override
  void initUser(User user){
    System.out.println(user.name + " is " + user.age + "years old!");
  }
}

5、Flutter側(cè)使用IUserService 通道

// 綁定通道(IUserService類是自動(dòng)生產(chǎn)的哦)
await Fidl.bindChannel(IUserService.CHANNEL_NAME, _channelConnection);
// 使用User類(`User類`以及它使用的`Gender枚舉`是自動(dòng)生成的哦)
User user = User();
user.name = 'Oscar';
user.age = 18;
user.gender = Gender.MALE;
user.country = 'China';
// 調(diào)用通道方法
await IUserService.initUser(user);

編譯又官,運(yùn)行不傅,你將能在Logcat中看到Oscar is 18 years old!

FIDL使用詳解

這一部分是對(duì)少啰嗦赏胚,先看東西部分的補(bǔ)充解釋访娶,觀眾姥爺們可以自行跳過(guò)。

上面的例子中的Map觉阅,一般來(lái)說(shuō)崖疤,在Java中會(huì)對(duì)應(yīng)一個(gè)類:

public class User {
  String name;
  int age;
  String country;
  Gender gender;
}
enum Gender {
  MALE, FEMALE
}

如果想讓flutter傳輸這個(gè)對(duì)象而不用在flutter層手動(dòng)去編寫User這個(gè)類秘车,以及編寫fromJson/toJson方法,你可以這樣做:

1劫哼、定義一個(gè)接口叮趴,添加注解@FIDL。這個(gè)注解將告知annotationProcessor生成一些接口和類的描述文件权烧。

@FIDL
public interface IUserService {
    void initUser(User user);
}

2眯亦、Android Studio點(diǎn)擊sync,或者執(zhí)行:

./gradlew assembleDebug

然后就會(huì)產(chǎn)生一堆json文件般码,如下:

image

這些json文件就是FIDL和類的描述文件妻率。沒(méi)錯(cuò),也會(huì)同時(shí)生成User引用的Gender類的描述文件板祝。

同時(shí)宫静,還會(huì)生成IUserService的實(shí)現(xiàn)IUserServiceStub。即:

  • com.infiniteloop.fidl_example.IUserService.fidl.json
  • com.infiniteloop.fidl_example.User.json
  • com.infiniteloop.fidl_example.Gender.json
  • com.infiniteloop.fidl_example.IUserServiceStub.java

3券时、進(jìn)入到你的flutter項(xiàng)目孤里,在lib目錄下創(chuàng)建fidl目錄,把上面的json文件拷貝到這個(gè)目錄橘洞,然后執(zhí)行:

flutter packages pub run fidl_model

然后就能在fidl目錄下自動(dòng)生成相關(guān)的dart類:

image

即:

  • User.dart
  • Gender.dart
  • IUserService.dart

4捌袜、使用

a. Android側(cè)在合適的地方打開IUserServiceStub通道

FidlChannel.openChannel(getFlutterEngine().getDartExecutor(), new IUserServiceStub() {
  @Override
  void initUser(User user){}
}

b. Flutter側(cè)綁定IUserService通道

await Fidl.bindChannel(IUserService.CHANNEL_NAME, _channelConnection);

c、Flutter調(diào)用通道方法

await IUserService.initUser(User());

d炸枣、Flutter可以在合適的時(shí)候接觸綁定

await Fidl.unbindChannel(IUserService.CHANNEL_NAME, _channelConnection);

e琢蛤、Android側(cè)可以在合適的時(shí)候關(guān)閉通道

FidlChannel.closeChannel(userServiceStub);

當(dāng)然,F(xiàn)IDL的功能不止于此

1抛虏、多個(gè)參數(shù)的FIDL接口

void init(String name, Integer age, Gender gender, Conversation conversation);

2、帶返回值的FIDL接口

UserInfo getUserInfo();

3套才、支持泛型類的生成

public class User<T> {
  T country;
}
public class AUser<String>{}

FIDL接口:

void initUser(AUser user);

將能在dart側(cè)生成AUser和User類迂猴,且能保持繼承關(guān)系。

4背伴、傳遞枚舉

void initEnum0(EmptyEnum e);
String initEnum1(MessageStatus status);

5沸毁、傳遞集合、Map

void initList0(List<String> ids);
void initList1(Collection<String> ids);
void initList7(Stack<String> ids);
void initList10(BlockingQueue ids);

6傻寂、傳遞復(fù)雜對(duì)象息尺。繼承、抽象疾掰、泛型搂誉、枚舉和混合類,來(lái)一個(gè)打一個(gè)静檬。

當(dāng)然炭懊,F(xiàn)IDL能做的不止于此

現(xiàn)在并级,F(xiàn)IDL項(xiàng)目只實(shí)現(xiàn)了從Dart側(cè)調(diào)用Android側(cè)的方法。還有以下工作要做:

  • Android側(cè)調(diào)用Dart側(cè)的方法
  • 其它平臺(tái)和Flutter方法的互相調(diào)用
  • EventChannel侮腹,EventChannel本質(zhì)上是可以通過(guò)MethodChannel實(shí)現(xiàn)的嘲碧,問(wèn)題不大

搞定了對(duì)象傳輸,這些問(wèn)題父阻,都是小case啦愈涩。

對(duì)于對(duì)象的序列化和反序列化

為了能滿足大佬們的定制化需求,我分別在Java側(cè)和Flutter側(cè)定義了序列化/反序列化的接口類加矛。

Java:

public interface ObjectCodec {
    List<byte[]> encode(Object... objects);
    <T> T decode(byte[] input, TypeLiteral<T> type);
}

Dart:

abstract class ObjectCodec {
  dynamic decode(Uint8List input);
  List<Uint8List> encode(List objects);
}

目前使用的是JsonObjectCodec履婉,經(jīng)過(guò)JSON的編解碼,性能會(huì)稍差荒椭。后面還希望和小伙伴們一起努力谐鼎,實(shí)現(xiàn)更高效的編解碼。

項(xiàng)目進(jìn)度

上述提到的功能趣惠,只要是從Flutter側(cè)調(diào)用Java側(cè)的方法相關(guān)的狸棍,大部分都已經(jīng)實(shí)現(xiàn)了。

我做了一個(gè)Demo味悄,模擬了一個(gè)在Android側(cè)依賴了IM(即時(shí)通訊)SDK草戈,需要在Flutter側(cè)聊天、獲取消息侍瑟、發(fā)消息的場(chǎng)景唐片。以下是Demo的截圖:

1、首頁(yè)涨颜,點(diǎn)擊按鈕調(diào)用Android側(cè)方法费韭,開啟聊天服務(wù)

image

2、聊天頁(yè)面

image

3庭瑰、發(fā)一條消息給Lucy并獲取和Lucy的聊天記錄

image

4星持、調(diào)用Android側(cè)方法發(fā)送N條消息給Wilson并獲取聊天記錄

image

最后

上次做開源項(xiàng)目已經(jīng)是3年前了,那是一個(gè)Android原生刷新控件弹灭,TwinklingRefreshLayout督暂,github 3.7k stars。后來(lái)由于工作的原因穷吮,整天跟Android Framework逻翁、C/C++打交道,精力也都是放到了公司的業(yè)務(wù)上捡鱼,也沒(méi)有時(shí)間和精力維護(hù)下去八回。

那么今天我想發(fā)布的這個(gè)Flutter開源項(xiàng)目,是想通過(guò)社區(qū)的力量,和大家一起把項(xiàng)目維護(hù)下去辽社。我在GayHub上建立了一個(gè)組織伟墙,https://github.com/flutterFIDL。稍晚一點(diǎn)時(shí)間滴铅,我會(huì)把項(xiàng)目開源出來(lái)戳葵,一兩天內(nèi),代碼會(huì)放在這里汉匙,https://github.com/flutterFIDL/FIDL拱烁。大家記得投幣、點(diǎn)贊噩翠、收藏,一鍵3連(大家如果覺得這個(gè)項(xiàng)目能很好解決跨平臺(tái)通信問(wèn)題擅笔,給個(gè)star可以嘛??)猛们。阿不狞洋,我需要一個(gè)團(tuán)隊(duì)跟我一起發(fā)展這個(gè)項(xiàng)目吉懊,希望你熟悉Flutter開發(fā)浆竭,了解Android和Java開發(fā)缤沦,熱愛開源,熟悉Flutter+iOS / Flutter + Web其中的一種届巩,并有相關(guān)項(xiàng)目經(jīng)歷瘾英,加我vx: w354850839。

這樣一個(gè)庫(kù)煌集,香嗎卷拘?告訴我乍赫,有多香诈皿。??

歡迎留言評(píng)論截歉,告訴我你的Flutter和原生通信的使用場(chǎng)景凉逛,以及遇到的痛點(diǎn)和問(wèn)題~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子攻礼,更是在濱河造成了極大的恐慌礁扮,老刑警劉巖太伊,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異绣的,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)芭概,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)文黎,“玉大人耸峭,你說(shuō)我怎么就攤上這事≡壕浚” “怎么了业汰?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵样漆,是天一觀的道長(zhǎng)放祟。 經(jīng)常有香客問(wèn)我,道長(zhǎng)舞竿,這世上最難降的妖魔是什么骗奖? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任醒串,我火速辦了婚禮芜赌,結(jié)果婚禮上缠沈,老公的妹妹穿的比我還像新娘错蝴。我一直安慰自己顷锰,他們只是感情好官紫,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布束世。 她就那樣靜靜地躺著毁涉,像睡著了一般薪丁。 火紅的嫁衣襯著肌膚如雪严嗜。 梳的紋絲不亂的頭發(fā)上漫玄,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天睦优,我揣著相機(jī)與錄音汗盘,去河邊找鬼隐孽。 笑死健蕊,一個(gè)胖子當(dāng)著我的面吹牛缩功,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嫡锌,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼蛛倦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起茸塞,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钾虐,失蹤者是張志新(化名)和其女友劉穎效扫,沒(méi)想到半個(gè)月后菌仁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體济丘,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摹迷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年峡碉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驮审。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鲫寄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出疯淫,到底是詐尸還是另有隱情塔拳,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布峡竣,位于F島的核電站靠抑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏适掰。R本人自食惡果不足惜颂碧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一荠列、第九天 我趴在偏房一處隱蔽的房頂上張望肌似。 院中可真熱鬧睬澡,春花似錦斗躏、人聲如沸云稚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春姐军,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工典徘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留础废,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓抛腕,卻偏偏與公主長(zhǎng)得像摔敛,于是被迫代替她去往敵國(guó)和親行楞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子池颈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容