Flutter踩坑之旅

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter踩坑之旅相关的知识,希望对你有一定的参考价值。

参考技术A 记录下自己踩过的坑,怕忘了

一.TextField:

1.去掉输入数字的计数:decoration中的counterStyle: TextStyle(color: Colors.transparent).

2.去掉获取和失去焦点时边框改变颜色的效果:decoration内border: InputBorder.none,

3.去边框时设置BorderSide的width为0或color: Colors.transparent后依然存在边框时,需要设置为borderSide: BorderSide.none

4.设置背景色需要在decoration内     filled:true,   fillColor: Colors.blue同时设置才会显示

二.Uint8List类型和string类型,List<int>的转换

连续两次base64解码时,参数只能使用string类型,但是base64解码后是Uint8List类型,此时需要将Uint8List类型转换为string类型,使用:utf8.decode(Uint8List)即可,需要import 'dart:convert';

List<int>转Uint8List:读取接口时获取的数据是List<int>的图片数据,想显示时需要转成Uint8List,然后使用Image.memory(),使用:Uint8List.fromList(List<int>)即可

三.报错:DioError [DioErrorType.DEFAULT]: FormatException: Unexpected character (at character 1)MGFlMFo0NEZ3RWNMbE5YbGNGOXZGcUlJdUhIS2x2Q3NlckxqWXlEeG5JWndZdXIrSUpLN3ZOczR...

这是因为dio请求返回的数据默认是以json的格式读取的,而返回的数据是密文形式,需要修改dio的Options的responseType为ResponseType.PLAIN,这样返回的数据就以字符串形式处理.

四.去掉点击控件背景出现的水波纹效果,即去掉md的效果:

在main.dart的MaterialApp内的theme加上splashColor: Colors.transparent

五.布局去掉沉浸式效果和布局设置占满全屏却无效的问题

使用Scaffold的body的布局默认是沉浸式的,将状态栏一起包含了,可以通过在body后添加一层SafeArea即可.

布局设置double.infinity占满全屏高度却无效,大部分情况都是因为某一级的父布局的高度已经有了限制,所以设置充满屏幕只会充满父布局,有些widget默认是按内容填充类似wrap_content就会导致写布局的过程中自己没有限制高度但最后的布局不是自己想要的,可以给各个父布局设置不同背景颜色来查看是从哪儿开始被限制了高度来排查问题.

六.占满剩余空间,类似android的match_parent可以使用double.infinity

七.LinearProgressIndicator

1.LinearProgressIndicator设置进度值的颜色为单一颜色:valueColor : new AlwaysStoppedAnimation(Color(JColor.blue))

2.给LinearProgressIndicator设置圆角:ClipRRect(

borderRadius:BorderRadius.circular(60.0),

  child:LinearProgressIndicator(value:0.2,backgroundColor:Color(JColor.grayBg),valueColor:new AlwaysStoppedAnimation(Color(JColor.blue)),

  )

八.Expanded:

1.若嵌套多层column且内容的高度都不确定需要占满剩余空间,需要每层的column的内容都嵌套一层expanded来申明每层都占满剩余的空间,否则最里面的内容层需要指定高度,不然会报错

九.Container设置最小/大宽度或高度:

constraints:BoxConstraints(minHeight:56),

十.滑动的widget嵌套:

1.解决滑动冲突:内层嵌套的滑动widget设置physics:NeverScrollableScrollPhysics()

2.解决滑动嵌套ui显示不出来或者报错,内层的滑动widget设置shrinkWrap:true

十一.使用multi_image_picker: ^4.3.4安卓运行报错Didn't find class "com.sangcomz.fishbun.FishBunFileProvider"

1.需要android工程支持androidx,需要在android工程的gradle.properties内添加android.enableJetifier=true和android.useAndroidX=true并点击右上角的open for editing in android studio,运行成功后就可以了

十二.使用textfield时的文字ui总是很高

使用了maxlength且只是在textfield的InputDecoration设置counterStyle的颜色为透明使下面的计数文字消失会导致文字ui很高,counter的计数文字只是颜色是透明但依然在布局中占了位置所以导致文字很高,直接使用counterText:""即可

十三.使用ListView报错Vertical viewport was given unbounded height

需要将ListView放入Expanded内部

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!

人们普遍认为,如果想构建一个良好的移动应用,则必须建立iOS和Android两个版本。与此同时大多数企业想要的是:只实现一次业务逻辑,并快速打包成具有原生体验感的用户界面。

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!
作者 | Gary Hunter

译者 | 弯月,责编 | 郭芮

出品 | CSDN(ID:CSDNnews)

以下为译文:

直到去年,我们公司的主要应用Easy Diet Diary还只有iOS原生版本。这是一款澳大利亚的通用减肥跟踪应用,另外还有一个面向研究以及不幸患有肾病用户的特殊版本。该应用程序的大致状况如下:
  • 拥有75,000行Objective C和Swift代码;

  • 亚马逊AWS后端:DynamoDB、Postgres和S3;

  • 每天都有22,000名用户和125万次下载。

后来,Flutter问世了(Beta版于2018年4月2日问世)。Flutter能够为我们提供足够多的功能:跨平台、良好的性能、快速实现、原生体验、开源,我们只需构建Flutter一个版本,就可以同时服务于iOS和Android。
六个月后,我发布了Google Open Beta,却没有使用原生代码。
本文是在Open Beta的基础上:
  • 通过谷歌应用商店发布Android版本;

  • 直接替换掉苹果的应用商店中原有的iOS原生应用。

本文的主要内容包括:
  • 代码行数与开发速度

  • Google Open Beta

  • 架构

  • 后端服务(亚马逊AWS)

  • 性能

  • 原生代码

  • 跨平台设计

  • 风格与方案

  • 总结

  • 后记


程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!

代码行数与开发速度

在导入代码的时候,我真实地感受到了声明式编程的效率有多么高,而且摆脱基于XML的故事板的束缚,能够重用界面代码是多么方便。好吧,随着Jetpack Compose和SwiftUI的推出,似乎这些也习以为常了。
最终我获得了35,000行Dart代码。此外,还有3000行Objective-C/Swift代码负责处理HealthKit等iOS特定的逻辑,以及500行Java图像处理代码。
导入完成后,Flutter应用的代码行数只有iOS原生应用的一半。

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!
Google Open Beta

我花了大量时间通过苹果的TestFlight流程来操纵应用,却发现将一个不断发展的应用交到广大用户手中是多么艰辛。而且我觉得短期内这种状况还无法得到改善,因为苹果认为其审核流程是确保应用符合某些标准的方式,他们并没有恶意刁难。对于能力很强的热心开发人员来说,可能会觉得很受打击。
相比之下,广大用户可以利用Google Open Beta的流程,在应用商店中像搜索其他应用一样搜索测试版的应用,而且还可以无缝地加入测试版程序,使用这些应用并提供(有限的)反馈。如果你对Open Beta版本感到满意,那么就可以升级到正式版本。如果应用的使用合理,那么用户很快就会接纳并提供建设性的反馈。至少我个人的经历如此——这是一种良好的开发方式。
随着我添加功能和修复错误,Easy Diet Diary累积了10,000个beta用户。于是,3月份我发布了1.0 Android版本。

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!


程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!
架构

去年刚开始的时候,我还不熟悉声明式UI编程以及随之而来的状态管理。对我来说,依赖于异步流的Redux和BLoC学习曲线十分陡峭,最终我利用InheritedWidgets在部件树中实现了状态同步。我想方设法将业务逻辑与表示逻辑分开,但并没有使用状态管理框架来强制两者的分离。
从那以后,有关状态管理的方法和热烈讨论与日俱增。将Flutter中状态管理的开源演变与SwiftUI的响应式编程框架(另一个更大的团队正在秘密开展工作)的开发进行对比是一件有趣的事情,这颇像史蒂夫·乔布斯的风格。Matt Gallagher对苹果的Combine框架进行了一些有趣的分析。
在2019年的Google I/O大会上,为了减少开发人员对于状态管理的恐惧心态(我认为部分原因是如此),并抑制越来越多的InheritedWidget封装库的出现,Flutter团队宣传了由Remi Rousselet开发的provider小部件,详细说明请点击这里(https://www.didierboelens.com/2019/07/provider---points-of-interest---points-to-care-about/)。Provider给予了我很大帮助。但我仍然没有使用更为正式的状态管理方法,比如BLoC或MobX(两者都可以与Provider一起使用),因为需要修改大量的代码。
在阅读了Didier Boelens的博客后,加速了我对状态管理的理解。虽然他是BLoC的粉丝,但他善于用客观的方式解释这些技术。

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!
后端服务(亚马逊AWS)

除了Crashlytics和ML Kit之外,所有Easy Diet Diary的云服务都在Amazon AWS上。
不幸的是,到目前为止,我们还没有适用于AWS的官方Flutter SDK,而与AWS相关的插件也非常少。
对我来说,这倒不是一个大问题,因为在我们的移动应用与所有的AWS服务之间,还有我们自己的服务器……除了S3(云文件存储)。我们的服务器负责验证和同步存储在DynamoDB中的用户日志。
iOS原生应用可以绕过我们的服务器,通过AWS S3 SDK直接上传和下载照片。如果想切换到Flutter,我只能使用到预签名的S3 URL(由AWS通过我们的服务器提供)。这种方法的效果很好。
虽然我感觉移植到Flutter并不会太痛苦,但我认为Flutter如果有AWS SDK插件就会更受欢迎(不一定是正式的插件)。如果说云服务商的收入能大致代表移动应用对于云服务的使用状况,那么AWS就是目前的市场领导者。

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!

我希望能够通过Dart来试验大量的AWS服务。我确信Azure也是如此,尽管我没有使用Azure。

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!
性能

我在Easy Diet Diary上测试Flutter的方法大概是,在屏幕中间显示一个可移动的相机的视口,或者在读取数百个20KB左右的JSON文件后显示图表。
在比较iOS原生版的应用与Flutter版时,我们的测试人员(实际上我们只有一位主要的测试人员)并未在手机上看到明显的性能下降,除了iPhone 6(该应用在6S上运行良好)。iPhone 6于2014年发布,但市场上还有销售,我十几岁的儿子就有一部。我们在其他手机上测试的时候,发现了一些较慢的设备,包括三星Galaxy J5 Pro和摩托罗拉G5S Plus(移植时我的手机)。
刚开始的时候,iPhone 6有点卡,还有一些抖动,特别是移动相机的视口,但随着几个月后新版本的Flutter发布,这种现象逐渐减弱(但没有完全消失)。该应用在其他速度较慢的测试手机上运行良好。
题外话:目前我的个人手机是Pixel 3a,一个Android 10的中档手机。它可以顺畅地运行Easy Diet Diary,而且还具备了Android的开放性和灵活性,同时比我用过的其他Android手机更接近iPhone的体验。这款手机可以很好地适应我希望不断发展跨平台的想法,只是需要更多具备弹性的应用。

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!
原生代码

在移植的过程中,我一直在极力避免原生代码。
然而,在图像处理、HealthKit集成和升级旧用户方面,我做得不够好。
对于HealthKit和升级旧版用户功能,我简单地沿用了iOS的原生Swift和Objective C代码。
对于图像处理,我编写了我的第一个Java代码,应用的用户可以在各种情况下拍照。现代手机拍摄的百万像素照片会占用大量空间,因此我在显示或上传之前进行了裁剪、缩放和压缩,这些处理都需要原生的iOS和Android代码。我找不到适合的插件(特别是能够正确保留EXIF元数据的插件),所以我利用开源的插件、StackOverflow上的解答以及旧的Objective-C代码拼凑了一个自己的解决方案。
按照这个说明(https://flutter.dev/docs/development/packages-and-plugins/developing-packages)编写插件包非常方便。在应用启动运行后,你可以通过配置启动原生代码,并设置断点等。当然,不支持热重载。
我原本希望将这些处理放到一个隔离区,这样它们可以自由地花时间处理和上传图像。但是,没想到我无法从隔离区调用插件代码,所以我只好在原生插件中分出来了一个线程。

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!
跨平台设计

你可以利用Flutter控制应用的原生状态。因为我想为现有用户编写iOS原生应用的替代品,所以我希望这个Flutter应用非常接近原始版本。
首先,我建立了一个Material Design应用。为了让自己沉浸在这个过程中,我把自己原来的iPhone换成了一款中档的Android设备——摩托罗拉G5S Plus——我不想要太高端的东西。
然后,在通过Open Beta流程建立了该应用的管理后,我打算做一个iOS版。如果放到今天,我肯定不会这么做。刚开始时,我选择了一些有iOS风格的小部件。然后,逐步进行扩展,发展到如今已经可以构建同时具备Material Design和iOS风格的应用了,而且还可以根据需要在窗口小部件树中替换小部件。
我不打算在本文中详细介绍我建立跨平台应用的过程。简而言之:
  • 有些看似重大的差异其实很容易实现。例如,因为UI全是小部件树的代码,所以你只需去掉底部标签栏上的Android侧滑菜单,换成iOS的“更多”按钮。

  • 有些小差异非常繁琐。例如,利用相同的代码在两个平台上显示原生的对话框,但是最终还是会有非常细微的差别。也许这不是一个小差异?

在我完成这些工作后,才发现了这个文档:平台特定的行为和修改(https://flutter.dev/docs/resources/platform-adaptations)。多么希望一开始就能看到这个文档!

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!
风格与方案

Flutter的设计旨在通过相同的代码构建可以在多个平台上运行的应用,但是如何在一个平台上通过相同的代码构建多个应用程序呢?
对我而言,我在其上花费的时间远远超出了预期。但最后,我也学习到了很多经验教训。
看起来很简单。Flutter有一个命令行开关(可以通过IDE设置),你可以将构建风格指定成Gradle产品风格或Xcode方案。
flutter build --flavor research

我希望复制原生Xcode项目中设置的内容。在Xcode中,你可以利用方案名称区分应用的版本。方案简单易用,在创建时,你只需告诉Xcode希望使用的配置和目标:

  • 这里的配置是一个普通文本文件,其扩展名为.xcconfig。你可以指定当前应用版本所特有的环境变量。例如,包标识符后缀等。

  • 这里的目标指的是所有构建的设置(可能有几百个)以及构建中包含的类、资源和自定义脚本的列表。每个新的Xcode项目都有一个目标,在Flutter中,它被称为“Runner”。

在原生的iOS应用中,不同版本的应用有不同的目标。大多数人都采用了这种方式。然而,如果你想让Flutter使用不同的目标,那么就要下一番苦功夫了(换句话说,Flutter的多目标几乎能用)。
最后,我得出了与Salvatore Giordano相同的结论,我使用了单个目标并完全依赖于配置。后来,我读到了Matt Thompson撰写的这篇好文(https://nshipster.com/xcconfig/),我就释然了。根据Mattt的说法,只有一个目标的配置文件可以带来以下好处:
  • 你不需要Xcode来管理它们。它们是纯文本,这意味着可以通过源代码控制系统管理他们,而且还可以使用任意编辑器进行修改。

  • 你可以使用它们来设置捆绑包的标识符、应用图标集(供Google服务信息文件使用)等。

此外,由于无法在iOS中使用不同的目标,所以我明白了导致iOS应用各个版本各异的原因,而且也让我感受到配置Android产品风格的简单性。

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!
总结

构建Flutter应用的方式:
  • 它的底层平台有点像metal游戏引擎。

  • 它的小部件树结构支持“热重载”,允许你快速灵活地构建用户界面。

  • 它为Android和iOS提供了一整套原生风格的小部件,可以根据平台在小部件树中轻松替换。

  • 你可以利用它的开源代码库,根据需要调试问题并调整或增强小部件,或者只是尝试各种功能。

上述这些优点都非常棒。
Flutter需要改进的地方(根据我的经验):
  • 更好地支持非Google云服务。就我的情况而言,需要支持亚马逊AWS。

  • 感觉GitHub上有一些关于Flutter的问题更适合放在Stack Overflow上。也许人们认为,那些创造了bug的开发人员(包括我在内)能够更好地回答问题?虽然我不知道如何改善这种情况,但也许这称不上问题?

  • 用更简单、更明确的指令,更顺畅地部署到iOS和Android。创建用户界面的工作很有意思。与Cocoapods和Gradle结合使用,就可以部署到特定平台,也不是特别难。开发人员的专业知识往往会偏向某个平台(比如我更熟悉iOS),因此部署到其他平台可能很困难。所以越简单越好。

  • 更高效的图像显示。iOS原生应用使用的SDWebImage库效果很好。Flutter的cached_network_image库则不太理想。

一点心得:
  • 在使用了多年的TestFlight后,我非常喜欢Google应用商店的Open Betas,我们利用它来让公众测试不断完善的应用。

  • 学习Flutter很有趣。Emily Fortuna在这个视频中解释了Flutter的关键功能(https://www.youtube.com/watch?v=kn0EOS-ZiIc)。

  • Flutter团队非常平易近人,他们在努力打造一个友好而多样化的开源社区。

  • 上周,Ray Wenderlich(一个对我学习iOS不可或缺的网站)推出了Flutter部分!Flutter一定会得到推广。

  • 至于面向Web的Flutter,虽然我很欣赏Flutter和Dart在这方面的独特优势,但我希望Flutter团队不要太过于分散精力,并且可以继续专注于改善Flutter的移动跨平台功能。


程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!
后记

无论SwiftUI或Jetpack Compose多么诱人,大多数公司趋之若鹜的仍然是一个优秀的跨平台移动解决方案。至少,我的经历是这样告诉我的。此外,在构建能够替代一个较大的iOS原生应用之后,我个人的感觉是Flutter值得考虑。
欢迎大家在下面留言。
原文:https://medium.com/flutter-community/finished-porting-a-75-000-line-native-ios-app-to-flutter-b5c0bff93715
作者:Gary Hunter,iOS native & Flutter开发。
本文为 CSDN 翻译,转载请注明来源出处。

【END】

如何少走弯路,利用不同区块链的数据结构实现项目上链?

数据架构是区块链的重要组成部分,了解数据架构,可以让我们对于自身业务是否适合上链做出明智的判断。

9月19日,【dfuse小聚:区块链数据应用讨论会】将在上海举行,dfuse CTO&联合创始人、EOS加拿大联合创始人 Alex Bourget;慢雾科技合伙人兼安全产品负责人启富(Keywolf);MYKET联合创始人/EOS Cannon联合创始人Ricky胖哥,与你一起深度探索区块链应用搭建以及区块链数据结构的奥秘,让你明白到底你的业务该如何上链!

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!

 热 文 推 荐 



点击阅读原文,输入关键词,即可搜索您想要的 CSDN 文章。

你点的每个“在看”,我都认真当成了喜欢

以上是关于Flutter踩坑之旅的主要内容,如果未能解决你的问题,请参考以下文章

程序员踩坑之旅:将 75000 行 iOS 原生代码迁移到 Flutter!

Flutter——实操踩坑:升级Flutter dart

Android Flutter踩坑

Flutter音视频裁剪flutter_ffmpeg踩坑笔记

Flutter 踩坑路由

Flutter开发百度地图,踩坑无数,保姆级教程