阅读 1299

老板喜欢的,Flutter实现多平台开发

一.Flutter简介

跨平台

Flutter的目标是使同一套代码同时运行在Android和iOS系统上,并且拥有媲美原生应用的性能。

flutter所支持的平台:

  1. 移动端
  2. 网页
  3. Windows、Linux和macOS

高性能

技术类型渲染方式性能开发效率动态代表框架
H5+原生封装原生(相机,联系人,设备等)+webview支持ionic,cordova
js+原生渲染原生的控件渲染支持weex,react native
原生+自绘引擎Skia 2D渲染引擎flutter

学习资源

  1. flutter中文网:flutterchina.club/
  2. flutter插件:pub.flutter-io.cn/
  3. flutter控件介绍:toly1994328.gitee.io/flutter_web…
  4. dart语言:www.dartcn.com/
  5. 开源项目:github

二.Flutter原理

框架结构

Flutter Framework

这是一个纯 Dart实现的 SDK,它实现了一套基础库,自底向上,我们来简单介绍一下:

  • 底下两层(Foundation和Animation、Painting、Gestures)是dart UI层,对应的是Flutter中的dart:ui包,它是Flutter引擎暴露的底层UI库,提供动画、手势及绘制能力。
  • Rendering层,这一层是一个抽象的布局层,它依赖于dart UI层,Rendering层会构建一个UI树,当UI树有变化时,会计算出有变化的部分,然后更新UI树,最终将UI树绘制到屏幕上。Rendering层可以说是Flutter UI框架最核心的部分,它除了确定每个UI元素的位置、大小之外还要进行坐标变换、绘制(调用底层dart:ui)。
  • Widgets层是Flutter提供的的一套基础组件库,在基础组件库之上,Flutter还提供了 Material 和Cupertino两种视觉风格的组件库。而我们Flutter开发的大多数场景,只是和这两层打交道

Flutter engine

这是一个纯 C++实现的 SDK,其中包括了 Skia引擎、Dart运行时、文字排版引擎等。在代码调用 dart:ui库时,调用最终会走到Engine层,然后实现真正的绘制逻辑。

如何绘制

  1. RenderObject:渲染树中所有节点的基类,定义了布局、绘制和合成相关的接口

  2. RendererBinding:是渲染树和Flutter引擎的胶水层,负责管理帧重绘、窗口尺寸和渲染相关参数变化的监听。

  3. 控件树中的每个控件通过实现RenderObjectWidget#createRenderObject(BuildContext context) → RenderObject方法来创建对应的不同类型的RenderObject对象,组成渲染对象树

三.混合开发

github地址:

github.com/alibaba/flu…

介绍:阿里出品

新一代Flutter-Native混合解决方案。 FlutterBoost是一个Flutter插件,它可以轻松地为现有原生应用程序提供Flutter混合集成方案。FlutterBoost的理念是将Flutter像Webview那样来使用。在现有应用程序中同时管理Native页面和Flutter页面并非易事。 FlutterBoost帮你处理页面的映射和跳转,你只需关心页面的名字和参数即可(通常可以是URL)

如何混合开发

1.新建flutterModule
2.pubspec.yaml添加插件
dependencies:
  flutter:
    sdk: flutter
  flutter_boost:
      git:
        url: 'https://github.com/alibaba/flutter_boost.git'
        ref: '1.17.1'
复制代码
3.原生添加依赖

build.gradle

implementation project(':flutter')
implementation project(':flutter_boost')
复制代码

settings.gradle

setBinding(new Binding([gradle: this]))
evaluate(new File(
        settingsDir,
        'flutter_module\\.android\\include_flutter.groovy'
))


include ':flutter_module'

复制代码
4.application初始化
private fun initFlutter() {
        val router =
            INativeRouter { context, url, urlParams, requestCode, exts ->
                val assembleUrl =
                    Utils.assembleUrl(url, urlParams)
                PageRouter.openPageByUrl(context, assembleUrl, urlParams)
            }

        val boostLifecycleListener: BoostLifecycleListener = object : BoostLifecycleListener {
            override fun beforeCreateEngine() {}
            override fun onEngineCreated() {

                // 注册MethodChannel,监听flutter侧的getPlatformVersion调用
                val methodChannel = MethodChannel(
                    FlutterBoost.instance().engineProvider().dartExecutor,
                    "flutter_native_channel"
                )
                methodChannel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
                    when (call.method) {
                        "getPlatformVersion" -> {
                            result.success(Build.VERSION.RELEASE)
                        }
                        "getPlatformChannel" -> {
                            result.success(BuildConfig.FLAVOR)
                        }
                        "getToken" -> {
                            result.success(SPUtils.getInstance().getString(Constants.Access_Token))
                        }
                        else -> {
                            result.notImplemented()
                        }
                    }
                }

                // 注册PlatformView viewTypeId要和flutter中的viewType对应
//                FlutterBoost
//                    .instance()
//                    .engineProvider()
//                    .platformViewsController
//                    .registry
//                    .registerViewFactory(
//                        "plugins.test/view",
//                        TextPlatformViewFactory(StandardMessageCodec.INSTANCE)
//                    )
            }

            override fun onPluginsRegistered() {}
            override fun onEngineDestroy() {}
        }


        //
        // AndroidManifest.xml 中必须要添加 flutterEmbedding 版本设置
        //
        //   <meta-data android:name="flutterEmbedding"
        //               android:value="2">
        //    </meta-data>
        // GeneratedPluginRegistrant 会自动生成 新的插件方式 
        //
        // 插件注册方式请使用
        // FlutterBoost.instance().engineProvider().getPlugins().add(new FlutterPlugin());
        // GeneratedPluginRegistrant.registerWith(),是在engine 创建后马上执行,放射形式调用
        //
        val platform = FlutterBoost.ConfigBuilder(this, router)
            .isDebug(true)
            .whenEngineStart(FlutterBoost.ConfigBuilder.ANY_ACTIVITY_CREATED)
            .renderMode(FlutterView.RenderMode.texture)
            .lifecycleListener(boostLifecycleListener)
            .build()
        FlutterBoost.instance().init(platform)
    }
复制代码
<meta-data android:name="flutterEmbedding"
    android:value="2">
</meta-data>

<activity
	android:name="com.idlefish.flutterboost.containers.BoostFlutterActivity"
                			     android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
            android:hardwareAccelerated="true"
            android:theme="@style/Theme.AppCompat"
            android:windowSoftInputMode="adjustResize"/>
复制代码
5.配置路由
class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();

    FlutterBoost.singleton.registerPageBuilders(<String, PageBuilder>{


      ///可以在native层通过 getContainerParams 来传递参数
      'flutterPage': (String pageName, Map<String, dynamic> params, String _) {
        print('flutterPage params:$params');

        return FlutterRouteWidget(params: params);
      },
    });
    FlutterBoost.singleton.addBoostNavigatorObserver(TestBoostNavigatorObserver());
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Boost example',
        builder: FlutterBoost.init(postPush: _onRoutePushed),
        home: Container(color: Colors.white));
  }

  void _onRoutePushed(
    String pageName,
    String uniqueId,
    Map<String, dynamic> params,
    Route<dynamic> route,
    Future<dynamic> _,
  ) {}
}
复制代码

native配置路由

public class PageRouter {

    public final static Map<String, String> pageName = new HashMap<String, String>() {{
        put("sample://flutterPage", "flutterPage");
    }};

    public static final String NATIVE_PAGE_URL = "sample://nativePage";
    public static final String FLUTTER_PAGE_URL = "sample://flutterPage";

    public static boolean openPageByUrl(Context context, String url, Map params) {
        return openPageByUrl(context, url, params, 0);
    }

    public static boolean openPageByUrl(Context context, String url, Map params, int requestCode) {

        String path = url.split("\\?")[0];

        Log.i("openPageByUrl",path);

        try {
            if (pageName.containsKey(path)) {
                Intent intent = BoostFlutterActivity.withNewEngine().url(pageName.get(path)).params(params)
                        .backgroundMode(BoostFlutterActivity.BackgroundMode.opaque).build(context);
                if(context instanceof Activity){
                    Activity activity=(Activity)context;
                    activity.startActivityForResult(intent,requestCode);
                }else{
                    context.startActivity(intent);
                }
                return true;
            }else if (url.startsWith(NATIVE_PAGE_URL)) {
                String aNative = (String) params.get("native");
                Timber.e("回传:"+aNative);
                NavigationUtils.INSTANCE.goWorkStateActivity();
                return true;
            }
            return false;

        } catch (Throwable t) {
            return false;
        }
    }
}
复制代码
6.路由跳转
  //原生
  val params= mutableMapOf<String,String>()
                params["test1"] = "v_test1"
                params["test2"] = "v_test2"
  //Add some params if needed.
  PageRouter.openPageByUrl(this, PageRouter.FLUTTER_PAGE_URL, params)
复制代码
onTap: () => FlutterBoost.singleton.open(
                  'sample://nativePage',
//                  urlParams: <String, dynamic>{
//                    'query': <String, dynamic>{'native': 'bbb'}
//                  },
                  urlParams: {"native": "我是参数乙"},
                ),
复制代码

四.Web开发

1.flutter SDK配置

sdk文件夹中找到flutter_console.bat

flutter channel
flutter channel beta
flutter upgrade
flutter config --enable-web
flutter devices
复制代码

2.安装web编译工具

flutter pub global activate webdev
复制代码

配置环境变量:path中添加 D:\flutter\fluttersssssss.pub-cache\bin

3.发布

如果你想查看release版本,可以运行

flutter build web
复制代码

会在项目的D:\flutter\flutter_web_app\build\web 生成打包文件

五.Windows开发

1.flutter SDK配置

sdk文件夹中找到flutter_console.bat

flutter channel
flutter channel master
flutter upgrade
flutter config --enable-windows-desktop
复制代码

2.如果你的电脑没有在开发者模式,使用插件会出错。 你可以在设置-->更新和安全-->开发者选项里设置

Building with plugins requires symlink support. Please enable Developer Mode in your system settings
复制代码

3.安装VisualStudio

选择c++开发版

Exception: Unable to find suitable Visual Studio toolchain. Please run flutter doctor for more details.

flutter doctor 查看错误

4.打包exe

flutter build windows
复制代码

会在该目录下生成exe D:\flutter\flutter_windows\build\windows\runner\Release

Advanced Installer 这个工具可以构建windows安装程序

桌面开发插件地址:github.com/google/flut…

我的demo地址:gitee.com/hhyq520/flu…

六.移动端mvvm+provider搭建环境

尽请期待。。。下期更精彩

七.总结

1.除了移动端,其他平台不成熟

2.依靠原生

3.潜力大

4.需要插件

5.一套代码多个平台

6.背靠谷歌爸爸

文章分类
阅读
文章标签