欢迎加入开源鸿蒙跨平台开发者社区:https://openharmonycrossplatform.csdn.net


摘要

在 Flutter 开发 OpenHarmony 应用过程中,启动页 + 新手引导页是几乎所有 App 的标配基础功能。本文基于 Flutter 框架,搭配已完成鸿蒙适配的三方库,从零手把手实现 App 冷启动白屏优化、自定义全屏启动页、轮播引导页、首次安装进入引导页、非首次直接跳转主页完整逻辑。操作步骤清晰、代码可直接复用、适配鸿蒙平台无白屏无崩溃,适合作为 Flutter 鸿蒙应用开发入门实战案例,全程使用鸿蒙化三方库,无任何未适配依赖,可直接在 OpenHarmony 设备编译运行。

一、项目实现功能

  • 自定义 Flutter 全屏启动页,优化鸿蒙原生冷启动白屏问题

  • 新手 3 页轮播引导页,支持左右滑动、页面指示器切换

  • 基于鸿蒙化三方库实现本地持久化存储,标记 App 是否首次打开

  • 首次安装打开:启动页(延时2秒)→ 引导页

  • 非首次打开:启动页(延时2秒)→ 直接进入主页

  • 全部依赖使用 OpenHarmony 已适配三方库,无编译报错、无运行崩溃

  • 界面自适应鸿蒙设备屏幕,兼容手机、平板等鸿蒙终端

二、技术选型与鸿蒙化三方库

所有依赖均来自 OpenHarmony TPC Flutter 生态仓库,已完成鸿蒙化适配,可安全用于鸿蒙应用开发,无需额外适配操作,直接调用即可:

三方库 作用 鸿蒙适配状态
flutter 跨平台 UI 框架,实现页面渲染与交互 ✅ 官方支持,兼容 OpenHarmony
provider 全局状态管理,管理启动页、引导页跳转逻辑与本地存储状态 ✅ 已鸿蒙化,稳定运行无异常
shared_preferences 本地轻量持久化存储,标记 App 是否首次打开,重启后状态不丢失 ✅ 已鸿蒙化,适配鸿蒙存储机制

三、开发环境要求

确保环境配置符合以下要求,避免编译报错,全程可顺利跟着操作:

  • Flutter SDK:3.10 及以上稳定版(推荐使用 Flutter-OpenHarmony 定制版,支持鸿蒙编译)

  • 开发工具:VS Code 或 Android Studio(安装 Flutter 插件)

  • 鸿蒙运行环境:DevEco Studio(用于连接鸿蒙模拟器/真机运行)

  • 项目路径:纯英文、无中文、无空格、无特殊字符(避免 hvigor、ohpm 编译报错)

四、创建项目与配置依赖

4.1 创建 Flutter 项目

打开终端,执行以下命令创建项目(复制粘贴即可,无需修改):

flutter create splash_guide_app
cd splash_guide_app

4.2 配置 pubspec.yaml 依赖

打开项目根目录下的 pubspec\.yaml 文件,在 dependencies 节点下添加鸿蒙化三方库依赖,完整配置如下:

dependencies:
  flutter:
    sdk: flutter

  # 鸿蒙化三方库(已适配 OpenHarmony)
  provider: ^6.1.2
  shared_preferences: ^2.2.3

添加完成后,在终端执行以下命令安装依赖:

flutter pub get

等待依赖安装完成,无报错即配置成功。

五、全局状态管理封装(核心逻辑)

新建 lib/app\_provider\.dart 文件,用于管理 App 启动状态、首次打开标记,兼容鸿蒙环境,增加异常捕获避免白屏:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class AppProvider extends ChangeNotifier {
  bool _isFirstOpen = true; // 是否首次打开 App
  bool _splashEnd = false; // 启动页是否结束

  // 对外提供获取状态的方法
  bool get isFirstOpen => _isFirstOpen;
  bool get splashEnd => _splashEnd;

  // 初始化 App 状态(读取本地存储,判断是否首次打开)
  Future<void> initAppFlag() async {
    try {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      // 读取本地存储的标记,默认是首次打开(true)
      _isFirstOpen = prefs.getBool("isFirstOpen") ?? true;
    } catch (e) {
      // 鸿蒙环境存储初始化异常时,默认视为首次打开
      _isFirstOpen = true;
      debugPrint("鸿蒙存储初始化异常:$e");
    }
    // 模拟启动页延时 2 秒(可根据需求调整)
    await Future.delayed(const Duration(seconds: 2));
    _splashEnd = true; // 标记启动页结束
    notifyListeners(); // 通知页面更新状态
  }

  // 进入主页后,标记为非首次打开(写入本地存储)
  Future<void> setNotFirst() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setBool("isFirstOpen", false);
    _isFirstOpen = false;
    notifyListeners();
  }
}

六、自定义启动页页面(优化鸿蒙白屏)

新建 lib/splash\_page\.dart 文件,实现全屏启动页,优化鸿蒙原生冷启动白屏问题,界面简洁美观,可直接复用:

import 'package:flutter/material.dart';

class SplashPage extends StatelessWidget {
  const SplashPage({super.key});

  
  Widget build(BuildContext context) {
    // 全屏启动页,背景色可根据需求修改
    return Scaffold(
      backgroundColor: Colors.blueAccent,
      body: SizedBox.expand(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: const [
            // 启动页图标(可替换为自己的 App 图标)
            Icon(Icons.android, size: 100, color: Colors.white),
            SizedBox(height: 20),
            // 启动页文字
            Text(
              "鸿蒙 Flutter 应用",
              style: TextStyle(fontSize: 24, color: Colors.white, fontWeight: FontWeight.w500),
            ),
            SizedBox(height: 30),
            // 加载指示器
            CircularProgressIndicator(color: Colors.white, strokeWidth: 3),
          ],
        ),
      ),
    );
  }
}

七、轮播引导页实现(新手引导)

新建 lib/guide\_page\.dart 文件,实现 3 页轮播引导页,支持左右滑动、页面指示器、下一页/开始使用按钮,逻辑完整:

import 'package:flutter/material.dart';
import 'app_provider.dart';
import 'package:provider/provider.dart';

class GuidePage extends StatefulWidget {
  const GuidePage({super.key});

  
  State<GuidePage> createState() => _GuidePageState();
}

class _GuidePageState extends State<GuidePage> {
  final PageController _pageCtrl = PageController(); // 页面控制器,控制轮播
  int _currentIndex = 0; // 当前引导页索引

  // 引导页数据(可根据需求修改文字和图标)
  final List<Map<String, dynamic>> _guideList = [
    {"title": "高性能跨平台", "desc": "Flutter 一套代码,多端运行", "icon": Icons.speed},
    {"title": "完美适配鸿蒙", "desc": "兼容所有 OpenHarmony 设备", "icon": Icons.device_hub},
    {"title": "开启全新体验", "desc": "简单操作,高效便捷", "icon": Icons.emoji_emotions},
  ];

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          // 引导页轮播区域
          Expanded(
            child: PageView.builder(
              controller: _pageCtrl,
              itemCount: _guideList.length,
              onPageChanged: (index) {
                // 页面切换时,更新当前索引
                setState(() => _currentIndex = index);
              },
              itemBuilder: (ctx, index) {
                // 构建每一页引导页
                return Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Icon(
                        _guideList[index]["icon"],
                        size: 120,
                        color: Colors.blue,
                      ),
                      const SizedBox(height: 30),
                      Text(
                        _guideList[index]["title"],
                        style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
                      ),
                      const SizedBox(height: 15),
                      Text(
                        _guideList[index]["desc"],
                        style: const TextStyle(fontSize: 16, color: Colors.grey),
                      ),
                    ],
                  ),
                );
              },
            ),
          ),
          // 底部指示器 + 按钮区域
          Padding(
            padding: const EdgeInsets.all(30),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                // 圆点指示器(根据引导页数量动态生成)
                Row(
                  children: List.generate(_guideList.length, (index) {
                    return Container(
                      margin: const EdgeInsets.symmetric(horizontal: 4),
                      width: _currentIndex == index ? 12 : 8,
                      height: 8,
                      decoration: BoxDecoration(
                        color: _currentIndex == index ? Colors.blue : Colors.grey[300],
                        borderRadius: BorderRadius.circular(4),
                      ),
                    );
                  }),
                ),
                // 跳过/下一页/开始使用按钮
                ElevatedButton(
                  onPressed: () async {
                    if (_currentIndex == _guideList.length - 1) {
                      // 最后一页,点击「开始使用」,标记非首次,跳转主页
                      await Provider.of<AppProvider>(context, listen: false)
                          .setNotFirst();
                      Navigator.pushReplacementNamed(context, "/home");
                    } else {
                      // 非最后一页,点击「下一页」,跳转到下一页引导页
                      _pageCtrl.nextPage(
                        duration: const Duration(milliseconds: 300),
                        curve: Curves.easeInOut,
                      );
                    }
                  },
                  style: ElevatedButton.styleFrom(
                    padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
                    borderRadius: BorderRadius.circular(30),
                  ),
                  child: Text(
                    _currentIndex == _guideList.length - 1 ? "开始使用" : "下一页",
                    style: const TextStyle(fontSize: 16),
                  ),
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}

八、主页简单示例(可直接扩展)

新建 lib/home\_page\.dart 文件,实现主页基础布局,无语法错误,可根据实际需求扩展功能:

import 'package:flutter/material.dart';

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("App 首页"),
        centerTitle: true,
        backgroundColor: Colors.blueAccent,
      ),
      body: const Center(
        child: Text(
          "欢迎使用 Flutter 鸿蒙应用",
          style: TextStyle(fontSize: 20, color: Colors.black87),
        ),
      ),
    );
  }
}

九、主入口整合路由逻辑(核心跳转)

修改 lib/main\.dart 文件,整合路由分发、状态管理,实现启动页、引导页、主页的自动跳转逻辑,兼容鸿蒙环境,无白屏:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'app_provider.dart';
import 'splash_page.dart';
import 'guide_page.dart';
import 'home_page.dart';

void main() {
  // 确保 Flutter 初始化完成,避免鸿蒙环境下白屏
  WidgetsFlutterBinding.ensureInitialized();
  runApp(
    // 提供全局状态管理
    ChangeNotifierProvider(
      create: (context) => AppProvider(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "鸿蒙启动页与引导页",
      debugShowCheckedModeBanner: false, // 隐藏调试横幅
      initialRoute: "/", // 初始路由
      routes: {
        "/": (ctx) => const RouteSwitchPage(), // 路由分发页
        "/guide": (ctx) => const GuidePage(), // 引导页
        "/home": (ctx) => const HomePage(), // 主页
      },
    );
  }
}

// 路由逻辑分发页:根据启动状态和首次打开标记,跳转对应页面
class RouteSwitchPage extends StatefulWidget {
  const RouteSwitchPage({super.key});

  
  State<RouteSwitchPage> createState() => _RouteSwitchPageState();
}

class _RouteSwitchPageState extends State<RouteSwitchPage> {
  
  void initState() {
    super.initState();
    // 页面渲染完成后,初始化 App 状态(避免阻塞 UI 导致白屏)
    WidgetsBinding.instance.addPostFrameCallback((_) {
      Provider.of<AppProvider>(context, listen: false).initAppFlag();
    });
  }

  
  Widget build(BuildContext context) {
    // 监听状态变化,动态切换页面
    return Consumer<AppProvider>(
      builder: (ctx, appProvider, child) {
        // 启动页未结束,一直显示启动页
        if (!appProvider.splashEnd) {
          return const SplashPage();
        }
        // 启动页结束,判断是否首次打开:首次→引导页,非首次→主页
        return appProvider.isFirstOpen ? const GuidePage() : const HomePage();
      },
    );
  }
}

十、项目运行

完整逻辑效果

  1. 首次安装打开 App:展示 2 秒启动页 → 自动进入引导轮播页
    在这里插入图片描述

  2. 引导页可左右滑动,点击「下一页」切换页面,最后一页点击「开始使用」
    在这里插入图片描述

  3. 点击「开始使用」后,标记为非首次打开,自动跳转至主页

  4. 第二次及以后打开 App:启动页展示 2 秒 → 直接进入主页,不再显示引导页

  5. 重启 App 后,本地存储的「非首次打开」标记不丢失,逻辑正常

10.3 鸿蒙适配核心要点(必看)

  • 三方库适配:所有使用的 provider、shared_preferences 均为鸿蒙已适配库,无未适配依赖,避免编译报错

  • 白屏优化:本地存储初始化增加 try-catch 异常捕获,避免鸿蒙环境下存储初始化失败导致白屏

  • 生命周期安全:使用 WidgetsBinding.instance.addPostFrameCallback 执行初始化,避免阻塞 UI 线程

  • 路径规范:项目路径严格为纯英文,避免 hvigor、ohpm 编译时出现文件找不到、路径错误

  • 兼容性:界面使用自适应布局,兼容不同尺寸的鸿蒙设备(手机、平板)

十一、常见问题与解决方案(避坑指南)

开发过程中遇到的常见报错,对应解决方案如下,可直接参考:

问题现象 原因分析 解决方案
鸿蒙启动白屏 异步存储初始化阻塞 UI 线程,或未做异常捕获 在 initAppFlag 方法中增加 try-catch 捕获异常,使用 addPostFrameCallback 延后初始化
引导页不跳转、按钮点击无反应 页面生命周期时机不对,未正确获取 Provider 状态 确保 Provider 全局注册,点击事件中使用 listen: false 获取 Provider
第二次打开仍进入引导页 setNotFirst 方法未执行,或本地存储未成功写入 检查引导页最后一页按钮点击逻辑,确保 setNotFirst 方法正常执行
鸿蒙编译 hvigor 报错 项目路径含中文/空格,或缓存损坏 将项目移至纯英文路径,执行 flutter clean 清理缓存后重新构建
HomePage 重复定义、import 位置错误 语法错误,import 指令写在声明之后,或重复定义类 确保 import 指令在文件最顶部,类只定义一次(参考本文第八步的 home_page.dart 代码)

十二、项目总结

本文基于 Flutter + 鸿蒙化三方库,完整实现了 OpenHarmony 应用的启动页延时、新手轮播引导、首次打开逻辑判断、本地状态持久化整套通用方案。项目结构规范、代码低耦合、无语法错误、无编译报错,可直接移植到任意 Flutter 鸿蒙项目中作为通用模板,无需额外修改。

通过本案例,可快速掌握 Flutter 鸿蒙化开发的核心要点:鸿蒙化三方库的调用、本地存储适配、页面路由跳转、白屏优化等,是 Flutter 三方库鸿蒙化开发非常实用的基础入门案例,适合零基础开发者快速上手 Flutter 鸿蒙应用开发。


Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐