Flutter入门系列-FlutterBoost 3.0混合开发

一、环境搭建

1. 首先确定下环境,如果环境不对,很可能出现问题,FlutterBoost 3.0用的Flutter SDK大于2.0

zfz:flutter_module zhangfengzhou$ flutter doctor -v
[✓] Flutter (Channel unknown, 2.0.5, on macOS 12.0.1 21A559 darwin-x64, locale zh-Hans-CN)
    • Flutter version 2.0.5 at /Users/zhangfengzhou/Develop/Flutter/flutter
    • Framework revision adc687823a (8 months ago), 2021-04-16 09:40:20 -0700
    • Engine revision b09f014e96
    • Dart version 2.12.3
    • Pub download mirror https://pub.flutter-io.cn
    • Flutter download mirror https://storage.flutter-io.cn

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at /Users/zhangfengzhou/Library/Android/sdk
    • Platform android-30, build-tools 30.0.2
    • ANDROID_HOME = /Users/zhangfengzhou/Library/Android/sdk
    • Java binary at: /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java
    • Java version Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 13.1, Build version 13A1030d
    • CocoaPods version 1.11.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[!] Android Studio (version 2020.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    ✗ Unable to find bundled Java version.
    • Try updating or re-installing Android Studio.

[✓] IntelliJ IDEA Ultimate Edition (version 2019.3.1)
    • IntelliJ at /Applications/IntelliJ IDEA.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.55.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.22.0

[✓] Connected device (2 available)
    • Android SDK built for x86 (mobile) • emulator-5554 • android-x86    • Android 10 (API 29) (emulator)
    • Chrome (web)                       • chrome        • web-javascript • Google Chrome 96.0.4664.93

! Doctor found issues in 1 category.

 2. 在FlutterBoostDemo 目录下创建名为 flutter_module 的 Flutter Module,命令如下:

zfz:flutter_module zhangfengzhou$ flutter create -t module flutter_module

Flutter 的Module 项目是没有 android 和 ios 目录的,这点要注意。 

3. 在FlutterBoostDemo 目录下创建名为 Android_demo 的 Android项目,最终的FlutterBoostDemo 目录结构如下:

4. 在flutter_module 项目的pubspec.yaml 中引入 flutter_boost :

environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  #闲鱼 flutter_boost
  flutter_boost:
    git:
      url: 'https://github.com/alibaba/flutter_boost.git'
      #ref: '1.17.1'
      ref: 'v3.0-preview.8'

5. 更新下依赖,看是否能够将 flutter_boost 下载下来,如果成功,则执行下一步

6.  创建Dart部分代码:

void main() {
  //添加全局生命周期监听类
  PageVisibilityBinding.instance.addGlobalObserver(AppLifecycleObserver());
  
  //CustomFlutterBinding 调用务必不可缺少,用于控制Boost状态的resume和pause
  CustomFlutterBinding();
  runApp(MyApp());
}
class AppLifecycleObserver extends GlobalPageVisibilityObserver{

  @override
  void onPagePush(Route<dynamic> route) {

  }

  @override
  void onBackground(Route<dynamic> route) {

  }

  @override
  void onForeground(Route<dynamic> route) {

  }

  @override
  void onPagePop(Route<dynamic> route) {

  }

  @override
  void onPageHide(Route<dynamic> route) {

  }

  @override
  void onPageShow(Route<dynamic> route) {

  }
}
//创建一个自定义的Binding, 继承和 With的关系如下,里面什么都不用写
class CustomFlutterBinding extends WidgetsFlutterBinding with BoostFlutterBinding {

}

7. Fluttter mainApp

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

  @override
  _MyAppPageState createState() => _MyAppPageState();
}

class _MyAppPageState extends State<MyApp> {

  @override
  Widget build(BuildContext context) {
    return FlutterBoostApp( //必修以此为根Widget
      routeFactory,
      appBuilder: appBuilder,
    );
  }
}
  Widget appBuilder(Widget home) {
    return MaterialApp(
      home: home,
      debugShowCheckedModeBanner: true,
      //必须加上builder参数,否则showDialog等会出现问题
      builder: (_,__){
        return home;
      },
    );
  }
//routeFactory 用于构建路由  
Route<dynamic> routeFactory(RouteSettings settings, String uniqueId){
    FlutterBoostRouteFactory func = routerMap[settings.name];
    if (func == null){
      return null;
    }
    return func(settings, uniqueId);
}


//RouterMap key是String, value是函数的实现 最后通过key获取函数的实现
//然后再调用这个函数,就可以获取到这个函数的返回值了 返回值就是具体的Route页面
  static Map<String, FlutterBoostRouteFactory> routerMap = {
    'mainPage': (settings, uniqueid){ //函数的实现
      return MaterialPageRoute (
          settings: settings,
          builder: (_){
            Map<String, Object> map = settings.arguments;
            String data = map['data'];
            return SimplePage(data: data,);
          });
    },
    'simplePage': (settings, uniqueid){ //函数的实现
      Map<String, Object> map = settings.arguments ?? {};
      String data = map['data'];
      print("从原生过来的数据:$data");
      return MaterialPageRoute (
          settings: settings,
          builder: (_){
            return SimplePage(data: data,);//简单页面
          });
    },
    'otherPage':(settings, uniqueId){
      return MaterialPageRoute(
          settings: settings,
          builder: (_){
            return OtherPage(); //其他Flutter页面
          });
    },
    'dialogPage': (settings, uniqueId){
       return PageRouteBuilder<dynamic> (
           opaque: false, //不开启新容器的flutter内部弹窗(推荐)
           barrierColor: Colors.black45,
           settings: settings,
           pageBuilder: (_,__,___)=>AlertDialog(title: Text('哈哈'),));
    },
    'popPage': (settings, uniqueId){
      return PageRouteBuilder<dynamic> (
          opaque: false, //不开启新容器的flutter内部弹窗(推荐)
          barrierColor: Colors.black45,
          settings: settings,
          pageBuilder: (_,__,___){
            return PopPage();
          });
    },
    'revalPage': (settings, uniqueId){
      return PageRouteBuilder<dynamic> (
          opaque: false, //不开启新容器的flutter内部弹窗(推荐)
          barrierColor: Colors.black45,
          settings: settings,
          pageBuilder: (_,__,___){
            return RevalPage();
          });
    }
  };

以上就是主页面的路由的注册和配置过程,后面就可以根据路由的名称进行Native页面跳转Flutter页面, Flutter页面 跳转 Flutter页面 操作。

8. Android Native 部分

前面已经初步完成Flutter 部分的代码,接下来实现Native与Flutter之间互相跳转。在前面的创建好的Android_demo 项目中首先引入 flutter_module 这个项目,具体在 settings.gradle 文件中添加如下代码:

include ':app'
rootProject.name = "Android_demo"
setBinding(new Binding([gradle: this]))
evaluate(new File(
        '../flutter_module/.android/include_flutter.groovy'
))
include ':flutter_module'
project(':flutter_module').projectDir = new File('../flutter_module')

注意:这里的引入的路径和名称按照自己的具体情况来确定。

9.  在 app 目录下的 gradle 文件中添加如下代码,然后点击同步按钮,可以看到引入的Flutter项目

//FlutterBoost 依赖
implementation project(":flutter")
implementation project(":flutter_boost")

10. 在清单文件中添加如下代码和初始化Application

<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" 
      >
</activity>
<meta-data android:name="flutterEmbedding"
    android:value="2">
</meta-data>
public class App extends Application {

    private static final String TAG = "App";

    @Override
    public void onCreate() {
        super.onCreate();
        //经过实验得出如下结论: pushNativeRoute 不是通过StartActivity过来的,而是从Flutter页面过来的
        //在Activity中通过 FlutterBoost.instance().open(options); 打开的页面是Flutter页面,不是原生界面
        FlutterBoost.instance().setup(this, new FlutterBoostDelegate() {
            @Override
            public void pushNativeRoute(FlutterBoostRouteOptions options) {
                Log.e(TAG, "pushNativeRoute "+options.pageName());
                //从 Flutter 打开Native 页面,具体打开哪个页面 是根据 options.pageName 来决定的
                //这里根据options.pageName来判断你想跳转哪个页面,这里简单给一个
                Intent intent = new Intent(FlutterBoost.instance().currentActivity(), SimpleNativeActivity.class);
                FlutterBoost.instance().currentActivity().startActivityForResult(intent, options.requestCode());
            }

            @Override
            public void pushFlutterRoute(FlutterBoostRouteOptions options) {
                System.out.println("pushFlutterRoute "+options.pageName());
                //打开Flutter 页面时调用到此处 1.Native 打开 Flutter 2. Flutter 打开 Flutter
                Intent intent = new FlutterBoostActivity.CachedEngineIntentBuilder(FlutterBoostActivity.class)
                        .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.transparent)
                        .destroyEngineWithActivity(false)
                        .uniqueId(options.uniqueId())
                        .url(options.pageName())
                        .urlParams(options.arguments())
                        .build(FlutterBoost.instance().currentActivity());
                FlutterBoost.instance().currentActivity().startActivity(intent);
            }
        }, engine -> {});
    }
}

如此以上,就基本上完成了Flutter混合开发的基本配置工作,后面需要进行的是Natvie与Flutter之间的互相跳转yiji。

11. Flutter 跳转 Flutter 

1. 普通带参数跳转

BoostNavigator.instance.push('otherPage', //页面在路由表中的名字
                  withContainer: false, //是否伴随原生容器弹出
                  arguments: {"name": "wangwu"}, //携带到下一页面的参数
                  opaque: true //页面是否透明
                  );

我们可以在路由配置代码那块获取传递的参数

 'otherPage':(settings, uniqueId){
      Map<String, Object> map = settings.arguments ?? {};
      String name = map['name'];
      print("从Flutter页面带过来的数据是 $name");
      return MaterialPageRoute(
          settings: settings,
          builder: (_){
            return OtherPage(); //其他Flutter页面
          });
    },

2. Flutter 跳转 Flutter 页面,然后带参数返回上一页

//如果要接收返回参数 注意在方法签名处加上 async 进行标记
final result = await BoostNavigator.instance.push("popPage");
print("返回的数据是 $result");
//返回到上一页并且返回数据【任意类型】,如果新开的页面是带容器的,则返回数据是Map类型的 
BoostNavigator.instance.pop("data from popPage");

3. Flutter 跳转 Native 页面

//如果要接收返回参数
BoostNavigator.instance.push("nativeSimplePage").then((value) {
  //从Native 返回 Flutter 时返回的数据
  print('retval data is $value');
});
//在前面的Application中的初始化Engine和plugin处,我们进行可以在 pushNativeRoute 方法中通过options.pageName 获取
//路由名称,然后根据路由名称来选择要跳转哪个Activity, 下面给出一个简单的例子
@Override
public void pushNativeRoute(FlutterBoostRouteOptions options) {
    Log.e(TAG, "pushNativeRoute "+options.pageName());
    //从 Flutter 打开Native 页面,具体打开哪个页面 是根据 options.pageName 来决定的
    //这里根据options.pageName来判断你想跳转哪个页面,这里简单给一个
    Intent intent = new Intent(FlutterBoost.instance().currentActivity(), SimpleNativeActivity.class);
    FlutterBoost.instance().currentActivity().startActivityForResult(intent, options.requestCode());
}
public class SimpleNativeActivity extends AppCompatActivity {

    private static final String TAG = "SimpleNativeActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple);
    }

    @Override
    public void finish() {
        Log.e(TAG, "finish: ");
        Intent intent = new Intent();
        intent.putExtra("msg","This message is from Native!!!");
        //intent.putExtra("bool", true);
        //intent.putExtra("int", 666);
        setResult(Activity.RESULT_OK, intent);  // 返回结果给dart
        super.finish();
    }
}

在intent设置好在该Activity结束的时候回传给Flutter页面的数据,我们就可以在 then 方法中获取传递过来的数据。

12. Native 跳转 Flutter 

1.  Native 正常跳转 Flutter 页面,不需要从 Flutter 回传数据

//第一种情况 统一打开打Flutter 页面方法  开Flutter页面 pageName就是路由名称
val options:FlutterBoostRouteOptions = FlutterBoostRouteOptions.Builder()
    .pageName("simplePage")
    .arguments(mapOf(Pair("data","我是来自Native的数据")))
    .build();
FlutterBoost.instance().open(options)

 simplePage 是在Flutter注册的路由名称

'simplePage': (settings, uniqueid){ //函数的实现
    Map<String, Object> map = settings.arguments ?? {};
    String data = map['data'];
    print("从原生过来的数据:$data");
    return MaterialPageRoute (
        settings: settings,
        builder: (_){
          return SimplePage(data: data,);//简单页面
        });
  },

2. Native 跳转 Flutter,并从Flutter 返回数据给Native 

//第二种情况,打开Flutter 页面,然后等待 Flutter 页面返回数据
val map = mapOf("name" to "Jack")
val intent = FlutterBoostActivity.CachedEngineIntentBuilder(FlutterBoostActivity::class.java)
    .backgroundMode(io.flutter.embedding.android.FlutterActivityLaunchConfigs.BackgroundMode.opaque)
    .destroyEngineWithActivity(false)
    .url("revalPage")
    .urlParams(map)
    .build(this)
startActivityForResult(intent, 1001)


override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 1001){
         //E/MainActivity: onActivityResult: I am from dart
         //onActivityResult: {reval=I am from dart}
         val msg = data?.getSerializableExtra(ACTIVITY_RESULT_KEY) as Map<*, *>  // 将数据转换成 Map 然后再取出来
         Log.e(TAG, "onActivityResult: ${msg.get("reval")}")
         Log.e(TAG, "onActivityResult: ${data.getSerializableExtra(ACTIVITY_RESULT_KEY)}")
    }
}

revalPage 是在Flutter 中注册的路由名称

'revalPage': (settings, uniqueId){
    Map<String, Object> map = settings.arguments ?? {};
    String name = map['name'];
    print("从Native页面带过来的数据是 $name"); //I/flutter: 从Native页面带过来的数据是 Jack
    return PageRouteBuilder<dynamic> (
        opaque: false, //不开启新容器的flutter内部弹窗(推荐)
        barrierColor: Colors.black45,
        settings: settings,
        pageBuilder: (_,__,___){
          return RevalPage();
        });
  }
InkWell(
  onTap: (){
    BoostNavigator.instance.pop({'reval': "I am from dart"}); //返回给Native的数据
  },
  child: Text('点击返回到native页面'), 
),

二、总结

FlutterBoost 是可以进行混合开发的框架,可以在原有的原生项目上接入Flutter项目的代码,使得原生与Flutter页面可以互相切换,提高了代码的复用性,后面还会针对Flutter Boost的其他特性进行研究,比如Flutter Boost的生命周期API,Flutter Boost消息发布与订阅,拦截器,PlatformView 等等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值