一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - IOS - Flutter Boost 混合開發(fā)框架

Flutter Boost 混合開發(fā)框架

2021-12-27 15:40xiangzhihong IOS

Flutter是一個(gè)由C++實(shí)現(xiàn)的Flutter Engine和由Dart實(shí)現(xiàn)的Framework組成的跨平臺(tái)技術(shù)框架,本文將在此做一個(gè)初步的講解

一、flutter boost簡(jiǎn)介

眾所周知,flutter是一個(gè)由c++實(shí)現(xiàn)的flutter engine和由dart實(shí)現(xiàn)的framework組成的跨平臺(tái)技術(shù)框架。其中,flutter engine負(fù)責(zé)線程管理、dart vm狀態(tài)管理以及dart代碼加載等工作,而dart代碼所實(shí)現(xiàn)的framework則負(fù)責(zé)上層業(yè)務(wù)開發(fā),如flutter提供的組件等概念就是framework的范疇。

隨著flutter的發(fā)展,國(guó)內(nèi)越來(lái)越多的app開始接入flutter。為了降低風(fēng)險(xiǎn),大部分app采用漸進(jìn)式方式引入flutter,在app里選幾個(gè)頁(yè)面用flutter來(lái)編寫,但都碰到了相同的問(wèn)題,在原生頁(yè)面和flutter頁(yè)面共存的情況下,如何管理路由,以及原生頁(yè)面與flutter頁(yè)面之間的切換和通信都是混合開發(fā)中需要解決的問(wèn)題。然而,官方?jīng)]有提供明確的解決方案,只是在混合開發(fā)時(shí),官方建議開發(fā)者,應(yīng)該使用同一個(gè)引擎支持多窗口繪制的能力,至少在邏輯上做到flutterviewcontroller是共享同一個(gè)引擎里面的資源。換句話說(shuō),官方希望所有的繪制窗口共享同一個(gè)主isolate,而不是出現(xiàn)多個(gè)主isolate的情況。不過(guò),對(duì)于現(xiàn)在已經(jīng)出現(xiàn)的多引擎模式問(wèn)題,flutter官方也沒(méi)有提供好的解決方案。除了內(nèi)存消耗嚴(yán)重外,多引擎模式還會(huì)帶來(lái)如下一些問(wèn)題

  • 冗余資源問(wèn)題。多引擎模式下每個(gè)引擎的isolate是相互獨(dú)立的,雖然在邏輯上這并沒(méi)有什么壞處,但是每個(gè)引擎底層都維護(hù)了一套圖片緩存等比較消耗內(nèi)存的對(duì)象,因此設(shè)備的內(nèi)存消耗是非常嚴(yán)重的。
  • 插件注冊(cè)問(wèn)題。在flutter插件中,消息傳遞需要依賴messenger,而messenger是由flutterviewcontroller去實(shí)現(xiàn)的。如果一個(gè)應(yīng)用中同時(shí)存在多個(gè)flutterviewcontroller,那么插件的注冊(cè)和通信將會(huì)變得混亂且難以維護(hù)。
  • flutter組件和原生頁(yè)面的差異化問(wèn)題。通常,flutter頁(yè)面是由組件構(gòu)成的,原生頁(yè)面則是由viewcontroller或者activity構(gòu)成的。邏輯上來(lái)說(shuō),我們希望消除flutter頁(yè)面與原生頁(yè)面的差異,否則在進(jìn)行頁(yè)面埋點(diǎn)和其它一些操作時(shí)增加一些額外的工作量。
  • 增加頁(yè)面通信的復(fù)雜度。如果所有的dart代碼都運(yùn)行在同一個(gè)引擎實(shí)例中,那么它們會(huì)共享同一個(gè)isolate,可以用統(tǒng)一的框架完成組件之間的通信,但是如果存在多個(gè)引擎實(shí)例會(huì)讓isolate的管理變得更加復(fù)雜。

如果不解決多引擎問(wèn)題,那么混合項(xiàng)目的導(dǎo)航棧如下圖所示。

Flutter Boost 混合開發(fā)框架

目前,對(duì)于原生工程混編flutter工程出現(xiàn)的多引擎模式問(wèn)題,國(guó)內(nèi)主要有兩種解決方案,一種是字節(jié)跳動(dòng)的修改flutter engine源碼方案,另一種是閑魚開源的flutterboost。由于字節(jié)跳動(dòng)的混合開發(fā)的方案沒(méi)有開源,所以現(xiàn)在能使用的就剩下flutterboost方案。

flutterboost是閑魚技術(shù)團(tuán)隊(duì)開發(fā)的一個(gè)可復(fù)用頁(yè)面的插件,旨在把flutter容器做成類似于瀏覽器的加載方案。為此,閑魚技術(shù)團(tuán)隊(duì)為希望flutterboost能完成如下的基本功能:

  • 可復(fù)用的通用型混合開發(fā)方案。
  • 支持更加復(fù)雜的混合模式,比如支持tab切換的場(chǎng)景。
  • 無(wú)侵入性方案,使用時(shí)不再依賴修改flutter的方案。
  • 支持對(duì)頁(yè)面生命周期進(jìn)行統(tǒng)一的管理。
  • 具有統(tǒng)一明確的設(shè)計(jì)概念。

并且,最近flutter boost升級(jí)了3.0版本,并帶來(lái)了如下的一些更新:

  • 不侵入引擎,兼容flutter的各種版本,flutter sdk的升級(jí)不需要再升級(jí)flutterboost,極大降低升級(jí)成本。
  • 不區(qū)分androidx和support分支。
  • 簡(jiǎn)化架構(gòu)和接口,和flutterboost2.0比,代碼減少了一半。
  • 雙端統(tǒng)一,包括接口和設(shè)計(jì)上的統(tǒng)一。
  • 支持打開flutter頁(yè)面,不再打開容器場(chǎng)景。
  • 頁(yè)面生命周期變化通知更方便業(yè)務(wù)使用。
  • 解決了2.0中的遺留問(wèn)題,例如,fragment接入困難、頁(yè)面關(guān)閉后不能傳遞數(shù)據(jù)、dispose不執(zhí)行,內(nèi)存占用過(guò)高等。

二、flutter boost集成

在原生項(xiàng)目中集成flutter boost只需要將flutter boost看成是一個(gè)插件工程即可。和其他flutter插件的集成方式一樣,使用flutterboost之前需要先添加依賴。使用android studio打開混合工程的flutter工程,在pubspec.yaml中添加flutterboost依賴插件,如下所示。

?
1
2
3
4
flutter_boost:
    git:
        url: 'https://github.com/alibaba/flutter_boost.git'
        ref: 'v3.0-hotfixes'

需要說(shuō)明的是,此處的所依賴的flutterboost的版本與flutter的版本是對(duì)應(yīng)的,如果不對(duì)應(yīng)使用過(guò)程中會(huì)出現(xiàn)版本不匹配的錯(cuò)誤。然后,使用flutter packages get命令將flutterboost插件拉取到本地。

2.1 android集成

使用android studio打開新建的原生android工程,在原生android工程的settings.gradle文件中添加如下代碼。

?
1
2
3
4
setbinding(new binding([gradle: this]))
evaluate(new file(
  settingsdir.parentfile,
  'flutter_library/.android/include_flutter.groovy'))

然后,打開原生android工程app目錄下的build.gradle文件,繼續(xù)添加如下依賴腳本。

?
1
2
3
4
dependencies {
  implementation project(':flutter_boost')
  implementation project(':flutter')
}

重新編譯構(gòu)建原生android工程,如果沒(méi)有任何錯(cuò)誤則說(shuō)明android成功了集成flutterboost。使用flutter boost 之前,需要先執(zhí)行初始化。打開原生android工程,新建一個(gè)繼承flutterapplication的application,然后在oncreate()方法中初始化flutterboost,代碼如下。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class myapplication extends flutterapplication {
 
 
    @override
    public void oncreate() {
        super.oncreate();
 
        flutterboost.instance().setup(this, new flutterboostdelegate() {
 
            @override
            public void pushnativeroute(string pagename, hashmap<string, string> arguments) {
                intent intent = new intent(flutterboost.instance().currentactivity(), nativepageactivity.class);
                flutterboost.instance().currentactivity().startactivity(intent);
            }
 
            @override
            public void pushflutterroute(string pagename, hashmap<string, string> arguments) {
                intent intent = new flutterboostactivity.cachedengineintentbuilder(flutterboostactivity.class, flutterboost.engine_id)
                        .backgroundmode(flutteractivitylaunchconfigs.backgroundmode.opaque)
                        .destroyenginewithactivity(false)
                        .url(pagename)
                        .urlparams(arguments)
                        .build(flutterboost.instance().currentactivity());
                flutterboost.instance().currentactivity().startactivity(intent);
            }
 
        },engine->{
            engine.getplugins();
        } );
    }
}

然后,打開原生android工程下的androidmanifest.xml文件,將application替換成自定義的myapplication,如下所示。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          package="com.idlefish.flutterboost.example">
 
    <application
        android:name="com.idlefish.flutterboost.example.myapplication"
        android:label="flutter_boost_example"
        android:icon="@mipmap/ic_launcher">
 
        <activity
            android:name="com.idlefish.flutterboost.containers.flutterboostactivity"
            android:theme="@style/theme.appcompat"
            android:configchanges="orientation|keyboardhidden|keyboard|screensize|locale|layoutdirection|fontscale|screenlayout|density"
            android:hardwareaccelerated="true"
            android:windowsoftinputmode="adjustresize" >
            <meta-data android:name="io.flutter.embedding.android.splashscreendrawable" android:resource="@drawable/launch_background"/>
 
        </activity>
        <meta-data android:name="flutterembedding"
                   android:value="2">
        </meta-data>
    </application>
</manifest>

由于flutter boost 是以插件的方式集成到原生android項(xiàng)目的,所以我們可以在native 打開和關(guān)閉flutter模塊的頁(yè)面。

?
1
2
flutterboost.instance().open("flutterpage",params);
flutterboost.instance().close("uniqueid");

而flutter dart的使用如下。首先,我們可以在main.dart文件的程序入口main()方法中進(jìn)行初始化。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void main() {
  runapp(myapp());
}
class myapp extends statefulwidget {
  @override
  _myappstate createstate() => _myappstate();
}
class _myappstate extends state<myapp> {
   static map<string, flutterboostroutefactory>
       routermap = {
    '/': (settings, uniqueid) {
      return pageroutebuilder<dynamic>(
          settings: settings, pagebuilder: (_, __, ___)
          => container());
    },
    'embedded': (settings, uniqueid) {
      return pageroutebuilder<dynamic>(
          settings: settings,
          pagebuilder: (_, __, ___) =>
          embeddedfirstroutewidget());
    },
    'presentflutterpage': (settings, uniqueid) {
      return pageroutebuilder<dynamic>(
          settings: settings,
          pagebuilder: (_, __, ___) =>
          flutterroutewidget(
                params: settings.arguments,
                uniqueid: uniqueid,
              ));
    }};
   route<dynamic> routefactory(routesettings settings, string uniqueid) {
    flutterboostroutefactory func =routermap[settings.name];
    if (func == null) {
      return null;
    }
    return func(settings, uniqueid);
  }
 
  @override
  void initstate() {
    super.initstate();
  }
 
  @override
  widget build(buildcontext context) {
    return flutterboostapp(
      routefactory
    );
  }

當(dāng)然,還可以監(jiān)聽頁(yè)面的生命周期,如下所示。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
class simplewidget extends statefulwidget {
  final map params;
  final string messages;
  final string uniqueid;
 
  const simplewidget(this.uniqueid, this.params, this.messages);
 
  @override
  _simplewidgetstate createstate() => _simplewidgetstate();
}
 
class _simplewidgetstate extends state<simplewidget>
    with pagevisibilityobserver {
  static const string _ktag = 'xlog';
  @override
  void didchangedependencies() {
    super.didchangedependencies();
    print('$_ktag#didchangedependencies, ${widget.uniqueid}, $this');
 
  }
 
  @override
  void initstate() {
    super.initstate();
   pagevisibilitybinding.instance.addobserver(this, modalroute.of(context));
   print('$_ktag#initstate, ${widget.uniqueid}, $this');
  }
 
  @override
  void dispose() {
    pagevisibilitybinding.instance.removeobserver(this);
    print('$_ktag#dispose, ${widget.uniqueid}, $this');
    super.dispose();
  }
 
  @override
  void onforeground() {
    print('$_ktag#onforeground, ${widget.uniqueid}, $this');
  }
 
  @override
  void onbackground() {
    print('$_ktag#onbackground, ${widget.uniqueid}, $this');
  }
 
  @override
  void onappear(changereason reason) {
    print('$_ktag#onappear, ${widget.uniqueid}, $reason, $this');
  }
 
  void ondisappear(changereason reason) {
    print('$_ktag#ondisappear, ${widget.uniqueid}, $reason, $this');
  }
 
  @override
  widget build(buildcontext context) {
    return scaffold(
      appbar: appbar(
        title: text('tab_example'),
      ),
      body: singlechildscrollview(
          physics: bouncingscrollphysics(),
          child: container(
              child: column(
            crossaxisalignment: crossaxisalignment.start,
            children: <widget>[
              container(
                margin: const edgeinsets.only(top: 80.0),
                child: text(
                  widget.messages,
                  style: textstyle(fontsize: 28.0, color: colors.blue),
                ),
                alignment: alignmentdirectional.center,
              ),
              container(
                margin: const edgeinsets.only(top: 32.0),
                child: text(
                  widget.uniqueid,
                  style: textstyle(fontsize: 22.0, color: colors.red),
                ),
                alignment: alignmentdirectional.center,
              ),
              inkwell(
                child: container(
                    padding: const edgeinsets.all(8.0),
                    margin: const edgeinsets.all(30.0),
                    color: colors.yellow,
                    child: text(
                      'open flutter page',
                      style: textstyle(fontsize: 22.0, color: colors.black),
                    )),
                ontap: () => boostnavigator.of().push("flutterpage",
                    arguments: <string, string>{'from': widget.uniqueid}),
              )
              container(
                height: 300,
                width: 200,
                child: text(
                  '',
                  style: textstyle(fontsize: 22.0, color: colors.black),
                ),
              )
            ],
          ))),
    );
  }
}

然后,運(yùn)行項(xiàng)目,就可以從原生頁(yè)面跳轉(zhuǎn)到flutter頁(yè)面,如下圖所示效果。

Flutter Boost 混合開發(fā)框架

2.2 ios集成

和android的集成步驟一樣,使用xcode打開原生ios工程,然后在ios的appdelegate文件中初始化flutter boost ,如下所示。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@interface appdelegate ()
 
@end
 
@implementation appdelegate
 
- (bool)application:(uiapplication *)application didfinishlaunchingwithoptions:(nsdictionary *)launchoptions
{
  myflutterboostdelegate* delegate=[[myflutterboostdelegate alloc ] init];
    [[flutterboost instance] setup:application delegate:delegate callback:^(flutterengine *engine) {
    } ];
 
    return yes;
}
@end

下面是自定義的flutterboostdelegate的代碼,如下所示。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@interface myflutterboostdelegate : nsobject<flutterboostdelegate>
@property (nonatomic,strong) uinavigationcontroller *navigationcontroller;
@end
 
@implementation myflutterboostdelegate
 
- (void) pushnativeroute:(fbcommonparams*) params{
    bool animated = [params.arguments[@"animated"] boolvalue];
    bool present= [params.arguments[@"present"] boolvalue];
    uiviewcontrollerdemo *nvc = [[uiviewcontrollerdemo alloc] initwithnibname:@"uiviewcontrollerdemo" bundle:[nsbundle mainbundle]];
    if(present){
        [self.navigationcontroller presentviewcontroller:nvc animated:animated completion:^{
        }];
    }else{
        [self.navigationcontroller pushviewcontroller:nvc animated:animated];
    }
}
 
- (void) pushflutterroute:(fbcommonparams*)params {
 
    flutterengine* engine =  [[flutterboost instance ] getengine];
    engine.viewcontroller = nil;
 
    fbflutterviewcontainer *vc = fbflutterviewcontainer.new ;
 
    [vc setname:params.pagename params:params.arguments];
 
    bool animated = [params.arguments[@"animated"] boolvalue];
    bool present= [params.arguments[@"present"] boolvalue];
    if(present){
        [self.navigationcontroller presentviewcontroller:vc animated:animated completion:^{
        }];
    }else{
        [self.navigationcontroller pushviewcontroller:vc animated:animated];
 
    }
}
 
- (void) poproute:(fbcommonparams*)params
         result:(nsdictionary *)result{
 
    fbflutterviewcontainer *vc = (id)self.navigationcontroller.presentedviewcontroller;
 
    if([vc iskindofclass:fbflutterviewcontainer.class] && [vc.uniqueidstring isequal: params.uniqueid]){
        [vc dismissviewcontrolleranimated:yes completion:^{}];
    }else{
        [self.navigationcontroller popviewcontrolleranimated:yes];
    }
 
}
 
@end

如果要在原生ios代碼中打開或關(guān)閉flutter頁(yè)面,可以使用下面的方式。

?
1
2
[[flutterboost instance] open:@"flutterpage" arguments:@{@"animated":@(yes)}  ];
[[flutterboost instance] open:@"secondstateful" arguments:@{@"present":@(yes)}];

三、flutter boost架構(gòu)

對(duì)于混合工程來(lái)說(shuō),原生端和flutter端對(duì)于頁(yè)面的定義是不一樣的。對(duì)于原生端而言,頁(yè)面通常指的是一個(gè)viewcontroller或者activity,而對(duì)于flutter來(lái)說(shuō),頁(yè)面通常指的是flutter組件。flutterboost框架所要做的就是統(tǒng)一混合工程中頁(yè)面的概念,或者說(shuō)弱化flutter組件對(duì)應(yīng)容器頁(yè)面的概念。換句話說(shuō),當(dāng)有一個(gè)原生頁(yè)面存在的時(shí)候,flutteboost就能保證一定有一個(gè)對(duì)應(yīng)的flutter的容器頁(yè)面存在。

flutterboost框架其實(shí)就是由原生容器通過(guò)消息驅(qū)動(dòng)flutter頁(yè)面容器,從而達(dá)到原生容器與flutter容器同步的目的,而flutter渲染的內(nèi)容是由原生容器去驅(qū)動(dòng)的,下面是flutter boost 給的一個(gè)flutter boost 的架構(gòu)示意圖。

Flutter Boost 混合開發(fā)框架

可以看到,flutter boost插件分為平臺(tái)和dart兩端,中間通過(guò)message channel連接。平臺(tái)側(cè)提供了flutter引擎的配置和管理、native容器的創(chuàng)建/銷毀、頁(yè)面可見性變化通知,以及flutter頁(yè)面的打開/關(guān)閉接口等。而dart側(cè)除了提供類似原生navigator的頁(yè)面導(dǎo)航接口的能力外,還負(fù)責(zé)flutter頁(yè)面的路由管理。

總的來(lái)說(shuō),正是基于共享同一個(gè)引擎的方案,使得flutterboost框架有效的解決了多引擎的問(wèn)題。簡(jiǎn)單來(lái)說(shuō),flutterboost在dart端引入了容器的概念,當(dāng)存在多個(gè)flutter頁(yè)面時(shí),flutterboost不需要再用棧的結(jié)構(gòu)去維護(hù)現(xiàn)有頁(yè)面,而是使用扁平化鍵值對(duì)映射的形式去維護(hù)當(dāng)前所有的頁(yè)面,并且每個(gè)頁(yè)面擁有一個(gè)唯一的id

四、flutterboost3.0更新

4.1 不入侵引擎

為了解決官方引擎復(fù)用引起的問(wèn)題,flutterboost2.0拷貝了flutter引擎embedding層的一些代碼進(jìn)行改造,這使得后期的升級(jí)成本極高。而flutterboost3.0采用繼承的方式擴(kuò)展flutteractivity/flutterfragment等組件的能力,并且通過(guò)在適當(dāng)時(shí)機(jī)給dart側(cè)發(fā)送appisresumed消息解決引擎復(fù)用時(shí)生命周期事件錯(cuò)亂導(dǎo)致的頁(yè)面卡死問(wèn)題,并且,flutterboost 3.0 也兼容最新的官方發(fā)布的 flutter 2.0。

4.2 不區(qū)分androidx和support分支

flutterboost2.0通過(guò)自己實(shí)現(xiàn)flutteractivityandfragmentdelegate.host接口來(lái)擴(kuò)展flutteractivity和flutterfragment的能力,而getlifecycle是必須實(shí)現(xiàn)的接口,這就導(dǎo)致對(duì)androidx的依賴。這也是為什么flutterboostview的實(shí)現(xiàn)沒(méi)有被放入flutterboost3.0插件中的原因。而flutterboost3.0通過(guò)繼承的方式擴(kuò)展flutteractivity/flutterfragment的能力的額外收益就是,可以做到不依賴androidx。

4.3 雙端設(shè)計(jì)統(tǒng)一,接口統(tǒng)一

很多flutter開發(fā)者只會(huì)一端,只會(huì)android 或者只會(huì)ios,但他需要接入雙端,所以雙端統(tǒng)一能降低他的 學(xué)習(xí)成本和接入成本。flutterboost3.0,在設(shè)計(jì)上 android和ios都做了對(duì)齊,特別接口上做到了參數(shù)級(jí)的對(duì)齊。

4.4 支持 【打開flutter頁(yè)面不再打開容器】 場(chǎng)景

在flutter模塊內(nèi)部,flutter 頁(yè)面跳轉(zhuǎn)flutter 頁(yè)面是可以不需要再打開flutter容器的,不打開容器,能節(jié)省內(nèi)存開銷。在flutterboost3.0上,打開容器和不打開容器的區(qū)別表現(xiàn)在用戶接口上僅僅是withcontainer參數(shù)是否為true就好。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
inkwell(
  child: container(
      color: colors.yellow,
      child: text(
        '打開外部路由',
        style: textstyle(fontsize: 22.0, color: colors.black),
      )),
  ontap: () => boostnavigator.of().push("flutterpage",
      arguments: <string, string>{'from': widget.uniqueid}),
),
inkwell(
  child: container(
      color: colors.yellow,
      child: text(
        '打開內(nèi)部路由',
        style: textstyle(fontsize: 22.0, color: colors.black),
      )),
  ontap: () => boostnavigator.of().push("flutterpage",
      withcontainer: true,
      arguments: <string, string>{'from': widget.uniqueid}),
)

4.5 生命周期的精準(zhǔn)通知

在flutterboost2.0上,每個(gè)頁(yè)面都會(huì)收到頁(yè)面生命周期通知,而flutterboost3.0只會(huì)通知頁(yè)面可見性實(shí)際發(fā)生了變化的頁(yè)面,接口也更符合flutter的設(shè)計(jì)。

4.6 其他issue

除了上面的一些特性外,flutter boost 3.0版本還解決了如下一些問(wèn)題:

  • 頁(yè)面關(guān)閉后參數(shù)的傳遞,之前只有ios支持,android不支持,目前在dart側(cè)實(shí)現(xiàn),ios 和android 都支持。
  • 解決了android 狀態(tài)欄字體和顏色問(wèn)題。
  • 解決了頁(yè)面回退willpopscope不起作用問(wèn)題。
  • 解決了不在棧頂?shù)捻?yè)面也收到生命周期回調(diào)的問(wèn)題
  • 解決了多次setstate耗性能問(wèn)題。
  • 提供了framgent 多種接入方式的demo,方便tab 場(chǎng)景的接入。
  • 生命周期的回調(diào)代碼,可以用戶代碼里面with的方式接入,使用更簡(jiǎn)單。
  • 全面簡(jiǎn)化了,接入成本,包括 dart側(cè),android側(cè)和ios
  • 豐富了demo,包含了基本場(chǎng)景,方便用戶接入 和測(cè)試回歸

到此這篇關(guān)于flutter boost 混合開發(fā)框架的文章就介紹到這了,更多相關(guān)flutter boost內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!,希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://segmentfault.com/a/1190000039760722

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 卫生间被教官做好爽HH视频 | 亚洲波霸 | 逼逼爱 | 91热这里只有精品 | 欧美激情影音先锋 | 国产精品久久久天天影视香蕉 | 色在线亚洲视频www 色欲麻豆国产福利精品 | 妹妹你插的我好爽 | ts人妖系列在线专区 | 欧美黑人换爱交换乱理伦片 | 国产精品午夜久久 | 日本不卡免免费观看 | 国产在线三级 | 欧美艳星julnaann | 久久精品国产亚洲AV麻豆欧美玲 | 袖珍人与大黑人性视频 | 欧美乱子伦xxxx12在线 | 亚洲精品国产一区二区第一页 | 91久久偷偷做嫩草影院免费看 | 亚洲激情在线 | 日本ccc三级 | 亚洲精品卡1卡二卡3卡四卡 | 亚洲aⅴ天堂 | 动漫jk美女被爆羞羞漫画 | kkkk4444在线看片 | 国产精品成人在线播放 | 好爽视频| 青青草在观免费 | 九九精品国产兔费观看久久 | 蛮荒的童话未删减在线观看 | 亚洲妇熟xxxxx妇色黄 | 精品视频在线观看 | 九九国产在线视频 | 性鸥美| 动漫美女胸被狂揉扒开吃奶动态图 | 视频在线播放 | 91制片厂制作传媒破解版免费 | 好爽轻点太大了太深了 | 99亚洲视频 | 天堂中文在线免费观看 | 天天操网 |