使用Flutter解决常见的跨平台问题

使用Flutter解决常见的跨平台问题

时间:2020-6-25 作者:gykj

我在网上看到很多关于Flutter进行Web开发的困惑,而不幸的是,由于错误的原因。

具体而言,人们有时会将其与较早的基于Web的移动(和桌面)跨平台框架相混淆,该框架基本上只是在包装应用程序中运行的浏览器中运行的网页。

从某种意义上说,接口是相同的,这确实是跨平台的,因为您只能访问通常可以在Web上访问的接口。

但是Flutter并不是这样:它可以在每个平台上本机运行,这意味着每个应用程序的运行就像是用Java / Kotlin或Android-iOS上的Objective-C / Swift编写的运行一样。您需要知道这一点,因为这意味着您需要照顾这些非常不同的平台之间的许多差异。

在本文中,我们将看到其中的一些差异以及如何克服它们。更具体地说,我们将讨论存储和UI差异,这是在编写希望跨平台的Flutter代码时,最经常引起开发人员困惑的问题。

示例1:存储

我最近在博客上写道,与移动应用程序相比,在Web应用程序中存储JWT的方法有所不同。

这是因为平台的存储选项的性质不同,并且需要了解每个平台及其本机开发工具。

网页

编写Web应用程序时,您拥有的存储选项是:

  1. 从磁盘下载文件或从磁盘上载文件,这需要用户交互,因此仅适用于打算由用户读取或创建的文件;
  2. 使用cookie,它可以从JS访问或不访问(取决于它们是否为httpOnly),并与请求一起自动发送到给定的域,并在它们作为响应的一部分时被保存;
  3. 使用JS localStoragesessionStorage,可以由网站上的任何JS访问,但只能从该网站页面中的JS访问。

移动

移动应用的情况则完全不同。存储选项如下:

  1. 该应用可访问的本地应用文档或缓存存储;
  2. 用户创建/可读文件的其他本地存储路径;
  3. NSUserDefaultsSharedPreferences分别在iOS和Android上存储键值;
  4. Keychain在iOS和KeyStoreAndroid上分别用于安全存储任何数据和加密密钥。

如果您不知道,那么您将使实现变得一团糟,因为您需要知道实际使用的存储解决方案以及优缺点。

跨平台解决方案:初始方法

使用Flutter shared_preferences软件包可localStorage在Web,SharedPreferencesAndroid和NSUserDefaultsiOS上使用。这些对您的应用程序具有完全不同的含义,尤其是在您存储敏感信息(例如会话令牌)的情况下:localStorage客户端可以读取它,因此如果您容易受到XSS的攻击,那就是一个问题。尽管移动应用是不是真的容易受到XSS,SharedPreferencesNSUserDefaults不是安全的存储方式,因为他们可以在客户端上,因为它们不是安全存储和加密不被破坏。这是因为它们是针对用户首选项的,正如在iOS的情况下提到的和Android文档中在谈论安全性库时提到的那样,安全性库旨在为包装程序提供包装SharedPreferences 专门用于在存储数据之前对其进行加密。

移动安全存储

在移动设备上的唯一安全的存储解决方案Keychain,并KeyStore分别在iOS和Android,而没有在网络上没有安全存储

但是,KeychainKeyStore本质上是非常不同的:Keychain是一种通用凭据存储解决方案,而KeyStore则用于存储(并可以生成)加密密钥(对称密钥或公共/私有密钥)。

这意味着,例如,如果您需要存储会话令牌,则可以在iOS上让OS管理加密部分并将令牌发送到Keychain,而在Android上则需要更多的手动体验,因为您需要生成(不是硬编码,这很不好)密钥,使用它来加密令牌,将加密的令牌存储在中SharedPreferences并将密钥存储在中KeyStore

可以采用不同的方法,就像安全性方面的大多数事情一样,但是最简单的方法可能是使用对称加密,因为您的应用程序既可以加密也可以解密令牌,因此不需要公钥加密。

显然,您不需要编写特定于移动平台的代码即可完成所有这些工作,例如,有一个Flutter插件可以完成所有这些工作。

WEB上缺乏安全存储

实际上,这就是迫使我写这篇文章的原因。我写过有关使用该程序包在移动应用程序上存储JWT的文章,人们希望获得该版本的Web版本,但是正如我所说,Web上没有安全的存储。它不存在。

这是否意味着您的JWT必须公开发布?

一点都不。您可以使用httpOnlycookie,不是吗?JS无法访问这些文件,并且仅将其发送到您的服务器。这样做的问题是,即使您的用户之一在其他人的网站上单击GET请求URL,并且该GET请求具有您或您的用户不喜欢的副作用,也总是将它们发送到您的服务器。这实际上也适用于其他请求类型,只是更加复杂。这就是所谓的“跨站点请求伪造”,而您不希望如此。这是Mozilla的MDN文档中提到的Web安全威胁之一,您可以在其中找到更完整的解释。

有预防方法。实际上,最常见的是有两个令牌:其中一个令牌作为httpOnlycookie 到达客户端,另一个作为响应的一部分。后者必须存储在localStorageCookie 中而不是cookie中,因为我们不希望将其自动发送到服务器。

同时解决

如果同时拥有移动应用程序和网络应用程序怎么办?

可以通过以下两种方式之一来解决:

  1. 使用相同的后端端点,但使用与cookie相关的HTTP标头手动获取和发送cookie;
  2. 创建一个单独的非Web后端终结点,该终结点将生成与Web应用程序使用的任一令牌不同的令牌,然后如果客户端能够提供仅移动令牌,则允许进行常规JWT授权。

在不同的平台上运行不同的代码

现在,让我们看看如何在不同的平台上运行不同的代码,以便能够弥补差异。

创建FLUTTER插件

尤其是为了解决存储问题,一种解决方法是使用插件包:插件提供通用的Dart界面,并且可以在不同平台上运行不同的代码,包括特定于平台的本机Kotlin / Java或Swift / Objective-C代码。开发软件包和插件相当复杂,但是在Web上和其他地方(例如Flutter的书中)都对此进行了解释,包括Flutter的官方文档

例如,对于移动平台,已经有一个安全的存储插件,那就是flutter_secure_storage,您可以在此处找到一个使用示例,但是例如在Web上不起作用。

在另一方面,对于简单的键值存储也工作在网络上,有谷歌开发的第一方所谓的插件包一个跨平台的shared_preferences,它有一个叫做Web相关的组件shared_preferences_web,其用途NSUserDefaultsSharedPreferenceslocalStorage根据不同的平台上。

FLUTTER上的TARGETPLATFORM

导入后package:flutter/foundation.dart,您可以与Theme.of(context).platform以下值进行比较:

  • TargetPlatform.android
  • TargetPlatform.iOS
  • TargetPlatform.linux
  • TargetPlatform.windows
  • TargetPlatform.macOS
  • TargetPlatform.fuchsia

并编写您的函数,以便对于您要支持的每个平台,它们都执行适当的操作。对于下一个平台差异示例(即在不同平台上显示小部件的方式差异),这将特别有用。

特别是对于该用例,还有一个相当流行的flutter_platform_widgets插件,它简化了平台感知的小部件的开发。

示例2:显示相同小部件的方式不同

您不能只编写跨平台代码并假装浏览器,电话,计算机和智能手表是同一回事–除非您希望Android和iOS应用程序成为WebView,并且希望使用Electron构建桌面应用程序。有很多理由不这样做,这并不是说服您使用Flutter之类的框架,而是让应用程序保持原生状态,同时具有所有性能和用户体验优势,同时允许您执行以下操作的目的也不是本文的重点。编写大多数时间在所有平台上都相同的代码。

但是,这需要注意和关注,至少需要了解要支持的平台,其实际本机API以及所有这些方面的基础知识。React Native用户需要更加注意这一点,因为该框架使用内置的OS小部件,因此您实际上需要通过在两个平台上进行广泛的测试来更加关注应用的外观,而无需在两个平台之间进行切换像Flutter一样,可以动态运行iOS和Material小部件。

没有您的要求会发生什么变化

切换平台时,应用程序UI的某些方面会自动更改。本节还提到在这方面Flutter和React Native之间的变化。

在Android和iOS之间(Flutter)

Flutter能够在iOS(和Android上的Cupertino(类似于iOS的)小部件)上渲染“材质”小部件,但是它不做的是在Android和iOS上显示完全相同的内容:材质主题特别适合每个平台的约定。

例如,导航动画,过渡效果和默认字体是不同的,但是它们对您的应用的影响不大。

在美学或用户体验方面,可能会影响您的某些选择的是,某些静态元素也会发生变化。具体来说,这两个平台之间的某些图标会发生变化,iOS上的应用栏标题位于中间,而Android上的应用栏标题则位于左侧(如果有后退按钮或打开抽屉的按钮,则位于可用空间的左侧(在此处说明)在“材料设计指南”中(也称为“汉堡”菜单)。这是带有抽屉的“材料”应用在Android上的外观:

Android应用程序的图像,显​​示应用程序栏标题在Flutter Android Material应用程序上的显示位置
在Android上运行的Material应用程序:AppBar标题位于可用空间的左侧。(大型预览

同样,非常简单的Material应用在iOS上看起来像:

iOS应用程序的图像,显​​示应用程序栏标题在Flutter iOS Material应用程序上的显示位置
在iOS上运行的Material应用程序:AppBar标题位于中间。(大型预览
在手机和网络之间以及带有屏幕凹槽(颤动)

在Web上存在一些不同的情况,正如在有关Flutter的响应式Web开发的Smashing文章中所提到的:尤其是,除了必须针对更大的屏幕进行优化并考虑人们期望浏览您的网站的方式之外, (这是本文的重点),您必须担心有时将小部件放置在浏览器窗口之外的事实。另外,某些手机的屏幕顶部会出现缺口,或者由于某种障碍而妨碍您正确查看应用程序。

通过将小部件包装在小部件中可以避免这两个问题SafeArea,这是一种特殊的填充小部件,可确保您的小部件落入可以实际显示的位置,而不会妨碍用户查看它们的能力。它是硬件还是软件约束。

在REACT NATIVE中

除了要求您至少运行iOS Simulator和Android Emulator以便能够在两个平台上测试您的应用程序之外,React Native还需要更多的关注和对每个平台的更深入的了解。相同,并将其JavaScript UI元素转换为平台特定的小部件。换句话说,您的React Native应用程序将始终看起来像iOS(有时称为Cupertino UI元素),而您的Android应用程序则始终看起来像常规的Material Design Android应用程序,因为它使用的是平台小部件。

区别在于Flutter使用其自己的低级渲染引擎来渲染其小部件,这意味着您可以在一个平台上测试这两个应用程序版本。

解决这个问题

除非您要进行非常具体的操作,否则您的应用在不同平台上的外观应该有所不同,否则某些用户会感到不满意。

就像您不应该简单地将移动应用程序发布到网络上(就像我在前面的Smashing帖子中所写的那样)一样,您也不应该将包含Cupertino小部件的应用程序发布给Android用户,例如,因为它会使用户感到困惑大部分。另一方面,有机会实际运行包含用于其他平台的小部件的应用程序,则可以测试该应用程序并将其显示给两个版本的用户,而不必为此使用两个设备。

另一面:出于正确的原因使用错误的小部件

但这也意味着您可以在Linux或Windows工作站上进行大部分Flutter开发,而无需牺牲iOS用户的体验,然后只需为其他平台构建应用程序,而不必担心对其进行全面测试。

下一步

跨平台框架很棒,但是它们将责任转移给了您(开发人员),以了解每个平台的工作方式以及如何确保您的应用程序适应并为用户带来愉悦的使用体验。如果要考虑的其他小问题,例如,如果在不同的平台上存在不同的约定,则对于本质上相同的事物可能使用不同的描述。

不必使用不同的语言分别构建两个(或多个)应用程序是很高兴的,但是从本质上讲,您仍然需要牢记要构建多个应用程序,这需要考虑要构建的每个应用程序。

版权所有:https://www.eraycloud.com 转载请注明出处