app_badger 3.1.2
app_badger: ^3.1.2 copied to clipboard
A Flutter plugin to manage app badge counts on Android, iOS, and macOS with modern Swift Package Manager and federated architecture support.
import 'dart:async';
import 'package:app_badger/app_badger.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final TextEditingController _channelIdController = TextEditingController();
final TextEditingController _channelNameController = TextEditingController();
final TextEditingController _smallIconController = TextEditingController();
String _appBadgeSupported = 'Unknown';
String _badgeStatus = '';
String _permissionStatus = 'Checking...';
bool _postNotification = true;
int _count = 0;
final List<String> _events = [];
String _lastEvent = '—';
StreamSubscription<dynamic>? _eventsSub;
@override
void initState() {
super.initState();
_initPlatformState();
_eventsSub = AppBadgeController.events.listen((e) {
setState(() {
_events.add(e.toString());
_lastEvent = e.toString();
});
}, onError: (_) {});
}
@override
void dispose() {
_eventsSub?.cancel();
_channelIdController.dispose();
_channelNameController.dispose();
_smallIconController.dispose();
super.dispose();
}
Future<void> _initPlatformState() async {
try {
final supported = await AppBadgeController.isFeatureSupported();
final perm = await AppBadgeController.readPermissionStatus();
setState(() {
_appBadgeSupported = supported ? 'Yes' : 'No';
_permissionStatus = perm.toString().split('.').last;
});
} on PlatformException {
setState(() {
_appBadgeSupported = 'Error';
_permissionStatus = 'Error';
});
}
}
Future<void> _addBadge() async {
try {
_count++;
await AppBadgeController.setBadgeValue(_count,
postNotification: _postNotification,
notificationChannelId: _channelIdController.text.isEmpty ? null : _channelIdController.text,
notificationChannelName: _channelNameController.text.isEmpty ? null : _channelNameController.text,
notificationSmallIcon: _smallIconController.text.isEmpty ? null : _smallIconController.text);
setState(() {
_badgeStatus = 'Badge set to $_count';
});
} on PlatformException {
setState(() {
_badgeStatus = 'Failed to set badge';
});
}
}
Future<void> _addBadgeNoNotification() async {
try {
_count++;
await AppBadgeController.setBadgeValue(_count, postNotification: false);
setState(() {
_badgeStatus = 'Badge set to $_count (no notification)';
});
} on PlatformException {
setState(() {
_badgeStatus = 'Failed to set badge';
});
}
}
Future<void> _removeBadge() async {
try {
_count = 0;
await AppBadgeController.clearBadgeValue();
setState(() {
_badgeStatus = 'Badge removed';
});
} on PlatformException {
setState(() {
_badgeStatus = 'Failed to remove badge';
});
}
}
Future<void> _openNotificationSettings() async {
try {
await AppBadgeController.openNotificationSettings();
} on PlatformException {
setState(() {
_badgeStatus = 'Failed to open notification settings';
});
}
}
Future<void> _requestPermission() async {
try {
final granted = await AppBadgeController.requestBadgePermission();
setState(() {
_permissionStatus = granted ? 'granted' : 'denied';
_badgeStatus = 'Permission request: ${granted ? 'Granted' : 'Denied'}';
});
} on PlatformException {
setState(() {
_badgeStatus = 'Failed to request notification permission';
});
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.indigo),
home: Scaffold(
appBar: AppBar(
title: const Text('App Badger Example'),
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(colors: [Color(0xFF4F46E5), Color(0xFF0EA5A4)]),
),
),
),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Status', style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8),
Text('Badge supported: $_appBadgeSupported'),
const SizedBox(height: 4),
Text('Permission: $_permissionStatus'),
const SizedBox(height: 4),
Text('Last: $_badgeStatus'),
],
),
),
),
const SizedBox(height: 12),
Card(
child: Padding(
padding: const EdgeInsets.all(12),
child: Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton.icon(
icon: const Icon(Icons.add),
label: const Text('Add (notify)'),
onPressed: _addBadge,
),
OutlinedButton.icon(
icon: const Icon(Icons.add),
label: const Text('Add (no notify)'),
onPressed: _addBadgeNoNotification,
),
ElevatedButton.icon(
icon: const Icon(Icons.delete),
label: const Text('Remove'),
onPressed: _removeBadge,
),
ElevatedButton.icon(
icon: const Icon(Icons.security),
label: const Text('Request Permission'),
onPressed: _requestPermission,
),
TextButton.icon(
icon: const Icon(Icons.settings),
label: const Text('Notification settings'),
onPressed: _openNotificationSettings,
),
Row(mainAxisSize: MainAxisSize.min, children: [
const Text('Post notification'),
Switch(value: _postNotification, onChanged: (v) => setState(() => _postNotification = v))
])
],
),
),
),
const SizedBox(height: 12),
Card(
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(children: [
TextField(controller: _channelIdController, decoration: const InputDecoration(labelText: 'Channel id (optional)')),
const SizedBox(height: 8),
TextField(controller: _channelNameController, decoration: const InputDecoration(labelText: 'Channel name (optional)')),
const SizedBox(height: 8),
TextField(controller: _smallIconController, decoration: const InputDecoration(labelText: 'Small icon drawable (optional)')),
const SizedBox(height: 8),
ElevatedButton(
onPressed: () {
AppBadgeController.setAndroidNotificationConfig(
channelId: _channelIdController.text.isEmpty ? null : _channelIdController.text,
channelName: _channelNameController.text.isEmpty ? null : _channelNameController.text,
smallIcon: _smallIconController.text.isEmpty ? null : _smallIconController.text,
);
setState(() {
_badgeStatus = 'Android notification config set';
});
},
child: const Text('Set Android defaults'),
)
]),
),
),
const SizedBox(height: 12),
Card(
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text('Events', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
Text('Last event: $_lastEvent'),
const SizedBox(height: 8),
SizedBox(
height: 160,
child: ListView.builder(
itemCount: _events.length,
itemBuilder: (context, idx) => Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Text(_events[idx]),
),
),
)
]),
),
),
],
),
),
),
),
);
}
}