I am developing a Flutter app that needs to send notifications even when the app is completely closed, including when it is removed from the recent apps list. I am using the following setup:
Packages:
flutter_local_notifications for notifications. battery_plus for detecting battery state changes (e.g., charger plugged in or disconnected). Goal:
Trigger a notification when the charger is plugged in or disconnected, even if the app is not running in the background. Current Issue:
Notifications work when the app is running or in the background but stop when the app is killed (removed from recent apps).
Getting notification when app is in recents…when clear not getting notification
main.dart:
import 'package:flutter/material.dart';
import 'package:battery_plus/battery_plus.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Charger Notification',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final Battery _battery = Battery();
final FlutterLocalNotificationsPlugin _notificationsPlugin =
FlutterLocalNotificationsPlugin();
BatteryState? _batteryState;
@override
void initState() {
super.initState();
_initializeNotifications();
_listenToBatteryState();
}
Future<void> _initializeNotifications() async {
// Request notification permission
if (await Permission.notification.isDenied) {
await Permission.notification.request();
}
const InitializationSettings initializationSettings = InitializationSettings(
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
);
await _notificationsPlugin.initialize(initializationSettings);
}
void _showNotification(String title, String body) async {
const AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails(
'charger_channel',
'Charger Notifications',
channelDescription: 'Notifications when charger is plugged or unplugged',
importance: Importance.high,
priority: Priority.high,
);
const NotificationDetails notificationDetails =
NotificationDetails(android: androidNotificationDetails);
await _notificationsPlugin.show(
0,
title,
body,
notificationDetails,
);
}
void _listenToBatteryState() {
_battery.onBatteryStateChanged.listen((BatteryState state) {
if (_batteryState != state) {
setState(() {
_batteryState = state;
});
if (state == BatteryState.charging) {
_showNotification('Charger Connected', 'Your device is now charging.');
} else if (state == BatteryState.discharging) {
_showNotification(
'Charger Disconnected', 'Your device is no longer charging.');
}
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Charger Notification App'),
),
body: Center(
child: Text(
_batteryState == BatteryState.charging
? 'Device is Charging'
: _batteryState == BatteryState.connectedNotCharging
? 'Device is Not Charging'
: 'Unknown State',
style: const TextStyle(fontSize: 20),
),
),
);
}
}
manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.BATTERY_STATS" />
<application
android:label="testbattery"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin.
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>