仅分享文字,见谅
Flutter
- Flutter 介绍
- 功能
- 跨平台性
- 架构
- 流行度
- Flutter vs React Native
- 配置 Windows Flutter App 环境
- 配置 Tizen Flutter App 环境
- 用 Dart 语言开发 Flutter App
- Flutter-Tizen 的限制
Flutter 介绍
Flutter 是由 Google 推出的开源移动应用开发框架,可用于快速构建高性能、美观的移动应用程序。它采用 Dart 语言进行开发,具有热重载功能,可以快速查看代码更改后的效果,极大地提高了开发效率
Flutter 的 UI 框架采用了现代化的响应式编程风格,可以轻松地创建漂亮且高度定制化的用户界面。它还提供了丰富的组件库,开发者可以根据自己的需求选择合适的组件来构建应用程序
Flutter 还支持跨平台开发,开发者可以使用同一套代码 base 开发 iOS 和 Android 应用,大大减少了开发成本和时间。同时,Flutter 还提供了丰富的工具和插件,帮助开发者更好地调试和优化应用程序
Flutter 的跨平台性
Flutter 支持移动端 (iOS, Android), Web 端,桌面端 (Windows, macOS, Linux) 和嵌入式 App 的开发,所有平台共用一套代码库,大大降低开发和维护成本
通过 Flutter-Tizen 工具 (https://github.com/flutter-tizen/flutter-tizen),也可在 Tizen 设备上运行 Flutter App
Flutter 架构
Flutter 的架构主要分为三层:框架层、引擎层和平台层
-
框架层(Framework Layer):框架层是 Flutter 的核心,包括了大量的 UI 组件、渲染、布局和手势等功能。开发者可以通过使用框架提供的组件和 API 来构建用户界面。框架层采用了现代化的响应式编程风格,可以快速地响应用户输入和数据变化
-
引擎层(Engine Layer):引擎层是 Flutter 的底层渲染引擎,负责处理 UI 渲染、输入事件处理、动画和布局等底层操作。引擎层使用 C++编写,包括 Skia 图形库、Dart 运行时和平台相关的代码
-
平台层(Platform Layer):平台层是 Flutter 与操作系统交互的部分,包括了与 Android 和 iOS 平台的通信、访问硬件功能和系统服务等。平台层负责将 Flutter 应用程序与底层系统进行交互,使应用程序能够在不同平台上运行
使用 Flutter 开发的应用
Flutter 作为一种跨平台移动应用开发框架,受到越来越多公司的青睐。较为知名的应用有:阿里巴巴的闲鱼,淘宝特价版,盒马,UC 浏览器,字节跳动的今日头条,西瓜视频,抖音火山版等
Flutter vs React Native
作为两款流行的跨平台应用开发框架,Flutter 和 React Native 的理念有许多相似之处,Flutter 的很多设计灵感来自 React:
- 组件化开发
- Flutter 的 Widget,React Native 的 Component,都支持组件化开发
- UI = f(State)
- Flutter 和 React Native 都采用了响应式 UI 的设计思想,由数据变化(State)驱动页面渲染更新
- Diff 算法
- 二者都使用 Diff 算法,逐层比对 Element 树的节点,标记更新
- 生命周期
- 二者的生命周期函数都是围绕着组件的创建,更新,销毁
Flutter 和 React Native 的不同:
- 语言
- Flutter 使用 Dart 语言,React Native 使用 JavaScript
- 性能
- Flutter 使用 Skia 图形引擎来渲染用户界面,而 React Native 使用原生控件来渲染用户界面,因此在 Flutter 性能方面表现更好
- 生态系统
- React Native 已经存在更长时间,因此有更大的生态系统和更多的第三方库和插件可供开发人员使用。Flutter 相对较新,但也在迅速发展,拥有一个活跃的社区和不断增长的生态系统
从流行程度上看,Flutter 略胜一筹
Github:
Google Trends(蓝线是 Flutter、红线是 React Native):
配置 Windows Flutter App 环境
- 配置代理和镜像源
- 安装 Flutter SDK
- 使用 VSCode 作为开发工具进行调试
- 常用 Flutter 命令
配置代理和镜像源
配置以下环境变量
变量 | 值 | 解释 |
---|---|---|
FLUTTER_STORAGE_BASE_URL | https://storage.flutter-io.cn | 下载包的地址 |
PUB_HOSTED_URL | https://pub.flutter-io.cn | 发布包的地址 |
HTTP_PROXY | http://109.123.97.11:8080/ | |
HTTPS_PROXY | http://109.123.97.11:8080/ | |
NO_PROXY | localhost,127.0.0.1,::1 | 用于本地调试 |
安装 Flutter SDK
-
下载 Flutter SDK 包
https://storage.googleapis.com/flutter_infra_release/releases/stable/windows/flutter_windows_3.19.1-stable.zip -
将 SDK 解压到准备放置 SDK 的路径下,如 D:\FlutterSDK
-
将 Flutter SDK 的 bin 文件夹添加到 Path
使用 VSCode 作为开发工具进行调试
安装以下两个扩展:
-
Flutter
Flutter 扩展用于创建、编辑、debug、运行 Flutter app -
Dart
Dart 扩展为 Dart 编程语言提供支持
-
按
Ctrl
+Shift
+P
,选择 Flutter: New Project
-
选择模板为 Flutter Application
-
在文件资源管理器中选择一个空文件夹作为新项目的路径
-
设置 Project Name
-
按下 Enter,等待片刻后,将创建新的 Flutter App
-
其中,最需要关注的是 lib\main.dart,这是 Flutter App 的入口文件
-
入口函数:
void main() { runApp(const MyApp()); }
-
-
安装依赖包
flutter pub get
-
按下 F5,等待 build 出 .exe 文件并开始 debug
常用 Flutter 命令
- 检查已安装的工具并列出所有连接的设备
flutter doctor -v
flutter devices
- 创建新的 Flutter 项目
flutter create 项目名称
- 构建项目并在目标设备上运行
- Debug 模式:
flutter run
- Release 模式:
flutter run --release
- Debug 模式:
- Build Release 版本的包
flutter build windows
,生成的包在 \build\windows\x64\runner\Release,只有单独的 .exe 文件无法运行,需要同级目录下的 .dll 文件和 data 文件夹- 其他平台可将
windows
替换为apk
、ios
等
配置 Tizen Flutter App 环境
- 安装 Tizen SDK
- 安装 Flutter-Tizen 工具
- 调试 Flutter-Tizen 项目
安装 Tizen SDK
-
打开 https://developer.tizen.org/development/tizen-studio/download ,下载 Tizen Studio 5.5 with CLI(command line interface) installer
-
将 Tizen SDK 解压到准备放置 SDK 的路径下,如 D:\tizen-studio-cli
-
将 Tizen SDK 的 tools 文件夹添加到 Path
安装 Flutter-Tizen 工具
- 在希望安装 Flutter-Tizen 工具的位置执行:
git clone https://github.com/flutter-tizen/flutter-tizen.git
-
将 flutter-tizen 的 bin 文件夹添加到 path
-
运行 flutter-tizen doctor -v,自动化检查、安装、配置环境
在 Tizen 上调试 Flutter 项目
-
创建 Tizen Flutter 项目
flutter-tizen create ./my_first_app
-
通过 VS Code 打开项目文件夹
-
下载依赖包
flutter pub get
-
通过 SDB 连接 TV
sdb connect TV的IP
Note
:如果出现类似 failed to connect to remote target 'TV 的 IP' 等报错,需要重新配置 Tizen 开发选项:buxton2ctl set-int32 system db/sdk/develop/mode 1 buxton2ctl set-string system db/sdk/develop/ip PC的IP sync systemctl start sdbd systemctl daemon-reload
-
在 VS Code 中,按下 Ctrl 和 ` 键调出控制台,输入以下命令,编出 Debug 包,传输到目标电视并 Launch 起来
flutter-tizen run
-
稍等片刻,App 将在目标电视将以 debug 模式启动
-
待 App 启动后,在 VS Code 的侧栏中选择运行与调试 Tab,点击 flutter-tizen: Attach
Note
:如果找不到 flutter-tizen:Attach,可能是 App 没有成功启动,或者在 VS Code 中打开的文件夹不是项目文件夹。
-
在 VS Code 中进行调试
常用 Flutter-Tizen 命令
- 检查已安装的工具并列出所有连接的设备
flutter-tizen doctor -v
flutter-tizen devices
- 创建新的 Flutter-Tizen 项目,或者为已存在的项目添加 Tizen 文件
flutter-tizen create 项目名称
- 构建项目并在 Tizen 设备上运行
- Debug 模式:
flutter-tizen run
- Release 模式:
flutter-tizen run --release
- Debug 模式:
- Build Release 版本的 tpk 包
flutter-tizen build tpk -ptv
,生成的包在 \build\tizen\tpk 文件夹下
用 Dart 语言开发 Flutter App
- Dart 语言介绍
- 用 Dart 语言编写组件
- 定义组件样式
- 动画
- 网络通信
- 播放媒体
- 使用 Flutter Inspector 工具进行调试
Dart 语言介绍
Flutter App 使用 Dart 语言进行开发。Dart 语言具有以下特点:
- Object-oriented programming:Dart 支持 OOP 的概念,包括类、继承、多态、封装等
- Functional programming:Dart 支持函数式编程的概念,包括高阶函数、闭包、柯里化等
- Asynchronous programming:Dart 提供了异步编程的支持,使用 async 和 await 关键字可以轻松实现异步编程
用 Dart 语言编写组件
Flutter 有两种类型的 Widget,StatelessWidget 和 StatefulWidget
StatelessWidget(无状态组件)指不含 State,创建后不再更新的 Widget,通常用于展示静态内容,例如文本、图像或图标等
class MyStatelessWidget extends StatelessWidget {
// build() 类似于 React 中的 render(),构建页面,描述页面的结构
@override
Widget build(BuildContext context) {
return const Text('I am StatelessWidget');
}
}
使用时,可在前面加入 const,提示 Flutter 框架此组件及其子组件无需刷新
Widget build(BuildContext context) {
return const MyStatelessWidget();
}
StatefulWidget(有状态组件)则包含 State,是一种可变的 Widget,其状态可以随用户交互或其他因素而改变
一个 StatefulWidget 一般需要两个类,一个继承自 StatefulWidget,负责创建 State 对象;一个继承 State,负责管理 Widget 的状态。以 Flutter 项目默认 App 为例:
class MyHomePage extends StatefulWidget {
// title 由父组件传递,类似于 React 中的 Prop
// 标记为 final,也是和 React Prop Immutable 的性质同理
final String title;
// 构造函数,required 代表父组件必须传递 title 这个参数
const MyHomePage({super.key, required this.title});
// 创建 State 对象,重载 createState 为 () => _MyHomePageState();
State<MyHomePage> createState() => _MyHomePageState();
}
State 类。注意 build() 在 State 类中,而非 StatefulWidget 类中:
class _MyHomePageState extends State<MyHomePage> {
// _counter 类似于 React 中的 state
// 下划线代表 counter 为私有属性
int _counter = 0;
// 更新 State 的函数
void _incrementCounter() {
// 调用 setState() 会告诉 Flutter 框架该状态发生了变化,从而重新运行下面的 build(),显
// 示更新后的值。如果直接更新 _counter 而没有调用 setState(),则不会重新构建
setState(() { _counter++; });
}
Widget build(BuildContext context) {
return …
}
}
@override
Widget build(BuildContext context) {
return Scaffold( // 页面结构脚手架
appBar: AppBar( // 标题栏
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center( // 主要内容
child: Column(
children: <Widget>[
const Text('You have pushed the button this many times:'),
Text('$_counter'),
],
),
),
floatingActionButton: FloatingActionButton( // 悬浮在页面右下角的按钮
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
定义组件样式
组件的样式通过传入的参数进行设定,以 Container 为例
child: Container(
width: 300,
height: 300,
decoration: BoxDecoration( // 装饰器
gradient: const LinearGradient( // 渐变色
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [Colors.purple, Colors.blue],
stops: [0.5, 0.7],
),
// 阴影
boxShadow: const [BoxShadow(spreadRadius: 25, blurRadius: 25)],
// 圆角
borderRadius: BorderRadius.circular(20),
),
),
动画
简单的动画可以使用 Flutter 封装的 AnimatedXXX 类来实现。如希望 Container 做出动画效果,对应使用 AnimatedContainer 类
child: AnimatedContainer(
duration: const Duration(milliseconds: 1000), // 单次动画的时间
width: 300,
height: _height,
color: Colors.blue,
),
通过修改 _height 的值,触发动画。如将某按钮绑定 setState(() {_height = _height + 100;}) 事件,则每点击一次按钮,Container 的高度将用一秒钟的时间缓慢增加 100
若涉及到循环重播、随时中断、多方协调等较复杂的动画,需使用 AnimatedBuilder 等进行手动控制,这里不作展开
网络通信
Flutter 中进行网络通信通常使用 http、https 等网络请求库来实现,以 http 为例:
- 在项目的 pubspec.yaml 文件中加入 http 依赖:
dependencies:
flutter:
sdk: flutter
http: ^1.2.0
- 在需要进行网络通信的 Dart 文件中引入 http 库和 convert 库。其中 convert 库是 Flutter 的一个标准库,用于在不同数据类型之间进行转换:
import 'package:http/http.dart' as http;
import 'dart:convert';
- 编写代码来发起 GET 请求并处理响应的数据:
fetchData() async {
// 发起请求
final response = await http.get(Uri.parse(
'https://homescreenmiscstg.samsungqbe.cn/homescreen/service/v1/weather'
'?position=江苏-南京-南京&countrycode=CN&modelid=22_PONTUSM_QTV&vdlangc'
'ode=zh_CN&duid=OU4ZNAX3AKJZX'));
<span class="hljs-keyword">if</span> (response.statusCode == <span class="hljs-number">200</span>) { <span class="hljs-comment">// 请求成功</span>
<span class="hljs-comment">// 对响应结果进行解码</span>
<span class="hljs-built_in">Map</span><<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>> data = json.decode(utf8.decode(response.bodyBytes));
setState(() {
text = data.toString();
});
} <span class="hljs-keyword">else</span> { <span class="hljs-comment">// 请求失败</span>
setState(() {
text = <span class="hljs-string">'Failed to fetch data'</span>;
});
}
}
播放媒体
图片
使用 Image 组件显示图片
child: Image.network(
imageUrl,
width: 1500,
height: 800,
),
视频
Flutter 框架默认不提供视频播放功能,因此需要引入 video_player 插件
然而,官方开发的视频播放器插件 video_player 不支持 Windows Desktop,为了在 Windows 平台上播放视频,还需引入 video_player 插件的衍生版本 video_player_win
- 在项目的 pubspec.yaml 文件中加入 video_player 和 video_player_win:
dependencies:
flutter:
sdk: flutter
video_player: ^2.5.1
video_player_win: ^2.0.0 # 二者需同时引入
- 创建 VideoPlayer 的控制器,并在组件初始化时对此 controller 进行初始化,加载网络媒体资源
final VideoPlayerController _controller = VideoPlayerController.network(videoUrl);
void initState() {
super.initState();
// video player 初始化完成后,开始播放
controller.initialize().then(() {
setState(() {
_controller.play();
});
});
}
-
构建 VideoPlayer 的 UI
- 在视频数据加载完毕之前,显示圆形进度指示器
- 在加载完毕后显示纵横比为视频比例的视频播放器
@override
Widget build(BuildContext context) {
return _controller.value.isInitialized
? AspectRatio( // 限制比例
aspectRatio: _controller.value.aspectRatio, // 将视频比例作为纵横比
child: VideoPlayer(_controller),
)
: const CircularProgressIndicator(); // 圆形进度指示器
}
开发 Tizen App 时,则需引入 video_player 和 video_player_tizen 依赖:
dependencies:
flutter:
sdk: flutter
video_player: ^2.4.2
video_player_tizen: ^2.4.9
并在 tizen-manifest.xml 中加入以下三个 privilege,分别用于访问内部存储、外部存储和网络上的视频资源:
<privileges>
<privilege>http://tizen.org/privilege/mediastorage</privilege>
<privilege>http://tizen.org/privilege/externalstorage</privilege>
<privilege>http://tizen.org/privilege/internet</privilege>
</privileges>
使用 Flutter Inspector 工具进行调试
Flutter Inspector 是一个用于调试和检查 Flutter 应用程序的强大工具。它提供了一种可视化方式来查看 Flutter widget 树、布局、颜色、边距和其他属性,帮助开发人员更好地理解应用程序的结构和外观
-
使用 VS Code 开始调试后,页面顶端显示以下几个图标:
从左到右分别代表暂停,Step Over,Step Into,Step Return,Hot Reload,Restart,断开连接,打开 Inspector
-
点击最后一个,弹出 Widget Inspector 窗口
Flutter Widget Inspector 由三个部分组成,Widget 树,测量面板和属性面板
- Widget 树 (Widget Tree): Widget 树以树形结构展示当前应用程序中的所有 Widget
- 属性面板 (Widget Details Tree): 属性面板显示了选定的 Widget 的所有属性,包括大小、位置、颜色、字体等
- 测量面板 (Layout Explorer): 测量面板显示了选定的 Widget 的实际布局情况,如大小、位置、边距等
-
点击左上角的 Toggle Select Widget Mode 图标 ,在选中某个 Widget 时,在 App 中高亮显示
-
更新代码
child: const Icon(Icons.add), // 改为 child: const Icon(Icons.search),
-
点击热重载按钮
Flutter 的热重载是一项非常强大的功能,它允许开发者在不需要重新启动应用程序的情况下,立即查看所做的更改。热重载还会保留应用程序的当前状态,包括当前页面和用户输入,使开发者能够快速验证他们所做的更改是否正确
-
页面样式发生改变
Flutter-Tizen 的限制
- 多数 flutter 库没有对 tizen 做适配,目前确认可以使用的 plugin 如下:https://github.com/flutter-tizen/plugins?tab=readme-ov-file
- 已做适配的 plugin 也可能存在一些功能上难以完全覆盖需求的部分,如 video_player_tizen 不支持 VideoPlayerController.network 的 httpHeaders
- Tizen 开发时,使用模拟器有很多限制,如 video_player_tizen 就无法在模拟器上正常工作
- Flutter-Tizen 没有主流开发工具的社区氛围,只依赖于 Samsung Research 维护和解答,当遇到问题时,解决途径比较狭窄
性能比较
分别用 Flutter 和 C# 实现计数器 App(包含一个按钮和一行文本,文本记录已按按钮的次数,每点按一次按钮数字加一),性能数据如下:
维度 | Flutter | C# | 解释 |
---|---|---|---|
tpk 包的大小 | 7902kB | 19kB | Flutter 除了应用程序本身外,还需包含 Flutter 框架,导致 Flutter 应用程序的包比传统 Tizen App 大 |
CPU 占用率(按按钮时) | 5.6% | 1.6% | Flutter 框架需要更多的计算资源来渲染复杂的 UI 和处理用户交互,虽然使用了 Diff 算法等尽量优化掉不必要的重绘,但优化本身仍要占用一定的计算资源 |
内存占用 | 35,668 | 18,261 | Flutter 框架会占用一定的内存空间 |
总结
Flutter 是谷歌开发的一款开源 UI 软件开发工具包,使用 Dart 进行开发,用于从单一代码库中构建 Mobile、Web 和 DeskTop 应用程序,提供热重载、基于 Widget 的用户界面、跨平台支持。通过 Flutter 框架,可以轻松实现绘制 UI,定义组件样式,动画效果,网络通信,播放媒体等功能。使用 Flutter-Tizen 开发 Tizen App 时,要注意额外的磁盘、内存和 CPU 消耗,以及各 plugin 支持受限的部分