FCM 을 활용한 PUSH 메세지 보내기 (2024-11-23)

프로그래밍/Android (Java)|2022. 10. 19. 16:16
반응형

New Project > Empty Views Activity 선택

Language : Java

Minimum SDK : API 24

이 상태로 진행하였습니다.

 

 

build.gradle 수정 (프로젝트 수준)

 

아래 내용을 파일에 추가 합니다.

...

buildscript {

    dependencies {
        classpath("com.google.gms:google-services:4.4.2")
    }
}

 

 

build.gradle 수정 (앱 수준)

 

아래 내용을 추가 합니다.

중간에 주석 부분도 추가해줍니다. 없을 경우 바로 아랫줄에 구문 에러 메세지가 출력됩니다.

plugins {
    alias(libs.plugins.android.application)
    id("com.google.gms.google-services")
}

...

dependencies {

    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:2.0.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    implementation(platform("com.google.firebase:firebase-bom:33.6.0"))
    implementation("com.google.firebase:firebase-analytics")
    implementation("com.google.firebase:firebase-messaging:24.1.0")
    implementation("com.google.firebase:firebase-core:21.1.1")
}

 

 

google-services.json 생성

 

Firebase console 페이지에 접근해서 프로젝트에 APP 을 추가합니다.

추가하는 과정에서 google-services.json 파일을 다운로드 받을 수 있으며,

해당 파일은 app 디렉토리 안에 넣어 놓습니다.

 

 

build.gradle 페이지에서 [Sync Now] 버튼을 눌러줍니다.

 

 

MyFirebaseMessagingService.java 생성

package kr.sysdocu.fcm;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;

import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onNewToken(@NonNull String token) {
        super.onNewToken(token);
        // token을 서버로 전송해서 저장하고 싶은 경우 이곳에 코드 입력
    }

    @Override
    public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        String messageContent;

        // 푸시 메시지 데이터 처리
        if (!remoteMessage.getData().isEmpty()) {
            // Data Payload 처리
            messageContent = remoteMessage.getData().get("message");
            String title = remoteMessage.getData().get("title");
            showNotification(title, messageContent); // 아래에서 정의한 알람을 실행하는 부분
        } else if (remoteMessage.getNotification() != null) {
            // Notification Payload 처리
            messageContent = remoteMessage.getNotification().getBody();
        } else {
            messageContent = "No Content";
        }

    }

    // 알람을 띄운다
    private void showNotification(String title, String message) {
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        String channelId = "default_channel_id";

        // Android 8.0 (API 26) 이상에서는 알림 채널을 생성해야 함
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    channelId,
                    "Default Channel",
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            notificationManager.createNotificationChannel(channel);
        }

        // 알림 클릭 시 실행할 Intent 정의
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 기존 Activity 스택 제거 후 실행

        // PendingIntent 생성
        PendingIntent pendingIntent = PendingIntent.getActivity(
                this,
                0,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE // 최신 상태 유지
        );

        // 알림 빌더 구성
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId)
                .setContentTitle(title)                     // 알림 제목
                .setContentText(message)                    // 알림 메시지
                .setSmallIcon(R.drawable.ic_icon)           // 알림 아이콘
                .setAutoCancel(true)                        // 알림 터치 후 제거
                .setContentIntent(pendingIntent);           // 알림 클릭 시 실행될 PendingIntent 설정

        // 알림 표시
        notificationManager.notify(0, notificationBuilder.build());
    }

}

 

 

MainActivity.java 수정

여기에서 코드를 작성할때 파란색 부분은 okhttp 라이브러리를 이용해 토큰을 웹서버로 전송하기 위한 부분입니다.

필요시 같이 작성하면 됩니다.

 

앱수준 build.gradle 파일에 dependencies 추가후 sync 맞추기

implementation("com.squareup.okhttp3:okhttp:4.11.0")

 

package kr.sysdocu.fcm;

import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.messaging.FirebaseMessaging;

public class MainActivity extends AppCompatActivity {

    private final OkHttpClient client = new OkHttpClient();

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 이 안의 부분은 처음 토큰을 받아올때 한 번만 실행 됩니다.
        FirebaseMessaging.getInstance().getToken().addOnSuccessListener(new OnSuccessListener<String>() {
            @Override
            public void onSuccess(String token) {

                // 토큰을 토스트로 간단히 확인
                Toast toast = Toast.makeText(getApplicationContext(), "TOKEN : " + token, Toast.LENGTH_LONG);
                toast.show();

                // 서버로 토큰 전송 (ssl 사용)
                new Thread(() -> {
                    try {
                        String url = "https://fcm.sysdocu.kr/register.html?token=" + token;
                        String result = run(url);
                        // 결과 처리 (예: 로그 출력)
                        System.out.println(result);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }).start();

            }
        });
    }

    // okhttp 라이브러리 사용
    // run 메서드는 클래스 수준에 정의해야 합니다.
    public String run(String url) throws IOException {
        Request request = new Request.Builder()
                .url(url)
                .build();
        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }

}

 

 

activity_main.xml 수정

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:background="#DFE5E5"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textColor="@color/black"
        android:text="토큰은 웹서버에서 확인하세요." />

</LinearLayout>

 

 

AndroidManifest.xml

 

아래 내용을 추가합니다.

(생략)

<uses-permission android:name="android.permission.INTERNET"/>


...

// <application> 안에 아래 내용 추가

<service
    android:name=".MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>

(생략)

 

프로젝트를 빌드하여 apk 파일을 생성하고, 핸드폰에 설치합니다.

 

잠깐, 앱을 실행하기 전에 아래 내용 확인해주세요.

위 소스에서 사용되었던 서버 URL (https://fcm.sysdocu.kr/register.html) 에 해당되는 파일을 미리 생성해 놓도록 합니다.

access log 에 접근 로그가 남아 token 확인을 쉽게하기 위함이니 빈 파일도 괜찮습니다.

 

 

PUSH 발송 테스트

 

방법1)

Firebase Console 에서 프로젝트 선택 > '실행' 메뉴 > 'Messaging' 메뉴 > (첫 번째 캠페인 만들기) 버튼 클릭 > Firebase 알림 메세지 체크 후 [만들기]

출력된 화면에서 적절한 내용으로 모두 입력 후 [검토] 버튼을 누르면, 앱을 설치한 모든 Device 로 FCM 메세지가 발송 됩니다.

 

방법2)

PHP 코드를 아래와 같이 작성 합니다.

현재 (2024년 11월) 는 이전에 사용하던 방식에서 FCM HTTP API의 v1 버전으로 전송 방식이 바뀌었습니다.

 

1) 사용자 계정 키 (json) 다운로드

서비스 계정 키 다운로드를 위해 Firebase Console (https://console.firebase.google.com/ ) 로 이동합니다.

프로젝트 설정 > 서비스 계정 > 새 비공개 키 생성 클릭. 

JSON 파일을 다운로드합니다.

다운로드 한 파일은 PHP 생성할 위치로 복사합니다.

 

2) php 파일 작성

v1 API 는 OAuth2 인증을 사용해야 하므로 google/apiclient 패키지를 설치합니다.

# composer require google/apiclient

 

아래 파란색 부분을 적절한 값으로 수정하여 작성합니다.

# vi fcm_send.php

<?php
require 'vendor/autoload.php';

use Google\Auth\Credentials\ServiceAccountCredentials;
use GuzzleHttp\Client;

function sendFCMMessage($serviceAccountPath, $projectId, $token, $title, $body) {
    // FCM 엔드포인트 URL
    $url = "https://fcm.googleapis.com/v1/projects/$projectId/messages:send";

    // 메시지 페이로드
    $message = [
        'message' => [
            'token' => $token,
            'data' => [
                'title' => $title,
                'message' => $body
            ]
        ]
    ];

    // Google OAuth2 인증
    $credentials = new ServiceAccountCredentials(
        'https://www.googleapis.com/auth/firebase.messaging',
        json_decode(file_get_contents($serviceAccountPath), true)
    );

    $accessToken = $credentials->fetchAuthToken()['access_token'];

    // HTTP 요청 헤더
    $headers = [
        'Authorization' => 'Bearer ' . $accessToken,
        'Content-Type' => 'application/json',
    ];

    // HTTP 클라이언트
    $client = new Client();

    try {
        // FCM 메시지 요청
        $response = $client->post($url, [
            'headers' => $headers,
            'body' => json_encode($message)
        ]);

        echo "Response: " . $response->getBody();
    } catch (Exception $e) {
        echo "Error: " . $e->getMessage();
    }
}

// 서비스 계정 JSON 파일 경로
$serviceAccountPath = './your-service-account.json';

// Firebase 프로젝트 ID
$projectId = 'your-project-id';

// FCM 토큰, 제목, 내용
$token = 'your-device-token';
$title = 'Test Title';
$body = 'Test Body';

// 메시지 전송 함수 호출
sendFCMMessage($serviceAccountPath, $projectId, $token, $title, $body);
?>

 

이제 작성한 파일을 실행만 하면 입력해놓은 특정 디바이스로 (token) FCM 메세지가 전송됩니다.

# php fcm_send.php

 

반응형

댓글()