Dependency
Firebase Messaging
Firebaseμ Messaging κΈ°λ₯μ μ¬μ©νκΈ° μν pub.
flutter pub add firebase_messaging
Dart
볡μ¬
iOS νλ‘μ νΈ μ€μ
β’
Required: Capability (xcode project setting)
β’
Required: νΈμ μΈμ¦μ μμ± (developer apple center)
β’
Optional: Remote Notification, Background fetch
Apple Developer μ€μ
AppID μμ±
μ±μ μ±μ€ν μ΄μ μΆμνκΈ° μν΄μ AppID κ° νμν©λλ€. κ·Έλ¦¬κ³ AppIDλ₯Ό μΆκ°νλ κ³Όμ μμ ν΄λΉ μ±μ Capabilityλ₯Ό μ€μ ν©λλ€. iOS νλ‘μ νΈ μ€μ μμ XCode Project μ Capabilityλ₯Ό μΆκ°νλ κ³Όμ μ μ§(?) μ΄λΌκ³ 보면 λ©λλ€. μ¬κΈ°μ Notification νλλ§ μΆκ°ν΄μ£Όλλ‘ ν©λλ€.
APN Key μμ±
FCM μΌλ‘ Notificationμ μ¬μ©νλ λ°©μμ 2κ°κ° μμ΅λλ€. νΈμ μΈμ¦μ, APN Key.
νΈμ μΈμ¦μλ κ³Όκ±°μ μ¬μ©νλ λ°©μμΌλ‘ 1λ
λ§λ€ κ°±μ ν΄μΌνλ λ²κ±°λ‘μμ΄ μμ΅λλ€. μ κ· νλ‘μ νΈλ₯Ό μμ±νλ€λ©΄ APN Key λ°©μμ μΆμ²ν©λλ€.
Firebase μ€μ
μμλμΈμ
Flutter iOS Push Notification, FCMλΌλ ν€μλ λ±μΌλ‘ iOSμμ Push notification μμ
μ νλ λΈλ‘κ·Έλ€μ΄ λ§μλ°, μ λΆ Capabilityμμ background fetchμ Remote notification μ΅μ
μ μ€μ νλΌκ³ ν©λλ€..
νμ§ λ§μΈμ
Push Notification λ§ μΆκ°ν΄μ£Όμλ©΄ λ©λλ€.
Push Notification λ§ μΆκ°ν΄μ£Όμλ©΄ λ©λλ€.background fetchμ Remote notificationλ μ©λ μμ²΄κ° λ€λ¦
λλ€...! λ€λ₯Έ λΈλ‘κ·Έμμλ μ μΆκ°νλΌλμ§ λͺ¨λ₯΄κ² μ΄μ..
fyi) background fetch λ μ±μ΄ background μνμ μμλ μ± λ΄ μΌλΆ κΈ°λ₯λ€μ μ€ννκΈ° μν΄ νμν κΆνμ λ°μ΅λλ€. μμ
μ±, μ νλΈ, λλ μκ°μ΄ μ€λ걸리λ μμ
μ΄μ΄μ background μμλ μ΄μ΄μ ν΄μΌνλ μμ
λ€μ ν΄μΌν λ νμν©λλ€.
remote notificationμ push notification μ€μμ content-available field κ°μ true λ‘ νλ κ²½μ°λ₯Ό μλ―Έν©λλ€. μ±μ΄ μ΄ pushλ₯Ό λ°μ κ²½μ°, νλ©΄ μλ¨μ notificationμ΄ λ¨μ§ μμ΅λλ€. λμ μ±μ΄ backgroundμμ μ€νλ©λλ€. μ¬μ©μ λͺ¨λ₯΄κ²μ..! μ± λ°±κ·ΈλΌμ΄λμμ API νΈμΆ λ±μ ν΅ν΄ μ± λ΄μ 보μ¬μ§λ 컨ν
μΈ λ€μ μ
λ°μ΄νΈ ν©λλ€. μ¬μ©μκ° μ±μ μΌμ μλ‘μ΄ λ΄μ©μ λ°μμ€κΈ° μ μ λΉ λ₯΄κ² λ¨Όμ μ
λ°μ΄νΈ ν λ μ¬μ©ν©λλ€.
Example
main.dart
import 'dart:developer';
import 'package:chai_booster/Constants.dart';
import 'package:chai_booster/Interceptor/authorizationInterceptor.dart';
import 'package:chai_booster/Pages/Loader/Loader.dart';
import 'package:chai_booster/Pages/RootPage.dart';
import 'package:chai_booster/Providers/Auth/AuthProvider.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:http_interceptor/http_client_with_interceptor.dart';
import 'package:provider/provider.dart';
import 'main.mapper.g.dart' show initializeJsonMapper;
void main() {
Constants.setEnvironment(Environment.PROD);
initializeJsonMapper();
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
class App extends StatefulWidget {
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
bool _initialized = false;
bool _error = false;
final client = HttpClientWithInterceptor.build(
interceptors: [
AuthorizationInterceptor()
],
retryPolicy:
ExpiredTokenRetryPolicy()
);
void initializeFlutterFire() async {
try {
await Firebase.initializeApp();
if (Constants.IS_DEBUG) {
await FirebaseAuth.instance.useEmulator('http://localhost:9099');
}
setState(() {
_initialized = true;
});
} catch(e) {
setState(() {
log(e.toString());
_error = true;
});
}
}
void initializeNotification() async { // ππππππππ μ¬κΈ°κ° ν΅μ¬
await Firebase.initializeApp();
FirebaseMessaging messaging = FirebaseMessaging.instance;
await messaging.setAutoInitEnabled(true);
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
await messaging.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
void initState() {
initializeFlutterFire();
initializeNotification();
super.initState();
}
Widget build(BuildContext context) {
if(_error || !_initialized) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Loader(),
),
)
);
}
return MaterialApp(
home: MultiProvider(
providers: [
ChangeNotifierProvider<AuthProvider>(create: (_) => AuthProvider()),
],
child: RootPage(),
)
);
}
}
Dart
볡μ¬
HomePage.dart // Notification Permission μμ²νκ³
mainPage.dart μμλ notification permissionμ μμ²ν μ μμ΅λλ€. λμ , μ¬μ©μλ μ΄ μ±μ΄ μ΄λ€ κ²½μ°μ μλ¦Όμ μ£Όλμ§λ λͺ¨λ₯Έμ± μλ¦Ό κΆν κ²°μ μ ν΄μΌν©λλ€. μ’μ UXκ° μλλλ€.
κ·Έλμ μ¬μ©μμκ² μλ―Έμλ νλ©΄μΈ HomePage.dartμμ κΆν μμ²μ λ°λλ‘ νμ΅λλ€.
import 'dart:convert';
import 'package:chai_booster/Constants.dart';
import 'package:chai_booster/Interceptor/authorizationInterceptor.dart';
import 'package:chai_booster/Pages/Tabs/BrandAlarmSubscriptions/BrandAlarmSettingPage.dart';
import 'package:chai_booster/Pages/Tabs/More/MorePage.dart';
import 'package:chai_booster/Pages/Tabs/Promotions/PromotionsPage.dart';
import 'package:chai_booster/Pages/Tabs/Today/TodayPage.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:http_interceptor/http_client_with_interceptor.dart';
class HomePage extends StatefulWidget {
HomePage({
Key key, this.title
}) : super(key: key);
final String title;
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _currentIndex = 0;
final _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
void _requestPermission() async {
await FirebaseMessaging.instance.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
final client = HttpClientWithInterceptor.build(
interceptors: [
AuthorizationInterceptor()
],
retryPolicy:
ExpiredTokenRetryPolicy()
);
FirebaseMessaging.instance.getToken().then((token){
// FCM ν ν°μ μλ²μ μ μ₯ πππππππππππ
client.post(Uri.parse(Constants.API + 'booster/v1/fcm-token'), body: jsonEncode({ 'fcmToken': "$token" }));
});
FirebaseMessaging.instance.onTokenRefresh.listen((token) {
// FCM ν ν°μ μλ²μ μ μ₯ πππππππππππ
client.post(Uri.parse(Constants.API + 'booster/v1/fcm-token'), body: jsonEncode({ 'fcmToken': "$token" }));
});
}
void didChangeDependencies() {
super.didChangeDependencies();
_requestPermission(); πππππππππ
}
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: [
for (final tabItem in TabNavigationItem.items()) tabItem.page,
],
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (int index) => setState(() => _currentIndex = index),
items: [
for (final tabItem in TabNavigationItem.items())
BottomNavigationBarItem(
icon: tabItem.icon,
label: tabItem.title,
)
],
unselectedItemColor: Colors.grey,
selectedItemColor: Colors.red,
unselectedLabelStyle: TextStyle(color: Colors.grey, fontSize: 10),
selectedLabelStyle: TextStyle(color: Colors.blueAccent, fontSize: 10),
showSelectedLabels: true,
showUnselectedLabels: true,
),
);
}
}
class TabNavigationItem {
final Widget page;
final String title;
final Icon icon;
TabNavigationItem({
this.page,
this.title,
this.icon,
});
static List<TabNavigationItem> items() {
return [
TabNavigationItem(
page: TodayPage(),
icon: Icon(Icons.home),
title: "ν",
),
TabNavigationItem(
page: PromotionPage(),
icon: Icon(Icons.money),
title: "νν",
),
TabNavigationItem(
page:BrandAlarmSettingPage(),
icon: Icon(Icons.alarm),
title: "μλ¦Ό",
),
TabNavigationItem(
page: MorePage(),
icon: Icon(Icons.more),
title: "λ보기",
),
];
}
Dart
볡μ¬
λ. FCMμ μ΄μ©ν΄ iOSμ±μ Push Notification μ μ μ‘νλ λ°©λ²μ λλ€.
λ€λ₯Έ λΈλ‘κ·Έλ₯Ό μ°Έκ³ ν΄λ³΄λ©΄ FirebaseMessagingμμ getInitialMessage, onOpenAppMessaging... λ± λΆνμν λ΄μ©λ€κΉμ§ λͺ¨λ ꡬνν΄λμλλΌκ΅¬μ. λ¬Όλ‘ μλΉμ€ κ³ λνν λ νμμ λ°λΌ ꡬνν΄μΌνλ λΆλΆλ€μ΄μ§λ§ λ¨μνκ² μ±μ notificationμ μ μ‘νλ κ². μ¬κΈ°κΉμ§κ° λμ
λλ€..!







