首页 > 其他分享 >Flutter实战篇

Flutter实战篇

时间:2024-08-23 18:52:22浏览次数:13  
标签:原生 25 实战篇 插件 flutter 组件 Flutter

第四章Flutter实战

4.1 Fluter APP 代码结构

1.png

  • ''lib” Dart代码目录
    2.png

  • “ios”、“android”是两个平台相关代码、配置目录

  • pubspec.yaml是依赖的组件库配置如:

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  http: 0.13.3
  dio: ^4.0.0  #大于等于4.0.0小于5.0.0
  image_picker: ^0.8.3+2

也可以配置本地图片,在工程目录下创建个images文件,将所需图片导入到该目录,并配置如下:

  # To add assets to your application, add an assets section, like this:
  assets:
     - images/

注意: 由于 yaml 文件对缩进严格,所以必须严格按照每一层两个空格的方式进行缩进,此处 assets 前面应有两个空格

4.2 代码实战

模拟微信APP,项目名称WeChatDemo。

  • 项目入口:main
void main() {
  runApp(MyApp());

}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        highlightColor: Color.fromRGBO(1, 0, 0, 0.0),
        splashColor: Color.fromRGBO(1, 0, 0, 0.0),
        cardColor: Color.fromRGBO(1, 1, 1, 0.65),//有透明层叠视图的设置
        primarySwatch: Colors.blue,
        appBarTheme: AppBarTheme(iconTheme: IconThemeData(color: Colors.black))
      ),
      home: RootPage(),
    );
  }
}
  • 主要模块:微信、通讯录、发现、我
 class RootPage extends StatefulWidget {
  const RootPage({Key? key}) : super(key: key);

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

class _RootPageState extends State<RootPage> {
  int _currentIndex = 0;
  List <Widget> _pages = [ChatPage(),FriendsPage(),DiscoverPage(),MinePage()];
  final PageController _controller = PageController(initialPage: 0);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView( //通过pageView 来保持状态
        physics: NeverScrollableScrollPhysics(), //不允许滚动
        children: _pages,
        controller: _controller,
      ),
      bottomNavigationBar: BottomNavigationBar(
        onTap: (index){
          setState(() {
            _currentIndex  = index;
          });
          _controller.jumpToPage(index);
        },
        selectedFontSize: 12,
        unselectedFontSize: 12,
        currentIndex: _currentIndex,
        fixedColor: Colors.green,
        type: BottomNavigationBarType.fixed,
        items: [
          BottomNavigationBarItem(
              icon: Image.asset('images/tabbar_chat.png',height: 25,width: 25),
              activeIcon: Image.asset('images/tabbar_chat_hl.png',height: 25,width: 25,),
              label: '微信'
          ),
          BottomNavigationBarItem(
              icon: Image.asset('images/tabbar_friends.png',height: 25,width: 25,),
              activeIcon: Image.asset('images/tabbar_friends_hl.png',height: 25,width: 25,),
              label: '通讯录'
          ),
          BottomNavigationBarItem(
              icon: Image.asset('images/tabbar_discover.png',height: 25,width: 25,),
              activeIcon: Image.asset('images/tabbar_discover_hl.png',height: 25,width: 25,),
              label: '发现'
          ),
          BottomNavigationBarItem(
              icon: Image.asset('images/tabbar_mine.png',height: 25,width: 25,),
              activeIcon: Image.asset('images/tabbar_mine_hl.png',height: 25,width: 25,),
              label: '我'
          ),
        ],
      ),
    );
  }
}

详细代码请参考项目WechatDemo

4.2.1 AutomaticKeepAliveClientMixin 混入

state 混入 AutomaticKeepAliveClientMixin,保持Tabbar 切换时state不被重新初始化

  • state 混入 AutomaticKeepAliveClientMixin
class _ChatPageState extends State<ChatPage>
    with AutomaticKeepAliveClientMixin
  • state 添加成员属性
  @override
  bool get wantKeepAlive => true;
  • 在 build 方法中添加
    super.build(context);
4.2.2 混合开发
  • Flutter调原生功能,如我的页面,更换头像需要调用系统相册,有两种实现方式
    1、MethodChannel 通道
    类似于通知,通过发送消息,监听消息回调实现与原生通讯
//第一步:Flutter端创建通道,传入唯一标识
 MethodChannel _methodChannel = MethodChannel('mine_page');
 
//第二步:Flutter端发送消息
_methodChannel.invokeListMethod('picture'); //发送了一条要更换图片的消息

//第三步:原生注册‘mine_page’通道,并监听消息发送
FlutterViewController *vc = (FlutterViewController *)self.window.rootViewController;
FlutterMethodChannel *methodChannel = [FlutterMethodChannel methodChannelWithName:@"mine_page" binaryMessenger:vc];
self.methodChannel = methodChannel;
//监听flutter消息
[methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
     if ([call.method isEqualToString:@"picture"]) {
           UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
           imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
           imagePicker.delegate = self;
           imagePicker.modalPresentationStyle = UIModalPresentationFullScreen;
           [vc presentViewController:imagePicker animated:YES completion:nil];
      }
 }];

//第四步:原生发送拿到相册消息
[self.methodChannel invokeMethod:@"imagePath" arguments:imagePath];

//第五步:dart监听回调,并更新状态
 _methodChannel.setMethodCallHandler((call) {
     if(call.method == 'imagePath') {
         String imagePath = call.arguments.toString().substring(7); //截取前面7个字符,拿到的参数带有file://
         setState(() {
           _avatarFile = File(imagePath);
         });
      }
    return Future(() => null);
 });

注:原生与Flutter交互的过程中必须确保是同一个通道,唯一性

2、ImagePicker,三方插件无需原生写多余代码

  void _imagePick() async {
    XFile? file =  await ImagePicker().pickImage(source: ImageSource.gallery); //相册
    if(file != null) {
      setState(() {
        _avatarFile = File(file.path);
      });
    }
  }
  • 原生项目中使用Flutter页面
    1、创建Flutter 组件,在组件项目中写dart代码
    3.png

    • Flutter App: 创建一个完整的flutter项目,里面包含安卓和iOS项目
    • Flutter Module: 创建Flutter组件时使用,混编到已有的安卓/iOS工程
    • Flutter Plugin:就是Plugin的方式进行开发,比如一些百度地图,flutter不提供,通过自建Plugin,通过Plugin中的android和ios原生项目,集成原生百度功能,通过plugin中的lib中的方法来进行flutter调用百度的相关方法
    • Flutter Package:纯Dart插件工程,仅包含Dart层的实现,往往定义一些公共Widget

    2、通过cocoapods 导入到原生项目中,如:本地有个flutter_moudle组件,原生项目中需要植入Flutter页面,podfile文件配置如下:
    4.png

    3、导入Flutter库,并使用
    注意:flutter页面和原生页面频繁切换会导致内存泄漏

4.2.3 安装包结构

用Xcode打开项目,选择真机编译,选择Products ->Runner.app -> 右键Show in Finder右键显示包内容,可以看到编译后结构:可执行文件、资源文件、签名、Frameworks。重点关注下Frameworks
5.png

  • App.framewok: dart代码编译后的产物,App可执行文件(二进制机器代码)
  • Flutter.framewok: 就是Flutter SDK源码文件,我们看到可执行文件大小是65.7M,而Flutter SDK目录下的同名framework也是65.7M,很好的证明了APP在打包过程中会将Flutter SDK 引擎导入到安装包中,这也是Flutter App安装包比原生项目体积大的原因
    6.png

路径:/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-armv7_arm64/Flutter.framework

4.3 Flutter 插件开发(plugin )
  • 1、Flutter插件介绍
    一种专用的Dart包,其中包含用Dart代码编写的API,以及针对Android(使用Java或Kotlin)和针对iOS(使用OC或Swift)平台的特定实现(另外也可以包含Native的组件代码),也就是说插件包括原生代码与Dart代码。插件开发完成后,将上传到dart插件管理服务仓库,类似于maven、pod库,然后在flutter开发过程中可以通过pubspec.yaml(dart包管理配置文件)来获取插件服务。

  • 2、为什么要开发Flutter插件
    首先,虽然Flutter的生态现在已经越来越完善了,但是相比于Android跟iOS原生的生态体系,还是远远不够。很多在Android跟iOS原生上有的很酷炫的库,在Flutter中还没有或者是并没有那么的完善。其次,想必大家在原生工程里都有一套用了多年的稳定基础组件,包括网络组件、数据组件等,要重新在Flutter中用dart来搭建一套,时间成本、风险成本、组件兼容性等都是不可控的。所以,最理想的方式就是Flutter的基础组件可以对我们现有原生的组件做一层包装,然后提供接口给Flutter模块进行调用,这样一来什么时间、风险、兼容性都不是问题。我们只要维护一套原生组件就好,Flutter组件只是一层包装,并不在意内部如何去实现。那么Flutter跟原生怎么进行交互呢?

  • 3、Flutter如何与原生交互
    1)MethodChannel 通道, 具体使用4.2.2混合开发已介绍。Flutter与原生的交互模型,类似于一种C-S模型。其中Flutter为Client层,原生为Server层,两者通过MethodChannel进行消息通信,原生端向Flutter提供已有的Native组件功能。

    2)究竟什么是MethodChannel
    Flutter定义了3种Channel模型,分别是: BasicMessageChannel:用于传递字符串和半结构化的信息;MethodChannel:用于传递方法调用(methodinvocation)EventChannel: 用于数据流(event streams)的通信。3种channel基本类似,这里以MethodChannel展开介绍
    3) MethodChannel有3个重要的成员变量:

- String name    
一个Channel对象通过name来进行唯一的标识,所以在Channel的命名上一定要独一无二,推荐采用组件名_Channel名 组合来进行命名

- BinaryMessenger messenger   
BinaryMessenger是Platform端与Flutter端通信的工具,其实是个中间信使,当我们初始化一个Channel,并向该Channel注册处理消息的Handler时,实际上会生成一个与之对应的BinaryMessageHandler,并以channel name为key,注册到BinaryMessenger中。当Flutter端发送消息到BinaryMessenger时,BinaryMessenger会根据其入参channel找到对应的BinaryMessageHandler,并交由其处理。BinaryMessenger维护了一个map

Binarymessenger在Android端是一个接口,其具体实现为FlutterNativeView。而其在iOS端是一个协议,名称为FlutterBinaryMessenger,FlutterViewController遵循了它。Binarymessenger只和BinaryMessageHandler打交道,而Channel和BinaryMessageHandler则是一一对应的。由于Channel从BinaryMessageHandler接收到的消息是二进制格式数据,无法直接使用,故Channel会将该二进制消息通过Codec(消息编解码器)解码为能识别的消息并传递给Handler进行处理。当Handler处理完消息之后,会通过回调函数返回result,并将result通过编解码器编码为二进制格式数据,通过BinaryMessenger返回。

- MethodCodec codec  
消息编解码器Codec主要用于将二进制格式的数据转化为Handler能够识别的数据,MethodCodec主要是对MethodCall中这个对象进行序列化与反序列化,MethodCall是Flutter向Native发起调用产生的对象,其中包含了方法名以及一个参数集合

  • 4、插件工程创建
    推荐通过命令行来创建,因为通过IDE来创建有时候会卡住,而且会比较慢
flutter create --org com.plug.jcfc.cn --template=plugin --platforms=android,ios -i objc -a java flutter_plug

  • 5、目录结构
    [图片上传失败…(image-236f71-1635245763669)]

  • ib dart模块

  • android android模块

  • ios iOS模块

  • example 示例测试工程可用于插件的调试

  • pubspec.yaml flutter项目的配置文件
    ….

    pubspec.yaml: dart生态下的包管理配置文件类似 Android中的gradle、iOS中的Podfile,在这里可以统一管理整个flutter工程的dart依赖包,以及管理整个插件的发布属性。

  • 6、原生端开发
    实现MethodCallHandler接口,注册MethodChannel对象,MethodChannel在创建时一定要保证name唯一
    将MethodHandler接口注册到MethodChannel中
    包装原生端组件,包括一些二方库、三方库,将包好的方法通过MethodCallHandler暴露给Flutter端

  • 7、Flutter端开发
    找到MethodChannel对象,通过唯一标识name,注意(name一定要与原生端注册的一致)
    定义dart方法,因为要保证方法的执行不产生阻塞,所以推荐用Future async await .相关的语法见dart语法
    调用methodChannel.invokeMothed()与原生进行通信

  • 8、插件测试
    在example/lib/main.dart下调用插件中的方法,然后直接通过命令将工程跑起来查看输出

fultter run

插件都还没有发布,为什么example工程可以直接引用?看一下example目录下的pubspec.yaml文件,里面有

dependencies:
  flutter:
    sdk: flutter

  flutter_plug:
    # When depending on this package from a real application you should use:
    #   flutter_plug: ^x.y.z
    # See https://dart.dev/tools/pub/dependencies#version-constraints
    # The example app is bundled with the plugin so we use a path dependency on
    # the parent directory to use the current plugin's version.
    path: ../ 相对路径

pubspec.yaml 不但可以引用服务器上的插件,也可以引用本地路径下的插件。如此我们可以在插件未发布的情况下,直接在本地的测试工程里对插件进行测试

  • 9、插件发布
  • 完善pubspec.yaml文件
name: 插件名称  
description: 插件描述  
version: 0.0.1 版本号  
homepage: 项目主页地址  
publish_to: 填写私有服务器的地址(如果是发布到flutter pub则不用填写,插件默认是上传到flutter pub)  
  • 检查发布条件
flutter packages pub publish --dry-run  

--dry-run 参数表示本次执行会检查插件的配置信息是否有效,插件是否满足上传条件。如果成功的话并不会真正的将插件上传,而是会显示本次要发布插件的信息,并提示成功。一般在插件的正式发布前,建议先执行该命令,避免在上传过程中出现错误
  • 正式发布
发布至pub平台
flutter packages pub publish  

4.3 Flutter 插件开发(Package)

纯Dart 语言,封装的有特定功能的Widget组件,创建和发布流程和plugin插件类似


参考资料
Flutter中文网
Dart和Flutter应用程序的官方软件包库
Dart语言中文网

标签:原生,25,实战篇,插件,flutter,组件,Flutter
From: https://blog.csdn.net/weixin_40035526/article/details/141468568

相关文章

  • Flutter 自定义日期范围选择组件,使用更加灵活,满足UI设计需要
    一、实现的效果图二、虽然Flutter也为我们提供了日期范围选择组件showDateRangePicker,但是毕竟系统的UI不符合我们的设计风格,所以被迫只能自己实现一个了系统样式三、日历整体实现逻辑其实也很简单,如下:首先获取每个月份具体有多少天int_getMonthDays(DateTimetim......
  • 第一个Flutter应用
    用VSCode创建的Flutter应用模板默认是一个简单的计数器示例。下面会仔细讲解一下这个计数器Demo的源码,让读者对Flutter应用程序结构有个基本了解,然后在随后的小节中将会基于此示例,一步一步添加一些新的功能来介绍Flutter应用的其他概念与技术。一、创建Flutter应用模......
  • 初识 Flutter
    一、Flutter简介Flutter是Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开发者可以通过Dart语言开发App,一套代码同时运行在iOS和Android平台。Flutter提供了丰富的组件、接口,开发者可以很快地为Flutter添加Native(即原生开发,指基于平台原生语言......
  • 搭建 Flutter 开发环境
    理论上可以使用任何文本编辑器与命令行工具来构建Flutter应用程序。不过,Flutter官方建议使用AndroidStudio和VSCode之一以获得更好的开发体验。这里选择使用VisualStudioCode作为编辑器,下面介绍其的安装。一、安装VSCode下载适用于Windows的VisualStudio......
  • flutter在本地化后启动时显示黑屏
    Flutter是一种跨平台的移动应用开发框架,可以同时在iOS和Android平台上构建高性能、美观的应用程序。当Flutter应用程序在本地化后启动时显示黑屏,可能是以下几个原因导致的:资源加载问题:在应用程序本地化后,可能存在资源文件加载失败的情况,导致应用程序无法正常显示。可以检查资源......
  • android开发通过wireshark实现flutter应用抓包
    android开发通过wireshark实现flutter应用抓包1.为什么要使用wireshark抓包1.有了上一篇Charles的抓包文章,为什么还写这篇抓包文章呢?单独论http请求抓包的话Charles比wireshark好用2.这是因为flutter应用使用的不是系统的证书,而是使用flutter框架自己的证书,这就导致了Char......
  • 【实战指南】使用 Redis 实现 Java 项目中的防重复提交功能:从原理到实战(实战篇)
    文章目录使用Redis实现Java项目中的防重复提交功能1.引言1.1为何需要防重复提交功能1.2重复提交导致的问题1.3引入Redis作为解决方案的一部分2.基础知识2.1Redis简介2.2Java环境搭建2.3环境配置3.理论基础3.1HTTP请求的特点3.2前端表单提交3.3后......
  • Flutter项目移动端SQLite升级指南:解决json_extract函数缺失问题
    引言在Flutter移动端项目中依赖于SQLite的高级功能(如json_extract),在低版本的Android系统上部署时,可能会遇到函数不支持的问题。本文将指导你如何通过升级项目中使用的SQLite版本来解决这一问题。前置条件Flutter项目使用sqflite:^2.3.3+1进行SQLite数据库操作。IMBoyA......
  • 「重构:改善既有代码的设计」实战篇
    背景在软件开发的世界里,代码重构是提升项目质量、适应业务变化的关键步骤。最近,我重新翻阅了《重构:改善既有代码的设计第二版》,这本书不仅重新点燃了我对重构的热情,还深化了我的理解:重构不仅仅是代码层面的整理,它更是一种软件开发的哲学,强调持续改进和适应变化的重要性。 书......
  • Android跨平台开发之Dart 3.5 与 Flutter 3.24:革新跨平台应用开发
    本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点Dart3.5与Flutter3.24:革新跨平台应用开发在软件开发领域,跨平台开发框架层出不穷,但鲜有能像Flutter这样在短时间内迅速崛起,获得广泛的认可和应用。随着Dart......