热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Flutter入门——Flutter功能概览

IT之家12月5日消息:今天谷歌官方宣布Flutter的1.0版本正式发布!Flutter是Google打造的UI工具包,帮助你通过一套代码同时在iOS和Android上构建媲美原

IT之家12月5日消息: 今天谷歌官方宣布Flutter 的 1.0 版本正式发布!Flutter是Google打造的UI工具包,帮助你通过一套代码同时在iOS 和Android上构建媲美原生体验的精美应用 —— 2018”

Google 刚公布Kotlin 成为 Android 官方开发语言没多久,Flutter就发布了 1.0 版本。虽然说搞不明白 google 的战略意图,但作为一个IT人员,既然有了新东西,尤其跟自己的工作息息相关,就得去了解一下了。

kotlin 自不必说,其大概功能以及优缺点已经在之前博客中进行了简单的说明:
从Java的角度看kotlin特性(一)
从Java的角度看kotlin特性(二)
其中已经对比了javakotlin部分差异以及功能。

那么Flutter到底是什么?能做些什么?要想弄明白这个,我们可以看一下官方说明:

Flutter is Google’s mobile UI framework for crafting high-quality native interfaces on iOS and Android in record time. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.

ok,一个跨平台的移动端框架,适用于Android 和 IOS 平台,开源,不同平台使用相同代码。

其实这种框架或者说想法从来不曾缺少,事实上,在很久之前就开始了跨平台的研究,各种跨平台理念层出不穷:

  • H5+原生
  • Javascript开发+原生渲染 (React Native、Weex等)

像上面两种方式是使用最多也是最通用的,那么Flutter 一个“初来乍到”的概念,对比之前的方式又有什么新颖之处?

从各种资料来看Flutter 宣扬的 “高明” 之处主要在于:

  1. 热重载
  2. 60FPS

热重载得益于Dart 语言的 AOT 和 JIT 两种运行模式。
60FPS则是由于自身实现了完整的2D图形引擎。

既然说优点这么多,那总得试一下效果才好;
首先我们尝试一下在Android(IOS)端开发过程。

一、 准备工作

按照官方文档,我们将 Flutter 环境安装完成。由于国外网站都被墙了,因此我们可以查看 Flutter 中文网 来完成预备步骤。

如果是Android 开发人员,这里我们直接 查看这里 入门: 在Windows上搭建Flutter开发环境

需要注意的是,Flutter SDK 是存放于 GITHUB 的一个开源项目,因此我们可以直接从GITHUB 上克隆下来。

然后中间教程会有说到需要执行:

flutter doctor

这相当于一个Flutter 的全局检查功能,所有错误或者缺少的东西,都会被检查到。

还有,Flutter 是依赖Dart SDK 的,所幸Flutter 会自动安装 Dart 到自身目录下,一般而言是这样的:

《Flutter入门——Flutter功能概览》

因此我们不需要单独再去下载其他功能包。

目前开发Android 使用的应该都是 AndroidStudio ,我们打开 AS 软件,然后搜索两个 plugin :

  1. flutter
  2. dart

《Flutter入门——Flutter功能概览》

《Flutter入门——Flutter功能概览》

安装后重启AS,就会在启动后看到这样的功能按钮:

《Flutter入门——Flutter功能概览》

当然,如果AS提示有错误,则可能是Flutter SDK路径未自动配置,想这样配置一下 Flutter 和 Dart

《Flutter入门——Flutter功能概览》

《Flutter入门——Flutter功能概览》

如果AS启动后,首页界面没有 Start a new Flutter project这个选项,则可能是有个 plugin 没打开,这是只要把这个插件置于打开状态就好:

《Flutter入门——Flutter功能概览》

二、 创建 Flutter Project

然后我们就可以创建一个flutter 项目了:

点击Start a new Flutter project,可能会有些慢,稍等几十秒,然后系统会弹出需要创建的 flutter 项目类型类型。

《Flutter入门——Flutter功能概览》

1、 创建 flutter application

flutter application 是指创建一个正常的Flutter ,即创建一个适用于Android 及 IOS移动设备的项目,创建过程由 idea 一键完成,并不需要有多复杂的步骤。

《Flutter入门——Flutter功能概览》

上面一次含义为:

  1. Project 项目名称,和一般项目相同
  2. Flutter SDK 目录,这个一般会自动配置
  3. 项目所在目录
  4. 项目介绍

这些和普通创建一个项目是没有区别的,点击 next ,配置项目其他信息:

《Flutter入门——Flutter功能概览》

先需要配置一下包名,包名对于android 和ios 来说,不同应用应该不同。

然后需要根据需求,配置 ios 是否需要加入swift支持,android 是否需要加入 kotlin支持。

然后点击 finish,项目创建成功:

《Flutter入门——Flutter功能概览》

  • androidios 目录下分别对应两个平台各自的代码。
  • lib 目录包含了我们将要编写的业务逻辑代码,这里会自动生成一个入口界面:main.dart
  • test 目录用于单元测试或者组件测试
  • pubspec.yaml 是所有配置所在的地方,其中指明了:项目名,项目描述,项目当前版本号,sdk版本,运行或开发时依赖等内容。

观察AS界面,可以看到如下部分:

《Flutter入门——Flutter功能概览》

在真机已连接,入口类已设定情况下,点击三角箭头,应用就会安装到真机上。然后就可以使用热更新进行快速高效的开发了。

《Flutter入门——Flutter功能概览》

这里我们不仔细讨论Flutter 如何编码,只用一个现有的例子来查看显示效果,主要模仿华容道进行一个关卡设置,可以针对卡片进行上下左右滑动:

代码可以在 github 上下载查看:checkpoint_one.dart

PlusPlugins.dart 代码在另一个类中,这里直接写出来:

///
/// 额外添加的class系列
///
///定义系列的返回特定类型的函数,只有一个参数
typedef RBoolOneP = bool Function(T obj);
typedef RVoidOneP = void Function(T obj);
typedef RIntOneP = int Function(T obj);
typedef BBB = int Function(List obj);
///定义系列的返回特定类型的函数,无参数
typedef RBoolZeroP = bool Function();
typedef RVoidZeroP = void Function();
typedef RIntZeroP = int Function();

这里只用 debug 包进行演示,只要知道 release 比 debug 模式要顺畅就可以了:

《Flutter入门——Flutter功能概览》

可以看到,流畅效果不比 原生的差了。

2 、创建 Flutter Plugin

Flutter Plugin 从名字就可以看出,主要是一个插件,主要作为一个中间件,来连接原生 与 flutter 。

flutter 如果需要调用原生功能,比如照相机等硬件设备时,自身肯定无法完成这种功能,这时就需要使用 plugin 插件,通过相互通信,让原生来调用设备能力。

Flutter Plugin 创建流程和 Application 差不多,创建完成后,代码结构如下所示:

《Flutter入门——Flutter功能概览》

lib下 的文件成为了 插件类,我们可以在其中约定原生与flutter 相互调用的方法,如,我们在 flutter_plugin.dart中添加如下代码:

import 'dart:async';
import 'package:flutter/services.dart';
///编写插件的部分
class FlutterPlugin {
///方法通道标识,用于在 平台间 调用接口,该字符串为多平台统一的
static const MethodChannel _channel = const MethodChannel('flutter_plugin');
///通道可调用的方法/参数: 需要设置为异步(确定不会阻塞主线程)
static Future get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
///获取随机的double值
static Future get randomCode async {
return await _channel.invokeMethod('getRandomCode');
}
}

然后在项目的 android 目录下,编写插件对应的android 实现(kotlin 语言)

《Flutter入门——Flutter功能概览》

然后在 example/lib/main.dart 中,可以测试插件是否编写的正确:

《Flutter入门——Flutter功能概览》

注意,example 是idea 自动帮我们生成的一个内置 project,我们可以看一下example/pubspec.yaml 文件:

《Flutter入门——Flutter功能概览》

即,example 项目引用了我们创建的 plugin ,所以,才可以使用该 project 测试插件的功能。

这里还有一个问题,flutter_plugin 插件如何知道 flutter 与 原生哪个类进行对应的?事实上,在 flutter_plugin/pubspec.yaml中也进行了指定:

《Flutter入门——Flutter功能概览》

红线标识部分说明了该插件对应了 com.knowledge.mnlin.flutter_plugin包下的 FlutterPlugin类,于是项目编译时,在 flutter_plugin/example/android/项目里,GeneratedPluginRegistrant会对指定的插件进行 注册。

《Flutter入门——Flutter功能概览》

说了那么多,来看一下,插件是否可以正常运行;我们指定这个类为入口,然后真机测试:

《Flutter入门——Flutter功能概览》

在这个类中,进行原生调用,然后查看效果(注意,这里放了一个三秒间隔的循环定时获取随机数):

class _MyAppState extends State {
String _platformVersion = 'Unknown';
double _random = 0xFFFFFFFF;
@override
void initState() {
super.initState();
initPlatformState();
//再次加载random
Timer.periodic(Duration(seconds: 3), (it){
initRandom();
});
}
// Platform messages are asynchronous, so we initialize in an async method.
Future initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await FlutterPlugin.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
Future initRandom() async {
_random = await FlutterPlugin.randomCode;
setState(() {
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text('Running on: $_platformVersion\nRandom:$_random'),
),
),
);
}
}

效果如图:

《Flutter入门——Flutter功能概览》

3、Flutter Package

Flutter Package 只是单纯的 flutter 包,我们在其中可以创建一个通用的 widget ,或者当做一个工具包等等,相当于一个弱化版的 Flutter Plugin。

创建过程不必多说,代码结构如图所示:

《Flutter入门——Flutter功能概览》

只需要在 lib目录 中编写公共的widget或者通用的逻辑方法即可。

4、Flutter Module

在继续往下介绍之前,可以先了解一下大致的flutter module 应用场景。

目前现有的应用,基本都已经成型,并且由于flutter 还并未完全成熟,因此如果使用的话,最多也只是替换现有项目部分内容当做一个Flutter模块。

Flutter 模块的创建需要遵循一定的规则,我们需要在项目的同级目录建立一个Flutter Module,然后有两种方式在原生代码中引入 Flutter (以Android 项目为例)

  1. 将Flutter当成一个 View 或者Fragment,并入到现有的Activity类中。
  2. 创建FlutterActivity 的实现类。

两者我更推崇后一个,因为后一个可以避免去处理多余的一些事件,比如返回键逻辑等等。

如果想以View 或者 Fragment 的方式引入 Flutter,可以参考这个博客完成:Android原生项目集成Flutter Module

当然这个博客都需要先看一下,里面包含了针对Android 的 build.gradle 以及 settings.gradle 的修改部分。这个是都需要配置的

如果以FlutterActivity 的形式引入Flutter,首先创建Flutter Module的过程都是一样的(都需要在原生项目同级目录下):

《Flutter入门——Flutter功能概览》

和一般的Flutter项目仅有微小的不同,就是在 pubspec.yaml中,会指明本项目为一个 附属module。

然后依照教程,使用AS在另一个窗口打开原生Android项目,在安卓项目的 settings.gradle中添加如下代码:

setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir.parentFile,
'gft_flutter_module/.android/include_flutter.groovy'
))

在 安卓项目主modulebuild.gradle文件中添加如下依赖:

dependencies {
// ... //flutter - module
implementation project(':flutter')
// ...
}

然后创建一个 FlutterActivity 的子类:

class FlutterContainerActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
}
companion object {
/** * 进入flutter时,可提供默认的路由 */
fun makeIntent(context: Context, routePage: String?): Intent {
var _routePage = routePage
if (_routePage == null || _routePage == "") {
_routePage = "/"
}
val intent = Intent(context, FlutterContainerActivity::class.java)
intent.action = Intent.ACTION_RUN
intent.putExtra("route", _routePage)
return intent
}
}
}

别忘了,该Acitivity 时需要 在 AndroidManifest 注册的 。

然后我们需要进入Flutter 模块功能界面时时,直接调用如下代码即可:

startActivity(FlutterContainerActivity.makeIntent(baseActivity, "/"))

这里展示一下使用Flutter模块效果图,开始是原生界面,然后点击进入的就是FlutterContainerActivity界面,两次进入传了不同的路由,因此显示了不同的Flutter界面:

《Flutter入门——Flutter功能概览》

当然,很多情况下,我们在引入module时,flutter中代码逻辑可能需要调用 原生代码,此时,可以直接修改一下FlutterContainerActivity代码:

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
registerWith(flutterView.pluginRegistry.registrarFor("***.***.***"))
}

注:***代替的字符串部分只要使用唯一标识就行,一般可以用项目包名

在 onCreate 方法中,最后添加了一行插件注入的代码;registerWith方法是静态导入的,源码在插件类中:

/** * Created on 2019/4/26 18:32 * function : 定义的 flutter 和 android 交互监听 * * @author mnlin */
class UsdpBridgePlugin : MethodChannel.MethodCallHandler {
override fun onMethodCall(methodCall: MethodCall, result: MethodChannel.Result) {
println("flutter在调用android端的方法: ${methodCall.arguments} +++ ${methodCall.arguments::class.java}")
when (methodCall.method) {
"getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}")
"changeLocaleLanguage" means "修改语言环境" ->
//...
"changeThemeMode" means "模式切换" ->
//...
else -> result.notImplemented()
}
}
}
/** * 注册插件回调 */
fun registerWith(registrar: PluginRegistry.Registrar) {
MethodChannel(registrar.messenger(), "***").setMethodCallHandler(UsdpBridgePlugin())
}

注:***代替的字符串须要和Flutter中指定Channel的字符串相同,这样才可以互相调用。如果忘了是哪个字符串,可以参考博客前面创建 Flutter Plugin的部分,在Flutter插件类中代码处static const MethodChannel _channel = const MethodChannel('***');传入的字符串。

当然,若还是不清楚原生项目和flutter-module如何交互,可以查看此博客:Flutter知识点: Flutter与原生(Android)的交互

最后一定别忘了,在原生项目的 Application类中 onCreate时,先把Flutter模块初始化了,保证Flutter 与 原生无缝切换界面:

//初始化flutter框架
FlutterMain.startInitialization(this);

以上简单讲述了 Flutter 的使用方式,其实主要关注两个就行:第一,创建flutter跨平台项目;第二,让Flutter可以与原生项目进行合并。

三、 flutter_web——向WEB端前进

既然Flutter已经做到了横跨Android 和 IOS 两大平台,那么能否把Web端包含在内呢?这样不就实现了前端的 统一么?

然而,可惜的是,Flutter 并没有这个功能。

不过解决问题的方式总比困难多一些,官方已经给出了解决方案,或者说是一个 超功能的库:flutter_web

实现Flutter 项目 向 web端的迁移 ,不得不说,这个想法很不错,dart语言的初衷就是为了替代 js ,虽然失败了,但至少有过丰富的失败经验,那么依据dart语言的flutter做这些工作时,至少不会再开头就碰到太多的难题,也不用担心 此种方案的可行性。

flutter_web的README很详细的说明了迁移需要做的工作,然而,实在是 不想看那么多的逻辑。

好在我们都使用的是AS,那我们直接看 AS如何一键操作就好了,何必那么麻烦。

然而,使用AS 发现还是有些问题,根本没办法创建web项目,因此我们改用 Intellij 开发工具。步骤在 readme中已经列出来,像这样:

  1. install the Flutter SDK
  2. set up your copy of IntelliJ or Android Studio
  3. configure IntelliJ or Android Studio to point to your local Flutter SDK
  4. create a new Dart project; note, for a Flutter for web app, you want to start from the Dart project wizard, not the Flutter project wizard
    from the Dart project wizard,
  5. select the ‘Flutter for web’ option for the application template
  6. create the project; pub get will be run automatically
  7. once the project is created, hit the run button on the main toolbar
  8. IntelliJ will use the webdev command-line tool to build and run your app; a new Chrome window should open, showing your running app

SDK在前面步骤已经下载过了,那么接下来我们就完成剩下步骤:

首先,打开intellij 的settings 配置,添加 Dart 和 Flutter 插件,没有插件,我们是没办法创建项目的。

然后按照如下图创建一个 flutter – web 项目:

《Flutter入门——Flutter功能概览》

接下来选择创建项目的类型一定不能出错:

《Flutter入门——Flutter功能概览》

指定一下项目名:

《Flutter入门——Flutter功能概览》

点击 finish 创建完成。

等待idea把需要的依赖下载完成后,点击配置一下浏览器(URL地址不要主动去更改了):

《Flutter入门——Flutter功能概览》

《Flutter入门——Flutter功能概览》

配置后点击三角启动图标,如果启动不起来,不要着急,把idea重启一下就可以了。

启动后网页会自动打开,然后显示出默认的界面:

《Flutter入门——Flutter功能概览》

现在回头我们再看一下flutter – web 的目录结构:

《Flutter入门——Flutter功能概览》

lib目录中存放的是移动端flutter代码。

web目录下包含两个文件,index.html是网页入口,web/main.dart可以理解为从 flutter 到 web 的一个过渡桥梁,代码很简单,就是在网页初始化完成后,启动真正显示的布局信息。

main() async {
await ui.webOnlyInitializePlatform();
app.main();
}

当然,从 flutter 的代码是不能直接迁移到 flutter-web 的,需要更改一小部分内容,具体逻辑在github的readme文档中已经进行了说明:

If you’d like to migrate existing Flutter code to run on the web preview, read the migration guide.

flutter-web的更新也类似于hot-reload,在项目中修改代码后,直接刷新一次网页就可以显示出最新效果。

调试开发完成后,我们还需要进行部署,这个时候,就需要主动调用命令了,我们在启动服务时,可以很清楚的看到这样的内容:

《Flutter入门——Flutter功能概览》

这里指明了 webdev 包所在的位置,在打正事环境包时,先关闭调试的服务器,执行以下代码即可:

E:\flutter_sdk\flutter\bin\cache\dart-sdk\bin\pub.bat global run webdev build

切记,webdev 包的路径每个设备可能不同,因此一定要查看清楚再调用命令。

执行完成后,项目目录下多出 了一个 :

《Flutter入门——Flutter功能概览》

这个 build 目录中内容就是我们需要的正事包。切记,这个包直接双击浏览器打开index.html 文件是不行的,必须要放到 http 服务器中,这个官方在 readme中也有说明:

This will create a build directory with index.html, main.dart.js and the rest of the files needed to run the application using a static HTTP server.

我们可以进行简单的测试,看这个正事包能否正常使用,为了简单起见,我们使用 node 搭建一个小型的服务器:

《Flutter入门——Flutter功能概览》

《Flutter入门——Flutter功能概览》

然后,我们把通过命令生成的 build 目录下所有的文件,都拷贝过来,放到 node 项目的 public 目录下:

《Flutter入门——Flutter功能概览》

点击上面的三角形运行标志启动http服务;然后在浏览器中输入地址(node服务器默认启动端口号为3000):

http://localhost:3000/

然后浏览器中就会显示 flutter 指定的界面:

《Flutter入门——Flutter功能概览》

目前 flutter_web大概只有2000多star,毕竟前端人员几乎都在使用vue,也没有 迁移转换使用dart 的必要性。

不过,将来的趋势肯定倾向于前端的大一统,相信随着google的大力推行,会有更多的人接触使用flutter。

参考资料主要来源:Flutter中文网


推荐阅读
  • 本问题探讨了在特定条件下排列儿童队伍的方法数量。题目要求计算满足条件的队伍排列总数,并使用递推算法和大数处理技术来解决这一问题。 ... [详细]
  • 本文作者分享了在阿里巴巴获得实习offer的经历,包括五轮面试的详细内容和经验总结。其中四轮为技术面试,一轮为HR面试,涵盖了大量的Java技术和项目实践经验。 ... [详细]
  • 本文详细解析了Java中hashCode()和equals()方法的实现原理及其在哈希表结构中的应用,探讨了两者之间的关系及其实现时需要注意的问题。 ... [详细]
  • 本文详细探讨了JavaScript中的作用域链和闭包机制,解释了它们的工作原理及其在实际编程中的应用。通过具体的代码示例,帮助读者更好地理解和掌握这些概念。 ... [详细]
  • 丽江客栈选择问题
    本文介绍了一道经典的算法题,题目涉及在丽江河边的n家特色客栈中选择住宿方案。两位游客希望住在色调相同的两家客栈,并在晚上选择一家最低消费不超过p元的咖啡店小聚。我们将详细探讨如何计算满足条件的住宿方案总数。 ... [详细]
  • Python 内存管理机制详解
    本文深入探讨了Python的内存管理机制,涵盖了垃圾回收、引用计数和内存池机制。通过具体示例和专业解释,帮助读者理解Python如何高效地管理和释放内存资源。 ... [详细]
  • Appium + Java 自动化测试中处理页面空白区域点击问题
    在进行移动应用自动化测试时,有时会遇到某些页面没有返回按钮,只能通过点击空白区域返回的情况。本文将探讨如何在Appium + Java环境中有效解决此类问题,并提供详细的解决方案。 ... [详细]
  • Coursera ML 机器学习
    2019独角兽企业重金招聘Python工程师标准线性回归算法计算过程CostFunction梯度下降算法多变量回归![选择特征](https:static.oschina.n ... [详细]
  • Hybrid 应用的后台接口与管理界面优化
    本文探讨了如何通过优化 Hybrid 应用的后台接口和管理界面,提升用户体验。特别是在首次加载 H5 页面时,为了减少用户等待时间和流量消耗,介绍了离线资源包的管理和分发机制。 ... [详细]
  • 反向投影技术主要用于在大型输入图像中定位特定的小型模板图像。通过直方图对比,它能够识别出最匹配的区域或点,从而确定模板图像在输入图像中的位置。 ... [详细]
  • 深入理解Lucene搜索机制
    本文旨在帮助读者全面掌握Lucene搜索的编写步骤、核心API及其应用。通过详细解析Lucene的基本查询和查询解析器的使用方法,结合架构图和代码示例,带领读者深入了解Lucene搜索的工作流程。 ... [详细]
  • 本文介绍如何使用 Android 的 Canvas 和 View 组件创建一个简单的绘图板应用程序,支持触摸绘画和保存图片功能。 ... [详细]
  • 本文将探讨Java编程语言中对象和类的核心概念,帮助读者更好地理解和应用面向对象编程的思想。通过实际例子和代码演示,我们将揭示如何在Java中定义、创建和使用对象。 ... [详细]
  • 本文详细介绍了如何在 Android 开发中高效地管理和使用资源,包括本地资源和系统资源的访问方法。通过实例和代码片段,帮助开发者更好地理解和应用资源管理的最佳实践。 ... [详细]
  • ZooKeeper集群脑裂问题及其解决方案
    本文深入探讨了ZooKeeper集群中可能出现的脑裂问题,分析其成因,并提供了多种有效的解决方案,确保集群在高可用性环境下的稳定运行。 ... [详细]
author-avatar
育霖培伦861
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有