More work on silent updates (not working in BG)

This commit is contained in:
Imran Remtulla
2022-09-24 18:43:05 -04:00
parent b65c6e1d41
commit 0a9373e65a
6 changed files with 73 additions and 33 deletions

View File

@@ -26,9 +26,23 @@ void bgTaskCallback() {
await notificationsProvider
.cancel(ErrorCheckingUpdatesNotification('').id);
await appsProvider.loadApps();
List<App> updates = await appsProvider.checkUpdates();
if (updates.isNotEmpty) {
notificationsProvider.notify(UpdateNotification(updates),
// List<String> existingUpdateIds = // TODO: Uncomment this and below when it works
// appsProvider.getExistingUpdates(installedOnly: true);
List<App> newUpdates = await appsProvider.checkUpdates();
// List<String> silentlyUpdated = await appsProvider
// .downloadAndInstallLatestApp(
// [...newUpdates.map((e) => e.id), ...existingUpdateIds], null);
// if (silentlyUpdated.isNotEmpty) {
// newUpdates
// .where((element) => !silentlyUpdated.contains(element.id))
// .toList();
// notificationsProvider.notify(
// SilentUpdateNotification(
// silentlyUpdated.map((e) => appsProvider.apps[e]!.app).toList()),
// cancelExisting: true);
// }
if (newUpdates.isNotEmpty) {
notificationsProvider.notify(UpdateNotification(newUpdates),
cancelExisting: true);
}
return Future.value(true);
@@ -85,7 +99,7 @@ class MyApp extends StatelessWidget {
if (settingsProvider.updateInterval > 0) {
Workmanager().registerPeriodicTask('bg-update-check', 'bg-update-check',
frequency: Duration(minutes: settingsProvider.updateInterval),
initialDelay: Duration(minutes: settingsProvider.updateInterval),
// initialDelay: Duration(minutes: settingsProvider.updateInterval),
constraints: Constraints(networkType: NetworkType.connected),
existingWorkPolicy: ExistingWorkPolicy.replace);
} else {

View File

@@ -25,8 +25,8 @@ class _AppPageState extends State<AppPage> {
var sourceProvider = SourceProvider();
AppInMemory? app = appsProvider.apps[widget.appId];
var source = app != null ? sourceProvider.getSource(app.app.url) : null;
if (!appsProvider.areDownloadsRunning()) {
appsProvider.getUpdate(app!.app.id).catchError((e) {
if (!appsProvider.areDownloadsRunning() && app != null) {
appsProvider.getUpdate(app.app.id).catchError((e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(e.toString())),
);
@@ -221,7 +221,7 @@ class _AppPageState extends State<AppPage> {
.downloadAndInstallLatestApp(
[app!.app.id],
context).then((res) {
if (res && mounted) {
if (res.isNotEmpty && mounted) {
Navigator.of(context).pop();
}
});

View File

@@ -98,6 +98,7 @@ class AppsProvider with ChangeNotifier {
.isNotEmpty;
Future<bool> canInstallSilently(App app) async {
// TODO: This is unreliable - try to get from OS
var osInfo = await DeviceInfoPlugin().androidInfo;
return app.installedVersion != null &&
osInfo.version.sdkInt! >= 30 &&
@@ -131,19 +132,20 @@ class AppsProvider with ChangeNotifier {
// Given a list of AppIds, uses stored info about the apps to download APKs and install them
// If the APKs can be installed silently, they are
// If no BuildContext is provided, apps that require user interaction are ignored
// If user input is needed and the App is in the background, a notification is sent to get the user's attention
// Returns upon successful download, regardless of installation result
Future<bool> downloadAndInstallLatestApp(
List<String> appIds, BuildContext context) async {
// Returns an array of Ids for Apps that were successfully downloaded, regardless of installation result
Future<List<String>> downloadAndInstallLatestApp(
List<String> appIds, BuildContext? context) async {
Map<String, String> appsToInstall = {};
for (var id in appIds) {
if (apps[id] == null) {
throw 'App not found';
}
// If the App has more than one APK, the user should pick one
// If the App has more than one APK, the user should pick one (if context provided)
String? apkUrl = apps[id]!.app.apkUrls[apps[id]!.app.preferredApkIndex];
if (apps[id]!.app.apkUrls.length > 1) {
if (apps[id]!.app.apkUrls.length > 1 && context != null) {
// ignore: use_build_context_synchronously
await askUserToReturnToForeground(context);
apkUrl = await showDialog(
@@ -152,9 +154,10 @@ class AppsProvider with ChangeNotifier {
return APKPicker(app: apps[id]!.app, initVal: apkUrl);
});
}
// If the picked APK comes from an origin different from the source, get user confirmation
// If the picked APK comes from an origin different from the source, get user confirmation (if context provided)
if (apkUrl != null &&
Uri.parse(apkUrl).origin != Uri.parse(apps[id]!.app.url).origin) {
Uri.parse(apkUrl).origin != Uri.parse(apps[id]!.app.url).origin &&
context != null) {
// ignore: use_build_context_synchronously
await askUserToReturnToForeground(context);
if (await showDialog(
@@ -173,7 +176,11 @@ class AppsProvider with ChangeNotifier {
apps[id]!.app.preferredApkIndex = urlInd;
await saveApp(apps[id]!.app);
}
appsToInstall.putIfAbsent(id, () => apkUrl!);
if (context != null ||
(await canInstallSilently(apps[id]!.app) &&
apps[id]!.app.apkUrls.length == 1)) {
appsToInstall.putIfAbsent(id, () => apkUrl!);
}
}
}
@@ -195,13 +202,15 @@ class AppsProvider with ChangeNotifier {
await installApk(u);
}
for (var i in regularInstalls) {
// ignore: use_build_context_synchronously
await askUserToReturnToForeground(context);
await installApk(i);
if (context != null) {
for (var i in regularInstalls) {
// ignore: use_build_context_synchronously
await askUserToReturnToForeground(context);
await installApk(i);
}
}
return downloadedFiles.isNotEmpty;
return downloadedFiles.map((e) => e.appId).toList();
}
Future<Directory> getAppsDir() async {
@@ -300,12 +309,13 @@ class AppsProvider with ChangeNotifier {
return updates;
}
List<String> getExistingUpdates() {
List<String> getExistingUpdates({bool installedOnly = false}) {
List<String> updateAppIds = [];
List<String> appIds = apps.keys.toList();
for (int i = 0; i < appIds.length; i++) {
App? app = apps[appIds[i]]!.app;
if (app.installedVersion != app.latestVersion) {
if (app.installedVersion != app.latestVersion &&
(app.installedVersion != null || !installedOnly)) {
updateAppIds.add(app.id);
}
}

View File

@@ -33,6 +33,22 @@ class UpdateNotification extends ObtainiumNotification {
}
}
class SilentUpdateNotification extends ObtainiumNotification {
SilentUpdateNotification(List<App> updates)
: super(
3,
'Apps Updated',
'',
'APPS_UPDATED',
'Apps Updated',
'Notifies the user that updates to one or more Apps were applied in the background',
Importance.defaultImportance) {
message = updates.length == 1
? '${updates[0].name} was updated to ${updates[0].latestVersion}.'
: '${(updates.length == 2 ? '${updates[0].name} and ${updates[1].name}' : '${updates[0].name} and ${updates.length - 1} more apps')} were updated.';
}
}
class ErrorCheckingUpdatesNotification extends ObtainiumNotification {
ErrorCheckingUpdatesNotification(String error)
: super(

View File

@@ -7,7 +7,7 @@ packages:
name: animations
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.0.5"
archive:
dependency: transitive
description:
@@ -175,7 +175,7 @@ packages:
name: file_picker
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
version: "5.2.0"
flutter:
dependency: "direct main"
description: flutter
@@ -215,7 +215,7 @@ packages:
name: flutter_local_notifications
url: "https://pub.dartlang.org"
source: hosted
version: "10.0.0"
version: "11.0.1"
flutter_local_notifications_linux:
dependency: transitive
description:
@@ -295,7 +295,7 @@ packages:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "4.6.0"
version: "4.7.0"
lints:
dependency: transitive
description:
@@ -393,7 +393,7 @@ packages:
name: permission_handler
url: "https://pub.dartlang.org"
source: hosted
version: "10.0.0"
version: "10.0.1"
permission_handler_android:
dependency: transitive
description:
@@ -414,7 +414,7 @@ packages:
name: permission_handler_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.7.0"
version: "3.7.1"
permission_handler_windows:
dependency: transitive
description:
@@ -538,7 +538,7 @@ packages:
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
@@ -566,7 +566,7 @@ packages:
name: timezone
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.0"
version: "0.9.0"
typed_data:
dependency: transitive
description:
@@ -636,7 +636,7 @@ packages:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
version: "2.1.4"
webview_flutter:
dependency: "direct main"
description:
@@ -650,7 +650,7 @@ packages:
name: webview_flutter_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.10.1"
version: "2.10.2"
webview_flutter_platform_interface:
dependency: transitive
description:

View File

@@ -38,7 +38,7 @@ dependencies:
cupertino_icons: ^1.0.5
path_provider: ^2.0.11
flutter_fgbg: ^0.2.0 # Try removing reliance on this
flutter_local_notifications: ^10.0.0
flutter_local_notifications: ^11.0.1
provider: ^6.0.3
http: ^0.13.5
webview_flutter: ^3.0.4