yx_app_upgrade_flutter/example/lib/main_enhanced.dart

739 lines
24 KiB
Dart

import 'dart:async';
import 'package:app_upgrade_plugin/app_upgrade_plugin_enhanced.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(const MyEnhancedApp());
}
class MyEnhancedApp extends StatelessWidget {
const MyEnhancedApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '增强版App升级插件示例',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const EnhancedUpgradePage(),
);
}
}
class EnhancedUpgradePage extends StatefulWidget {
const EnhancedUpgradePage({super.key});
@override
State<EnhancedUpgradePage> createState() => _EnhancedUpgradePageState();
}
class _EnhancedUpgradePageState extends State<EnhancedUpgradePage> with SingleTickerProviderStateMixin {
final _plugin = AppUpgradePluginEnhanced.instance;
late TabController _tabController;
// 状态变量
Map<String, String>? _appInfo;
NetworkStatus? _networkStatus;
DownloadTask? _currentDownload;
UpgradeInfo? _upgradeInfo;
Map<String, dynamic>? _cacheStats;
// 配置选项
bool _wifiOnly = true;
bool _autoCheck = true;
bool _supportBreakpoint = true;
bool _verifyIntegrity = true;
VersionCompareStrategy _versionStrategy = VersionCompareStrategy.semantic;
// 测试数据
final _testVersions = ['1.0.0', '1.1.0', '1.2.0', '2.0.0-beta.1', '2.0.0'];
String _currentTestVersion = '1.0.0';
String _remoteTestVersion = '2.0.0';
@override
void initState() {
super.initState();
_tabController = TabController(length: 4, vsync: this);
_initPlugin();
_loadData();
}
@override
void dispose() {
_tabController.dispose();
_plugin.removeUpgradeCallback(_onUpgradeInfo);
_plugin.removeDownloadCallback(_onDownloadProgress);
_plugin.removeErrorCallback(_onError);
super.dispose();
}
void _initPlugin() {
// 配置插件
_plugin.configure(
debugMode: true,
autoCheck: _autoCheck,
wifiOnly: _wifiOnly,
supportBreakpoint: _supportBreakpoint,
verifyIntegrity: _verifyIntegrity,
versionStrategy: _versionStrategy,
);
// 添加回调
_plugin.addUpgradeCallback(_onUpgradeInfo);
_plugin.addDownloadCallback(_onDownloadProgress);
_plugin.addErrorCallback(_onError);
// 监听网络状态
NetworkMonitor.instance.statusStream.listen((status) {
setState(() {
_networkStatus = status;
});
});
}
Future<void> _loadData() async {
// 请求权限
await _requestPermissions();
// 获取App信息
_appInfo = await _plugin.getAppInfo();
// 获取网络状态
_networkStatus = _plugin.networkStatus;
// 获取缓存统计
_cacheStats = await _plugin.getCacheStats();
setState(() {});
}
Future<void> _requestPermissions() async {
if (Theme.of(context).platform == TargetPlatform.android) {
await [
Permission.storage,
Permission.requestInstallPackages,
Permission.notification,
].request();
}
}
void _onUpgradeInfo(UpgradeInfo info) {
setState(() {
_upgradeInfo = info;
});
// 显示升级对话框
UpgradeDialog.show(
context,
upgradeInfo: info,
primaryColor: Theme.of(context).colorScheme.primary,
);
}
void _onDownloadProgress(DownloadTask task) {
setState(() {
_currentDownload = task;
});
}
void _onError(String error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(error),
backgroundColor: Colors.red,
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('增强版App升级插件'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
bottom: TabBar(
controller: _tabController,
tabs: const [
Tab(text: '基础功能'),
Tab(text: '高级配置'),
Tab(text: '网络监测'),
Tab(text: '版本管理'),
],
),
),
body: TabBarView(
controller: _tabController,
children: [
_buildBasicTab(),
_buildConfigTab(),
_buildNetworkTab(),
_buildVersionTab(),
],
),
);
}
// 基础功能标签页
Widget _buildBasicTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// App信息卡片
if (_appInfo != null)
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'App信息',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Text('应用名称: ${_appInfo!['appName']}'),
Text('包名: ${_appInfo!['packageName']}'),
Text('版本: ${_appInfo!['version']}'),
Text('构建号: ${_appInfo!['buildNumber']}'),
],
),
),
),
const SizedBox(height: 16),
// 升级信息卡片
if (_upgradeInfo != null)
Card(
color: Colors.amber.shade50,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.system_update, color: Colors.amber),
const SizedBox(width: 8),
const Text(
'发现新版本',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
],
),
const SizedBox(height: 12),
Text('版本: ${_upgradeInfo!.versionName}'),
Text('强制更新: ${_upgradeInfo!.isForceUpdate ? "" : ""}'),
if (_upgradeInfo!.apkSize != null) Text('大小: ${_formatBytes(_upgradeInfo!.apkSize!)}'),
],
),
),
),
const SizedBox(height: 16),
// 下载进度卡片
if (_currentDownload != null)
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'下载进度',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
LinearProgressIndicator(value: _currentDownload!.progress),
const SizedBox(height: 8),
Text('状态: ${_getDownloadStatusText(_currentDownload!.status)}'),
Text('进度: ${(_currentDownload!.progress * 100).toStringAsFixed(1)}%'),
if (_currentDownload!.totalSize != null)
Text(
'${_formatBytes(_currentDownload!.downloadedSize)} / ${_formatBytes(_currentDownload!.totalSize!)}'),
if (_currentDownload!.errorMessage != null)
Text('错误: ${_currentDownload!.errorMessage}', style: const TextStyle(color: Colors.red)),
],
),
),
),
const SizedBox(height: 16),
// 操作按钮
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton.icon(
onPressed: () => _checkUpdate(),
icon: const Icon(Icons.refresh),
label: const Text('检查更新'),
),
if (_currentDownload != null) ...[
if (_currentDownload!.status == DownloadStatus.downloading)
ElevatedButton.icon(
onPressed: () => _plugin.pauseDownload(),
icon: const Icon(Icons.pause),
label: const Text('暂停'),
),
if (_currentDownload!.status == DownloadStatus.paused)
ElevatedButton.icon(
onPressed: () => _plugin.resumeDownload(),
icon: const Icon(Icons.play_arrow),
label: const Text('继续'),
),
if (_currentDownload!.status == DownloadStatus.failed)
ElevatedButton.icon(
onPressed: () => _plugin.retryDownload(),
icon: const Icon(Icons.replay),
label: const Text('重试'),
),
OutlinedButton.icon(
onPressed: () => _plugin.cancelDownload(),
icon: const Icon(Icons.cancel),
label: const Text('取消'),
),
],
],
),
],
),
);
}
// 高级配置标签页
Widget _buildConfigTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'升级配置',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
SwitchListTile(
title: const Text('仅WiFi下载'),
subtitle: const Text('只在WiFi环境下自动下载更新'),
value: _wifiOnly,
onChanged: (value) {
setState(() {
_wifiOnly = value;
});
_plugin.configure(wifiOnly: value);
},
),
SwitchListTile(
title: const Text('自动检查更新'),
subtitle: const Text('定期自动检查是否有新版本'),
value: _autoCheck,
onChanged: (value) {
setState(() {
_autoCheck = value;
});
_plugin.configure(autoCheck: value);
},
),
SwitchListTile(
title: const Text('断点续传'),
subtitle: const Text('支持暂停后继续下载'),
value: _supportBreakpoint,
onChanged: (value) {
setState(() {
_supportBreakpoint = value;
});
_plugin.configure(supportBreakpoint: value);
},
),
SwitchListTile(
title: const Text('文件校验'),
subtitle: const Text('下载完成后校验文件完整性'),
value: _verifyIntegrity,
onChanged: (value) {
setState(() {
_verifyIntegrity = value;
});
_plugin.configure(verifyIntegrity: value);
},
),
const Divider(),
ListTile(
title: const Text('版本比较策略'),
subtitle: Text(_getVersionStrategyText(_versionStrategy)),
trailing: DropdownButton<VersionCompareStrategy>(
value: _versionStrategy,
onChanged: (value) {
if (value != null) {
setState(() {
_versionStrategy = value;
});
_plugin.configure(versionStrategy: value);
}
},
items: VersionCompareStrategy.values.map((strategy) {
return DropdownMenuItem(
value: strategy,
child: Text(_getVersionStrategyText(strategy)),
);
}).toList(),
),
),
const Divider(),
// 缓存管理
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'缓存管理',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
if (_cacheStats != null) ...[
Text(
'内存缓存: ${_cacheStats!['memoryCache']['sizeFormatted']} (${_cacheStats!['memoryCache']['count']}项)'),
Text(
'磁盘缓存: ${_cacheStats!['diskCache']['sizeFormatted']} (${_cacheStats!['diskCache']['count']}项)'),
Text('总计: ${_cacheStats!['total']['sizeFormatted']} (${_cacheStats!['total']['count']}项)'),
],
const SizedBox(height: 12),
Row(
children: [
ElevatedButton(
onPressed: () async {
_cacheStats = await _plugin.getCacheStats();
setState(() {});
},
child: const Text('刷新'),
),
const SizedBox(width: 8),
OutlinedButton(
onPressed: () async {
await _plugin.clearCache();
_cacheStats = await _plugin.getCacheStats();
if (mounted) {
setState(() {});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('缓存已清空')),
);
}
},
child: const Text('清空缓存'),
),
],
),
],
),
),
),
],
),
);
}
// 网络监测标签页
Widget _buildNetworkTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'网络状态',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
if (_networkStatus != null) ...[
Card(
color: _networkStatus!.isConnected ? Colors.green.shade50 : Colors.red.shade50,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
_networkStatus!.isConnected ? Icons.wifi : Icons.wifi_off,
color: _networkStatus!.isConnected ? Colors.green : Colors.red,
),
const SizedBox(width: 8),
Text(
_networkStatus!.isConnected ? '已连接' : '未连接',
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
],
),
const SizedBox(height: 12),
Text('网络类型: ${_getNetworkTypeText(_networkStatus!.type)}'),
Text('网络质量: ${_getNetworkQualityText(_networkStatus!.quality)}'),
Text('计费网络: ${_networkStatus!.isMetered ? "" : ""}'),
if (_networkStatus!.downloadSpeed != null)
Text('下载速度: ${_formatBytes(_networkStatus!.downloadSpeed!.toInt())}/s'),
if (_networkStatus!.ping != null) Text('延迟: ${_networkStatus!.ping} ms'),
const SizedBox(height: 12),
Text(
'适合大文件下载: ${_networkStatus!.isSuitableForLargeDownload ? "" : ""}',
style: TextStyle(
color: _networkStatus!.isSuitableForLargeDownload ? Colors.green : Colors.orange,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
const SizedBox(height: 16),
// 下载策略建议
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'下载策略建议',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
...NetworkMonitor.instance.getSuggestedDownloadStrategy().entries.map((e) {
return Text('${e.key}: ${e.value}');
}),
],
),
),
),
] else
const Center(child: CircularProgressIndicator()),
],
),
);
}
// 版本管理标签页
Widget _buildVersionTab() {
final comparator = _plugin.versionComparator;
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'版本比较测试',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
// 版本选择
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('当前版本:'),
DropdownButton<String>(
value: _currentTestVersion,
isExpanded: true,
onChanged: (value) {
setState(() {
_currentTestVersion = value!;
});
},
items: _testVersions.map((v) {
return DropdownMenuItem(value: v, child: Text(v));
}).toList(),
),
],
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('远程版本:'),
DropdownButton<String>(
value: _remoteTestVersion,
isExpanded: true,
onChanged: (value) {
setState(() {
_remoteTestVersion = value!;
});
},
items: _testVersions.map((v) {
return DropdownMenuItem(value: v, child: Text(v));
}).toList(),
),
],
),
),
],
),
const SizedBox(height: 16),
// 比较结果
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'比较结果',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Text('需要更新: ${comparator.isUpdateAvailable(_currentTestVersion, _remoteTestVersion) ? "" : ""}'),
Text('更新类型: ${comparator.getVersionDifference(_currentTestVersion, _remoteTestVersion)}'),
Text('主要版本更新: ${comparator.isMajorUpdate(_currentTestVersion, _remoteTestVersion) ? "" : ""}'),
Text('次要版本更新: ${comparator.isMinorUpdate(_currentTestVersion, _remoteTestVersion) ? "" : ""}'),
Text('修订版本更新: ${comparator.isPatchUpdate(_currentTestVersion, _remoteTestVersion) ? "" : ""}'),
],
),
),
),
const SizedBox(height: 16),
// 版本列表排序
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'版本排序',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Text('升序: ${comparator.sortVersions(_testVersions).join(', ')}'),
Text('降序: ${comparator.sortVersions(_testVersions, descending: true).join(', ')}'),
Text('最新版本: ${comparator.getLatestVersion(_testVersions)}'),
],
),
),
),
],
),
);
}
// 检查更新
Future<void> _checkUpdate() async {
// 模拟服务器地址
const url = 'https://api.example.com/check-update';
final info = await _plugin.checkUpdateSmart(
url,
forceRefresh: true,
cacheDuration: const Duration(hours: 1),
);
if (info == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已是最新版本')),
);
}
}
// 工具方法
String _formatBytes(int bytes) {
if (bytes < 1024) return '$bytes B';
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(2)} KB';
if (bytes < 1024 * 1024 * 1024) return '${(bytes / (1024 * 1024)).toStringAsFixed(2)} MB';
return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB';
}
String _getDownloadStatusText(DownloadStatus status) {
switch (status) {
case DownloadStatus.pending:
return '等待中';
case DownloadStatus.downloading:
return '下载中';
case DownloadStatus.paused:
return '已暂停';
case DownloadStatus.completed:
return '已完成';
case DownloadStatus.failed:
return '失败';
case DownloadStatus.cancelled:
return '已取消';
}
}
String _getNetworkTypeText(NetworkType type) {
switch (type) {
case NetworkType.none:
return '无网络';
case NetworkType.mobile:
return '移动网络';
case NetworkType.wifi:
return 'WiFi';
case NetworkType.ethernet:
return '以太网';
case NetworkType.bluetooth:
return '蓝牙';
case NetworkType.vpn:
return 'VPN';
case NetworkType.other:
return '其他';
}
}
String _getNetworkQualityText(NetworkQuality quality) {
switch (quality) {
case NetworkQuality.unknown:
return '未知';
case NetworkQuality.poor:
return '';
case NetworkQuality.moderate:
return '中等';
case NetworkQuality.good:
return '良好';
case NetworkQuality.excellent:
return '优秀';
}
}
String _getVersionStrategyText(VersionCompareStrategy strategy) {
switch (strategy) {
case VersionCompareStrategy.numeric:
return '数字比较';
case VersionCompareStrategy.semantic:
return '语义化版本';
case VersionCompareStrategy.timestamp:
return '时间戳';
case VersionCompareStrategy.buildNumber:
return '构建号';
case VersionCompareStrategy.custom:
return '自定义';
}
}
}