mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-08-19 05:00:21 +02:00
Try using foreground tasks for reliability
This commit is contained in:
256
lib/main.dart
256
lib/main.dart
@@ -9,16 +9,15 @@ import 'package:obtainium/providers/native_provider.dart';
|
||||
import 'package:obtainium/providers/notifications_provider.dart';
|
||||
import 'package:obtainium/providers/settings_provider.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:dynamic_color/dynamic_color.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:background_fetch/background_fetch.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
// ignore: implementation_imports
|
||||
import 'package:easy_localization/src/easy_localization_controller.dart';
|
||||
// ignore: implementation_imports
|
||||
import 'package:easy_localization/src/localization.dart';
|
||||
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
|
||||
|
||||
List<MapEntry<Locale, String>> supportedLocales = const [
|
||||
MapEntry(Locale('en'), 'English'),
|
||||
@@ -86,16 +85,35 @@ Future<void> loadTranslations() async {
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
void backgroundFetchHeadlessTask(HeadlessTask task) async {
|
||||
String taskId = task.taskId;
|
||||
bool isTimeout = task.timeout;
|
||||
if (isTimeout) {
|
||||
print('BG update task timed out.');
|
||||
BackgroundFetch.finish(taskId);
|
||||
return;
|
||||
void startCallback() {
|
||||
FlutterForegroundTask.setTaskHandler(MyTaskHandler());
|
||||
}
|
||||
|
||||
class MyTaskHandler extends TaskHandler {
|
||||
static const String incrementCountCommand = 'incrementCount';
|
||||
|
||||
// Called when the task is started.
|
||||
@override
|
||||
Future<void> onStart(DateTime timestamp, TaskStarter starter) async {
|
||||
print('onStart(starter: ${starter.name})');
|
||||
bgUpdateCheck('bg_check', null);
|
||||
}
|
||||
await bgUpdateCheck(taskId, null);
|
||||
BackgroundFetch.finish(taskId);
|
||||
|
||||
// Called based on the eventAction set in ForegroundTaskOptions.
|
||||
@override
|
||||
void onRepeatEvent(DateTime timestamp) {
|
||||
bgUpdateCheck('Foreground service bg_check', null);
|
||||
}
|
||||
|
||||
// Called when the task is destroyed.
|
||||
@override
|
||||
Future<void> onDestroy(DateTime timestamp, bool isTimeout) async {
|
||||
print('Foreground service onDestroy(isTimeout: $isTimeout)');
|
||||
}
|
||||
|
||||
// Called when data is sent using `FlutterForegroundTask.sendDataToTask`.
|
||||
@override
|
||||
void onReceiveData(Object data) {}
|
||||
}
|
||||
|
||||
void main() async {
|
||||
@@ -119,6 +137,7 @@ void main() async {
|
||||
}
|
||||
final np = NotificationsProvider();
|
||||
await np.initialize();
|
||||
FlutterForegroundTask.initCommunicationPort();
|
||||
runApp(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
@@ -136,7 +155,6 @@ void main() async {
|
||||
),
|
||||
),
|
||||
);
|
||||
BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
|
||||
}
|
||||
|
||||
class Obtainium extends StatefulWidget {
|
||||
@@ -152,32 +170,72 @@ class _ObtainiumState extends State<Obtainium> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
initPlatformState();
|
||||
// FlutterForegroundTask.addTaskDataCallback(onReceiveForegroundServiceData);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
requestNonOptionalPermissions();
|
||||
initForegroundService();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> initPlatformState() async {
|
||||
await BackgroundFetch.configure(
|
||||
BackgroundFetchConfig(
|
||||
minimumFetchInterval: 15,
|
||||
stopOnTerminate: false,
|
||||
startOnBoot: true,
|
||||
enableHeadless: true,
|
||||
requiresBatteryNotLow: false,
|
||||
requiresCharging: false,
|
||||
requiresStorageNotLow: false,
|
||||
requiresDeviceIdle: false,
|
||||
requiredNetworkType: NetworkType.ANY,
|
||||
Future<void> requestNonOptionalPermissions() async {
|
||||
final NotificationPermission notificationPermission =
|
||||
await FlutterForegroundTask.checkNotificationPermission();
|
||||
if (notificationPermission != NotificationPermission.granted) {
|
||||
await FlutterForegroundTask.requestNotificationPermission();
|
||||
}
|
||||
if (!await FlutterForegroundTask.isIgnoringBatteryOptimizations) {
|
||||
await FlutterForegroundTask.requestIgnoreBatteryOptimization();
|
||||
}
|
||||
}
|
||||
|
||||
void initForegroundService() {
|
||||
FlutterForegroundTask.init(
|
||||
androidNotificationOptions: AndroidNotificationOptions(
|
||||
channelId: 'bg_update',
|
||||
channelName: tr('placeholder'),
|
||||
channelDescription: tr('placeholder'),
|
||||
onlyAlertOnce: true,
|
||||
),
|
||||
iosNotificationOptions: const IOSNotificationOptions(
|
||||
showNotification: false,
|
||||
playSound: false,
|
||||
),
|
||||
foregroundTaskOptions: ForegroundTaskOptions(
|
||||
eventAction: ForegroundTaskEventAction.repeat(900000),
|
||||
autoRunOnBoot: true,
|
||||
autoRunOnMyPackageReplaced: true,
|
||||
allowWakeLock: true,
|
||||
allowWifiLock: true,
|
||||
),
|
||||
(String taskId) async {
|
||||
await bgUpdateCheck(taskId, null);
|
||||
BackgroundFetch.finish(taskId);
|
||||
},
|
||||
(String taskId) async {
|
||||
context.read<LogsProvider>().add('BG update task timed out.');
|
||||
BackgroundFetch.finish(taskId);
|
||||
},
|
||||
);
|
||||
if (!mounted) return;
|
||||
}
|
||||
|
||||
Future<ServiceRequestResult> startForegroundService() async {
|
||||
if (await FlutterForegroundTask.isRunningService) {
|
||||
return FlutterForegroundTask.restartService();
|
||||
} else {
|
||||
return FlutterForegroundTask.startService(
|
||||
serviceTypes: [ForegroundServiceTypes.specialUse],
|
||||
serviceId: 666,
|
||||
notificationTitle: tr('placeholder'),
|
||||
notificationText: tr('placeholder'),
|
||||
notificationIcon: NotificationIcon(
|
||||
metaDataName: 'dev.imranr.obtainium.service.NOTIFICATION_ICON',
|
||||
),
|
||||
callback: startCallback,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// void onReceiveForegroundServiceData(Object data) {
|
||||
// print('onReceiveTaskData: $data');
|
||||
// }
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Remove a callback to receive data sent from the TaskHandler.
|
||||
// FlutterForegroundTask.removeTaskDataCallback(onReceiveForegroundServiceData);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -186,15 +244,14 @@ class _ObtainiumState extends State<Obtainium> {
|
||||
AppsProvider appsProvider = context.read<AppsProvider>();
|
||||
LogsProvider logs = context.read<LogsProvider>();
|
||||
NotificationsProvider notifs = context.read<NotificationsProvider>();
|
||||
|
||||
startForegroundService();
|
||||
if (settingsProvider.prefs == null) {
|
||||
settingsProvider.initializeSettings();
|
||||
} else {
|
||||
bool isFirstRun = settingsProvider.checkAndFlipFirstRun();
|
||||
if (isFirstRun) {
|
||||
logs.add('This is the first ever run of Obtainium.');
|
||||
// If this is the first run, ask for notification permissions and add Obtainium to the Apps list
|
||||
Permission.notification.request();
|
||||
// If this is the first run, add Obtainium to the Apps list
|
||||
if (!fdroid) {
|
||||
getInstalledInfo(obtainiumId)
|
||||
.then((value) {
|
||||
@@ -236,68 +293,71 @@ class _ObtainiumState extends State<Obtainium> {
|
||||
notifs.checkLaunchByNotif();
|
||||
});
|
||||
|
||||
return DynamicColorBuilder(
|
||||
builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
|
||||
// Decide on a colour/brightness scheme based on OS and user settings
|
||||
ColorScheme lightColorScheme;
|
||||
ColorScheme darkColorScheme;
|
||||
if (lightDynamic != null &&
|
||||
darkDynamic != null &&
|
||||
settingsProvider.useMaterialYou) {
|
||||
lightColorScheme = lightDynamic.harmonized();
|
||||
darkColorScheme = darkDynamic.harmonized();
|
||||
} else {
|
||||
lightColorScheme = ColorScheme.fromSeed(
|
||||
seedColor: settingsProvider.themeColor,
|
||||
return WithForegroundTask(
|
||||
child: DynamicColorBuilder(
|
||||
builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
|
||||
// Decide on a colour/brightness scheme based on OS and user settings
|
||||
ColorScheme lightColorScheme;
|
||||
ColorScheme darkColorScheme;
|
||||
if (lightDynamic != null &&
|
||||
darkDynamic != null &&
|
||||
settingsProvider.useMaterialYou) {
|
||||
lightColorScheme = lightDynamic.harmonized();
|
||||
darkColorScheme = darkDynamic.harmonized();
|
||||
} else {
|
||||
lightColorScheme = ColorScheme.fromSeed(
|
||||
seedColor: settingsProvider.themeColor,
|
||||
);
|
||||
darkColorScheme = ColorScheme.fromSeed(
|
||||
seedColor: settingsProvider.themeColor,
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
}
|
||||
|
||||
// set the background and surface colors to pure black in the amoled theme
|
||||
if (settingsProvider.useBlackTheme) {
|
||||
darkColorScheme = darkColorScheme
|
||||
.copyWith(surface: Colors.black)
|
||||
.harmonized();
|
||||
}
|
||||
|
||||
if (settingsProvider.useSystemFont) NativeFeatures.loadSystemFont();
|
||||
|
||||
return MaterialApp(
|
||||
title: 'Obtainium',
|
||||
localizationsDelegates: context.localizationDelegates,
|
||||
supportedLocales: context.supportedLocales,
|
||||
locale: context.locale,
|
||||
navigatorKey: globalNavigatorKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: settingsProvider.theme == ThemeSettings.dark
|
||||
? darkColorScheme
|
||||
: lightColorScheme,
|
||||
fontFamily: settingsProvider.useSystemFont
|
||||
? 'SystemFont'
|
||||
: 'Montserrat',
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: settingsProvider.theme == ThemeSettings.light
|
||||
? lightColorScheme
|
||||
: darkColorScheme,
|
||||
fontFamily: settingsProvider.useSystemFont
|
||||
? 'SystemFont'
|
||||
: 'Montserrat',
|
||||
),
|
||||
home: Shortcuts(
|
||||
shortcuts: <LogicalKeySet, Intent>{
|
||||
LogicalKeySet(LogicalKeyboardKey.select):
|
||||
const ActivateIntent(),
|
||||
},
|
||||
child: const HomePage(),
|
||||
),
|
||||
);
|
||||
darkColorScheme = ColorScheme.fromSeed(
|
||||
seedColor: settingsProvider.themeColor,
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
}
|
||||
|
||||
// set the background and surface colors to pure black in the amoled theme
|
||||
if (settingsProvider.useBlackTheme) {
|
||||
darkColorScheme = darkColorScheme
|
||||
.copyWith(surface: Colors.black)
|
||||
.harmonized();
|
||||
}
|
||||
|
||||
if (settingsProvider.useSystemFont) NativeFeatures.loadSystemFont();
|
||||
|
||||
return MaterialApp(
|
||||
title: 'Obtainium',
|
||||
localizationsDelegates: context.localizationDelegates,
|
||||
supportedLocales: context.supportedLocales,
|
||||
locale: context.locale,
|
||||
navigatorKey: globalNavigatorKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: settingsProvider.theme == ThemeSettings.dark
|
||||
? darkColorScheme
|
||||
: lightColorScheme,
|
||||
fontFamily: settingsProvider.useSystemFont
|
||||
? 'SystemFont'
|
||||
: 'Montserrat',
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: settingsProvider.theme == ThemeSettings.light
|
||||
? lightColorScheme
|
||||
: darkColorScheme,
|
||||
fontFamily: settingsProvider.useSystemFont
|
||||
? 'SystemFont'
|
||||
: 'Montserrat',
|
||||
),
|
||||
home: Shortcuts(
|
||||
shortcuts: <LogicalKeySet, Intent>{
|
||||
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
|
||||
},
|
||||
child: const HomePage(),
|
||||
),
|
||||
);
|
||||
},
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user