9.3 多端支持

Flutter 支持 Android、iOS、Web、桌面(Windows/macOS/Linux)多个平台从同一代码库构建。了解各端差异与适配策略是多端开发的关键。


一、Flutter Desktop

1.1 启用桌面支持

bash 复制代码
flutter config --enable-windows-desktop
flutter config --enable-macos-desktop
flutter config --enable-linux-desktop

flutter run -d macos
flutter run -d windows
flutter build macos --release

1.2 Window Manager(窗口管理)

yaml 复制代码
dependencies:
  window_manager: ^0.3.9
dart 复制代码
import 'package:window_manager/window_manager.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await windowManager.ensureInitialized();

  // 配置窗口
  await windowManager.waitUntilReadyToShow(
    const WindowOptions(
      size: Size(1200, 800),
      minimumSize: Size(800, 600),
      center: true,
      backgroundColor: Colors.transparent,
      skipTaskbar: false,
      titleBarStyle: TitleBarStyle.hidden, // 隐藏原生标题栏
    ),
    () async {
      await windowManager.show();
      await windowManager.focus();
    },
  );

  runApp(const DesktopApp());
}

// 自定义标题栏
class CustomTitleBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanStart: (_) => windowManager.startDragging(), // 拖拽移动窗口
      child: Container(
        height: 40,
        color: Theme.of(context).colorScheme.surface,
        child: Row(
          children: [
            const Expanded(child: Text('My Desktop App')),
            // 窗口控制按钮
            WindowControlButton(icon: Icons.minimize, onTap: windowManager.minimize),
            WindowControlButton(icon: Icons.crop_square, onTap: windowManager.maximize),
            WindowControlButton(icon: Icons.close, onTap: windowManager.close),
          ],
        ),
      ),
    );
  }
}

1.3 平台自适应布局

dart 复制代码
class AdaptiveLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    if (Platform.isWindows || Platform.isMacOS || Platform.isLinux) {
      // 桌面布局:侧边栏 + 主内容区
      return Row(
        children: [
          SizedBox(width: 250, child: DesktopSidebar()),
          Expanded(child: MainContent()),
        ],
      );
    }
    // 移动端布局
    return MobileLayout();
  }
}

二、Flutter Web

2.1 启用 Web 支持

bash 复制代码
flutter config --enable-web
flutter run -d chrome
flutter build web --release

2.2 Web 渲染器选择

bash 复制代码
# Canvaskit 渲染(基于 WASM,像素级一致,包体较大)
flutter build web --web-renderer canvaskit

# HTML 渲染(基于浏览器 API,包体小,兼容性好)
flutter build web --web-renderer html

# Auto(手机 html,桌面 canvaskit)
flutter build web --web-renderer auto

2.3 Web 特有适配

dart 复制代码
// 检测平台
import 'package:flutter/foundation.dart' show kIsWeb;
import 'dart:io' show Platform;

bool get isWeb => kIsWeb;
bool get isMobile => !kIsWeb && (Platform.isAndroid || Platform.isIOS);
bool get isDesktop => !kIsWeb && (Platform.isWindows || Platform.isMacOS || Platform.isLinux);

// Web URL 策略
void main() {
  usePathUrlStrategy(); // 使用路径 URL(去掉 #)
  runApp(const MyApp());
}

// SEO 元标签(web/index.html)
// <meta name="description" content="My Flutter Web App">
// <meta property="og:title" content="My App">

三、平台视图(PlatformView)

3.1 AndroidView

将 Android 原生 View 嵌入 Flutter:

dart 复制代码
// 使用 AndroidView 嵌入 Google Maps
Widget build(BuildContext context) {
  return Platform.isAndroid
      ? AndroidView(
          viewType: 'google_map_view',
          onPlatformViewCreated: _onViewCreated,
          layoutDirection: TextDirection.ltr,
        )
      : const Text('Android only');
}

// Android 侧注册 View Factory
// FlutterActivity 中
flutterEngine.platformViewsController.registry.registerViewFactory(
    "google_map_view",
    { id -> GoogleMapView(context, id) }
)

3.2 UiKitView(iOS)

dart 复制代码
Widget build(BuildContext context) {
  return Platform.isIOS
      ? UiKitView(
          viewType: 'ios_map_view',
          onPlatformViewCreated: _onViewCreated,
        )
      : const SizedBox.shrink();
}

注意: PlatformView 性能开销较大,仅在无 Flutter 替代方案时使用。


四、平台检测工具

dart 复制代码
class PlatformUtils {
  static bool get isDesktop =>
      !kIsWeb && (Platform.isWindows || Platform.isMacOS || Platform.isLinux);

  static bool get isMobile =>
      !kIsWeb && (Platform.isAndroid || Platform.isIOS);

  static bool get isWeb => kIsWeb;

  // 屏幕类型
  static ScreenSize getScreenSize(BuildContext context) {
    final width = MediaQuery.of(context).size.width;
    if (width < 600) return ScreenSize.compact;       // 手机
    if (width < 1200) return ScreenSize.medium;       // 平板
    return ScreenSize.expanded;                        // 桌面
  }
}

enum ScreenSize { compact, medium, expanded }

小结

平台 状态 主要适配点
Android / iOS ✅ 稳定 原生特性调用
Web ✅ 稳定 URL 策略、SEO、渲染器选择
macOS ✅ 稳定 窗口管理、菜单栏
Windows ✅ 稳定 窗口管理、系统托盘
Linux ✅ 稳定 GTK 适配

👉 下一章:十、测试与发布

相关推荐
woodWu13 小时前
Flutter 复杂拖拽排序实战:同源排序 + 跨容器拖拽完整落地
flutter
小小小小小鹿13 小时前
Vibe Coding 实战:Flutter 自定义路径布局
flutter·vibecoding
程序员老刘17 小时前
Dart 3.12 更新要点:乏善可陈
flutter·ai编程·dart
●VON17 小时前
鸿蒙Flutter实战:水平滑动分类标签筛选栏
flutter·华为·harmonyos
●VON19 小时前
鸿蒙Flutter实战:24小时新建标签提示组件
android·flutter·华为·harmonyos·鸿蒙
●VON20 小时前
鸿蒙Flutter实战:MultiProvider多状态管理架构实践
flutter·华为·架构·harmonyos·鸿蒙
●VON21 小时前
鸿蒙Flutter实战:放弃sqflite选纯Dart JSON文件存储
flutter·华为·json·harmonyos·鸿蒙
J船长1 天前
把该死的Provider再讲一遍
flutter
Fansi1 天前
看着无解的 UI,其实只是没拆够 —— 以"凹角卡片"为例
flutter