이번 글에서는 안드로이드에서 실제로 수행되고 있는지를 테스트해 보겠습니다.
안드로이드 코드 과정에 대해서는 자세히 파악하지 못했기 때문에 ChatGPT를 함께 이용하였습니다.
본 코드를 테스트해 보기 위해서는 안드로이드 스튜디오가 필요합니다.
FCM 안드로이드 파일 다운로드
우선, 만들어 둔 FCM 프로젝트로 이동한 뒤 플랫폼 (안드로이드 등)을 선택합니다.
패키지 명 작성
안드로이드 스튜디오에서 프로젝트를 만들고, 프로젝트의 패키지 명을 작성합니다.
FCM 파일 다운로드
FCM 클라이언트 파일 (google-services.json)을 다운로드합니다.
다운로드 한 google-services.json 파일을 위의 사진이 안내하는 것처럼 앱 수준 루트 디렉터리에 보관합니다.
build.gradle 등록
프로젝트 수준의 build.gradle에 google-services를 등록합니다.
plugins {
id 'com.google.gms.google-services' version '4.3.15' apply false
alias(libs.plugins.androidApplication) apply false
}
앱 수준의 build.gradle에도 파이어베이스 구현체를 등록합니다.
plugins {
alias(libs.plugins.androidApplication)
id 'com.google.gms.google-services' // google-services 등록
}
android {
namespace 'hyunjoon.mju.fcm' // 본인의 namespace
compileSdk 34
defaultConfig {
applicationId "hyunjoon.mju.fcm" // 본인의 application id
minSdk 24
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
// FCM 관련 구현체
implementation platform('com.google.firebase:firebase-bom:31.3.0')
implementation 'com.google.firebase:firebase-analytics-ktx'
implementation 'com.google.firebase:firebase-messaging:23.0.3'
implementation libs.appcompat
implementation libs.material
implementation libs.activity
implementation libs.constraintlayout
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
}
AndroidManifest.xml
AndroidManifest.xml에는 알림 권한, Firebase 설정 등을 작성합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 필요한 권한 추가 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Fcm"
tools:targetApi="31">
<!-- Firebase 설정 -->
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<!-- 메인 액티비티 설정 -->
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MyFirebaseMessagingService
MyFirebaseMessagingService는 FirebaseMessagingService를 상속받은 커스텀 클래스입니다. 알림을 받았을 때 실질적으로 알림을 표현하는 등의 코드가 작성됩니다.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage != null && remoteMessage.getData().size() > 0) {
sendNotification(remoteMessage);
}
}
private void sendNotification(RemoteMessage remoteMessage) {
String title = remoteMessage.getNotification().getTitle();
String message = remoteMessage.getNotification().getBody();
Log.d(TAG, title);
Log.d(TAG, message);
final String CHANNEL_ID = "ChannerID";
NotificationManager mManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
final String CHANNEL_NAME = "ChannerName";
final String CHANNEL_DESCRIPTION = "ChannerDescription";
final int importance = NotificationManager.IMPORTANCE_HIGH;
// add in API level 26
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, importance);
mChannel.setDescription(CHANNEL_DESCRIPTION);
mChannel.enableLights(true);
mChannel.enableVibration(true);
mChannel.setVibrationPattern(new long[]{100, 200, 100, 200});
mChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
mManager.createNotificationChannel(mChannel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.setSmallIcon(R.drawable.ic_launcher_background);
builder.setAutoCancel(true);
builder.setDefaults(Notification.DEFAULT_ALL);
builder.setWhen(System.currentTimeMillis());
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentTitle(title);
builder.setContentText(message);
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
builder.setContentTitle(title);
builder.setContentText(message);
builder.setVibrate(new long[]{500, 500});
}
mManager.notify(0, builder.build());
}
@Override
public void onNewToken(String s) {
Log.d(TAG, "token = " + s);
super.onNewToken(s);
}
}
- onNewToken은 앱을 처음 실행했을 때 FCM이 발급한 토큰값을 확인하기 위해 로그로 남기도록 하였습니다.
- onMessageReceived는 메시지를 수신했을 때의 메서드를 의미합니다. 내부적으로 sendNotification 메서드를 호출하여, 받은 알림의 값을 로그로 확인하고 알림을 표현하도록 하였습니다.
실제 실행 예
이전 글에서 스프링 서버로 알림을 전송할 때 실제적으로 전달이 되는지 확인해 보면 아래와 같습니다.
토큰 발급 확인
먼저, 앱을 처음 실행할 경우 토큰 값을 확인할 수 있습니다.
알림 전송 수신
포스트맨과 스프링 서버를 이용해 알림을 전달했을 시 아래 사진과 같이 에뮬레이터에 알림이 전달된 것을 볼 수 있습니다.
Reference
안드로이드 코드 또한 리포지터리에 별도로 작성해 두었습니다. 샘플 코드를 빠르게 받아보실 수 있습니다.