导出jar插件_Fluttify输出的Flutter插件工程详解
系列文章:
yohom:Fluttify輸出的Flutter插件工程詳解?zhuanlan.zhihu.comyohom:開發(fā)Flutter插件必備原生SDK->Dart接口生成引擎`Fluttify`介紹?zhuanlan.zhihu.comyohom:如何使用Fluttify開發(fā)一個(gè)新的Flutter插件?zhuanlan.zhihu.com注:目前Fluttify本身并不對(duì)外開放,但是內(nèi)測(cè)階段可以免費(fèi)為你生成插件,只要提供android端的jar/aar和ios端的framework/.h+.a,或者maven坐標(biāo)和cocoapods名稱即可,聯(lián)系方法請(qǐng)看文末
工程結(jié)構(gòu)
Fluttify的輸出工程是標(biāo)準(zhǔn)的Flutter插件工程,其中輸出的原生語(yǔ)言是java(android)和objc(ios)。
android端使用java是因?yàn)閺淖止?jié)碼反編譯到j(luò)ava的時(shí)候,如果字節(jié)碼來自kotlin,那么會(huì)有一些特殊的標(biāo)記,導(dǎo)致一些情況下(比如基礎(chǔ)類型和對(duì)應(yīng)包裝類的混淆)需要多余的工作去適配,為了加強(qiáng)兼容性,所以后期選擇了java作為生成的原生語(yǔ)言。
ios端選擇objc也是類似的原因,objc的方法轉(zhuǎn)為swift的方法時(shí),方法名會(huì)自動(dòng)轉(zhuǎn)換,一些涉及到介詞的方法名都會(huì)被轉(zhuǎn)換為swift風(fēng)格,這也導(dǎo)致了一些額外的工作去轉(zhuǎn)換objc方法名到swift,所以最終選擇了objc作為輸出語(yǔ)言。
dart端結(jié)構(gòu)
引用自上一篇文章:
Fluttify的產(chǎn)物是一個(gè)標(biāo)準(zhǔn)的Flutter的插件工程,所以lib文件夾之上的結(jié)構(gòu)都和普通插件一樣。lib文件夾下會(huì)分成android和ios文件夾,分別放置各平臺(tái)SDK中的類(枚舉/接口等)對(duì)應(yīng)的Dart類(枚舉/接口等)。android/ios文件夾下還會(huì)各自生成:- function.g.dart文件:生成的所有頂層函數(shù);
- type_op.g.dart文件:所有的as和is方法,用來判斷類型和造型;
- ios/android.export.g.dart文件:導(dǎo)出所有的ios/android類型;
- platformview文件夾:生成的所有PlatformView;
習(xí)慣上會(huì)在lib文件夾下再加一個(gè)dart文件夾,放置對(duì)各平臺(tái)進(jìn)行抽象的代碼,并且最后對(duì)外export的時(shí)候,只export這個(gè)文件夾下的文件。lib文件夾結(jié)構(gòu)概覽:
.
├── janalytics_fluttify.dart
└── src
├── android
│ ├── android.export.g.dart
│ ├── cn ... android端對(duì)應(yīng)的dart接口
│ └── type_op.g.dart
├── dart
│ └── janalytics_service.dart
└── ios
├── JANALYTICSBrowseEvent.g.dart
├── ...其他生成文件
├── functions.g.dart
├── ios.export.g.dart
└── type_op.g.dart
原生端結(jié)構(gòu)
原生端生成的文件分成兩種。
第一種是PlatformViewFactory類,負(fù)責(zé)PlatformView的創(chuàng)建,Fluttify會(huì)掃描到SDK內(nèi)所有的View類并為其生成PlatformViewFactory類。第二種是主Plugin類,負(fù)責(zé)所有的MethodChannel的調(diào)用處理。
示例的android端的文件夾結(jié)構(gòu),ios端類似:
. └── me└── yohom└── amap_map_fluttify├── AmapMapFluttifyPlugin.java // 主Plugin├── DownloadProgressViewFactory.java // 以下都是PlatformViewFactory├── MapViewFactory.java├── TextureMapViewFactory.java└── WearMapViewFactory.java語(yǔ)言元素的映射
類
java中的類一般都會(huì)有作為命名空間使用的包名,平時(shí)使用的時(shí)候都會(huì)先import,再使用簡(jiǎn)稱來引用。Fluttify實(shí)現(xiàn)初期,生成的dart類也是直接使用java類的簡(jiǎn)稱,但這很容易就會(huì)出現(xiàn)類名沖突,所以最終決定使用全類名來生成java對(duì)應(yīng)的dart類。其規(guī)則為:
java:
轉(zhuǎn)換為dart:
class com_test_A {}在這點(diǎn)上objc就直接了很多,因?yàn)閛bjc類本身就沒有命名空間,類名就是它的全名,所以objc這邊的類名不需要轉(zhuǎn)換直接用到dart類名上即可,規(guī)則為:
@interface TestClassA @end轉(zhuǎn)換為:
class TestClassA {}接口
所謂接口在java和objc的語(yǔ)境下都是代表可以多重繼承的類型。雖然dart也有隱式接口,但是objc的接口(protocol)可以有實(shí)現(xiàn)且子類可以不實(shí)現(xiàn)所有的方法,而dart一旦implements了一個(gè)隱式接口,就必須實(shí)現(xiàn)所有的方法,所以dart的隱式接口不能作為objc的protocol的等價(jià)角色。
萬幸的是dart支持mixin,mixin正好能夠處理objc的protocol特性。
示例
java:
轉(zhuǎn)換為dart:
class com_test_ClassA extends java_lang_Object with com_test_Interface {}objc:
@protocol TestInterfaceA @end@interface TestClassA @end轉(zhuǎn)換為dart:
class TestClassA extends NSObject with TestInterfaceA {}方法
java,objc以及dart的方法在概念上基本一致,除了objc端的一些指針類型和值類型的區(qū)分,其他的都差不多。這里給一個(gè)例子闡述一下:
java:
轉(zhuǎn)換為dart:
class com_test_TestClassA {String testMethod(int arg) { /* 調(diào)用原生代碼 */ } }objc:
@interface TestClassA - (NSString*) testMethod: (NSInteger) arg; @end轉(zhuǎn)換為dart:
class TestClassA {String testMethod(int arg) { /* 調(diào)用原生代碼 */} }函數(shù)
java沒有頂層函數(shù),所以沒有需要處理的。
objc的函數(shù)實(shí)際上就是c函數(shù),而dart也支持頂層函數(shù),且與objc的函數(shù)語(yǔ)義上沒有太大的出入。
常量
目前支持轉(zhuǎn)換java的類常量到dart的類常量。
回調(diào)
回調(diào)分為lambda和delegate,不過在Fluttify的生成代碼中的角色差不多。
回調(diào)的實(shí)現(xiàn)主要通過雙向的MethodChannel調(diào)用來實(shí)現(xiàn),比如說java端有一個(gè)方法:
void setCallback(Callback callback) { /* 代碼 */ }生成的dart代碼會(huì)是這樣的:
Future<void> setCallback(Callback callback) async {await MethodChannel('some channel').invokeMethod('some method');// 這里會(huì)接收到native端的調(diào)用MethodChannel('some channel callback').setMethodHandler((methodResult) {// 處理原生的回調(diào)callback.onXXX();}); }內(nèi)存管理
dart端
Dart端的所有SDK類都會(huì)間接繼承foundation_fluttify中定義的Ref類,這個(gè)類代表是一個(gè)引用類,內(nèi)部含有一個(gè)refId字段,保存的是原生端對(duì)應(yīng)對(duì)象的id。
目前這個(gè)id的實(shí)現(xiàn)使用的是對(duì)象的hashCode。android端所有的對(duì)象都會(huì)有hashCode()方法,而ios端只有繼承NSObject的類才有hash字段,如果碰到有處理結(jié)構(gòu)體的需要,則用NSValue包裝結(jié)構(gòu)體后再調(diào)用其hash字段。
當(dāng)調(diào)用SDK類的方法時(shí),會(huì)把refId傳遞給原生,然后原生從全局HEAP中獲取到目標(biāo)對(duì)象,然后再在目標(biāo)對(duì)象上進(jìn)行調(diào)用。
dart端還提供了一個(gè)kNativeObjectPool全局集合對(duì)象,這個(gè)集合對(duì)象保存了所有的原生對(duì)象的引用(即refId),在需要釋放對(duì)象時(shí),可以對(duì)這個(gè)集合進(jìn)行操作。
原生端
foundation_fluttify的原生端提供了一個(gè)HEAP全局集合,用來存放插件調(diào)用過程中產(chǎn)生的原生對(duì)象。當(dāng)dart端開始一個(gè)方法調(diào)用時(shí),原生端便會(huì)先從HEAP中獲取到目標(biāo)對(duì)象,再調(diào)用對(duì)應(yīng)方法。
如果需要把釋放一個(gè)對(duì)象需要把它從HEAP中刪除,不然HEAP會(huì)一直強(qiáng)引用對(duì)象導(dǎo)致一直占用內(nèi)存。從HEAP中刪除后,后續(xù)的內(nèi)存管理就交給系統(tǒng)來處理了。
結(jié)語(yǔ)
本文對(duì)Fluttify輸出的插件工程的結(jié)構(gòu)作了大致的介紹。這些其實(shí)也包含了很多我在實(shí)現(xiàn)Fluttify過程中遇到的困難,包括java/objc/dart這些語(yǔ)言在語(yǔ)法上的統(tǒng)一,如何實(shí)現(xiàn)回調(diào)等等,還有很多很多細(xì)節(jié)的問題,更有甚者還要給SDK作者的一些騷操作騷寫法擦屁股。
最后還是推薦一波,如果有想要生成插件的老鐵也可以聯(lián)系我(382146139@qq.com),目前Fluttify還處于內(nèi)測(cè)階段,不會(huì)收取任何費(fèi)用,有任何反饋都可以往fluttify-feedback提issue,歡迎各位的反饋。
總結(jié)
以上是生活随笔為你收集整理的导出jar插件_Fluttify输出的Flutter插件工程详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue2 怎么用vite_vue3vit
- 下一篇: python字符串创建_在Python上