fix(splash): 修复华为设备启动动画兼容性问题
- 添加 core-splashscreen 依赖支持 Android 12+ SplashScreen API - 配置原生 Splash 主题消除冷启动白屏 - 添加 values-v31 和 values-night-v31 适配 Android 12+ - 更新 launch_background.xml 显示品牌 Logo - MainActivity 添加 installSplashScreen() 处理 - 视频转码为 H.264 格式解决华为 HEVC 解码器兼容问题 - 添加视频初始化调试日志 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
2e44263834
commit
7bfd6822a7
|
|
@ -43,6 +43,11 @@ fun getAutoVersionName(): String {
|
|||
return "$flutterVersionName.$autoVersionCode"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// SplashScreen API for Android 12+ compatibility
|
||||
implementation("androidx.core:core-splashscreen:1.0.1")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.rwadurian.rwa_android_app"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ package com.rwadurian.rwa_android_app
|
|||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
|
@ -13,6 +15,22 @@ class MainActivity : FlutterActivity() {
|
|||
private val INSTALLER_CHANNEL = "com.rwadurian.app/apk_installer"
|
||||
private val MARKET_CHANNEL = "com.rwadurian.app/app_market"
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// Install splash screen - must be called before super.onCreate()
|
||||
val splashScreen = installSplashScreen()
|
||||
|
||||
// Keep splash screen visible until Flutter is ready
|
||||
var keepSplashScreen = true
|
||||
splashScreen.setKeepOnScreenCondition { keepSplashScreen }
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// Dismiss splash screen after a short delay to ensure smooth transition
|
||||
window.decorView.postDelayed({
|
||||
keepSplashScreen = false
|
||||
}, 300)
|
||||
}
|
||||
|
||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||
super.configureFlutterEngine(flutterEngine)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<!-- Launch background with brand color and logo (API 21+) -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
<!-- Background color matching splash theme -->
|
||||
<item android:drawable="@color/splash_background" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<!-- Centered app icon -->
|
||||
<item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
android:src="@mipmap/ic_launcher" />
|
||||
</item>
|
||||
</layer-list>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<!-- Launch background with brand color and logo -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
<!-- Background color matching splash theme -->
|
||||
<item android:drawable="@color/splash_background" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<!-- Centered app icon -->
|
||||
<item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
android:src="@mipmap/ic_launcher" />
|
||||
</item>
|
||||
</layer-list>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- SplashScreen theme for dark mode (Android 12+ API 31+) -->
|
||||
<style name="LaunchTheme" parent="Theme.SplashScreen">
|
||||
<!-- Splash screen background color (same as light mode for brand consistency) -->
|
||||
<item name="windowSplashScreenBackground">#FFF5E6</item>
|
||||
<!-- Splash screen icon -->
|
||||
<item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item>
|
||||
<!-- Icon animation duration (max 1000ms) -->
|
||||
<item name="windowSplashScreenAnimationDuration">800</item>
|
||||
<!-- Post-splash theme -->
|
||||
<item name="postSplashScreenTheme">@style/NormalTheme</item>
|
||||
<!-- Remove the branding image at bottom (Android 12+) -->
|
||||
<item name="android:windowSplashScreenBrandingImage">@null</item>
|
||||
</style>
|
||||
|
||||
<!-- Normal theme after splash (dark mode) -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
@ -1,17 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<!-- SplashScreen theme for dark mode (Android 11 and below) -->
|
||||
<style name="LaunchTheme" parent="Theme.SplashScreen">
|
||||
<!-- Splash screen background color (same as light mode for brand consistency) -->
|
||||
<item name="windowSplashScreenBackground">#FFF5E6</item>
|
||||
<!-- Splash screen icon -->
|
||||
<item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item>
|
||||
<!-- Post-splash theme -->
|
||||
<item name="postSplashScreenTheme">@style/NormalTheme</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<!-- Normal theme after splash (dark mode) -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- SplashScreen theme for Android 12+ (API 31+) -->
|
||||
<style name="LaunchTheme" parent="Theme.SplashScreen">
|
||||
<!-- Splash screen background color -->
|
||||
<item name="windowSplashScreenBackground">#FFF5E6</item>
|
||||
<!-- Splash screen icon -->
|
||||
<item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item>
|
||||
<!-- Icon animation duration (max 1000ms) -->
|
||||
<item name="windowSplashScreenAnimationDuration">800</item>
|
||||
<!-- Post-splash theme -->
|
||||
<item name="postSplashScreenTheme">@style/NormalTheme</item>
|
||||
<!-- Remove the branding image at bottom (Android 12+) -->
|
||||
<item name="android:windowSplashScreenBrandingImage">@null</item>
|
||||
</style>
|
||||
|
||||
<!-- Normal theme after splash -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
<!-- Splash screen background color (cream/light orange) -->
|
||||
<color name="splash_background">#FFF5E6</color>
|
||||
</resources>
|
||||
|
|
@ -1,17 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<!-- SplashScreen theme for Android 11 and below -->
|
||||
<style name="LaunchTheme" parent="Theme.SplashScreen">
|
||||
<!-- Splash screen background color -->
|
||||
<item name="windowSplashScreenBackground">#FFF5E6</item>
|
||||
<!-- Splash screen icon (uses app icon) -->
|
||||
<item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item>
|
||||
<!-- Post-splash theme -->
|
||||
<item name="postSplashScreenTheme">@style/NormalTheme</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<!-- Normal theme after splash -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -44,11 +44,30 @@ class _SplashPageState extends ConsumerState<SplashPage> {
|
|||
|
||||
/// 初始化视频播放器
|
||||
Future<void> _initializeVideo() async {
|
||||
debugPrint('[SplashPage] ========== 开始初始化视频 ==========');
|
||||
debugPrint('[SplashPage] 视频路径: assets/videos/splash.mp4');
|
||||
|
||||
try {
|
||||
// 从 assets 加载视频
|
||||
debugPrint('[SplashPage] 创建 VideoPlayerController...');
|
||||
_videoController = VideoPlayerController.asset('assets/videos/splash.mp4');
|
||||
|
||||
debugPrint('[SplashPage] 开始 initialize()...');
|
||||
final stopwatch = Stopwatch()..start();
|
||||
await _videoController!.initialize();
|
||||
stopwatch.stop();
|
||||
debugPrint('[SplashPage] initialize() 完成,耗时: ${stopwatch.elapsedMilliseconds}ms');
|
||||
|
||||
// 打印视频信息
|
||||
final value = _videoController!.value;
|
||||
debugPrint('[SplashPage] 视频信息:');
|
||||
debugPrint('[SplashPage] - 尺寸: ${value.size.width} x ${value.size.height}');
|
||||
debugPrint('[SplashPage] - 时长: ${value.duration.inMilliseconds}ms');
|
||||
debugPrint('[SplashPage] - 是否已初始化: ${value.isInitialized}');
|
||||
debugPrint('[SplashPage] - 是否有错误: ${value.hasError}');
|
||||
if (value.hasError) {
|
||||
debugPrint('[SplashPage] - 错误信息: ${value.errorDescription}');
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
|
|
@ -59,7 +78,9 @@ class _SplashPageState extends ConsumerState<SplashPage> {
|
|||
_videoController!.addListener(_onVideoStateChanged);
|
||||
|
||||
// 开始播放视频
|
||||
debugPrint('[SplashPage] 开始播放视频...');
|
||||
await _videoController!.play();
|
||||
debugPrint('[SplashPage] play() 调用完成,isPlaying: ${_videoController!.value.isPlaying}');
|
||||
|
||||
// 1秒后显示跳过按钮
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
|
|
@ -70,8 +91,23 @@ class _SplashPageState extends ConsumerState<SplashPage> {
|
|||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('[SplashPage] 视频初始化失败: $e');
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[SplashPage] ========== 视频初始化失败 ==========');
|
||||
debugPrint('[SplashPage] 错误类型: ${e.runtimeType}');
|
||||
debugPrint('[SplashPage] 错误信息: $e');
|
||||
debugPrint('[SplashPage] 堆栈跟踪:\n$stackTrace');
|
||||
|
||||
// 检查 controller 状态
|
||||
if (_videoController != null) {
|
||||
final value = _videoController!.value;
|
||||
debugPrint('[SplashPage] Controller 状态:');
|
||||
debugPrint('[SplashPage] - 是否已初始化: ${value.isInitialized}');
|
||||
debugPrint('[SplashPage] - 是否有错误: ${value.hasError}');
|
||||
if (value.hasError) {
|
||||
debugPrint('[SplashPage] - 错误描述: ${value.errorDescription}');
|
||||
}
|
||||
}
|
||||
|
||||
// 如果视频加载失败,直接进行跳转
|
||||
_navigateToNextPage();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue