版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
PlatformView提供了在Flutter的Widget層級中嵌入原生視圖(iOS/Android等),PlatformView在用來描述iOS平臺是視圖用的是UIKitView,Android平臺的視圖是AndoirdView,本文所有描述都是針對iOS平臺,按官方的描述該功能還是在發(fā)布預(yù)覽階段,并且是非常昂貴的操作;以下是官方API文檔原文注釋:EmbeddingUlViewsisstillinreleasepreview,toenablethepreviewforaniOSappaddabooleanfieldwiththekey'io.flutter.embedded_views_preview'andthevaluesetto'YES'totheapplication'sInfo.plistfile.AlistofopenissuedwithembeddingUlViewsisavailableonGithub.EmbeddingiOSviewsisanexpensiveoperationandshouldbeavoidedwhenaFlutterequivalentispossible.場景每個技術(shù)點(diǎn)的出現(xiàn)必然有它的價值所在,所以即便PlatfromView目前存在一些問題,并且Flutter本身就是一個UI框架,一些業(yè)務(wù)場景下只能依賴于它完成,例如:地圖、原生廣告、WebView等等;所以Flutter開發(fā)者還是得點(diǎn)亮PlatformView技能樹;問題在Flutterl.12版本中遇到過在PageView、ListView等容器視圖中將PlatformView移動到屏幕外,并且Widget沒銷毀的場景會引起引擎崩潰,由于問題出在Flutter引擎內(nèi)部,遇到問題的時候可以做這三件事:.FlutterGitHub倉庫提issue,等待官方解決;.定制引擎,編譯Flutter引擎找到問題并解決;.曲線規(guī)避問題發(fā)生場景;當(dāng)然在業(yè)務(wù)迭代中通常優(yōu)先選擇第三點(diǎn)曲線規(guī)避當(dāng)前問題,然后給官方提issue,定制引擎這個選項最好在有足夠把握的時候選擇,不嚴(yán)謹(jǐn)?shù)母膭涌赡軙鹨幌盗袉栴};使用流程需求:創(chuàng)建一個可以將黃色的UlView顯示到窗口的插件;1.創(chuàng)建Flutter插件創(chuàng)建插件可以通過命令行生成插件模板工程,工程名只能用小寫:fluttercreate -iobjc-ajavaplatfoirM_yiew這里創(chuàng)建的是iOS端使用OC語言Android端使用Java語言的插件,創(chuàng)建成功后可以看到這樣的目錄結(jié)構(gòu):platfonn.viewlibraryroot,*/project/pl?tform-.view二.dartjoolhi.idea ―^?Andoird源碼之a(chǎn)ndroid[platform.view.android]example-示例工程毓los “iOS源碼fe'iib TDart源碼BQtest.gltlgnoreil.metadatail.packages二CHANGELOG.mdLICENSE0platform.view.lmlpubspec.lockvmlpubspec.yaml二README.md.封裝UIKitView在lib目錄下創(chuàng)建color_view.dart存放UIKitView的一些操作,F(xiàn)lutter可以利用平臺通道Methodchannel與原生平臺進(jìn)行數(shù)據(jù)交互,方法調(diào)用在發(fā)送之前被編碼為二進(jìn)制,接收到的二進(jìn)制結(jié)果被解碼為Dart值。import'packageiflutter/^atenal.dart1 'package.flatter/services.dart1;constStringsingleColor=,,sii^gleColorJ,;classColorViewextendsStatefulVJidget{^override_ColorVie\A/StatectreateState()=>jCoIorV/ewSt?te();)class_ColorVicostateextendsState<Co(orVie\A/>{///平臺通道,消息使用平臺通道在客戶端(UQ和宿主(平臺)之間傳遞
^overrideWidgetbui(d(BuHdCoiatextcontext){returnUiKitView(//視圖類型,作為唯一標(biāo)識符vie\A/Type:sMgleColoc//創(chuàng)建參數(shù):將會傳遞給iOS端側(cè),可以傳遞任意類型參數(shù)creationParakv\s:"yellow1^//用于將"左打。八作s編碼后再發(fā)送到平臺端。//這里使用Flutter標(biāo)準(zhǔn)二進(jìn)制編碼creatioi^Pairai^sCodec:StandardMe$sageCodec()j//原生視圖創(chuàng)建回調(diào)oiaPlatfor^v\Vie\A/Cseated:_onPlatforkvxViewCreatedj);)///原生視圖創(chuàng)建回調(diào)操作///id是原生視圖唯一標(biāo)識符void^oiaPlatformVie^Created(intid){//每個id對應(yīng)創(chuàng)建唯一的平臺通道_ckaniael=MethodCha八八elCsingleColoH,');//設(shè)置平臺通道的響應(yīng)函數(shù)_chank\el.setMetkodCallHaiadler(_haiadleMethod);}///平臺通道的響應(yīng)函數(shù)Future<void>_ham.dlel^ethod(b4ethodCallcall)async{///視圖沒被裝載的情況不響應(yīng)操作if(iMounted){returnFuture.valueO;}switch(call.Method){default:throwUinsuppoirted.Eriror("U^recog^.izedmethod.");})).添加iOS平臺代碼使用Xcode編輯iOS平臺代碼之前,首先確保代碼至少被構(gòu)建過一次,即從IDE/編輯器執(zhí)行示例程序,或在終端中執(zhí)行以下命令:cdplatforkv\_yiew/exakv\ple;flutterbuildio$--debug-no-codesign打開PlatforM_view/example/ios/R.um.in.er.xcworkspaceiOS工程,插件的iOS平臺代碼位于項目導(dǎo)航中的這個位置:Pods/Deve.lopw\ev\tPods/platforM_view/../../exakv\ple/ios/.syiwlinks/plugiias/platfoirkv\_view/io$/ClassesPlatformViewPlugin此文件創(chuàng)建插件工程時生成的,在程序啟動的時候會將AppDeleage注冊進(jìn)來,這里的AppDeleage繼承自FlutterAppDelegate遵守了FlutterPluginRegistry,FlutterAppLifeCycleProvider協(xié)議,前者為了提供應(yīng)用程序上下文和注冊回調(diào)的方法,后者為了方便后續(xù)在插件中獲取應(yīng)用生命周期事件;^import"Platfroi^Vie^Factory.h11///注冊插件///@「久曰3registrar提供應(yīng)用程序上下文和注冊回調(diào)的方法+(void)FegisteYWithRegistrair:(NSObject〈FLtteirPliAgi八RegistYair〉*)iregistFaK{//注冊視圖工廠//綁定工廠唯一標(biāo)識符這里與FlutterU/KrtView所使用viewTgpe一致[registrarregisterViewFactory:[[Platfroi^ViewFactoiryalloc]inrtrWitkMessenger:[registermessengeU]
witkld:@"sing(eColoir”];@e八dPlatfromViewFactory#ikv\port<Fouyxdatio^/Fou^datio^..h>#import<Flb(tter/Flutter.k>NS_ASSUME_NONNULL_BEGINinterfacePlatfromViewFactory:NSObject<FlutterPlatforkv\Vie\A/Factory>///初始化視圖工廠///^parakvxkvxessager用于與Flutter傳輸二進(jìn)制消息通信-(ins亡。八cetgpeyVu'tWitkMesse八ger:(NS。句ect〈F山tterBi八〃rgMesse八ger〉*)Messager;@endNS_ASSUME_NONNULL_END#iMport"PlatfromViewFactory.kn#import"Platfori^Vie^.k"
^interfacePlatfromVie\A/Factory0///用于與Flutter傳輸二進(jìn)制消息通信@*opertg(八。八尤。2七strong)NSObjcct<FlutterBinairyMes$ei^ger>*nAesse八ger;@end-(i^tairLcetype)i^.itVJithMe^e^ger.(NSObject<FlutterBi^aryMe^e^ger>*)Mess〃ger{self=[superinit];if(se份(se/f.messenger=messages}returnself;#p/agMaw\ark-FlutterPlatfon^\/ie\A/Factory///創(chuàng)建一個"FlutierPlatfor^Viewn///由iOS代碼實現(xiàn),該代碼公開了一個用于嵌入Fitter應(yīng)用程序的“UMew。///這個方法的實現(xiàn)應(yīng)該創(chuàng)建一個新的"U/View”并返回它。///@/必出frai^eFlutter通過其布局widget來計算得來/// viewld視圖的唯一標(biāo)識符,創(chuàng)建一個UIKitView該值會+1/// args對應(yīng)Flutter端UIKitView的creatioiaPara^s參數(shù)-(nonnullNSObject<FlutteirPlatfori^Vie\A/>^)create\AJithFrai^e:(CGRect)frai^eviewdentifieir:(ict64_t)viewlcl〃邯(kv\e八ts:(/_Nullable}arg^(Platforkv\Vie\A/ tforknView=[[P/atForwiViewalloc]in/tVJitkWitkFrakv\e:frai^eviewldectifienviewldargui^eiats:args。,八"rgMesse八gerse/f.kvtesse八ger*];returnplatfoirmView;///使用Flutter標(biāo)準(zhǔn)二進(jìn)制編碼-(NSObject<F(utterMessageCodec>*)createA/Codec{return[FlutterStandardMessageCodecskated伉stance];@e八dFlutter端UIKitView的viewType與工廠ID相同才能建立關(guān)聯(lián),工廠的核心方法createWithFrame,這里三個參數(shù)都是由Flutter端傳遞過來的,UIKitView的大小是由父Widget決定的,frame也就是Flutter通過其布局widget來計算得來,viewld是創(chuàng)建一個UIKitView該值會+1,并且是唯一的,args對應(yīng)Flutter端UIKitView的creationParams參數(shù):PlatformViewPlatformView繼承自FlutterPlatformView協(xié)議,工廠調(diào)用PlatformView對象來創(chuàng)建真正的view實例:"import<Foundation/Foundation.h>#import<Fluttetr/Flutter.h>NS_ASSUME_NONNULL_BEGIN^interfacePlatformView:NSObject<FlutterPlatforkv\View>-(iiostaMetype)initWitk\A/itlaFrame:(CClRect)frame-Wew/de八力E'er:。認(rèn)亡£4_t)Wew以arguten_Nullable)arg5'八〃ryMesse八ger:(NSO旬ect<F/utteKBiMrgMesse嶺eK〉*)kv\esse八ger;@e八dNS_ASSUME_NONNULL_END^import"Platfor^Viev^.k"@icterfacePlatfor^Vie\A/()///視圖^property(八。八atoFvuZ,strong)UMew*yef/owV/ew;///平臺通道@propertg(八。八atoMic,strong)FlutterMetkodChanMl*c〃a八八e/;@e八d^ikvxplei^entationPlatforkv\Vie\A/-(in$taMetype)initWitk\A/itkFrai^e:(CG^ct)frai^evie\A/ldeiatifier:(int64_t)vie\A/ldargui^e^ts:(id^Nullable)args匕心aryMessenger:(NS。句ectxF/utterBi八〃rgMessen_ger〉*)MAesse八ger{if([superinit]){///初始化視圖self.gellowView=[[UMewalloc]init];seif.yello\A/Vie\A/.backgroundcolor=UlColor.yellowColor;///這里的c九m八e/N〃Fwe是和F/utter創(chuàng)建MethodChMnel時的名字保持一致的,保證一個原生視圖有一個平臺通道傳遞消息NSStnng八八=[NSStnng$triiag\A/ithForkv\at:@,,siiagleColor_%lld,,JWew/dJ;se/F.ck〃n八e/=[FlutterMetkodChaiaMlkv\ethodChanMl\A/ithNai^e:ckanMlNakv\e囪認(rèn)argMessehgeckwessengerj;//處理Flutter發(fā)送的消息事件[self.chai^MlsetMetkodCallHai^dler:^(FlutterMethodCall*c〃",F(xiàn)lutterResultresult){if([call.i^etkodi^EqualToStnng:^'"1]){}}l}returnself;}^pragmai^ark-FlutterPlatfori^View///返回真正的視圖-(UM'ew")Wew{returnself.gellowView;}@e八d.使用在example工程中的lib/main.dart中使用封裝好的ColorView:import1package:flutter/Katerial.dart1vv^port,package:p(atfori^_yie\^/color_yie\A/.dart,;voidkvuu'nf)=>runApp(MyAppO);classM9AppextendsStatefulVJidget{^override_MyAppStatecreateStateO=>_MyAppState();}class_MyAppStateextendsState<MyApp>{^overrideWidgetbuild(BuildCo^textcontext){returnMateH?【App(koi^e:Scaffold(appBar:AppBa《),body:Center(//由于原生視圖的大小由父Widget決定,//這里添加CovxtaiMr作為父Widget并設(shè)置寬高為1OOchild:Com.taiMr(width:lOO.Ojheight:1.00.0,child:ColorX/iewOj),),),);.開啟嵌入原生視圖功能由于嵌入UlViews仍在版本預(yù)覽中,默認(rèn)此功能是關(guān)閉的,需要在認(rèn)年同度進(jìn)行配置,開啟嵌入原生視圖:<key>io.f(utter.ei^bedded_yie\A/s_previe\A/</key><tnxe/>.運(yùn)行結(jié)果
寬高各100的黃色UlView就顯示出來了,這里只是舉了個最簡單的場景,可以根據(jù)業(yè)務(wù)需求定制和原生平臺的交互。.■II中國移動令下午.■II中國移動令下午6:30PlatformViewPlugin源碼解析1.原生視圖功能開關(guān)剛剛我們運(yùn)行應(yīng)用前在info.plist配置了開啟原生視圖預(yù)覽,可以看到源碼中獲取了開啟狀態(tài),在沒開啟的時候返回nullptr,嵌入式視圖要求GPU和平臺視圖的線程相同,即主線程;不開啟則是由GPU線程繪制畫布上的UI;//ThelaakvxeoftheInfo.plistflagtoenabletheembeddediOSHewspreWew.constconstkEi^beddedVie\A/sPreview-"io.Rutter.embedded_yiews_pireview";boolIslosEi^beddedViewPrevie^EMbledO{returvx[[[NSBtmd/e nBu八d(e]objectForlnfoPictionaryKey:^(kEi^beddedVie\A/sPrevie\A/)]boolValue];JExtemalViewEi^beddeK^lOSSurfaceSoftware^GetExtemalVie^Ei^bedderO{if(lslosE^v\beddedVie\A/sPre\/ie\A/EnabledO){returnthis;}else{returnnullptr;}}if(flutter::lslo^E^bedded\/ie\A/^Previe\A/EMb(ed(y){//EmbeddedHewsrequiresthegpuandtheplatformviewstobethe//Thep/n八istoeveiatuallydynamicallyv^erge,thethreadswhenthere'sa//platformviewMthelayertree.//Fornowweuseafixedthreadconfigurationwiththes〃kv\ethreadusedasthe//gpuandplatformtaskrunner.
//TODO(ai^irh/ckinkv\aygarde):removethis,av\d.dynamicallychangetkethreadconfiguration.//kttps://github.cokv\/ftutter/flutter/issues/2.5q75flutter::TaskRui^Mrstask_ru^Mrs(threadLabe(.UTF8String,//labelf^l::MessageLoop::GetCuirre^tO.GetTaskRuiaMrOJ//platformW/::Mess〃geLoop::GetC〃rrentO.GerraskR〃KuaerO,//gpu_threadHost.ui_thread->6ietTa$kR.uk\MrOJ//ui^threadHo$t.io_tkiread->GetTaskRunMirO//io);//Createtheshe/LThisisablockingoperation._$hell=flutter::Shell::Create($td::kv\ove(task_runMirs)J//taskrunnersstd::MOve(setti八gs), //settingsoia_create_platfori^_yie\A/J//platformHewcreationo^_create_rasterizer//rasterziero^_create_rasterizer//rasterziercreation);}else{flutter::TaskRuianerstask_ruv\Mrs(threadL-abe(.UTF8String,//labelFhA/::Mess〃geLoop::CetC,”Ciat0.aetTaskRtm"rO'//platform_threadHost.gpu_thread->GetTa^kR.u^.MrOJ//gpu_threadHo$t.ui_thiread->^ietTaskR.uk\MrOJ//ui_threadHost.io_thread->GetTaskRunneirO//io);//Createtheshell.Thisisablockingoperation._^hell-也tter::S〃e"::Cwate(std::hA0\/e(t〃skj(x2\ers)_,//taskrunnersstd::w\ove(settiv^g^)j//settingson_create_platfon^_vie\A/j//platformviewcreationon__creatcjrastenzer //r^sterz/ercreation);)
2.創(chuàng)建流程接著來看看UIKitView創(chuàng)建后是怎么到iOS端側(cè)的:619619620621622623624625626627628629630631632633634635636637?點(diǎn)進(jìn)UIKitView源碼可以看到時一個StafulWidget,接著看看它的State里面實現(xiàn);Future<^oitf>_createNewUiKitView()asy乎《intid=platformViBwsRegist&JgetNextPlatfonnViewId();]finalUiKitViewControllercontroller=awaitPlatformViewsService.initUiKitid:id,viewType:widget.viewType,layoutDirection:-layoutDirectionJcreationParams:widget?creationParams,creationParamsCodec:widget.creationParamsCodec,);if(!mounted){controller.dispose();return;}if(widget.onPlatformViewCreated!=null){widget.onPlatformViewCreated(id);}setState((){controller=controller;});} 知乎二頭兄弟拉才}getNextPlatformViewId實際上的操作是內(nèi)部記錄了viewld的值,每次調(diào)用后+lji'ntgetNextPlatforMViewld()=>_nextP/atfor>w\/iewM++;后面的UiKitViewController看起來就是核心控制層了;
staticFuture<UiKitViewController>initUiKitView({?requiredintid,@requiredStringviewType,?requiredTextDirectionlayoutDirection,dynamiccreationParams,MessageCodec<dynamic>creationParamsCodec,})async{assert(id!=null);assert(viewType!=null);assert(layoutDirection!=null);assert(creationParams=null11creationParamsCodec!=null);//TODO(arnirh):passlayoutDirectiononcethesystemchannelsupportsit.finalMap<String,dynamioargs=<String,dynamic>{'id':id,'viewType':viewType,};if(creationParams!=null){finalByteDfataparamsByteData=creationParamsCodec.encodeMessage(creationPaiargs['params']=Uint8List.view(paramsByteData.buffer,0,paramsByteData.lengthlnBytes,);|awaitSystemChannel.s.platform_views.invokeMethod<void>v71rratc jreturnUiKitViewController._(id,layoutDirection);?可以看到Flutter封裝了內(nèi)部使用的platform_views平臺通道,發(fā)送了create事件;Flutter的framwork層,在原生視圖的事件響應(yīng)中調(diào)用了OnCreate方法;8B》.product*〉■Source)*thMter)■?hH>£?plattorm).darwin)。E)的h?m?wofk';■Sourc*).AuttarRatforw^wmiwvt'?No"ecBn30///僚生視圖事件哨應(yīng)voidFlutterPlatformViewsController::OnMethodCall(FlutterMethodCall*call,FlutterRe$ult&rif([[callmethod]isEqualToString:9Mcreate"]){33 //創(chuàng)建原生視圖? OnCreate(callf result);)elseif([[callmethod]i$EqualToString:pMdispose"])(36 //銷我原生視圖OnDispose(call,result);}elseif([[callmethod]isEqualToString:9MacceptGesture"]){39 //接收手勢??c OnAcceptGesture(callt result);}elseif([[callmethod]isEqualToString:GNrejectGesture*]){42 //拒絕手勢?3 OnRejectGesture(call, result);u}else(result(FlutterMethodNotImplemented); ,「門-(7 1li-小a-'二必} 汕亍「9兀二兄—47)?最后我們來看下OnCreate方法,代碼中截取了部分主要流程:voidFlutterPlatforkv\\/ie\A/sContiroller::OnCreate(FlutterMetkodCalliecall,FlutterRe$ult&result){NSDictio八a叫〈NSStH八g*,id〉*args=[callarguments];//獲取viewidlongviewld=[arg^[^"id"]longValue];//獲取viewTgpestd:stringWewT^pe([args[@"v7ewT]ype"JUTF8String]);//通過viewTgpe獲取視圖工廠NSObjec僅Fbtte/PlatfoYMViewFactoty〉*factory=factorie$_[^iewType].get();idpatrails=nil;//解碼參數(shù)if([factoryrespond$ToSelector:@selector(cireateAirgsCodec)]){NSObjec僅FlutteirMessageCodec〉*codec=[factorycreateArgsCodecJ)if(codec/=nil&&a呼!=nil){FlutterStaiadardTypedData^para^sData=a呼params=[codecdecode:param$Data.data];}}//通過視圖工廠創(chuàng)建嵌入
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 小程序隱私協(xié)議范文7篇
- 中醫(yī)生理學(xué)測試題及答案
- 2025年正德職業(yè)技術(shù)學(xué)院高職單招語文2018-2024歷年參考題庫頻考點(diǎn)含答案解析
- 專題02 代詞(第02期) 帶解析
- 能源供應(yīng)的應(yīng)急預(yù)案
- 幼兒重陽節(jié)教育活動策劃方案五篇
- ios培訓(xùn)師聘用合同
- 工業(yè)研發(fā)設(shè)計軟件在各行業(yè)的應(yīng)用現(xiàn)狀與前景
- 小轎車車輛租賃合同年
- 藥店營業(yè)員聘用合同
- 城市基礎(chǔ)設(shè)施修繕工程的重點(diǎn)與應(yīng)對措施
- GB 12710-2024焦化安全規(guī)范
- 【牛客網(wǎng)】2024秋季校園招聘白皮書
- 2024-2025銀行對公業(yè)務(wù)場景金融創(chuàng)新報告
- 2025屆鄭州市高三一診考試英語試卷含解析
- 腫瘤中醫(yī)治療及調(diào)養(yǎng)
- 2022年公務(wù)員多省聯(lián)考《申論》真題(遼寧A卷)及答案解析
- 北師大版四年級下冊數(shù)學(xué)第一單元測試卷帶答案
- 術(shù)后肺炎預(yù)防和控制專家共識解讀課件
- 中石化高級職稱英語考試
- 小學(xué)五年級英語閱讀理解(帶答案)
評論
0/150
提交評論