# 先看设备能力，再选应用平台

原文: https://yishto.com/learn/application-platforms/choose-runtime-and-platform/

作者: [Yishto](https://yishto.com/about/)

以离线资料阅读器为例，把文件访问、通知、后台下载和分发渠道拆成可验证条件，再选择运行时与平台。

首次发布: 2026-11-10
内容更新: 2026-11-10

一个离线资料阅读器要让用户导入文件、保存阅读位置，并在没有网络时继续阅读。页面看起来相似，运行环境却会决定文件从哪里来、程序暂停后还能做什么，以及更新怎样送到用户设备。选型应从这些动作开始。

本课用三份合成资料作为测试输入：短文本、带图片的文档和无法识别的文件。先限定为个人设备上的阅读工具，暂不引入团队协作、付费或模型服务。这样的边界能把平台差异与业务功能分开检查。

## 把需求改写成设备上的动作

“支持离线”需要拆成首次下载、保存成功、断网打开、进程退出后重开四个动作。只在当前页面缓存了内容，重启就丢失，不符合这里的要求。导入文件也要说明是用户通过选择器选一个文件，还是应用持续扫描某个目录；两者需要的权限和平台能力不同。

给每个动作写验收条件。导入成功后应显示资料标题和存储状态；取消选择器不应产生空记录；保存位置后关闭应用，重开仍定位到同一段落。对通知，要说明它只是提醒打开资料，还是要求在锁屏后按计划执行下载。后一种需求涉及操作系统对后台工作的调度，不能用一个常驻计时器代替。

将需求分为硬条件与偏好。必须持续访问指定目录，可以排除无法满足这一条件的目标环境；“开发者熟悉 JavaScript”只是降低学习成本的偏好。硬条件不能被漂亮的界面或较高总分抵消。尚未测试的能力记为未知，不要直接标成支持。

## 语言、框架与运行时分别负责什么

Swift 和 Kotlin 是语言，SwiftUI 和 Compose 是 UI 框架。它们各自依赖目标系统的工程、构建和运行约束。Dart 的 Flutter 应用共享较多界面与业务代码，但插件、系统权限和平台包仍要分别检查。不能因为都能写按钮，就把这些环境视为可以任意交换。

网页通过浏览器运行，PWA 增加安装、缓存等能力，具体支持随浏览器和操作系统变化。Electron 将 Chromium 与 Node.js 的能力组织进桌面应用，需要处理进程权限和更新维护。共享代码减少重复实现，但不会自动消除设备权限、输入方式和发布流程的差别。

阅读器可以共用资料 ID、阅读位置和错误码等契约。文件选择器、持久化位置、通知授权则封装成平台适配器。这样平台差异进入明确接口，页面无需到处判断系统名称；也便于用假实现先验证业务流程。

## 用能力表筛选，再做偏好比较

先建立一张表，每一行对应“退出后还能读”“用户选文件”“后台恢复下载”“指定渠道安装”等动作。列出目标设备和系统版本，填写已证实、未证实或不满足，并链接到官方说明和自己的测试记录。官方概览说明有某类能力，不等于每个目标浏览器都具备。

下面的离线 Python 例子只演示硬条件过滤。`device_api` 是虚构需求名称，`False` 是本次假设，不是对整个 Web 平台的能力判断。把实际调查结果放入同样的结构之前，应先定义该字段到底表示哪一个设备操作。

```python
options = {"web": {"offline": True, "device_api": False},
           "native": {"offline": True, "device_api": True}}
required = {"offline", "device_api"}
eligible = [name for name, capabilities in options.items()
            if all(capabilities.get(key, False) for key in required)]
assert eligible == ["native"]
print(eligible)
```

输出 `['native']`：两个候选都有离线字段，只有第二个满足此处假定的设备接口条件。断言检查筛选逻辑，没有运行浏览器、原生构建或设备接口，也不能推出原生应用在任何项目中都更合适。

## 做一个真正的能力验证工程

从候选平台的官方入门工程开始，记录工具链版本和最低目标系统。只实现导入按钮、资料列表、正文和恢复阅读位置。资料仓库负责解析及保存，页面只接收列表、选中 ID 和错误。先用合成文件运行，再替换为用户明确选择的文件。

按顺序检查：首次启动没有资料时显示空状态；导入后等待保存完成；进入飞行模式阅读；强制退出再打开；重新连接网络后恢复未完成任务。每一步截图或记录观察值。若平台只允许用户主动挑选文件，而需求要求自动扫描，就在这里停止该候选的评估，避免先实现完整页面才发现缺口。

后台能力另做小实验。记录程序进入后台、系统暂停、重新打开时任务的状态，验证暂停后能从持久记录继续。操作系统没有保证的执行时机不要写进产品承诺。能恢复任务，也不意味着能在任意时间持续运行。

## 成本与失败路径进入决策

比较候选时，将构建环境、包分发、权限说明、平台升级和插件维护计入成本。通过 URL 使用的工具与需要安装包的工具拥有不同更新路径；面向两个移动系统的共享代码工程仍有两个需要验收的产物。这里不估算通用费用或审核周期，因为它们取决于渠道和当前政策。

阅读器的错误也影响选型。文件格式不支持应保留原文件并报告原因；空间不足时不把记录标成可离线；下载中断保留任务 ID 和完成部分的有效性信息。删除本地副本与删除资料索引是不同操作，界面要分别命名，避免用户误以为内容已经被安全保存。

记录每个未知项的下一步：查具体 API 可用性，补真机测试，或者收窄需求。不要把未知项藏在总分里。加权评分只能表达这次项目的偏好，权重和分数来自你的假设，不能当作行业客观排名。

## 练习：写出可复核的选型结论

选择两个候选平台，给阅读器列出至少六个设备动作。为每个硬条件设计最小实验，并在表中记录目标系统、操作步骤、实际现象与限制。如果只能在模拟器完成，注明真机项仍未验证。

验收时让另一位读者只按记录操作，能够复现断网重启阅读、取消导入和下载失败后的恢复。结论应说明所选平台满足哪些必需动作、哪些功能被延后，以及未解决项会阻止哪一种发布。下一阶段再扩展搜索和同步，避免用功能数量掩盖运行环境的约束。

## 资料来源与延伸阅读

- [Progressive web applications](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps)
- [Flutter architectural overview](https://docs.flutter.dev/resources/architectural-overview)
- [Electron process model](https://www.electronjs.org/docs/latest/tutorial/process-model)
- [SwiftUI application structure](https://developer.apple.com/documentation/swiftui)
- [Compose state and architecture](https://developer.android.com/develop/ui/compose/state)

资料核验：2026-11-10。教学示例不代表线上实测。

## 相关文章

- [把需求变成能验证的原型和界面](https://yishto.com/learn/product-building/prototypes-design-systems-and-assets/)
- [从容器到集群，哪些责任发生了变化](https://yishto.com/learn/delivery/containers-orchestration-and-iac/)
