flutter fcm push
flutter에서 push를 보내려면
2가지 라이브러리를 써야한다.
https://pub.dev/packages/flutter_local_notifications
https://pub.dev/packages/firebase_messaging
실질적으로 창을 띄우는역활을 하는 flutter_local_notifications와
데이터를 받는부분의 firebase_messaging
flutter_local_notifications의 android 셋팅
flutter-android-build.gradle에
com.android.tools.build.gradle은 최소 4.2.2를 써야하고 (이보다 높으면 놔둬라)
buildscript {
...
dependencies {
classpath 'com.android.tools.build:gradle:4.2.2'
...
}
flutter-android-app-src-build.gradle에 들어가서 각각 부분에 아래정보들을 복붙한다.
android {
compileSdkVersion 33 // 최소 33이상이여야한다
defaultConfig {
multiDexEnabled true
}
compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 8
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.window:window:1.0.0'
implementation 'androidx.window:window-java:1.0.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
}
flutter-android-app-src-main-AndroidManifest.xml 에 들어가서
MainActivity에다 아래정보 추가 showWhenLocked,trunScreenOn true 추가
<activity
android:name=".MainActivity"
android:showWhenLocked="true"
android:turnScreenOn="true">
flutter_local_notifications의 ios셋팅
xcode-Runner-Runner-AppDelegate에 들어가서 값추가
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
예시)
import UIKit
import Flutter
import flutter_local_notifications
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// This is required to make any communication available in the action isolate.
FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (registry) in
GeneratedPluginRegistrant.register(with: registry)
}
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
fcm의 ios셋팅
ios개발자 - certificates,Identifiers&Profiles에 들어가서 Identifiers- 본인프로젝트 클릭
![img.png](https://blog.kakaocdn.net/dn/7BzS3/btr6TlYESGl/jKwOfAWwSVROtj5gS3fYVk/img.png)
쭉내리다보면 Push Notifications 발견하면 클릭후 저장한다
![img.png](https://blog.kakaocdn.net/dn/dTQJzX/btr6UDkIivb/JWe7AroMWIh8fKEihvcxf0/img.png)
xcode로 와서Runner-Signing& Capabilities에 Capability버튼 클릭
![img.png](https://blog.kakaocdn.net/dn/PkD8B/btr6TmXsYT1/6xEgY1Mwkx5UlQLXjqP8U1/img.png)
push와 back ground modes를 검색하여 더블클릭해서 추가한다.
![img.png](https://blog.kakaocdn.net/dn/bWqjaN/btr62XPjg9G/HgZuUOHwKp5UukTP61t9K0/img.png)
Background fetch에 체크하면된다
![img.png](https://blog.kakaocdn.net/dn/ML8Kh/btr6RBURkIX/8jw1Mwz4o1FGbfDrlW05KK/img.png)
그리고
xcode-Runner-runner-info에서 FirebaseAppDelegateProxyEnabled No로 추가해야 로그에 에러가안뜬다
![img.png](https://blog.kakaocdn.net/dn/bp9pZN/btr65BlBrA9/kBwv1s2YLknG0FQlh5k4r0/img.png)
이제 apn 설정
ios개발자 - certificates,Identifiers&Profiles에 keys에 들어가서 +를 누른다
![img.png](https://blog.kakaocdn.net/dn/djIhkp/btr62Y8ytN5/g29LZUhODr6qOcrUI1fps1/img.png)
Apple Push Notifications service (APNs)를 클릭후 원하는이름 지정 후 다음
![img.png](https://blog.kakaocdn.net/dn/bPZt8K/btr6Tl5n1wC/CSn1iQgtOeVNYHgElnul41/img.png)
건들것없다 생성
![img.png](https://blog.kakaocdn.net/dn/c2rPYb/btr60EwejeX/Dj5EkW5KbpK6XSX1kRB7t0/img.png)
이제 만든키를 다운받고 key id를 복사해놓는다
![img.png](https://blog.kakaocdn.net/dn/ySVuO/btr6RAuZxBs/n8qxsiSrrGMiEkAJiiCTFK/img.png)
firebase프로젝트 설정 - 클라우드 메시징 - apple 앱 구성에 apn 인증서 업로드 클릭
![img.png](https://blog.kakaocdn.net/dn/cJZdyo/btr6TnhPbhQ/SHugrZ4UjecxH6Ga0q9zok/img.png)
아래와같이 찾아보기 클릭 후 아까 다운받은 인증서 클릭해서 넣고 복사한키도 같이 붙여넣는다.
팀id는 firebase에 미리넣어둔사람은 바로뜨는데 안넣어놔서 안떴다면
ios개발자 - certificates,Identifiers&Profiles에 들어가서 Identifiers- 본인프로젝트 클릭 들어가면 App ID Prefix라고 뜨는데 이거다
![img.png](https://blog.kakaocdn.net/dn/PEb3c/btr60DYn37s/MaLPQepW1myeECUMG4cnRK/img.png)
업로드하면 아래와같이 들어가져있다
![img.png](https://blog.kakaocdn.net/dn/QobWC/btr6RZPbnRT/VkDIUqjT1qkBSsBqaUZwr1/img.png)
앱에서 푸쉬를 받는 상황은
앱켜진상태 background,foreground
앱이 꺼진상태
flutter-main안에 추가
//앱이 꺼졌을때 //앱 백그라운드
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
//앱 포그라운드
FirebaseMessaging.onMessage.listen(
showFlutterNotification,
);
//앱 백그라운드에서 푸쉬클릭시
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
Get.toNamed(message.data.keys.first,
arguments: int.parse(message.data.values.first));
});
//앱꺼진상태에서 푸시클릭시 이동
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
if (message != null) {
Get.toNamed(message.data.keys.first,
arguments: int.parse(message.data.values.first));
}
});
if (!kIsWeb) {
await setupFlutterNotifications();
}
background 셋팅부분
//앱이 꺼졌을때 //앱 백그라운드
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await setupFlutterNotifications();
// showFlutterNotification(message);firebase에서 자동으띄워줌(주석지우면 2번뜸)
}
background 클릭 이벤트부분
//앱 백그라운드에서 푸쉬클릭시
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
Get.toNamed(message.data.keys.first,
arguments: int.parse(message.data.values.first));
});
foreground셋팅부분
FirebaseMessaging.onMessage.listen(
showFlutterNotification,
);
void showFlutterNotification(RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
payload: jsonEncode(message.data),//필수
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
// TODO add a proper drawable resource to android, for now using
// one that already exists in example app.
icon: '@mipmap/launcher_icon',
),
),
);
}
}
foreground 클릭 이벤트부분
//setupFlutterNotifications안에 onDidReceiveNotificationResponse 이부분이다
flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveBackgroundNotificationResponse: onSelectNotification,
onDidReceiveNotificationResponse: onSelectNotification,
);
onSelectNotification(NotificationResponse details) async {
if (details.payload != null) {
Map<String, dynamic> data = jsonDecode(details.payload ?? "");
Get.toNamed(data.keys.first, arguments: int.parse(data.values.first));
}
}
앱꺼졌을시
셋팅부분(백그라운드와 중복)
//앱이 꺼졌을때 //앱 백그라운드
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await setupFlutterNotifications();
// showFlutterNotification(message);firebase에서 자동으띄워줌(주석지우면 2번뜸)
}
앱꺼졌을시
클릭 이벤트부분
//앱꺼진상태에서 푸시클릭시 이동
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
if (message != null) {
Get.toNamed(message.data.keys.first,
arguments: int.parse(message.data.values.first));
}
});
기본셋팅부분
Future<void> setupFlutterNotifications() async {
if (isFlutterLocalNotificationsInitialized) {
return;
}
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description: 'This channel is used for important notifications.',
// description
importance: Importance.high,
);
var initializationSettingsAndroid =
const AndroidInitializationSettings('@mipmap/launcher_icon');
var initializationSettingsIos = const DarwinInitializationSettings();
var initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIos,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveBackgroundNotificationResponse: onSelectNotification,
onDidReceiveNotificationResponse: onSelectNotification,
);
/// Create an Android Notification Channel.
///
/// We use this channel in the `AndroidManifest.xml` file to override the
/// default FCM channel to enable heads up notifications.
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
isFlutterLocalNotificationsInitialized = true;
}
이제 파이어베이스 콘솔-Messaging으로 가서 첫 번째 캠페인 만들기 클릭
![img.png](https://blog.kakaocdn.net/dn/bxGZp7/btr6UDypYn2/mid04VVkKLhan2Lr67GVC0/img.png)
첫번째꺼 클릭 후 만들기
![img.png](https://blog.kakaocdn.net/dn/dgPHax/btr6RYv5Uz5/4imqKYCfis8cG2UD0nz1I1/img.png)
푸쉬로 보낼 제목과 텍스트를 입력
![img.png](https://blog.kakaocdn.net/dn/bRNfLH/btr6ZAVGKrs/kAq9B3U6uvYUbMPDccr5k0/img.png)
타겟에서 안드로이드와 ios 원하는것 선택
![img.png](https://blog.kakaocdn.net/dn/b4x3mA/btr6QryoUw1/U8bV76GGtDpaVF2eJ9HIL0/img.png)
예약하고싶으면 설정하고
이동하고싶은 경로가 있으면 추가옵션에 맞춤데이터에 값을 넣는다.
다 설정후 절대 검토를 누르면 안된다!!! 실제로 날라감
![img.png](https://blog.kakaocdn.net/dn/u5uj6/btr63lo9eqC/tB5fDbIu00BGt8BHhIN8Ik/img.png)
검토 대신 다시 알림으로 돌아가서 테스트메시지 전송을 눌르면 된다
![img.png](https://blog.kakaocdn.net/dn/bGET2f/btr61gWsNCN/RS40n8GhTMrAuMd6KcK8Bk/img.png)
누르면 아래와같이 뜨는데 FCM 등록 토큰 추가 이부분에 클릭해서 토큰을 추가해야한다
앱의 토큰 보는방법은
var token = await FirebaseMessaging.instance.getToken();
token값을 아래에 넣으면 된다
![img.png](https://blog.kakaocdn.net/dn/bHdbnl/btr610FDAa7/KAXsEKcGFxxnPFTMplZXA1/img.png)
그리고 체크 후 테스트 누르면 푸쉬가 매우 잘 날라온다.
테스트할때는 ios는 무조건 실제폰에서 android는 에뮬레이터로 된다 앱이 꺼졌을때 테스트시 android는 release모드로 빌드해서 테스트해야한다