badge_kit 0.1.0
badge_kit: ^0.1.0 copied to clipboard
A Flutter plugin to update the app icon badge and clear notifications through a single API. Swift Package Manager only on iOS.
import 'package:flutter/material.dart';
import 'package:badge_kit/badge_kit.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
final _notifications = FlutterLocalNotificationsPlugin();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await _notifications.initialize(
settings: const InitializationSettings(
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
iOS: DarwinInitializationSettings(),
),
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: BadgeDemoPage());
}
}
class BadgeDemoPage extends StatefulWidget {
const BadgeDemoPage({super.key});
@override
State<BadgeDemoPage> createState() => _BadgeDemoPageState();
}
class _BadgeDemoPageState extends State<BadgeDemoPage> {
int _count = 0;
int _notificationId = 0;
String _status = '';
@override
void initState() {
super.initState();
// Android 13+ requires a runtime permission to post notifications.
_notifications
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission();
}
/// Runs [action] and shows its result in the status line. When [action]
/// returns a message it is displayed as-is; otherwise '<label>: OK'.
Future<void> _run(String label, Future<String?> Function() action) async {
try {
final message = await action();
setState(() => _status = message ?? '$label: OK');
} catch (e) {
setState(() => _status = '$label: $e');
}
}
Future<void> _sendNotification(String tag) async {
// Let the notification itself set the app icon badge, the same way an
// FCM push does with `aps.badge` / `notification_count`.
setState(() => _count++);
await _notifications.show(
id: _notificationId++,
title: 'badge_kit demo',
body: "Notification tagged '$tag'",
notificationDetails: NotificationDetails(
android: AndroidNotificationDetails(
'badge_kit_demo',
'badge_kit demo',
tag: tag,
number: _count,
),
// badge_kit matches iOS notifications by thread identifier
// (or a "tag" key in the payload).
iOS: DarwinNotificationDetails(
threadIdentifier: tag,
badgeNumber: _count,
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('badge_kit example')),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
Text('Badge count: $_count',
style: Theme.of(context).textTheme.headlineSmall),
const SizedBox(height: 16),
Text('Send', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
FilledButton(
onPressed: () => _run('send chat', () async {
await _sendNotification('chat');
return null;
}),
child: const Text("Send notification tagged 'chat'"),
),
const SizedBox(height: 8),
FilledButton(
onPressed: () => _run('send news', () async {
await _sendNotification('news');
return null;
}),
child: const Text("Send notification tagged 'news'"),
),
const SizedBox(height: 16),
Text('Badge', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
FilledButton.tonal(
onPressed: () => _run('setBadge', () async {
setState(() => _count++);
await BadgeKit.setBadge(_count);
return null;
}),
child: const Text('Increment badge'),
),
const SizedBox(height: 8),
FilledButton.tonal(
onPressed: () => _run('clearBadge', () async {
setState(() => _count = 0);
await BadgeKit.clearBadge();
return null;
}),
child: const Text('Clear badge (keep notifications)'),
),
const SizedBox(height: 8),
FilledButton.tonal(
onPressed: () => _run('clearBadge+notifications', () async {
setState(() => _count = 0);
await BadgeKit.clearBadge(removeNotifications: true);
return null;
}),
child: const Text('Clear badge and notifications'),
),
const SizedBox(height: 16),
Text('Erase', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
OutlinedButton(
onPressed: () => _run('clearAllNotifications', () async {
await BadgeKit.clearAllNotifications();
return null;
}),
child: const Text('Clear all notifications'),
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: () => _run('clearNotificationsByTag', () async {
await BadgeKit.clearNotificationsByTag('chat');
return null;
}),
child: const Text("Clear notifications tagged 'chat'"),
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: () => _run('clearNotificationsByTags', () async {
await BadgeKit.clearNotificationsByTags(['chat', 'news']);
return null;
}),
child: const Text("Clear notifications tagged 'chat' or 'news'"),
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: () => _run('isBadgeSupported', () async {
final supported = await BadgeKit.isBadgeSupported();
return 'isBadgeSupported: $supported';
}),
child: const Text('Is badge supported?'),
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: () => _run('activeNotifications', () async {
final active = await _notifications.getActiveNotifications();
return 'active: ${active.length} ids=${active.map((n) => n.id).toList()}';
}),
child: const Text('List active notifications'),
),
const SizedBox(height: 16),
Text(_status),
],
),
);
}
}