外观
平台集成与 Web 适配
共享业务,显式处理差异
布局、数据模型和大部分业务逻辑可以共享,但权限、文件路径、相机、通知和窗口行为需要按平台验证。先定义应用需要的能力,再选择插件或自己实现适配层。
| 需求 | 起点 | 需要验证 |
|---|---|---|
| 常见原生能力 | 支持目标平台的插件 | 平台矩阵、最低版本、权限、失败行为 |
| 调用少量原生方法 | MethodChannel | 方法名、参数、编解码和错误约定 |
| 连续的原生事件 | EventChannel | 订阅、取消、线程和资源释放 |
| 较多类型化接口 | Pigeon 代码生成 | 两侧生成代码与接口版本一致 |
| 调用 C ABI 库 | Dart FFI | 内存所有权、库分发及平台限制 |
平台通道通过消息连接 Dart 与宿主代码,调用通常以异步形式返回,但不意味着原生处理自动运行在后台线程。线程规则和接入步骤参见 官方平台通道指南。
示例:给原生能力加一道边界
下面只展示 Dart 侧适配层。它不会自动获得设备能力:必须在 Android / iOS 宿主实现同名通道和方法,或改用已经提供该能力的插件。
dart
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
class BatteryService {
static const _channel = MethodChannel('notes/device');
Future<int?> readLevel() async {
if (kIsWeb) return null;
try {
final level = await _channel.invokeMethod<int>('getBatteryLevel');
if (level == null || level < 0 || level > 100) return null;
return level;
} on MissingPluginException {
return null;
} on PlatformException {
return null;
}
}
}界面把 null 展示为「暂不支持读取电量」,不要误写成 0%。真实业务可将不支持、权限拒绝和运行失败拆成不同结果,供 UI 决定是否重试。增加或修改宿主实现后,需要重新构建应用。
Web 适配检查
编译与能力支持
kIsWeb 能帮助运行时分支判断,但不能修复不兼容的 import。共享文件直接导入 dart:io 或仅原生支持的库,仍可能让 Web 构建失败;用条件导入或独立实现文件隔离平台代码。
引入文件、数据库或安全存储包时,检查它的 Web 实现是否可用以及语义是否相同。不要假设移动端的绝对文件路径在浏览器中也存在。
网络与导航
浏览器请求受跨域策略约束,服务端需要配置允许的来源;HTTPS 页面调用 HTTP 接口还可能受到混合内容限制。这类问题应从请求地址和服务端配置定位。
需要可分享的详情链接时,使用能同步浏览器地址的路由方案,并测试直接打开详情 URL、刷新和前进后退。采用 path URL 时,静态托管要将应用路由回退到入口文件,同时保留静态资源的正常响应。见 路由笔记 与 官方 Web 发布指南。
输入与布局
按窗口宽度检查内容,而不是仅区分「手机」和「电脑」。测试鼠标悬停、键盘 Tab、焦点提示、滚轮、文本选择和较大字体,避免只有触屏手势能触达功能。
练习与验收
sh
flutter run -d chrome
flutter build web在本地静态服务器中验证 build/web 产物,再对照移动端执行同一条主流程。记录每个能力的平台支持和降级文案,确认不支持的能力不会让整个页面崩溃。