MoodCanvas/lib/core/home_start_page.dart
fengshengxiong 91b7eebbf2 接入TopON
2026-01-22 16:34:55 +08:00

204 lines
5.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'dart:io';
import 'package:aesthetica_wallpaper/core/app_ads_tools.dart';
import 'package:flutter/material.dart';
import 'package:app_tracking_transparency/app_tracking_transparency.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import '../widgets/main_screen.dart';
class HomeStartPage extends StatefulWidget {
HomeStartPage({Key? key}) : super(key: key);
@override
State<HomeStartPage> createState() => _HomeStartPageState();
}
class _HomeStartPageState extends State<HomeStartPage> with WidgetsBindingObserver {
Timer? _timeoutTimer;
bool _isNavigating = false;
// 使用这个标志位来防止并发请求,而不是彻底锁死
bool _isRequestingATT = false;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
WidgetsBinding.instance.addPostFrameCallback((_) {
_initPermissionsAndSDK();
});
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_timeoutTimer?.cancel();
super.dispose();
}
/// 监听生命周期:这是通过审核的关键“补救”措施
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
// 审核场景审核员启动App -> 立即切后台 -> 再切回来
// 此时如果 ATT 还没弹出来,我们需要检查并再次触发
_checkATTOnResume();
}
}
/// 回到前台时的检查逻辑
Future<void> _checkATTOnResume() async {
if (Platform.isIOS) {
try {
// 只有当状态依然是“未决定”时,才去尝试请求
// 如果用户已经点过允许或拒绝,这里就不会再打扰用户
final status = await AppTrackingTransparency.trackingAuthorizationStatus;
if (status == TrackingStatus.notDetermined) {
debugPrint("App resumed and ATT is not determined. Retrying request...");
await _requestATT();
}
} catch (e) {
debugPrint("Error checking ATT on resume: $e");
}
}
}
Future<void> _initPermissionsAndSDK() async {
// 1. 启动时的安全延迟,等待 LaunchScreen 消失
await Future.delayed(const Duration(milliseconds: 500));
if (!mounted) return;
// 2. iOS ATT 授权
if (Platform.isIOS) {
await _requestATT();
}
// 3. 初始化 SDK
try {
await AppAdsTools.instance.init();
debugPrint("✅ Max SDK Initialized");
} catch (error) {
debugPrint("❌ SDK Initialization failed: $error");
}
// 4. 加载广告
if (mounted) {
_startAdLoadingProcess();
}
}
/// 核心 ATT 请求逻辑(加入了防并发锁)
Future<void> _requestATT() async {
// 如果当前正在请求中,直接返回,防止重复弹窗
if (_isRequestingATT) return;
_isRequestingATT = true;
try {
TrackingStatus status = await AppTrackingTransparency.trackingAuthorizationStatus;
// 只有未决定的状态才弹窗
if (status == TrackingStatus.notDetermined) {
debugPrint("Requesting ATT Authorization...");
// 请求弹窗
status = await AppTrackingTransparency.requestTrackingAuthorization();
debugPrint("ATT Status Result: $status");
// 只有当用户真正做出了选择(不再是 notDetermined才延迟一下给动画时间
if (status != TrackingStatus.notDetermined) {
await Future.delayed(const Duration(milliseconds: 500));
}
}
} catch (e) {
debugPrint("ATT Request Error: $e");
} finally {
// 无论成功失败,释放锁,允许后续重试(万一失败了)
_isRequestingATT = false;
}
}
void _startAdLoadingProcess() {
debugPrint("开始加载开屏广告...");
// 如果之前已经有个定时器(比如因为生命周期变化重复触发),先取消掉
_timeoutTimer?.cancel();
_timeoutTimer = Timer(const Duration(seconds: 15), () {
debugPrint("广告加载超时 (15秒)。");
_navigateToHome();
});
AppAdsTools.instance.loadInitialSplashAd(
onAdReady: (AdPlacement placement) {
debugPrint("开屏广告已就绪: ${placement.name}");
_navigateToHome(adHomePlacement: placement);
},
onAllAdsFailed: () {
debugPrint("所有开屏广告都加载失败。");
_navigateToHome();
},
);
}
void _navigateToHome({AdPlacement? adHomePlacement}) {
if (_isNavigating) return;
_isNavigating = true;
_timeoutTimer?.cancel();
if (!mounted) return;
Navigator.of(context).pushReplacement(
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) =>
MainScreen(adShowPlacement: adHomePlacement),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xff1F2124),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/aesthloco.png',
width: 100,
height: 100,
),
const SizedBox(height: 5),
const Text(
'.Resource Loading.',
style: TextStyle(
fontSize: 14,
color: Color(0xff7D45E5),
fontWeight: FontWeight.w500,
decoration: TextDecoration.none,
),
),
const SizedBox(height: 5),
const SpinKitCubeGridIndicator(),
],
),
),
);
}
}
class SpinKitCubeGridIndicator extends StatelessWidget {
const SpinKitCubeGridIndicator({super.key});
@override
Widget build(BuildContext context) {
return const SpinKitThreeBounce(color: Color(0xff7D45E5), size: 23.0);
}
}