mirror of
https://github.com/zapstore/zapstore.git
synced 2026-10-05 12:38:24 +00:00
Add BackgroundPackageManager and InstalledPackagesSnapshot classes for managing package installations and snapshots in the background. This includes methods for saving and loading installed packages, with error handling for file operations.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import 'package:models/models.dart';
|
||||
import 'package:zapstore/services/package_manager/installed_packages_snapshot.dart';
|
||||
import 'package:zapstore/services/package_manager/package_manager.dart';
|
||||
|
||||
/// Background-safe PackageManager that avoids EventChannel usage.
|
||||
final class BackgroundPackageManager extends PackageManager {
|
||||
BackgroundPackageManager(super.ref);
|
||||
|
||||
// Zapstore currently targets arm64 APKs for background checks.
|
||||
@override
|
||||
String get platform => 'android-arm64-v8a';
|
||||
|
||||
@override
|
||||
String get packageExtension => '.apk';
|
||||
|
||||
@override
|
||||
bool get supportsSilentInstall => false;
|
||||
|
||||
@override
|
||||
Future<void> install(
|
||||
String appId,
|
||||
String filePath, {
|
||||
required String expectedHash,
|
||||
required int expectedSize,
|
||||
required FileMetadata target,
|
||||
}) {
|
||||
throw UnsupportedError('Install not supported in background');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> uninstall(String appId) {
|
||||
throw UnsupportedError('Uninstall not supported in background');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> launchApp(String appId) {
|
||||
throw UnsupportedError('Launch not supported in background');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> requestPermission() {
|
||||
throw UnsupportedError('Permission not supported in background');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> hasPermission() async => false;
|
||||
|
||||
@override
|
||||
Future<void> syncInstalledPackages() async {
|
||||
final installed = await InstalledPackagesSnapshot.load();
|
||||
state = state.copyWith(installed: installed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:zapstore/services/package_manager/package_manager.dart';
|
||||
|
||||
class InstalledPackagesSnapshot {
|
||||
static const _fileName = 'installed_packages_snapshot.json';
|
||||
|
||||
static Future<File> _file() async {
|
||||
final dir = await getApplicationSupportDirectory();
|
||||
return File(path.join(dir.path, _fileName));
|
||||
}
|
||||
|
||||
static Future<void> save(Map<String, PackageInfo> installed) async {
|
||||
try {
|
||||
final file = await _file();
|
||||
final tmp = File('${file.path}.tmp');
|
||||
final list = installed.values
|
||||
.map(
|
||||
(p) => <String, dynamic>{
|
||||
'appId': p.appId,
|
||||
'name': p.name,
|
||||
'version': p.version,
|
||||
'versionCode': p.versionCode,
|
||||
'signatureHash': p.signatureHash,
|
||||
'canInstallSilently': p.canInstallSilently,
|
||||
},
|
||||
)
|
||||
.toList(growable: false);
|
||||
final payload = jsonEncode({
|
||||
'v': 1,
|
||||
'savedAt': DateTime.now().millisecondsSinceEpoch,
|
||||
'installed': list,
|
||||
});
|
||||
await tmp.writeAsString(payload, flush: true);
|
||||
if (await file.exists()) {
|
||||
await file.delete();
|
||||
}
|
||||
await tmp.rename(file.path);
|
||||
} catch (e) {
|
||||
// Best-effort snapshot only.
|
||||
if (kDebugMode) {
|
||||
debugPrint('[InstalledPackagesSnapshot] Save failed: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Future<Map<String, PackageInfo>> load() async {
|
||||
try {
|
||||
final file = await _file();
|
||||
if (!await file.exists()) return {};
|
||||
|
||||
final raw = await file.readAsString();
|
||||
final decoded = jsonDecode(raw);
|
||||
if (decoded is! Map) return {};
|
||||
final version = decoded['v'];
|
||||
if (version != null && version is! int && kDebugMode) {
|
||||
debugPrint('[InstalledPackagesSnapshot] Unknown schema: $version');
|
||||
}
|
||||
final installed = decoded['installed'];
|
||||
if (installed is! List) return {};
|
||||
|
||||
final result = <String, PackageInfo>{};
|
||||
for (final item in installed) {
|
||||
if (item is! Map) continue;
|
||||
final map = Map<String, dynamic>.from(item);
|
||||
final appId = map['appId'] as String?;
|
||||
if (appId == null || appId.isEmpty) continue;
|
||||
result[appId] = PackageInfo(
|
||||
appId: appId,
|
||||
name: map['name'] as String?,
|
||||
version: (map['version'] as String?) ?? '0.0.0',
|
||||
versionCode: map['versionCode'] as int?,
|
||||
signatureHash: (map['signatureHash'] as String?) ?? '',
|
||||
installTime: null,
|
||||
canInstallSilently: (map['canInstallSilently'] as bool?) ?? false,
|
||||
);
|
||||
}
|
||||
return result;
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
debugPrint('[InstalledPackagesSnapshot] Load failed: $e');
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user