跳至主要内容

功能与政策

大多数现实世界的应用程序都需要适应不同设备和平台的功能和策略。此页面包含有关如何在代码中处理这些场景的建议。

针对每种设备类型的优势进行设计

#

考虑不同设备的独特优势和劣势。除了屏幕尺寸和输入(如触摸、鼠标、键盘)之外,您还可以利用哪些其他独特功能?Flutter 使您的代码能够在不同的设备上运行,但强大的设计不仅仅是运行代码。考虑每个平台最擅长的方面,并查看是否有独特的功能可以利用。

例如:Apple 的 App Store 和 Google 的 Play Store 有不同的规则,应用程序需要遵守这些规则。不同的主机操作系统在时间上以及彼此之间也具有不同的功能。

另一个示例是利用 Web 极低的共享障碍。如果您要部署 Web 应用程序,请确定要支持哪些深层链接,并以此为基础设计导航路由。

Flutter 建议的用于根据这些独特功能处理不同行为的模式是为您的应用程序创建一组CapabilityPolicy类。

功能

#

功能定义代码或设备可以做什么。功能的示例包括

  • API 的存在
  • 操作系统强制执行的限制
  • 物理硬件要求(如摄像头)

策略

#

策略定义代码应该做什么。

策略的示例包括

  • 应用商店指南
  • 设计偏好
  • 引用主机设备的资源或副本
  • 服务器端启用的功能

如何构建策略代码

#

最简单的机械方法是Platform.isAndroidPlatform.isIOSkIsWeb。这些 API 可以机械地让您知道代码在哪里运行,但在应用程序扩展到可以运行的位置以及主机平台添加功能时存在一些问题。

以下指南说明了开发应用程序的功能和策略时的最佳实践

避免使用Platform.isAndroid和类似函数来做出布局决策或假设设备可以做什么。

相反,在方法中描述您想要分支的内容。

示例:您的应用程序有一个在网站上购买商品的链接,但出于策略原因,您不想在 iOS 设备上显示该链接。

dart
bool shouldAllowPurchaseClick() {
  // Banned by Apple App Store guidelines. 
  return !Platform.isIOS;
}

...
TextSpan(
  text: 'Buy in browser',
  style: new TextStyle(color: Colors.blue),
  recognizer: shouldAllowPurchaseClick ? TapGestureRecognizer()
    ..onTap = () { launch('<some url>') : null;
  } : null,

通过添加额外的间接层获得了什么?代码使分支路径存在的原因更加清晰。此方法可以直接存在于类中,但代码的其他部分可能也需要相同的检查。如果是这样,请将代码放在一个类中。

policy.dart
dart

class Policy {

  bool shouldAllowPurchaseClick() {
    // Banned by Apple App Store guidelines. 
    return !Platform.isIOS;
  }
}

通过将此代码放在一个类中,任何 widget 测试都可以模拟Policy().shouldAllowPurchaseClick并独立于设备运行位置验证行为。这也意味着,以后如果您决定在 Web 上购买不是 Android 用户的正确流程,则可以更改实现,并且可点击文本的测试无需更改。

功能

#

有时您希望代码执行某些操作,但 API 不存在,或者您可能依赖于尚未在您支持的所有平台上实现的插件功能。这是设备可以做什么的限制。

这些情况类似于上面描述的策略决策,但这些被称为功能。当类的结构相似时,为什么要将策略类与功能分开?Flutter 团队发现,在生产环境的应用程序中,在应用程序可以做什么和应该做什么之间进行逻辑区分有助于大型产品响应平台可以做什么或需要什么的变化,以及在编写初始代码后您自己的偏好。

例如,考虑以下情况:一个平台添加了一个新的权限,该权限要求用户在代码调用敏感 API 之前与系统对话框进行交互。您的团队为平台 1 完成了这项工作,并创建了一个名为requirePermissionDialogFlow的功能。然后,如果平台 2 添加了类似的要求,但仅适用于新的 API 版本,则requirePermissionDialogFlow的实现现在可以检查 API 级别并针对平台 2 返回 true。您已经利用了您已经完成的工作。

策略

#

我们建议最初从Policy类开始,即使看起来您不会做出很多基于策略的决策。随着类的复杂性或输入数量的增加,您可能决定按功能或其他一些标准分解策略类。

对于策略实现,您可以使用编译时、运行时或远程过程调用 (RPC) 支持的实现。

编译时策略检查适用于平台偏好不太可能更改并且意外更改值可能会产生重大后果的情况。例如,如果平台要求您不要链接到 Play 商店,或者要求您根据应用程序的内容使用特定的支付提供商。

运行时检查可以用于确定用户是否可以使用触摸屏。Android 具有您可以检查的功能,并且您的 Web 实现可以检查最大触点数。

RPC 支持的策略更改适用于增量功能推出或以后可能会更改的决策。

总结

#

使用Capability类定义代码可以做什么。您可以根据 API 的存在、操作系统强制执行的限制和物理硬件要求(如摄像头)进行检查。功能通常涉及编译或运行时检查。

使用Policy类(或根据复杂性使用多个类)定义代码应该做什么以符合应用商店指南、设计偏好以及需要引用主机设备的资源或副本。策略可以是编译、运行时或 RPC 检查的组合。

通过模拟功能和策略来测试分支代码,这样当功能或策略更改时,widget 测试就不需要更改。

根据功能和策略类中尝试分支的内容为方法命名,而不是根据设备类型命名。