yx_app_upgrade_flutter/lib/app_upgrade_plugin_enhanced...

639 lines
18 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:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; // Added for MethodChannel
import 'package:flutter/widgets.dart'; // Added for WidgetsBinding
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import 'app_upgrade_plugin_platform_interface.dart';
import 'core/cache_manager.dart';
import 'core/download_manager.dart';
import 'core/network_monitor.dart';
import 'core/notification_helper.dart';
import 'core/upgrade_config.dart';
import 'core/version_comparator.dart';
import 'models/upgrade_info.dart';
export 'core/cache_manager.dart';
export 'core/download_manager.dart';
export 'core/network_monitor.dart';
export 'core/upgrade_config.dart';
export 'core/version_comparator.dart';
export 'models/upgrade_info.dart';
export 'widgets/widgets.dart';
/// 升级回调
typedef UpgradeCallback = void Function(UpgradeInfo info);
typedef DownloadCallback = void Function(DownloadTask task);
typedef ErrorCallback = void Function(String error);
/// 增强版App升级插件
class AppUpgradePluginEnhanced {
static AppUpgradePluginEnhanced? _instance;
/// 获取单例实例
static AppUpgradePluginEnhanced get instance {
_instance ??= AppUpgradePluginEnhanced._();
return _instance!;
}
AppUpgradePluginEnhanced._() {
_init();
}
// 核心组件
final UpgradeConfig _config = UpgradeConfig.instance;
final DownloadManager _downloadManager = DownloadManager.instance;
final NetworkMonitor _networkMonitor = NetworkMonitor.instance;
final CacheManager _cacheManager = CacheManager.instance;
final NotificationHelper _notificationHelper = NotificationHelper.instance;
late VersionComparator _versionComparator;
final Dio _dio = Dio();
// 回调
final List<UpgradeCallback> _upgradeCallbacks = [];
final List<DownloadCallback> _downloadCallbacks = [];
final List<ErrorCallback> _errorCallbacks = [];
// 状态
UpgradeInfo? _currentUpgradeInfo;
String? _currentDownloadTaskId;
Timer? _autoCheckTimer;
StreamSubscription<NetworkStatus>? _networkSubscription;
// 内存管理
final List<StreamSubscription> _subscriptions = [];
final Map<String, WeakReference<Object>> _weakRefs = {};
/// 初始化
void _init() {
_versionComparator = VersionComparator(
strategy: _config.debugMode ? VersionCompareStrategy.buildNumber : VersionCompareStrategy.semantic,
);
// 延迟初始化Flutter相关服务直到绑定完全初始化
_scheduleFlutterServicesInit();
// 监听网络状态 - 这个可以立即初始化因为不依赖Flutter绑定
_networkSubscription = _networkMonitor.statusStream.listen(_onNetworkStatusChanged);
_subscriptions.add(_networkSubscription!);
// 启动自动检查
if (_config.autoCheck) {
_startAutoCheck();
}
}
/// 延迟初始化Flutter相关服务
void _scheduleFlutterServicesInit() {
// 如果绑定已经初始化,直接执行
_initFlutterServices();
}
/// 初始化Flutter相关服务
void _initFlutterServices() {
try {
// 初始化通知,并设置点击回调
_notificationHelper.initialize(_onNotificationClick);
// 监听原生渠道的安装请求
const MethodChannel('app_upgrade_plugin_channel').setMethodCallHandler((call) async {
if (call.method == 'installApkFromNotification') {
final filePath = call.arguments as String?;
if (filePath != null) {
await installApkSmart(filePath);
}
}
});
} catch (e) {
debugPrint('Failed to initialize Flutter services: $e');
}
}
/// 配置插件
void configure({
bool? debugMode,
int? checkIntervalHours,
bool? autoCheck,
bool? wifiOnly,
int? downloadTimeout,
int? connectTimeout,
int? maxRetryCount,
bool? supportBreakpoint,
bool? verifyIntegrity,
VersionCompareStrategy? versionStrategy,
Map<String, String>? customHeaders,
}) {
_config.updateConfig(
debugMode: debugMode,
checkIntervalHours: checkIntervalHours,
autoCheck: autoCheck,
wifiOnly: wifiOnly,
downloadTimeout: downloadTimeout,
connectTimeout: connectTimeout,
maxRetryCount: maxRetryCount,
supportBreakpoint: supportBreakpoint,
verifyIntegrity: verifyIntegrity,
customHeaders: customHeaders,
);
if (versionStrategy != null) {
_versionComparator = VersionComparator(strategy: versionStrategy);
}
// 重启自动检查
if (autoCheck != null) {
if (autoCheck) {
_startAutoCheck();
} else {
_stopAutoCheck();
}
}
}
/// 获取平台版本(无需平台接口)
Future<String?> getPlatformVersion() async {
try {
final info = await PackageInfo.fromPlatform();
return info.version;
} catch (e) {
debugPrint('getPlatformVersion failed: $e');
return null;
}
}
/// 获取当前App信息
Future<Map<String, String>> getAppInfo() async {
return await _cacheManager.get<Map<String, String>>(
'app_info',
strategy: CacheStrategy.cacheFirst,
networkFetcher: _getPackageInfoMap,
) ??
{};
}
/// 检查更新(智能版)
Future<UpgradeInfo?> checkUpdateSmart(
String url, {
Map<String, dynamic>? params,
bool forceRefresh = false,
Duration? cacheDuration,
}) async {
try {
// 检查网络状态
if (!_networkMonitor.isConnected) {
_notifyError('No network connection');
return null;
}
// 检查是否可以下载
if (_config.wifiOnly && !_networkMonitor.isWifi) {
_notifyError('WiFi required for update check');
return null;
}
// 使用缓存策略
final strategy = forceRefresh ? CacheStrategy.networkFirst : CacheStrategy.cacheFirst;
final upgradeInfo = await _cacheManager.get<UpgradeInfo>(
'upgrade_info_$url',
strategy: strategy,
networkFetcher: () async {
final info = await _fetchUpgradeInfo(url, params: params);
if (info != null) {
// 智能版本比较
final appInfo = await getAppInfo();
final currentVersion = appInfo['version'] ?? '0.0.0';
if (_versionComparator.isUpdateAvailable(currentVersion, info.versionName)) {
// 判断更新类型
final isMajor = _versionComparator.isMajorUpdate(currentVersion, info.versionName);
// 根据更新类型调整策略
if (isMajor && !info.isForceUpdate) {
// 主要版本更新建议强制
debugPrint('Major update detected, suggesting force update');
}
return info;
}
}
return null;
},
);
if (upgradeInfo != null) {
_currentUpgradeInfo = upgradeInfo;
_notifyUpgrade(upgradeInfo);
// 预下载(如果配置了静默下载)
if (_config.silentDownload && upgradeInfo.downloadUrl != null && _networkMonitor.isWifi) {
_startSilentDownload(upgradeInfo.downloadUrl!);
}
}
return upgradeInfo;
} catch (e) {
_notifyError('Check update failed: $e');
return null;
}
}
Future<Map<String, String>> _getPackageInfoMap() async {
final packageInfo = await PackageInfo.fromPlatform();
return {
'appName': packageInfo.appName,
'packageName': packageInfo.packageName,
'version': packageInfo.version,
'buildNumber': packageInfo.buildNumber,
};
}
/// 直接通过网络请求拉取升级信息,避免依赖平台接口实现
Future<UpgradeInfo?> _fetchUpgradeInfo(
String url, {
Map<String, dynamic>? params,
}) async {
try {
final appInfo = await getAppInfo();
final requestParams = <String, dynamic>{
'version': appInfo['version'],
'buildNumber': appInfo['buildNumber'],
'platform': Platform.isAndroid ? 'android' : 'ios',
...?params,
};
final response = await _dio.get(url, queryParameters: requestParams);
if (response.statusCode == 200 && response.data != null) {
return UpgradeInfo.fromJson(response.data);
}
return null;
} catch (e) {
debugPrint('fetch upgrade info failed: $e');
return null;
}
}
/// 智能下载APK
Future<String?> downloadApkSmart(
String url, {
String? versionName, // 新增版本名,用于标准化文件名
Function(DownloadProgress)? onProgress,
String? savePath,
String? md5,
String? sha256,
bool resumeIfExists = true,
}) async {
if (!Platform.isAndroid) {
throw UnsupportedError('downloadApk only supports Android platform');
}
try {
// 检查网络状态
final networkStatus = _networkMonitor.currentStatus;
if (networkStatus == null || !networkStatus.isConnected) {
_notifyError('No network connection for download');
return null;
}
// 创建下载任务
_currentDownloadTaskId = await _downloadManager.createTask(
url: url,
savePath: savePath,
md5: md5,
sha256: sha256,
versionName: versionName ?? _currentUpgradeInfo?.versionName,
);
// 监听下载进度
final progressSubscription = _downloadManager.getProgressStream(_currentDownloadTaskId!)?.listen((task) {
_notifyDownload(task);
// 更新通知栏进度
_updateNotificationForTask(task);
if (onProgress != null && task.totalSize != null) {
onProgress(DownloadProgress(received: task.downloadedSize, total: task.totalSize!));
}
});
if (progressSubscription != null) {
_subscriptions.add(progressSubscription);
}
// 开始下载
final success = await _downloadManager.startDownload(_currentDownloadTaskId!);
if (success) {
final task = _downloadManager.getTask(_currentDownloadTaskId!);
return task?.savePath;
}
return null;
} catch (e) {
_notifyError('Download failed: $e');
return null;
}
}
/// 安装APK带权限检查
Future<bool> installApkSmart(String filePath) async {
if (!Platform.isAndroid) {
return false;
}
try {
// 检查文件是否存在
final file = File(filePath);
if (!await file.exists()) {
_notifyError('APK file not found');
return false;
}
// 检查文件完整性如果有MD5
if (_currentUpgradeInfo?.apkMd5 != null) {
final isValid = await DownloadManager.verifyFileInIsolate({
'filePath': filePath,
'md5': _currentUpgradeInfo!.apkMd5,
});
if (!isValid) {
_notifyError('APK file integrity check failed');
return false;
}
}
return await AppUpgradePluginPlatform.instance.installApk(filePath);
} catch (e) {
_notifyError('Install failed: $e');
return false;
}
}
/// 跳转到应用商店(直接使用 url_launcher避免依赖平台通道
Future<bool> goToAppStore(String url) async {
try {
final uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
return await launchUrl(uri, mode: LaunchMode.externalApplication);
}
return false;
} catch (e) {
_notifyError('Failed to open app store: $e');
return false;
}
}
/// 暂停下载
void pauseDownload() {
if (_currentDownloadTaskId != null) {
_downloadManager.pauseDownload(_currentDownloadTaskId!);
}
}
/// 恢复下载
Future<bool> resumeDownload() async {
if (_currentDownloadTaskId != null) {
return await _downloadManager.resumeDownload(_currentDownloadTaskId!);
}
return false;
}
/// 取消下载
void cancelDownload() {
if (_currentDownloadTaskId != null) {
_downloadManager.cancelDownload(_currentDownloadTaskId!);
_notificationHelper.cancelNotification(); // 取消时移除通知
_currentDownloadTaskId = null;
}
}
/// 重试下载
Future<bool> retryDownload() async {
if (_currentDownloadTaskId != null) {
return await _downloadManager.retryDownload(_currentDownloadTaskId!);
}
return false;
}
/// 获取下载任务
DownloadTask? getCurrentDownloadTask() {
if (_currentDownloadTaskId != null) {
return _downloadManager.getTask(_currentDownloadTaskId!);
}
return null;
}
/// 添加升级回调
void addUpgradeCallback(UpgradeCallback callback) {
_upgradeCallbacks.add(callback);
}
/// 移除升级回调
void removeUpgradeCallback(UpgradeCallback callback) {
_upgradeCallbacks.remove(callback);
}
/// 添加下载回调
void addDownloadCallback(DownloadCallback callback) {
_downloadCallbacks.add(callback);
}
/// 移除下载回调
void removeDownloadCallback(DownloadCallback callback) {
_downloadCallbacks.remove(callback);
}
/// 添加错误回调
void addErrorCallback(ErrorCallback callback) {
_errorCallbacks.add(callback);
}
/// 移除错误回调
void removeErrorCallback(ErrorCallback callback) {
_errorCallbacks.remove(callback);
}
/// 开始自动检查
void _startAutoCheck() {
_stopAutoCheck();
_autoCheckTimer = Timer.periodic(Duration(hours: _config.checkIntervalHours), (_) async {
// 自动检查需要在WiFi环境下
if (_config.wifiOnly && !_networkMonitor.isWifi) {
return;
}
// 执行检查使用缓存的URL
final lastCheckUrl = await _cacheManager.get<String>('last_check_url');
if (lastCheckUrl != null) {
await checkUpdateSmart(lastCheckUrl);
}
});
}
/// 停止自动检查
void _stopAutoCheck() {
_autoCheckTimer?.cancel();
_autoCheckTimer = null;
}
/// 静默下载
void _startSilentDownload(String url) async {
if (!_config.silentDownload) return;
if (!_networkMonitor.isWifi) return;
try {
final taskId = await _downloadManager.createTask(url: url);
await _downloadManager.startDownload(taskId);
} catch (e) {
debugPrint('Silent download failed: $e');
}
}
/// 网络状态变化处理
void _onNetworkStatusChanged(NetworkStatus status) {
if (_config.debugMode) {
debugPrint('Network status changed: ${status.toJson()}');
}
// 网络恢复时恢复下载
if (status.isConnected && _currentDownloadTaskId != null) {
final task = _downloadManager.getTask(_currentDownloadTaskId!);
if (task != null && task.status == DownloadStatus.paused) {
resumeDownload();
}
}
// WiFi环境下启动静默下载
if (status.type == NetworkType.wifi && _config.silentDownload && _currentUpgradeInfo?.downloadUrl != null) {
_startSilentDownload(_currentUpgradeInfo!.downloadUrl!);
}
}
/// 通知升级信息
void _notifyUpgrade(UpgradeInfo info) {
for (final callback in _upgradeCallbacks) {
callback(info);
}
}
/// 通知下载进度
void _notifyDownload(DownloadTask task) {
for (final callback in _downloadCallbacks) {
callback(task);
}
}
/// 通知错误
void _notifyError(String error) {
if (_config.debugMode) {
debugPrint('AppUpgrade Error: $error');
}
for (final callback in _errorCallbacks) {
callback(error);
}
}
/// 通知点击回调
Future<void> _onNotificationClick(NotificationResponse response) async {
if (response.payload != null && response.payload!.startsWith('download_complete:')) {
final filePath = response.payload!.split(':').last;
await installApkSmart(filePath);
}
}
/// 根据下载任务状态更新通知
void _updateNotificationForTask(DownloadTask task) async {
final progress = (task.progress * 100).toInt();
final appInfo = await _cacheManager.get<Map<String, String>>('app_info', strategy: CacheStrategy.cacheFirst);
final appName = appInfo?['appName'] ?? '应用';
switch (task.status) {
case DownloadStatus.downloading:
_notificationHelper.showDownloadProgressNotification(
progress: progress,
title: '$appName 下载中...',
body: '${(task.progress * 100).toStringAsFixed(1)}%',
);
break;
case DownloadStatus.completed:
_notificationHelper.showDownloadCompleteNotification(
title: '$appName 下载完成',
body: '点击安装新版本',
filePath: task.savePath,
);
break;
case DownloadStatus.failed:
_notificationHelper.showDownloadFailedNotification(
title: '$appName 下载失败',
body: task.errorMessage ?? '请检查网络后重试',
);
break;
case DownloadStatus.cancelled:
_notificationHelper.cancelNotification();
break;
default:
break;
}
}
/// 获取缓存统计
Future<Map<String, dynamic>> getCacheStats() {
return _cacheManager.getCacheStats();
}
/// 清空缓存
Future<void> clearCache() {
return _cacheManager.clear();
}
/// 获取网络状态
NetworkStatus? get networkStatus => _networkMonitor.currentStatus;
/// 刷新网络状态
Future<void> refreshNetworkStatus() async {
await _networkMonitor.refreshNetworkStatus();
}
/// 获取当前配置
UpgradeConfig get config => _config;
/// 获取版本比较器
VersionComparator get versionComparator => _versionComparator;
/// 释放资源(优化内存)
void dispose() {
// 停止自动检查
_stopAutoCheck();
// 取消所有订阅
for (final subscription in _subscriptions) {
subscription.cancel();
}
_subscriptions.clear();
// 清理回调
_upgradeCallbacks.clear();
_downloadCallbacks.clear();
_errorCallbacks.clear();
// 释放组件资源
_downloadManager.dispose();
_networkMonitor.dispose();
_cacheManager.dispose();
// 清理弱引用
_weakRefs.clear();
// 清空当前状态
_currentUpgradeInfo = null;
_currentDownloadTaskId = null;
}
}