[기능구현][RN] Firebase를 이용한 Push notification 만들기

Wonhyun Kwon·2023년 5월 23일
1

기능 구현

목록 보기
2/4
post-thumbnail

Environment

  1. 개발 플랫폼: macOS
  2. 개발 언어: JavaScript, TypeScript
  3. 개발 프레임워크: React Native(0.68.5), firebase(14.11.0)
  4. 버전 관리: GitHub
  5. 개발 도구: Visual Studio Code
  6. 배포 환경: Xcode(14.1), Android Studio(chipmunk 2021.2.1)

개발 목적

1. 문제점 도출

  • none

2. 요구 사항

  • 공지 또는 기타 알림을 전체 사용자에게 notice 하기 위한 목적

3. 기대값 설정

  • firebase 에서 원하는 메시지 작성 및 배포하면 해당 앱을 설치한 사용자에게 전부 notice
  • 앱이 꺼져있을 때, 켜져있을 때 상관없이 전부 notice

문제 해결

참고

[React Native] 🔥 Firebase 로 푸쉬 알림 구현하기 - (1) 안드로이드 앱에서 푸시 알림 띄우기!
[React Native] 🔥 Firebase 로 푸쉬 알림 구현하기 - (2) iOS 앱에서 푸시 알림 띄우기!

1. 환경설정

RN에서 Push 알람을 구현하는 방법은 여러 가지다.
1) 서버

  • firebase

2) 로컬

  • @notifee/react-native
  • react-native-push-notification
    • @react-native-community
    • push-notification-ios (iOS)
    • react-native-notifications

이 글에선 서버에서 Push 알람을 보내주는 firebase 플랫폼을 이용하여 구현하는 방법을 기술한다.


2. firebase 세팅

firebase 란 ?

FirebaseGoogle에서 제공하는 모바일 및 웹 애플리케이션 개발을 위한 플랫폼이다.
클라우드 기반으로 동작하며, 다양한 개발자 도구와 서비스를 포함하고 있어 앱 개발을 보다 간편하게 만들어준다.

이를 위해 다음 라이브러리를 설치해준다.

1) @react-native-firebase/app

firebase 를 사용하기 위한 코어 기능을 제공한다.

2) @react-native-firebase/messaging

firebase 에서 제공하는 다양한 기능 중 하나이다.
FCM (Firebase Cloud Messaging) 을 통해 Push 알람을 수신하기 위해 사용된다.

🔔 참고
필자는 위 두 개 라이브러리의 버전은 모두 "14.11.0"' 을 사용하였다.


fireabse 프로젝트 생성

  • https://console.firebase.google.com/ 링크에 접속한다.

  • 아래 이미지의 우측 '프로젝트 추가' 또는 처음 프로젝트 생성 시 프로젝트 생성 버튼을 클릭한다.

  • 프로젝트명 및 애널리스틱 설정 등을 마친 후, 프로젝트 생성을 마무리한다.

  • 원하는 플랫폼 아이콘을 클릭하여 앱 추가를 추가한다.
    이 후 플랫폼 별 세부 설정은 아래 내용을 참고 바란다.


3. 세부 설정

1) iOS

  1. 아래 이미지와 같이 Apple Bundle ID를 입력 후 앱 등록 버튼을 누른다.

  2. 그 외 info.plist 파일 및 native 단에서 초기화 코드 추가 과정은 상기 이미지에 나와있는 온보딩에 따라하면 된다.
    다만, Firebase SDK 추가 항목은 무시해도 된다.
    앞 전에 설치 한 @react-native-firebase/app 라이브러리에 SDK파일이 들어가 있기 때문이다.

    ❗️ VS Code와 같은 에디터에서 작업하지 말고, 반드시 Xcode를 켜서 작업해야 한다.
    IDE 환경에서는 native 단과 동기화가 안되는 경우가 발생하기 때문에 반드시 직접 넣어줘야 한다.

  3. APN(Apple Push Notification) 설정을 위해 다음 과정을 거친다.
    Apple은 Push 알람 서비스를 제공하기 위해 develop 수준에서 따로 서비스 신청을 해야한다.

    1. 인증서 발급
    2. 인증키 생성
    3. App configure 설정
    4. Firebase에 생성해둔 내 iOS 앱에 APN 인증 키 등록
    5. Xcode > Capabilities 추가
    6. iOS 코드레벨에서 알림 권한 요청

    3-1) 인증서 발급
    cmd + space 누른 후 '키체인 접근'을 입력하여 진입한다.

    메뉴에서 인증서 지원 -> 인증 기관에서 인증서 요청 을 클릭한다.
    이메일 주소를 입력하고 요청 항목에 디스크에 저장됨 / 본인이 키 페어 정보 지정 을 체크하고 다음으로 넘어간다.

    인증서를 저장한 후 아래와 같은 이미지에 따라 설정을 끝낸다.


3-2) 인증키 생성하기
https://developer.apple.com/ 접속 후 로그인을 한다.
Account > 인증서(영문) 클릭
아래 사진 경로에서 Keys + 버튼을 클릭한다.

Key Name을 작성하고 하기 선택 항목 중 'Apple Push Notifications service (APNs) 를 체크한다.

정보 확인 후 Register 를 클릭한다.

아래와 같은 화면이 뜨면, Key ID 를 반드시 어딘가에 저장하고, Download 버튼을 눌러 안전한 곳에 인증키 를 다운받는다.

❗️ 노란 경고박스에도 쓰여있듯이, 인증키는 최초 한 번만 다운로드 가능하기 때문에 잊어버리지 말아야한다.


3-3) App configure 설정
다음 과정은 App ID가 있다는 가정이다.

Identifiers > 설정하고자 하는 App ID 클릭한다.

아래 보면 여러 가지 service를 제공해주는데, 여기서 우리가 필요한 것은 Push Notifications 항목이다. 찾아서 체크해준다.

Push Notifications 를 사용하기 위해선 위에서 발급받은 인증서를 등록해야 한다. 필자는 이미 등록해둔 상태여서 Certificates (2) 라고 되어있지만, 처음한다면 Certificates (0) 으로 보이는 것이 정상이다.

Edit 을 누르면 아래와 같이 개발용 / Production용 두 가지를 지원한다. 둘 다 같은 방식으로 진행하면 된다.

Create Certificate 를 클릭한다.

Choose File 을 누르고 3-1) 에서 발급 받은 CertificateSigningRequest.certSigningRequest 를 업로드한다.

올린 내용이 맞는지 확인 후, Download 를 눌러 안전한 곳에 저장한다.

두 가지 모두 등록하면 아래와 같은 파일이 저장된 것을 확인할 수 있다.


3-4) Firebase에 생성해둔 내 iOS 앱에 APN 인증 키 등록

앞서 3-2) 에서 생성한 인증키Firebase Console에 등록하는 과정이다.
Firebase Console에 들어가 톱니바퀴 > 프로젝트 설정에 들어간다.

클라우드 메시징 탭으로 이동하면 아래와 같이 iOS 앱 구성 항목이 나온다.

❗️ 아래 'APN 인증서' 부분은 .p12 인증서를 요구하므로 헷갈리지 않도록 한다.

'APN 인증 키' 라고 적힌 항목에 3-2) 에서 만든 .p8 인증키를 업로드 한다.
또한, 역시 3-2)에서 만든 Key ID 를 넣고 이 링크를 통해 Team ID 를 확인 후 함께 넣고 업로드를 한다.


3-5) Xcode > Capabilities 추가
아래 이미지를 참고하여 다음 항목을 추가한다.

  • + Capability
    • Push Notifications 추가
    • Background Modes 추가 > Remote Notifications 체크

이로써 iOS 앱에서 __Push notification` 을 받을 준비는 끝났다.


3-6) iOS 코드레벨에서 알림 권한 요청
iOS는 사용자의 승인을 받지 않은 notification 을 수신하지 못하도록 해놓았다. 따라서 아이폰 사용자라면 하기 이미지와 같은 메시지를 받은 경험이 있을 것이다.

바로 이 창을 띄워 앱이 알림을 허용하게끔 유도해야 한다.
이는 우리가 설치한 messaging 라이브러리에서 requestPermission 메서드를 이용하면 된다.

import messaging from '@react-native-firebase/messaging';

const requestUserPermission = async () => {
  const authStatus = await messaging().requestPermission();
  const enabled =
    authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
    authStatus === messaging.AuthorizationStatus.PROVISIONAL;

  if (enabled) {
    console.log('Authorization status: ', authStatus);
  }
};

requestUserPermission();

이는 최초 첫 요청 시에만 권한을 묻는다. 그 이후로는 위에서 지정한 변수 authStatus 에 현재 notification 상태를 저장하고 이를 근거로 Push 알림 수신을 결정한다.

authStatus 의 상태는 다음과 같다

  • 0 : 거절
  • 1 : 승인
  • 2 : iOS 12 이상에서 '잠정적 승인' 상태. 유저에게 권한을 묻지 않고 코드 레벨에서 잠정적으로 승인 상태로 만들어 버리는 것. 자세한 내용은 여기를 클릭!

2) Android

  1. iOS와 마찬가지로 firebaseAndroid 앱을 추가한다.
    여기서 Android 패키지 이름 항목은 반드시 내 프로젝트의 AndroidManifest.xml 파일에 적힌 <manifest> 태그 안의 pakage 에 적힌 것을 넣어야 한다.

    android > app > src > main > AndroidManifest.xml

    📌 참고
    디버그 서명 인증서 SHA-1 선택사항의 경우, 동적 링크, 초대, Google 로그인 등의 기능을 구현할 때 필요하다.
    필요 할 경우, cd android && ./gradlew signingReport 커맨드를 실행하여 debug 키의 SHA1 를 긁어와 입력하면 된다.

    # 커맨드 입력
    $ cd android && ./gradlew signingReport
    
    # 결과
    > Task :app:signingReport
    Variant: debug
    Config: debug
    Store: /Users/whkwon/Desktop/workspace/github/KeywalletTouch_v3/android/app/debug.keystore
    Alias: androiddebugkey
    MD5: 20:F4:61:48:B7:2D:8E:5E:5C:A2:3D:37:A4:F4:14:90
    SHA1: 5E:8F:16:06:2E:A3:CD:2C:4A:0D:54:78:76:BA:A6:F3:8C:AB:F6:25 # here
    SHA-256: FA:C6:17:45:DC:09:03:78:6F:B9:ED:E6:2A:96:2B:39:9F:73:48:F0:BB:6F:89:9B:83:32:66:75:91:03:3B:9C
    Valid until: 205251일 수요일
  2. 그 외 google-services.json 파일 및 native 단에서 Firebase SDK 추가하는 방법은 마찬가지로 앱 추가할 때 나오는 온보딩 안내를 따르면 된다.

    ❗️ VS Code와 같은 에디터에서 작업하지 말고, 반드시 Android Studio를 켜서 작업해야 한다.
    IDE 환경에서는 native 단과 동기화가 안되는 경우가 발생하기 때문에 반드시 직접 넣어줘야 한다.


4. firebase로 Push 알람 받기

앱은 세 가지 경우에서 message를 받는다.

  1. Foreground : 앱이 현재 실행되고 있는 상태
  2. Background : 실행되고 있지만, 화면에서 벗어나 있는 상태
  3. Quit : 앱이 완전히 종료된 상태

meesage를 받을 때 위 경우를 모두 고려해서 분기 처리 해줘야 한다.
관련 내용은 공식 문서를 참고하면 더 좋다.
앞으로 작성 할 내용은 공식 문서를 토대로 보기 쉽게 작성한 내용임을 알린다.


  1. Foreground
    Foreground 상태에선 messaing 라이브러리에서 제공해주는 onMessage 메서드를 이용하면 된다.

    가장 우선적으로 Listening 해야하기 때문에 앱의 가장 앞 단 (ex. App.tsx)에 해당 코드를 집어 넣는 것이 합리적이다.

    // App.tsx
    import React, { useEffect } from 'react';
    import { Alert } from 'react-native';
    import messaging from '@react-native-firebase/messaging';
    
    function App() {
     useEffect(() => {
       const unsubscribe = messaging().onMessage(async remoteMessage => {
         Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
       });
    
       return unsubscribe;
     }, []);
    }

  1. Background, Quit
    Background 상태와 Quit 상태는 동일한 메소드로 message를 수신할 수 있다.

    이 경우 messaging 라이브러리에서 제공해주는 setBackgroundMessageHandler 메서드를 이용하면 된다.
    공식 문서엔 이 메서드가 최대한 빨리 불려야 한다고 적혀있으므로 이 역시 가장 앞 단 (ex. App.tsx)에 코드를 작성하였다.

    // App.tsx
    import { AppRegistry } from 'react-native';
    import messaging from '@react-native-firebase/messaging';
    import App from './App';
    
    // Register background handler
    messaging().setBackgroundMessageHandler(async remoteMessage => {
     console.log('Message handled in the background!', remoteMessage);
    });

    Push 알림이 수신되었을 때, console.log 가 찍히도록 되어 있다.
    Background 에서는 바로 찍히지만, Quit 상태에선 Push 알림을 눌러 앱을 켰을 때 찍힌다.


5. Firebase Console에서 테스트 메시지 보내기

🔔 참고
iOS실 디바이스에서만 테스트가 가능하며, Android시뮬레이터, 실 디바이스 모두 테스트 가능하다.

  1. Firebase Console에 접속하여 참여 > Messaging 카테고리에 진입한다.
  1. 새 캠페인 > 알림

  2. 제목텍스트를 작성 후 다음을 클릭한다. (그 외 선택사항)

  3. 테스트 할 앱을 선택 후 다음을 클릭한다.
    (Android와 iOS는 한꺼번에 Push 알림할 수 없다. 동일한 내용이라도 플랫폼 별로 따로 보내야 하는 번거로움이 존재한다.)

  4. 언제 Push 알림을 할 것인지 시간을 정할 수 있다.
    우리는 바로 테스트 결과를 봐야하기 때문에 지금을 선택 후 검토를 클릭하면 완료된다.

6. 결과

  1. iOS
    1) Foreground

    2) Background

  1. Android

    1) Foreground

2) Background


이슈 사항

1. Android > app > build.gradle 추가 항목

@react-native-firebase/messaging 라이브러리를 사용하기 위해선 Android 에서 다음과 같이 앱 수준 build.gradle 에 추가해야 할 항목이 있다.

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])

    implementation project(':react-native-splash-screen')

    //noinspection GradleDynamicVersion
    implementation "com.facebook.react:react-native:+"  // From node_modules
Expand All
	@@ -308,8 +308,9 @@ dependencies {
    implementation 'com.facebook.fresco:webpsupport:2.5.0'

    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
    implementation platform('com.google.firebase:firebase-bom:32.0.0')
    implementation 'com.google.firebase:firebase-analytics'
    implementation 'com.google.firebase:firebase-messaging:23.1.2' // >> 이 부분 추가

    debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
        exclude group:'com.facebook.fbjni'

본인이 FCM 버전이 어떤 건지 모른다면, 이 사이트에서 Cloud MessagingLatest version을 참고하면 된다.


2. react-native-gesture 라이브러리 타입 에러

이번 Push 알림 기능 구현을 하면서 발생한 에러인지, 아니면 우연히 생긴건지 알 수 없지만 작성한다.
Android Studio 에서 build 시 발생하는 에러이며, 내용은 다음과 같다.

Type mismatch: inferred type is Context? but Context was expected

내용을 대충 설명하자면, Context 라는 변수의 타입이 예상한 타입과 일치하지 않는다는 것을 뜻한다. 즉, 이 변수가 실제 객체를 가질 수도 있고, null 일 수도 있다는 뜻이다. 하지만, 실제 작성 된 타입은 non-null 을 받는 형태이기에 null 일 경우를 대비해 컴파일 단계에서 에러가 난 것이다.

이 경우 반드시 값이 존재한다는 kotlin 문법인 !! 문법을 사용하여 해결하였다.

해결 경로 및 작성 코드는 다음과 같다.

node_modules > react-native-gesture-handler > android > lib > src > main > java > com > swmansion > gesturehandler > PanGestureHandler.kt

...
init {
  val vc = ViewConfiguration.get(context!!) // context에 non-null(!!) 추가
  val touchSlop = vc.scaledTouchSlop
  defaultMinDistSq = (touchSlop * touchSlop).toFloat()
  minDistSq = defaultMinDistSq
}
...

3. SDK 버전 호환 이슈

Android 빌드 시 발생했으며 내용은 다음과 같다.

Build failed error: cannot find symbol if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {

이는 SDK의 version이 안맞아서 생기는 문제로 아래 코드 내용에 따라 수정하면 된다.

android > build.gradle

buildscript {
    ext {
        buildToolsVersion = "31.0.0"
        minSdkVersion = 21
        compileSdkVersion = 33 // 31 -> 33 변경
        targetSdkVersion = 33 // 31 -> 33 변경
      ...
    }
}

개선 및 향상

앱 개발 전에는 당연하게 사용하던 Push 알림 기능을 직접 구현해본 값진 경험이었다.

먼저, Firebase 플랫폼에 대해 접할 수 있었으며, 제공하는 많은 기능 중 FCM을 통한 무료 서버로 Push 알림을 구현함으로서 사용자에게 원하는 시간에 원하는 정보를 inform 할 수 있다는 점이 매력적이었다.

또한, iOS는 비교적 세팅하는 데 있어 손이 유난히 많이 갔다. iOS 에서 실시하는 Push notification의 정책을 이해하고 인증서부터 키까지 직접 발급받으며 수행했을 때 사용자에게 더 이상 일방적인 Push 알림을 지양하고 반드시 필요할 때만 수행해야한다는 것을 이해하는 데 도움이 많이 됐다.


아쉬운 점

아쉬운 점은 딱히 없었다. 다만, 추가해야 할 기능의 필요성은 느꼈다.

이 포스트에서 구현한 것은 다시 한번 말하지만, Firebase 에서 제공하는 서버를 베이스로 했기 때문에 몇 가지 제약 사항이 있다.

  1. Firebase console 에서 메시지를 보내면 즉각 알림이 뜨지 않는다.
  2. 앱 상에서 어떤 작업이 완료되었을 때, 그것을 notice 하는 경우는 서버가 아닌 로컬에서 구현해야 한다.

따라서 차후 포스트에선 @notifee 와 같은 라이브러리를 통한 로컬에서의 Push 알림을 구현해볼까 한다.

profile
모든 사용자가 만족하는 UI를 만드는 FE 개발자 권원현입니다.

0개의 댓글