feat(mobile): check for update on app resume from background
- Mix in WidgetsBindingObserver to detect foreground/background transitions - On resumed: run a silent version check (no dialog) and only show the update dialog if a new version is actually available - Throttle resume checks to once per 2 minutes to avoid excessive API calls - Once the update dialog has been shown, skip further checks for the rest of the session; user won't be re-prompted until next cold start Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d174b74764
commit
cc966fb022
|
|
@ -18,10 +18,24 @@ class MainShell extends StatefulWidget {
|
||||||
State<MainShell> createState() => _MainShellState();
|
State<MainShell> createState() => _MainShellState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MainShellState extends State<MainShell> {
|
/// 混入 WidgetsBindingObserver 以监听 App 生命周期变化(前后台切换)
|
||||||
|
class _MainShellState extends State<MainShell> with WidgetsBindingObserver {
|
||||||
int _currentIndex = 0;
|
int _currentIndex = 0;
|
||||||
|
|
||||||
|
/// 首次进入 Shell 是否已触发过更新检查(防止 didChangeDependencies 多次调用)
|
||||||
bool _updateChecked = false;
|
bool _updateChecked = false;
|
||||||
|
|
||||||
|
/// 上一次执行更新检查的时间(用于节流,避免短时间内重复检查)
|
||||||
|
DateTime? _lastUpdateCheck;
|
||||||
|
|
||||||
|
/// 本次 App 生命周期(冷启动到下次冷启动)是否已向用户展示过更新弹窗。
|
||||||
|
///
|
||||||
|
/// 设计逻辑:
|
||||||
|
/// - 若检查到新版本并弹窗,此标志置为 true,之后从后台切回不再重复弹窗,
|
||||||
|
/// 避免用户选择"稍后再说"后频繁打扰。
|
||||||
|
/// - 标志仅存活于内存,App 被彻底杀死并重启后自动重置,届时再次检查。
|
||||||
|
bool _updatePromptShown = false;
|
||||||
|
|
||||||
final _pages = const [
|
final _pages = const [
|
||||||
HomePage(),
|
HomePage(),
|
||||||
MarketPage(),
|
MarketPage(),
|
||||||
|
|
@ -29,19 +43,68 @@ class _MainShellState extends State<MainShell> {
|
||||||
ProfilePage(),
|
ProfilePage(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
// 注册生命周期观察者,以便在 didChangeAppLifecycleState 中感知前后台切换
|
||||||
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
|
// 冷启动后仅执行一次:等待 3 秒页面稳定后检查更新
|
||||||
if (!_updateChecked) {
|
if (!_updateChecked) {
|
||||||
_updateChecked = true;
|
_updateChecked = true;
|
||||||
_checkForUpdate();
|
_checkForUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// App 从后台切换回前台时触发
|
||||||
|
@override
|
||||||
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
|
if (state == AppLifecycleState.resumed) {
|
||||||
|
// 本次 session 已弹过更新弹窗(用户选择了"稍后"),不再重复打扰,
|
||||||
|
// 等用户下次冷启动 App 时才会再次检查
|
||||||
|
if (_updatePromptShown) return;
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
// 节流:两次后台唤起检查之间至少间隔 2 分钟,防止频繁切换时多次触发网络请求
|
||||||
|
if (_lastUpdateCheck == null ||
|
||||||
|
now.difference(_lastUpdateCheck!) > const Duration(minutes: 2)) {
|
||||||
|
_checkForUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 执行静默版本检查,有新版本时才弹更新弹窗
|
||||||
|
///
|
||||||
|
/// 流程:
|
||||||
|
/// 1. 记录本次检查时间(用于节流)
|
||||||
|
/// 2. 延迟 3 秒,确保页面已完全渲染
|
||||||
|
/// 3. 先调用 silentCheck() 查询服务端是否有新版本(不弹窗)
|
||||||
|
/// 4. 若有新版本,标记 _updatePromptShown = true 后调用 checkForUpdate() 弹窗
|
||||||
|
/// 若无新版本,静默结束,下次切回前台满 2 分钟后再次检查
|
||||||
Future<void> _checkForUpdate() async {
|
Future<void> _checkForUpdate() async {
|
||||||
|
_lastUpdateCheck = DateTime.now();
|
||||||
await Future.delayed(const Duration(seconds: 3));
|
await Future.delayed(const Duration(seconds: 3));
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
await UpdateService().checkForUpdate(context);
|
|
||||||
|
final updateService = UpdateService();
|
||||||
|
final versionInfo = await updateService.silentCheck();
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
if (versionInfo != null) {
|
||||||
|
// 有新版本:先锁定标志,再弹窗(无论用户选更新还是关闭,本 session 均不再弹)
|
||||||
|
_updatePromptShown = true;
|
||||||
|
await updateService.checkForUpdate(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue