fix:第一轮跑
This commit is contained in:
1 parent
e834ec7586
commit
33235f450b
56 files changed
+4357
-210
No files matched your search
@@ -0,0 +1,34 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import '../data/update_api_client.dart';
|
||||
|
||||
class UpdateSessionGate {
|
||||
var _used = false;
|
||||
bool takeColdLaunchSlot() => _used ? false : (_used = true);
|
||||
}
|
||||
|
||||
final updateSessionGateProvider = Provider<UpdateSessionGate>(
|
||||
(_) => UpdateSessionGate(),
|
||||
);
|
||||
|
||||
class UpdateController extends StateNotifier<AsyncValue<UpgradeInfo?>> {
|
||||
UpdateController(this._read) : super(const AsyncData(null));
|
||||
final T Function<T>(ProviderListenable<T>) _read;
|
||||
|
||||
Future<UpgradeInfo> checkUpgrade() async {
|
||||
state = const AsyncLoading();
|
||||
try {
|
||||
final result = await _read(updateApiClientProvider).checkUpgrade();
|
||||
state = AsyncData(result);
|
||||
return result;
|
||||
} catch (error, stackTrace) {
|
||||
state = AsyncError(error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final updateControllerProvider =
|
||||
StateNotifierProvider<UpdateController, AsyncValue<UpgradeInfo?>>(
|
||||
(ref) => UpdateController(ref.read),
|
||||
);
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import 'update_controller.dart';
|
||||
import 'update_service.dart';
|
||||
|
||||
/// 前后台切换仅低频检查一次,网络失败或无新版本均静默结束。
|
||||
abstract final class UpdateForegroundService {
|
||||
static DateTime? _lastCheck;
|
||||
static Future<void>? _running;
|
||||
static Future<void> check(BuildContext context, WidgetRef ref) {
|
||||
final now = DateTime.now();
|
||||
if (_lastCheck != null &&
|
||||
now.difference(_lastCheck!) < const Duration(minutes: 30)) {
|
||||
return Future.value();
|
||||
}
|
||||
return _running ??= _run(context, ref).whenComplete(() => _running = null);
|
||||
}
|
||||
|
||||
static Future<void> _run(BuildContext context, WidgetRef ref) async {
|
||||
_lastCheck = DateTime.now();
|
||||
try {
|
||||
final info = await ref
|
||||
.read(updateControllerProvider.notifier)
|
||||
.checkUpgrade();
|
||||
if (context.mounted) {
|
||||
await UpdateService.showIfNeeded(
|
||||
context,
|
||||
ref,
|
||||
info,
|
||||
source: UpgradeCheckSource.automatic,
|
||||
);
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app_update/flutter_app_update.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../data/update_api_client.dart';
|
||||
|
||||
enum UpgradeCheckSource { automatic, manual }
|
||||
|
||||
class UpdateService {
|
||||
static bool get isSupported =>
|
||||
!kIsWeb && (Platform.isAndroid || Platform.isIOS);
|
||||
|
||||
static Future<void> showIfNeeded(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
UpgradeInfo info, {
|
||||
required UpgradeCheckSource source,
|
||||
VoidCallback? onLatest,
|
||||
}) async {
|
||||
final shouldShow = source == UpgradeCheckSource.automatic
|
||||
? info.show == 1 && info.hasPublishedUpdate
|
||||
: info.hasPublishedUpdate;
|
||||
if (!shouldShow) {
|
||||
onLatest?.call();
|
||||
return;
|
||||
}
|
||||
final uri = Uri.tryParse(info.url);
|
||||
if (uri == null || uri.scheme != 'https' || !uri.hasAuthority) return;
|
||||
final force = info.force == 1;
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: !force,
|
||||
builder: (dialogContext) => PopScope(
|
||||
canPop: !force,
|
||||
child: AlertDialog(
|
||||
title: Text(
|
||||
'发现新版本${info.latestVersion.isEmpty ? '' : ' ${info.latestVersion}'}',
|
||||
),
|
||||
content: Text(info.message.isEmpty ? '发现新版本,建议立即更新。' : info.message),
|
||||
actions: [
|
||||
if (!force)
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(dialogContext),
|
||||
child: const Text('稍后再说'),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () async {
|
||||
Navigator.pop(dialogContext);
|
||||
final package = await PackageInfo.fromPlatform();
|
||||
try {
|
||||
await ref
|
||||
.read(updateApiClientProvider)
|
||||
.reportClick(
|
||||
buildId: info.versionCode.isEmpty
|
||||
? package.buildNumber
|
||||
: info.versionCode,
|
||||
source: source == UpgradeCheckSource.manual
|
||||
? 'manual'
|
||||
: 'auto',
|
||||
);
|
||||
} catch (_) {}
|
||||
await _startUpdate(uri);
|
||||
},
|
||||
child: Text(Platform.isIOS ? '前往更新' : '下载更新'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> _startUpdate(Uri uri) async {
|
||||
if (Platform.isIOS) {
|
||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
return;
|
||||
}
|
||||
await AzhonAppUpdate.update(
|
||||
UpdateModel(
|
||||
uri.toString(),
|
||||
'jinzhi-update.apk',
|
||||
'ic_launcher',
|
||||
'https://apps.apple.com/search?term=%E9%87%91%E5%80%BC',
|
||||
showNotification: true,
|
||||
showBgdToast: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user