Flutter跨平台开发技术

仅分享文字,见谅

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:

  1. 组件化开发
    1. Flutter 的 Widget,React Native 的 Component,都支持组件化开发
  2. UI = f(State)
    1. Flutter 和 React Native 都采用了响应式 UI 的设计思想,由数据变化(State)驱动页面渲染更新
  3. Diff 算法
    1. 二者都使用 Diff 算法,逐层比对 Element 树的节点,标记更新
  4. 生命周期
    1. 二者的生命周期函数都是围绕着组件的创建,更新,销毁

Flutter 和 React Native 的不同:

  1. 语言
    1. Flutter 使用 Dart 语言,React Native 使用 JavaScript
  2. 性能
    1. Flutter 使用 Skia 图形引擎来渲染用户界面,而 React Native 使用原生控件来渲染用户界面,因此在 Flutter 性能方面表现更好
  3. 生态系统
    1. 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

  1. 下载 Flutter SDK 包
    https://storage.googleapis.com/flutter_infra_release/releases/stable/windows/flutter_windows_3.19.1-stable.zip

  2. 将 SDK 解压到准备放置 SDK 的路径下,如 D:\FlutterSDK

  3. 将 Flutter SDK 的 bin 文件夹添加到 Path

使用 VSCode 作为开发工具进行调试

安装以下两个扩展:

  1. Flutter

    Flutter 扩展用于创建、编辑、debug、运行 Flutter app

  2. Dart

    Dart 扩展为 Dart 编程语言提供支持

  1. Ctrl + Shift + P,选择 Flutter: New Project

  2. 选择模板为 Flutter Application

  3. 在文件资源管理器中选择一个空文件夹作为新项目的路径

  4. 设置 Project Name

  1. 按下 Enter,等待片刻后,将创建新的 Flutter App

    • 其中,最需要关注的是 lib\main.dart,这是 Flutter App 的入口文件

    • 入口函数:

    void main() {
       runApp(const MyApp());
    }
    
  2. 安装依赖包

    flutter pub get
    
  1. 按下 F5,等待 build 出 .exe 文件并开始 debug

常用 Flutter 命令

  • 检查已安装的工具并列出所有连接的设备
    • flutter doctor -v
    • flutter devices
  • 创建新的 Flutter 项目
    • flutter create 项目名称
  • 构建项目并在目标设备上运行
    • Debug 模式:flutter run
    • Release 模式:flutter run --release
  • Build Release 版本的包
    • flutter build windows,生成的包在 \build\windows\x64\runner\Release,只有单独的 .exe 文件无法运行,需要同级目录下的 .dll 文件和 data 文件夹
    • 其他平台可将 windows 替换为 apkios

配置 Tizen Flutter App 环境

  • 安装 Tizen SDK
  • 安装 Flutter-Tizen 工具
  • 调试 Flutter-Tizen 项目

安装 Tizen SDK

  1. 打开 https://developer.tizen.org/development/tizen-studio/download ,下载 Tizen Studio 5.5 with CLI(command line interface) installer

  2. 将 Tizen SDK 解压到准备放置 SDK 的路径下,如 D:\tizen-studio-cli

  3. 将 Tizen SDK 的 tools 文件夹添加到 Path

安装 Flutter-Tizen 工具

  1. 在希望安装 Flutter-Tizen 工具的位置执行:
    git clone https://github.com/flutter-tizen/flutter-tizen.git
  1. 将 flutter-tizen 的 bin 文件夹添加到 path

  2. 运行 flutter-tizen doctor -v,自动化检查、安装、配置环境

在 Tizen 上调试 Flutter 项目

  1. 创建 Tizen Flutter 项目

    flutter-tizen create ./my_first_app
    
  2. 通过 VS Code 打开项目文件夹

  3. 下载依赖包

    flutter pub get
    
  1. 通过 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
    
  1. 在 VS Code 中,按下 Ctrl 和 ` 键调出控制台,输入以下命令,编出 Debug 包,传输到目标电视并 Launch 起来

    flutter-tizen run
    

  1. 稍等片刻,App 将在目标电视将以 debug 模式启动

  2. 待 App 启动后,在 VS Code 的侧栏中选择运行与调试 Tab,点击 flutter-tizen: Attach

    Note:如果找不到 flutter-tizen:Attach,可能是 App 没有成功启动,或者在 VS Code 中打开的文件夹不是项目文件夹。

  1. 在 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
  • 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();
@override
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++; });
}

@override
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 为例:

  1. 在项目的 pubspec.yaml 文件中加入 http 依赖:
dependencies:
  flutter:
    sdk: flutter
  http: ^1.2.0
  1. 在需要进行网络通信的 Dart 文件中引入 http 库和 convert 库。其中 convert 库是 Flutter 的一个标准库,用于在不同数据类型之间进行转换:
import 'package:http/http.dart' as http;
import 'dart:convert';
  1. 编写代码来发起 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>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; 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">&#x27;Failed to fetch data&#x27;</span>;
  });
}

}

播放媒体

图片

使用 Image 组件显示图片

child: Image.network(
  imageUrl,
  width: 1500,
  height: 800,
),

视频

Flutter 框架默认不提供视频播放功能,因此需要引入 video_player 插件

然而,官方开发的视频播放器插件 video_player 不支持 Windows Desktop,为了在 Windows 平台上播放视频,还需引入 video_player 插件的衍生版本 video_player_win

  1. 在项目的 pubspec.yaml 文件中加入 video_player 和 video_player_win:
dependencies:
  flutter:
    sdk: flutter
  video_player: ^2.5.1
  video_player_win: ^2.0.0 # 二者需同时引入
  1. 创建 VideoPlayer 的控制器,并在组件初始化时对此 controller 进行初始化,加载网络媒体资源
final VideoPlayerController _controller = VideoPlayerController.network(videoUrl);
void initState() {
  super.initState();

// video player 初始化完成后,开始播放
controller.initialize().then(() {
setState(() {
_controller.play();
});
});
}

  1. 构建 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 树、布局、颜色、边距和其他属性,帮助开发人员更好地理解应用程序的结构和外观

  1. 使用 VS Code 开始调试后,页面顶端显示以下几个图标:

    从左到右分别代表暂停,Step Over,Step Into,Step Return,Hot Reload,Restart,断开连接,打开 Inspector

  1. 点击最后一个,弹出 Widget Inspector 窗口

Flutter Widget Inspector 由三个部分组成,Widget 树,测量面板和属性面板

  • Widget 树 (Widget Tree): Widget 树以树形结构展示当前应用程序中的所有 Widget
  • 属性面板 (Widget Details Tree): 属性面板显示了选定的 Widget 的所有属性,包括大小、位置、颜色、字体等
  • 测量面板 (Layout Explorer): 测量面板显示了选定的 Widget 的实际布局情况,如大小、位置、边距等

  1. 点击左上角的 Toggle Select Widget Mode 图标 ,在选中某个 Widget 时,在 App 中高亮显示

  1. 更新代码

    child: const Icon(Icons.add),
    // 改为
    child: const Icon(Icons.search),
    
  2. 点击热重载按钮

    Flutter 的热重载是一项非常强大的功能,它允许开发者在不需要重新启动应用程序的情况下,立即查看所做的更改。热重载还会保留应用程序的当前状态,包括当前页面和用户输入,使开发者能够快速验证他们所做的更改是否正确

  3. 页面样式发生改变

Flutter-Tizen 的限制

  1. 多数 flutter 库没有对 tizen 做适配,目前确认可以使用的 plugin 如下:https://github.com/flutter-tizen/plugins?tab=readme-ov-file
  2. 已做适配的 plugin 也可能存在一些功能上难以完全覆盖需求的部分,如 video_player_tizen 不支持 VideoPlayerController.network 的 httpHeaders
  3. Tizen 开发时,使用模拟器有很多限制,如 video_player_tizen 就无法在模拟器上正常工作
  4. 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 支持受限的部分

Thank You

相关推荐

  1. 重新认识Flutter平台技术(上)

    2024-07-15 03:16:01       24 阅读
  2. 探索Flutter 3.0:平台开发的新越界

    2024-07-15 03:16:01       29 阅读
  3. Flutter之旅:探索安卓与平台开发的无限可能

    2024-07-15 03:16:01       34 阅读
  4. 掌握Qt开发技能:打造平台应用的利器

    2024-07-15 03:16:01       37 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-15 03:16:01       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-15 03:16:01       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-15 03:16:01       58 阅读
  4. Python语言-面向对象

    2024-07-15 03:16:01       69 阅读

热门阅读

  1. SQL执行慢的原因?如何排查?

    2024-07-15 03:16:01       23 阅读
  2. 常用设计模式

    2024-07-15 03:16:01       22 阅读
  3. Mybatis 传递数组给sql解析 解决not in失效问题

    2024-07-15 03:16:01       20 阅读
  4. sqlalchemy使用with_entities返回指定数据列

    2024-07-15 03:16:01       16 阅读
  5. Redis如何高效安全的遍历所有key

    2024-07-15 03:16:01       12 阅读
  6. ansible安装

    2024-07-15 03:16:01       18 阅读
  7. RocketMQ~生产者与消费者的消费模式(pull or push)

    2024-07-15 03:16:01       20 阅读
  8. Go语言基础数据类型、变量及自增语法

    2024-07-15 03:16:01       20 阅读