What is Notification Permission
What is Notification Permission?
Notification permission is the authorization given by the user to allow an app to:
✔ Show push notifications
✔ Display banners, alerts, and pop-ups
✔ Play notification sounds
✔ Show badges on the app icon
✔ Deliver critical alerts (iOS only)
Most operating systems treat notifications as privacy-sensitive features.
Because of this, they require explicit user consent before an app can send or display notifications.
When your app needs notification access, you call a function inside your notification service class, usually named:
requestNotificationPermission()
==============or=============
final NotificationServices _notificationServices = NotificationServices();
_notificationServices.requestNotificationPermission();
import 'package:firebase/notification_services.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
final String title;
const HomeScreen({super.key, required this.title});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _counter = 0;
// Create Notification Service Instance
final NotificationServices _notificationServices = NotificationServices();
@override
void initState() {
super.initState();
// Request permission on app start
_notificationServices.requestNotificationPermission();
// Initialize foreground notifications listener
_notificationServices.firebaseInit(context);
// Handle notification click when app is opened from notification
_notificationServices.handleNotificationClick(context);
// Optional: Print FCM Token
_notificationServices.getDeviceToken();
}
This function internally triggers:
🔹 The OS permission dialog
🔹 Firebase Messaging authorization
🔹 Permission statuses (authorized / denied / provisional)
❓
Why Do Apps Need Notification Permission?
Here are the key reasons:
- Respecting User Privacy
Users should have full control over which apps can interrupt them with alerts.
- Preventing Notification Spam
Without permission control, apps could misuse notifications and annoy users.
- OS Policy Requirements
Android 13+ and iOS require apps to request permission before sending notifications.
If the user denies it → notifications will NOT appear.
- Compliance with Play Store & App Store guidelines
Both Google & Apple enforce strict rules about permission usage.
- Better User Engagement
An app that politely requests permission usually gets a higher approval rate.
📱
Notification Permission on Android
Android ≤ 12
Notifications are allowed by default, unless the user disables them manually.
Android 13+ (API 33+)
Google introduced the POST_NOTIFICATIONS runtime permission.
Apps must explicitly request permission, similar to camera or location.
If permission is not granted:
❌ Firebase messages will not show
❌ Foreground notifications won't appear
❌ No banner, sound, or alerts
🍎
Notification Permission on iOS
Apple requires notification permission for all iOS versions.
When your app requests permission, the user sees a system popup like:
“App wants to send you notifications”
Allow / Don't Allow
If the user denies:
❌ All notifications are blocked
❌ App cannot ask again (unless user changes settings manually)
That’s why a well-designed permission request strategy is very important.
🧠
Best Practices for Asking Notification Permission
✔ Ask permission after explaining why (not on app launch)
✔ Trigger the request after a meaningful user action
✔ Show a custom screen before the first system popup
✔ If denied → redirect user to system settings screen
✔ Never spam the permission dialog
Syntax to Request Notification Permission (Flutter)
Before using it inside your UI, you must understand the syntax:
🔹 Syntax
_notificationServices.requestNotificationPermission();
This means:
_notificationServices → an object of your NotificationServices class
requestNotificationPermission() → a method inside that class
It triggers the notification permission popup
It handles authorized / provisional / denied cases
📌
When Should You Call It?
You typically call it inside initState():
When the Home Screen loads
Or after a user performs a meaningful action
Do NOT call it immediately on app launch (user may deny it).
void initState() {
super.initState();
// Request permission on app start
_notificationServices.requestNotificationPermission();
// Initialize foreground notifications listener
_notificationServices.firebaseInit(context);
// Handle notification click when app is opened from notification
_notificationServices.handleNotificationClick(context);
// Optional: Print FCM Token
_notificationServices.getDeviceToken();
}
Example (After Theory)
Now that we understand why permission is needed and what the syntax is, here is how you usually place it inside a Stateful widget:
@override
void initState() {
super.initState();
// Asking notification permission
_notificationServices.requestNotificationPermission();
}
Full code
Step 1: Import Dependencies
Add this to your pubspec.yaml:
dependencies:
firebase_core: ^3.0.0
firebase_messaging: ^15.0.0
app_settings: ^5.1.1
Run:
flutter pub get
📌 Step 2: Create Notification Service Class
Create a file:
lib/notification_services.dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:app_settings/app_settings.dart';
class NotificationServices {
final FirebaseMessaging _messaging = FirebaseMessaging.instance;
/// REQUEST PERMISSION
Future<void> requestNotificationPermission() async {
NotificationSettings settings = await _messaging.requestPermission(
alert: true,
announcement: true,
badge: true,
carPlay: false,
criticalAlert: true,
provisional: true,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print("User granted permission");
} else if (settings.authorizationStatus == AuthorizationStatus.provisional) {
print("User granted provisional permission");
} else {
print("User denied permission");
AppSettings.openAppSettings(type: AppSettingsType.notification);
}
}
/// GET FCM TOKEN
Future<String?> getDeviceToken() async {
String? token = await _messaging.getToken();
print("FCM Token: $token");
return token;
}
/// HANDLE FOREGROUND NOTIFICATIONS
void firebaseInit(BuildContext context) {
FirebaseMessaging.onMessage.listen((message) {
if (message.notification != null) {
_showPopup(
context,
message.notification!.title ?? "Notification",
message.notification!.body ?? "",
);
}
});
}
void _showPopup(BuildContext context, String title, String body) {
showDialog(
context: context,
builder: (_) => AlertDialog(
title: Text(title),
content: Text(body),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text("OK"),
)
],
),
);
}
/// HANDLE CLICK EVENTS
void handleNotificationClick(BuildContext context) {
FirebaseMessaging.onMessageOpenedApp.listen((message) {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => NotificationClickScreen(
title: message.notification!.title ?? "",
body: message.notification!.body ?? "",
),
),
);
});
}
}
class NotificationClickScreen extends StatelessWidget {
final String title;
final String body;
const NotificationClickScreen({
super.key,
required this.title,
required this.body,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Notification Details")),
body: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Title: $title",
style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
Text("Body: $body", style: const TextStyle(fontSize: 18)),
],
),
),
);
}
}
📌 Step 3: Use Notification Service in HomeScreen
Update your HomeScreen:
class _HomeScreenState extends State<HomeScreen> {
final NotificationServices _notificationServices = NotificationServices();
@override
void initState() {
super.initState();
_notificationServices.requestNotificationPermission();
_notificationServices.firebaseInit(context);
_notificationServices.handleNotificationClick(context);
_notificationServices.getDeviceToken();
}
}
📌 Step 4: Initialize Firebase in main.dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await FirebaseApi().initNotifications(); // optional background handler
runApp(const MyApp());
}
Top comments (0)