Flutter android_splash_screen 在鸿蒙上的使用指南

插件介绍

Flutter android_splash_screen 是一个展示如何在 Android 12+ 上实现原生启动屏(Splash Screen)与 Flutter UI 平滑过渡的示例项目。虽然它不是一个传统意义上的可直接导入的插件,但它提供了一套完整的实现方案和最佳实践,开发者可以将其作为参考,在鸿蒙(HarmonyOS)应用中实现类似的启动屏效果。

主要功能和特点:

  • 利用 Android 12 新增的 SplashScreen API 实现原生启动屏
  • 支持启动屏动画效果
  • 实现启动屏到 Flutter UI 的平滑过渡
  • 处理启动屏动画与 Flutter UI 加载完成的时序问题
  • 支持全屏显示和边缘到边缘(edge-to-edge)的界面设计

在鸿蒙上,我们可以借鉴这套实现方案,结合鸿蒙的启动页配置,创建出类似的流畅启动体验。

包的引入

由于这是一个示例项目而非传统插件,我们需要将其作为参考代码导入。在您的鸿蒙 Flutter 项目中,按照以下步骤配置:

  1. 打开项目根目录下的 pubspec.yaml 文件
  2. dependencies 部分添加以下配置:
dependencies:
  # 注意:这是一个示例项目,实际使用时需要参考其实现方式集成到您的项目中
  android_splash_screen:
    git:
      url: "https://gitcode.com/openharmony-tpc/flutter_packages.git"
      path: "packages/flutter_samples/android_splash_screen"
  1. 运行 flutter pub get 命令获取参考代码

实现方法

鸿蒙启动页配置

  1. 在鸿蒙项目的 resources 目录下创建启动页资源
  2. 配置 config.json5 文件,设置应用的启动页:
{
  "module": {
    "abilities": [
      {
        "name": "EntryAbility",
        "launchType": "standard",
        "icon": "$media:icon",
        "label": "$string:app_name",
        "splashScreenAbility": "$ability:SplashScreenAbility",
        "description": "$string:entryability_description",
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["action.system.home"]
          }
        ]
      },
      {
        "name": "SplashScreenAbility",
        "icon": "$media:icon",
        "label": "$string:app_name",
        "description": "$string:splashability_description",
        "type": "splashScreen",
        "splashScreen": {
          "backgroundColor": "#FFFFFF",
          "image": {
            "imageResource": "$media:splash_image",
            "alignment": {
              "x": 0.5,
              "y": 0.5
            },
            "objectFit": "contain"
          },
          "duration": 2000
        },
        "skills": []
      }
    ]
  }
}

集成 Flutter 与鸿蒙启动页过渡

  1. 创建 SplashScreenAbility.ets 文件,实现启动页逻辑:
import Ability from '@ohos.app.ability.Ability';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';

export default class SplashScreenAbility extends Ability {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
    // 启动页初始化逻辑
  }

  onWindowStageCreate(windowStage: window.WindowStage) {
    windowStage.loadContent('pages/SplashScreen', (err, data) => {
      if (err.code) {
        console.error('Failed to load splash screen content.');
        return;
      }

      // 设置全屏显示
      windowStage.getMainWindow((err, window) => {
        if (err.code) {
          console.error('Failed to get main window.');
          return;
        }

        window.setFullScreen(true);
        window.setSystemBarEnable(['status', 'navigation']);
        window.setSystemBarProperties({
          statusBarContentColor: '#FFFFFF',
          navigationBarContentColor: '#FFFFFF'
        });
      });
    });
  }

  onForeground() {
    // 2秒后自动跳转到主页面
    setTimeout(() => {
      this.jumpToMainAbility();
    }, 2000);
  }

  private jumpToMainAbility() {
    let want: Want = {
      bundleName: this.context.abilityInfo.bundleName,
      abilityName: 'EntryAbility'
    };

    this.startAbility(want).then(() => {
      this.terminateSelf();
    }).catch((err) => {
      console.error('Failed to start EntryAbility.');
    });
  }
}
  1. 创建启动页 UI 组件 SplashScreen.ets
import router from '@ohos.router';
import promptAction from '@ohos.promptAction';

@Entry
@Component
struct SplashScreen {
  @State logoOpacity: number = 0;
  @State logoScale: number = 0.8;

  aboutToAppear() {
    // 执行启动页动画
    this.playSplashAnimation();
  }

  playSplashAnimation() {
    // logo 淡入动画
    animateTo({
      duration: 1000,
      curve: Curve.EaseOut,
      onFinish: () => {
        // 动画完成后保持1秒
        setTimeout(() => {
          // 执行淡出动画
          this.fadeOutAndNavigate();
        }, 1000);
      }
    }, () => {
      this.logoOpacity = 1;
      this.logoScale = 1;
    });
  }

  fadeOutAndNavigate() {
    animateTo({
      duration: 500,
      curve: Curve.EaseIn,
      onFinish: () => {
        // 跳转到主页面
        router.replaceUrl({
          url: 'pages/Index'
        });
      }
    }, () => {
      this.logoOpacity = 0;
    });
  }

  build() {
    Column() {
      Image($r('app.media.app_logo'))
        .width(120)
        .height(120)
        .opacity(this.logoOpacity)
        .scale({ x: this.logoScale, y: this.logoScale })
      Text('鸿蒙 Flutter 应用')
        .fontSize(24)
        .fontColor('#333333')
        .margin({ top: 20 })
        .opacity(this.logoOpacity)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#FFFFFF')
  }
}

Flutter 端集成

在 Flutter 项目的 lib/main.dart 中,我们可以参考 android_splash_screen 的实现,确保 Flutter UI 与鸿蒙启动页的平滑过渡:

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

Future<void> main() async {
  // 可以在这里执行一些初始化操作
  WidgetsFlutterBinding.ensureInitialized();
  await initializeApp();
  runApp(const MyApp());
}

// 模拟应用初始化过程
Future<void> initializeApp() async {
  // 可以在这里加载资源、初始化插件等
  await Future.delayed(const Duration(milliseconds: 500));
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '鸿蒙 Flutter 应用',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      home: const SplashScreen(),
    );
  }
}

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

  
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  
  void initState() {
    super.initState();
    // 这里可以添加一些额外的初始化逻辑
    // 然后跳转到主页面
    Timer(const Duration(seconds: 1), () {
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(builder: (context) => const HomePage()),
      );
    });
  }

  
  Widget build(BuildContext context) {
    // 这个页面会在鸿蒙启动页之后短暂显示
    // 为了实现平滑过渡,我们可以让它与鸿蒙启动页的最后一帧保持一致
    return Scaffold(
      backgroundColor: Colors.white,
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Image.asset(
              'assets/images/app_logo.png',
              width: 120,
              height: 120,
            ),
            const SizedBox(height: 20),
            const Text(
              '鸿蒙 Flutter 应用',
              style: TextStyle(
                fontSize: 24,
                color: Color(0xFF333333),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

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

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('鸿蒙 Flutter 应用'),
      ),
      body: const Center(
        child: Text('欢迎使用鸿蒙 Flutter 应用!'),
      ),
    );
  }
}

总结

Flutter android_splash_screen 示例为我们提供了一套完整的启动屏实现方案,虽然它是为 Android 12+ 设计的,但我们可以借鉴其核心思想和实现方式,在鸿蒙应用中创建类似的启动屏效果。

主要实现要点:

  1. 利用鸿蒙的启动页配置创建原生启动屏
  2. 实现启动屏动画效果
  3. 处理启动屏与 Flutter UI 的过渡时序
  4. 确保过渡过程的平滑性

通过这种方式,我们可以为鸿蒙 Flutter 应用创建出专业、流畅的启动体验,提升用户的第一印象。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.youkuaiyun.com

在构建 Flutter 应用时,如果 AndroidManifest.xml 文件中的 `package` 属性设置不正确,确实可能导致构建失败。根据你描述的错误信息: > Incorrect package="com.example.jianshen" found in source AndroidManifest.xml 这通常意味着 AndroidManifest.xml 中的 `package` 属性值与 Gradle 构建配置中的 `namespace` 或 `applicationId` 不匹配。在较新版本的 Android Gradle 插件中(7.0+),`package` 属性在 AndroidManifest.xml 中仅用于指定应用的主包名,而不再用于定义构建时的命名空间[^1]。 ### 解决方案 #### 1. 更新 AndroidManifest.xml 文件 确保 `AndroidManifest.xml` 中的 `package` 属性值与你在 `build.gradle`(模块级)中定义的 `namespace` 一致。例如: ```xml <!-- app/src/main/AndroidManifest.xml --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.jianshen"> ``` #### 2. 配置 build.gradle (Module-level) 在 `build.gradle` 文件中指定 `namespace` 和 `applicationId`,确保它们与 `AndroidManifest.xml` 中的 `package` 一致: ```gradle // app/build.gradle android { namespace 'com.example.jianshen' compileSdk 33 defaultConfig { applicationId "com.example.jianshen" minSdk 21 targetSdk 33 versionCode 1 versionName "1.0" } } ``` #### 3. 检查 Flutter 的 `pubspec.yaml` 如果你使用了第三方插件(如 `flutter_native_splash`),请确保插件配置中的包名也与你的应用包名一致: ```yaml flutter_native_splash: image: "assets/images/splash.png" color: "#FFFFFF" ``` #### 4. 清理项目并重新构建 有时候旧的构建文件可能残留导致冲突。运行以下命令清理项目并重新构建: ```bash flutter clean flutter pub get flutter build ``` #### 5. 检查文件路径和文件是否存在 如果构建过程中提示 `AndroidManifest.xml not found`,请确认文件路径是否正确,并确保文件确实存在于 `app/src/main/` 目录中[^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值