feat: 添加启动屏幕图像和主题样式;优化 H5 壳的封面隐藏逻辑
|
After Width: | Height: | Size: 39 KiB |
BIN
android/app/src/main/res/drawable-nodpi/splash_content.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
@@ -9,4 +9,12 @@
|
||||
android:endColor="#FFFFFF" />
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:width="220dp"
|
||||
android:height="260dp"
|
||||
android:gravity="center">
|
||||
<bitmap
|
||||
android:gravity="fill"
|
||||
android:src="@drawable/splash_content" />
|
||||
</item>
|
||||
</layer-list>
|
||||
|
||||
@@ -9,4 +9,12 @@
|
||||
android:endColor="#FFFFFF" />
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:width="220dp"
|
||||
android:height="260dp"
|
||||
android:gravity="center">
|
||||
<bitmap
|
||||
android:gravity="fill"
|
||||
android:src="@drawable/splash_content" />
|
||||
</item>
|
||||
</layer-list>
|
||||
|
||||
13
android/app/src/main/res/values-night-v31/styles.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Material.Light.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:windowSplashScreenBackground">#F8FBFF</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/splash_android12_icon</item>
|
||||
<item name="android:windowSplashScreenIconBackgroundColor">#F8FBFF</item>
|
||||
</style>
|
||||
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Material.Light.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?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">
|
||||
<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>
|
||||
@@ -12,7 +12,7 @@
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
13
android/app/src/main/res/values-v31/styles.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Material.Light.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:windowSplashScreenBackground">#F8FBFF</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/splash_android12_icon</item>
|
||||
<item name="android:windowSplashScreenIconBackgroundColor">#F8FBFF</item>
|
||||
</style>
|
||||
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Material.Light.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 72 KiB |
@@ -32,6 +32,6 @@
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="LaunchImage" width="168" height="185"/>
|
||||
<image name="LaunchImage" width="220" height="260"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -99,6 +99,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
||||
String? _loadError;
|
||||
bool _showShellCover = true;
|
||||
bool _shellBrandingLoaded = false;
|
||||
Timer? _shellCoverFallbackTimer;
|
||||
late ShellBranding _shellBranding;
|
||||
|
||||
@override
|
||||
@@ -112,6 +113,10 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
||||
WebViewController _buildController() {
|
||||
return WebViewController()
|
||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||
..addJavaScriptChannel(
|
||||
'OpenIMShell',
|
||||
onMessageReceived: _handleShellMessage,
|
||||
)
|
||||
..setBackgroundColor(_shellBackground)
|
||||
..setNavigationDelegate(
|
||||
NavigationDelegate(
|
||||
@@ -121,6 +126,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
||||
}
|
||||
},
|
||||
onPageStarted: (_) {
|
||||
_shellCoverFallbackTimer?.cancel();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_loadError = null;
|
||||
@@ -134,6 +140,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
||||
},
|
||||
onWebResourceError: (error) {
|
||||
if (error.isForMainFrame ?? true) {
|
||||
_shellCoverFallbackTimer?.cancel();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_loadError = error.description;
|
||||
@@ -147,6 +154,12 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_shellCoverFallbackTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _runJavaScriptSafely(String source) async {
|
||||
try {
|
||||
await _controller.runJavaScript(source);
|
||||
@@ -165,9 +178,42 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_progress = 100;
|
||||
_showShellCover = false;
|
||||
});
|
||||
}
|
||||
_scheduleShellCoverFallback();
|
||||
}
|
||||
|
||||
void _handleShellMessage(JavaScriptMessage message) {
|
||||
try {
|
||||
final decoded = jsonDecode(message.message);
|
||||
if (decoded is Map && decoded['type'] == 'first-screen-ready') {
|
||||
_hideShellCover();
|
||||
}
|
||||
} catch (_) {
|
||||
if (message.message == 'first-screen-ready') {
|
||||
_hideShellCover();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _scheduleShellCoverFallback() {
|
||||
_shellCoverFallbackTimer?.cancel();
|
||||
_shellCoverFallbackTimer = Timer(
|
||||
const Duration(seconds: 4),
|
||||
_hideShellCover,
|
||||
);
|
||||
}
|
||||
|
||||
void _hideShellCover() {
|
||||
_shellCoverFallbackTimer?.cancel();
|
||||
if (!mounted || !_showShellCover) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_progress = 100;
|
||||
_showShellCover = false;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadShellBrandingIfNeeded() async {
|
||||
@@ -212,6 +258,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
||||
final targetUrl = AppConfig.canonicalizeMainFrameUrl(url);
|
||||
|
||||
if (mounted) {
|
||||
_shellCoverFallbackTimer?.cancel();
|
||||
setState(() {
|
||||
_loadError = null;
|
||||
_progress = 0;
|
||||
|
||||