728x90

[ 푸시알림 완벽구현 - 최종판 ]

https://honeystorage.tistory.com/306

 

notification 기능도 구현하기 나름인것같다.

firebase의 remote notification만 있으면

만능일줄 알았건만

 

local notification을 쓸일이 생겨

지웠던 라이브러리를 다시 설치하고

셋팅하는 상황이 발생했다.

 

워낙 간단했지만

그래도 필요한 이들을 위해서 공유한다.

(혹은, 미래의 나를 위해...)

 

먼저, remote notification이

구현되어 있음에도 local notification이 필요했던 이유는

앱 안에서 채널톡 SDK를 통해

채널톡이 구현되어있는데...

 

운영자가 답장을 해줘도 사용자가 답장이 왔는지

알길이 없는 상황에 봉착했다.

(알림을 주던지, 카톡을 주던, 문자를 보내주던

무언가는 있어야지

사용자가 답변이 왔음을 알것이다.)

 

그래서 나는

setBackgroundMessagehandler에서

ChannelIO.isChannelPushNotification 메소드로

채널톡 메시지가 수신되었음이 감지됐을때

local에서 notification을 발생시켜

사용자에게 알려주는 전략을 취하기로했다.

 

// https://developers.channel.io/docs/mobile-channel-io#ischannelpushnotification

import messaging from '@react-native-firebase/messaging';
import {ChannelIO} from 'react-native-channel-plugin';

componentDidMount() {
    this.backgroundMessageHandler = messaging().setBackgroundMessageHandler(
      async (remoteMessage) => {
        ChannelIO.isChannelPushNotification(remoteMessage.data).then((result) => {
            if (result) {
              ChannelIO.receivePushNotification(remoteMessage.data).then((_) => { });
            } else {
              // TODO : Your FCM code
            }
          },
        );
      },
    );
}

componentWillUnmount() {
  this.backgroundMessageHandler();
}

 

채널톡에서도 그럴때 쓰라고 만들어 둔것인지

이렇게 예제를 제공하기도 한다.

 

result === true일때 

local notification이 작동되도록 코드를 설정했으며

아래와 같이

local notification을 세팅할수있다.

 

1. 설치 ( >= 0.60)

// react-native-push-notification 설치
npm install --save react-native-push-notification

// @react-native-community/push-notification-ios 설치
npm i @react-native-community/push-notification-ios --save

// pod file download
cd ios && pod install && cd..
// --- android ---

// android/app/src/main/AndroidManifest.xml
.....
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <application ....>
        <!-- local notification code -->
        <meta-data  android:name="com.dieam.reactnativepushnotification.notification_foreground" android:value="false"/>
        <meta-data  android:name="com.dieam.reactnativepushnotification.notification_color" android:resource="@color/white"/> <!-- or @android:color/{name} to use a standard color -->

        <!-- common notification code -->
        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationActions" />
        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
            </intent-filter>
        </receiver>

        <!-- common notification code -->
        <service
            android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
     .....
// ios

// AppDelegate.h
// --- local notification code ---
#import <UserNotifications/UNUserNotificationCenter.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate>
UNUserNotificationCenterDelegate <-- 이거 추가됨




// AppDelegate.m
// --- local notification code ---
#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>


// --- local notification code ---
// Required for the register event.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
 [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// Required for the notification event. You must call the completion handler after handling the remote notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
  [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
// Required for the registrationError event.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
 [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
}
// Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler
{
  [RNCPushNotificationIOS didReceiveNotificationResponse:response];
}


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  ...
  // Define UNUserNotificationCenter
  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
  center.delegate = self;

  return YES;
}


//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
  completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}

 

 

2. 코드 작성

import PushNotificationIOS from '@react-native-community/push-notification-ios';
import PushNotification from 'react-native-push-notification';

type NotiOptoin = {
  title: string;
  message: string;
}

export class LocalNotification {
  private channel: any;

  constructor() {
    this.init();
  }

  private init() {
  // Must be outside of any component LifeCycle (such as `componentDidMount`).
    PushNotification.configure({
      // (optional) Called when Token is generated (iOS and Android)
      onRegister: function (token) {
        // console.log('TOKEN:', token);
      },

      // (required) Called when a remote is received or opened, or local notification is opened
      onNotification: function (notification) {
        // console.log('NOTIFICATION:', notification);

        // process the notification

        // (required) Called when a remote is received or opened, or local notification is opened
        notification.finish(PushNotificationIOS.FetchResult.NoData);
      },

      // (optional) Called when Registered Action is pressed and invokeApp is false, if true onNotification will be called (Android)
      onAction: function (notification) {
        // console.log('ACTION:', notification.action);
        // console.log('NOTIFICATION:', notification);

        // process the action
      },

      // (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS)
      onRegistrationError: function (err) {
        console.error(err.message, err);
     },

      // IOS ONLY (optional): default: all - Permissions to register.
      permissions: {
        alert: true,
        badge: true,
        sound: true,
      },

      // Should the initial notification be popped automatically
      // default: true
      popInitialNotification: false,

      /**
      * (optional) default: true
      * - Specified if permissions (ios) and token (android and ios) will requested or not,
      * - if not, you must call PushNotificationsHandler.requestPermissions() later
      * - if you are not using remote notification or do not have Firebase installed, use this:
      *     requestPermissions: Platform.OS === 'ios'
      */
      requestPermissions: false,
    });

    PushNotification.createChannel({
      channelId: 'com.myApp',
      channelName: '앱이름',
    }, (created) => {
      console.log('noti channeld is created')
    })
  }

  fire = (option: NotiOptoin) => {
    PushNotification.localNotification({
      title: option.title,
      message: option.message,
      largeIcon: "ic_launcher",
      smallIcon: "ic_launcher",
      bigLargeIcon: "ic_launcher",

      /* Android Only Properties */
      channelId: "com.myApp", // (required) channelId, if the channel doesn't exist, notification will not trigger.
      vibrate: true,
      vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000
      priority: 'high',
      
      /* iOS and Android properties */
      id: 0, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID
      playSound: true, // (optional) default: true
      soundName: "default", // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played)
    });
  }
}

export {PushNotification};

* 주의 : 채널을 생성해주지 않으면 알림이 뜨지 않습니다...

 

 

3. 코드 연동

const localNoti = new LocalNotification();
messaging().setBackgroundMessageHandler(async remoteMessage => {
  Platform.OS === 'ios' && Vibration.vibrate([400]);
  console.log('Message handled in the background!', remoteMessage);
  
  ChannelIO.isChannelPushNotification(remoteMessage.data).then(result => {
    if (result) {
      localNoti.fire({ title: '제목', message: '메시지' });
    } else {
      // TODO : Your FCM code
    }
  });
});

참고로,

Platform.OS === 'ios' && Vibration.vibrate([400]);

이 부분은 이 전편에서 다루었던 내용으로

ios에서 백그라운드 알림에 대한

진동이 울리지않아서

트릭용으로 추가한 코드입니다.

 

 

[ 푸시알림 완벽구현 - 최종판 ]

https://honeystorage.tistory.com/306

728x90
반응형