로그인
회원가입
Loading...
Loading...

Board

게시판

FCM 푸시 알림 앱 서버 PHP 가이드

FCM 푸시 알림 안드로이드 앱 가이드에 이어서 앱 서버와 FCM 연결 서버(FCM connection servers)간의 통신을 다루어 보고자 한다.

공식 가이드 : https://firebase.google.com/docs/cloud-messaging/server

이 글에서는 다음의 모델을 가정한다.

- 앱 서버는 일반적인 웹 서버상의 PHP + MySQL 기반이다. 예제는 그누보드를 사용한다.
- 주제 토픽이나 세그먼트 단위의 브로드 캐스팅이 아니라 디바이스 토큰으로 정확하게 타겟팅한 푸시를 보낸다.
- HTTP 통신, JSON 형식, 다운스트림 메시지를 보낸다.

- overview -



모바일 디바이스 / 앱 서버 / FCM 연결 서버가 각각 어떤 역할을 수행하는지는 다음 이미지로 간단하게 요약이 된다.


image by https://medium.com/@ankushaggarwal/

1 - 디바이스에 앱이 설치된후 최초 실행되면서 고유 식별자인 디바이스 토큰이 발급된다. 이 토큰을 앱 서버에 등록한다.
2 - 앱 서버에서 FCM 연결 서버로 푸시 알림을 요청한다. 이때 준비물은 디바이스 토큰과 API 서버 키이다.
3 - FCM 연결 서버는 토큰을 대상으로 알림 메시지를 푸시한다.


- sendRegistrationToServer -



1단계의 토큰 등록을 위해 앱 소스를 수정해보자.

github 샘플 : MyFirebaseInstanceIDService.java

안드로이드 앱 가이드에서 추가한 MyFirebaseInstanceIDService.java에는 sendRegistrationToServer 함수가 onTokenRefresh시점에서 호출되고 있다.
하지만, 내용이 비어있는 함수라서 토큰 등록을 직접 구현해야 한다.

먼저 앱 레벨 build.gradle에서 dependencies항목에 okhttp3 라이브러리 사용을 추가한다.

compile 'com.squareup.okhttp3:okhttp:3.2.0'
이후 내용이 비어있는 sendRegistrationToServer를 다음 처럼 수정해보자.

private void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to your app server.
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder().add("Token", token).build();
Request request = new Request.Builder().url("http://yourserver.com/fcm/register_token.php").post(body).build();
try {
client.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
}

HTTP POST 요청으로 register.php에 디바이스 토큰을 송신했다.
(onTokenRefresh는 앱 설치후 딱 한번만 해당되기에 디버깅을 위한 반복 테스트를 하려면 다른 트리거에서 sendRegistrationToServer를 호출해야 한다.)


- register_token.php -



POST로 넘어온 토큰을 DB에 등록해보자.

먼저, 간단한 구조의 테이블을 만들어둔다. 디버깅을 위해서라면 레코드가 작성된 시점을 기록하는 컬럼이 있어도 무방하다.

CREATE TABLE users (
id INT(20) unsigned NOT NULL auto_increment,
Token VARCHAR(255) NOT NULL,
mb_id VARCHAR(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY (Token)
);



register_token.php 를 다음처럼 작성해두자.

include_once('../common.php');
$token = $_POST["Token"] or $_GET["Token"];
$_SESSION["dtkn"] = $token;
$query = "INSERT INTO users(Token) Values ('$token') ON DUPLICATE KEY UPDATE Token = '$token' ";
sql_query($query);

FCM 앱을 설치, 실행하고 나서 몇초후 DB를 조회해보면 152자의 토큰이 등록된 것을 확인할 수 있다.
디바이스 토큰이 준비되었다.


- send_fcm.php -



파이어베이스 콘솔
에서 프로젝트 > 설정 > 클라우드 메시징으로 접근해서 서버 키를 알아낸다.



서버 키는 이전 서버 키(legacy key)도 함께 메모해두자.
구글에서는 새로운 서버 키를 권장하지만, 오히려 이전 서버 키를 써야만 작동하는 경우도 있다.

send_fcm.php를 만들어서 핵심 파트인 send_fcm 함수를 정의한다.

define("GOOGLE_SERVER_KEY", "yourserverkey");
function send_fcm($message, $id) {
$url = 'https://fcm.googleapis.com/fcm/send';

$headers = array (
'Authorization: key=' . GOOGLE_SERVER_KEY,
'Content-Type: application/json'
);

$fields = array (
'data' => array ("message" => $message),
'notification' => array ("body" => $message)
);

if(is_array($id)) {
$fields['registration_ids'] = $id;
} else {
$fields['to'] = $id;
}

$fields['priority'] = "high";

$fields = json_encode ($fields);

$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_POST, true );
curl_setopt ( $ch, CURLOPT_HTTPHEADER, $headers );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $fields );

$result = curl_exec ( $ch );
if ($result === FALSE) {
//die('FCM Send Error: ' . curl_error($ch));
}
curl_close ( $ch );
return $result;
}


$id인자로 배열을 넘겼다면 다중발송을 요청하고, 단일 토큰을 넘겼다면 단일 디바이스로 요청하는 방식이다.
이제 필요한 시점에 send_fcm.php를 영입한후 send_fcm()함수를 호출하면 된다.

메시지의 JSON 포맷은 FCM 메시지 정보를 참조바란다.


- 푸시 알림 -



그누보드의 경우, 공지사항을 전체 앱 사용자에게 배포하려면 /bbs/write_updte.php 혹은 $board_skin_path/write_update.skin.php 에 다음처럼 코드를 추가한다.

if($bo_table == 'yournoticeboard') {
include_once('../fcm/send_fcm.php');
$result = sql_query("Select Token From users");
while ($row = sql_fetch_array($result)) {
if($row["Token"]) {
$tokens[] = $row["Token"];
}
}
$rt = send_fcm($wr_subject, $tokens);
}

등록된 모든 토큰을 배열로 묶고, 인자로 넘겼다.
당연히, 어느정도 사용자 규모가 커진다면 이런 방식은 추천되지 않는다.

$rt = send_fcm($wr_subject, "yourapp-notice");
전체 앱 디바이스를 타겟으로 한다면 주제 단위 전송을 하는 것이 권장된다.
참조 : https://firebase.google.com/docs/cloud-messaging/android/topic-messaging


- 회원별 푸시 알림 -



register_token.php을 다시보면 DB에 토큰을 등록하기전, 서버 세션에 먼저 등록시켜놓았었다.

$_SESSION["dtkn"] = $token;
이 때문에 현재 접속중인 사용자가 로그인을 할 경우 멤버 ID와 토큰을 연결시키는 것이 가능해진다.

/bbs/login_check.php 하단에 코드를 추가하자.

if($_SESSION['dtkn']) {
sql_query("INSERT INTO users(Token, mb_id) Values ('{$_SESSION['dtkn']}', '{$mb['mb_id']}') ON DUPLICATE KEY UPDATE Token = '{$_SESSION['dtkn']}', mb_id = '{$mb['mb_id']}'");
}

users테이블에서 토큰을 유니크 컬럼으로 지정했기에, 로그인 시점마다 멤버 아이디가 갱신이 된다.

그누보드 로그아웃은 세션을 모두 초기화 시켜버리기에 /bbs/logout.php을 손을 봐야 한다.
$dtkn = $_SESSION['dtkn'];
~~~~~~
session_unset();
session_destroy();
~~~~~~
session_start();
$_SESSION["dtkn"] = $dtkn;

세션 초기화 전후로 세션에 토큰을 유지시키는 로직을 추가시켰다.
이제, A로 로그인 -> 로그아웃 -> B로 로그인을 하면 토큰에 연결된 멤버 아이디가 변경되는 것을 확인 가능하다.

쪽지가 도착했을때 해당 회원의 디바이스에 푸시 알림을 보내려면 /bbs/memo_form_update.php에서 send_fcm을 호출하자.

include_once('../fcm/send_fcm.php');
$result = sql_query("Select Token From users where mb_id = '{$recv_mb_id}'");
while ($row = sql_fetch_array($result)) {
if($row["Token"]) {
$tokens[] = $row["Token"];
}
}
if(count($tokens)) { $rt = send_fcm('쪽지가 도착했습니다', $tokens); }

해당 멤버 아이디로 로그인 했던 모든 디바이스에 푸시 알림이 전송되는 방식이다.

기본적으로 JSON 데이터를 HTTP 통신으로 FCM 연결 서버로 넘기는 부분이 핵심이고, 특별한 라이브러리나 프레임웍이 필요한 것은 아니다.
사용하는 서버 사이드 환경에 따라 적절히 변경해서 적용하자.


-- FCM 푸시 알림 --

FCM 푸시 알림 안드로이드 앱 가이드
FCM 푸시 알림 앱 서버 PHP 가이드
FCM 푸시 알림 iOS 앱 가이드

COMMENTS