From 7ef9c43ee37d52f51cb0a62f9078b0ac1e7f3b99 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 18 Aug 2023 19:36:56 -0400 Subject: [PATCH] Don't wait for foreground if install is silent --- android/app/build.gradle | 1 - lib/providers/apps_provider.dart | 60 ++++++++++++++++++++++---------- pubspec.lock | 9 +++++ pubspec.yaml | 10 ++++-- 4 files changed, 57 insertions(+), 23 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 09eb008..764d501 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -49,7 +49,6 @@ android { } defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "dev.imranr.obtainium" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index ec9c104..bc03997 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -7,6 +7,7 @@ import 'dart:io'; import 'package:android_intent_plus/flag.dart'; import 'package:android_package_installer/android_package_installer.dart'; +import 'package:android_package_manager/android_package_manager.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; @@ -29,6 +30,8 @@ import 'package:http/http.dart'; import 'package:android_intent_plus/android_intent.dart'; import 'package:flutter_archive/flutter_archive.dart'; +final pm = AndroidPackageManager(); + class AppInMemory { late App app; double? downloadProgress; @@ -322,16 +325,39 @@ class AppsProvider with ChangeNotifier { .isNotEmpty; Future canInstallSilently(App app) async { - return false; - // TODO: Uncomment the below if silent updates are ever figured out - // // NOTE: This is unreliable - try to get from OS in the future - // if (app.apkUrls.length > 1) { - // return false; - // } - // var osInfo = await DeviceInfoPlugin().androidInfo; - // return app.installedVersion != null && - // osInfo.version.sdkInt >= 30 && - // osInfo.version.release.compareTo('12') >= 0; + if (app.apkUrls.length > 1) { + // Manual API selection means silent install is not possible + return false; + } + + var osInfo = await DeviceInfoPlugin().androidInfo; + String? installerPackageName; + try { + installerPackageName = osInfo.version.sdkInt >= 30 + ? (await pm.getInstallSourceInfo(packageName: app.id)) + ?.installingPackageName + : (await pm.getInstallerPackageName(packageName: app.id)); + } catch (e) { + // Probably not installed - ignore + } + if (installerPackageName != obtainiumId) { + // If we did not install the app (or it isn't installed), silent install is not possible + return false; + } + var targetSDK; + try { + targetSDK = (await pm.getPackageInfo(packageName: app.id)) + ?.applicationInfo + ?.targetSdkVersion; + } catch (e) { + // Weird if you get here - ignore + } + + // The OS must also be new enough and the APK should target a new enough API + return osInfo.version.sdkInt >= 30 && + targetSDK != null && + targetSDK >= // https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int) + (osInfo.version.sdkInt - 3); } Future waitForUserToReturnToForeground(BuildContext context) async { @@ -359,8 +385,7 @@ class AppsProvider with ChangeNotifier { zipFile: File(filePath), destinationDir: Directory(destinationPath)); } - Future installXApkDir(DownloadedXApkDir dir, - {bool silent = false}) async { + Future installXApkDir(DownloadedXApkDir dir) async { // We don't know which APKs in an XAPK are supported by the user's device // So we try installing all of them and assume success if at least one installed // If 0 APKs installed, throw the first install error encountered @@ -373,8 +398,7 @@ class AppsProvider with ChangeNotifier { if (file.path.toLowerCase().endsWith('.apk')) { try { somethingInstalled = somethingInstalled || - await installApk(DownloadedApk(dir.appId, file), - silent: silent); + await installApk(DownloadedApk(dir.appId, file)); } catch (e) { logs.add( 'Could not install APK from XAPK \'${file.path}\': ${e.toString()}'); @@ -394,8 +418,7 @@ class AppsProvider with ChangeNotifier { } } - Future installApk(DownloadedApk file, {bool silent = false}) async { - // TODO: Use 'silent' when/if ever possible + Future installApk(DownloadedApk file) async { var newInfo = await PackageArchiveInfo.fromPath(file.file.path); AppInfo? appInfo; try { @@ -571,7 +594,6 @@ class AppsProvider with ChangeNotifier { } bool willBeSilent = await canInstallSilently( apps[downloadedFile?.appId ?? downloadedDir!.appId]!.app); - willBeSilent = false; // TODO: Remove this when silent updates work if (!(await settingsProvider?.getInstallPermission(enforce: false) ?? true)) { throw ObtainiumError(tr('cancelled')); @@ -584,9 +606,9 @@ class AppsProvider with ChangeNotifier { notifyListeners(); try { if (downloadedFile != null) { - await installApk(downloadedFile, silent: willBeSilent); + await installApk(downloadedFile); } else { - await installXApkDir(downloadedDir!, silent: willBeSilent); + await installXApkDir(downloadedDir!); } } finally { apps[id]?.downloadProgress = null; diff --git a/pubspec.lock b/pubspec.lock index 41f8b1e..65b039e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -26,6 +26,15 @@ packages: url: "https://github.com/ImranR98/android_package_installer" source: git version: "0.0.1" + android_package_manager: + dependency: "direct main" + description: + path: "." + ref: master + resolved-ref: "5f58196561734d0f499bb844cdb43e7762a8f019" + url: "https://github.com/ImranR98/android_package_manager" + source: git + version: "0.5.4" animations: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index b445ab3..df430a3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: obtainium -description: A new Flutter project. +description: Get Android App Updates Directly From the Source. # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. @@ -55,9 +55,13 @@ dependencies: git: url: https://github.com/ImranR98/android_package_installer ref: main + android_package_manager: + git: + url: https://github.com/ImranR98/android_package_manager + ref: master share_plus: ^7.0.0 - installed_apps: ^1.3.1 - package_archive_info: ^0.1.0 + installed_apps: ^1.3.1 # TODO: Remove when android_package_manager supports getting icon as UInt8List and versionCode + package_archive_info: ^0.1.0 # TODO: Remove when android_package_manager supports getting versionCode android_alarm_manager_plus: ^3.0.0 sqflite: ^2.2.0+3 easy_localization: ^3.0.1