fcm push notification example / (fcm) 안드로이드 푸시 알림 (2)

북마크 추가

 

 

Firebase Cloud Messaging을 사용하여 안드로이드 푸시 알림을 구현 하는 방법 입니다.

 

 

1. project level의  build.gradle 파일에 google-service를 추가합니다.

 

dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
//classpath 'com.google.gms:google-services:3.0.0'
classpath 'com.google.gms:google-services:3.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}

2. app level의 build.gradle 파일에 firebase-messaging을 추가합니다. 그리고 google-service plugin을 apply 해줍니다.

 

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'

compile 'com.google.firebase:firebase-messaging:9.0.2'

}
apply plugin: 'com.google.gms.google-services'

 

 

3. Android-manifest.xml

 

<application></application> 태그 안에 아래 내용을 추가해 줍니다.
<service
android:name=".FirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service
android:name=".FirebaseInstanceIDService" >
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>

4. FirebaseInstanceIDService.java

/**
* Created by HKH on 2016-06-28.
*/
import android.util.Log;

import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;


public class FirebaseInstanceIDService extends FirebaseInstanceIdService {

private static final String TAG = "MyFirebaseIIDService";

// [START refresh_token]
@Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String token = FirebaseInstanceId.getInstance().getToken();

}

}

사용자 기기별 token을 생성하는 클래스 입니다.

나중에 push 알림을 특정 타겟에게 보낼 때 사용되는 고유 키 값 입니다.

이 토큰값을 용도에 맞게 사용하시면 됩니다.


5. FirebaseMessagingService.java


/**
* Created by HKH on 2016-06-28.
*/
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.PowerManager;
import android.support.v4.app.NotificationCompat;

import com.google.firebase.messaging.RemoteMessage;

import java.io.BufferedInputStream;
import java.net.URL;
import java.net.URLConnection;


public class FirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService {
private static final String TAG = "FirebaseMsgService";

// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

sendPushNotification(remoteMessage.getData().get("message"));
}

private void sendPushNotification(String message) {
System.out.println("received message : " + message);
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);

Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.noti).setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher) )
.setContentTitle("Push Title ")
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri).setLights(000000255,500,2000)
.setContentIntent(pendingIntent);

NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakelock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "TAG");
wakelock.acquire(5000);

notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}

}


푸시메세지가 들어왔을때 실제 사용자에게 푸시알림을 만들어서 띄워주는 클래스 입니다.

Api를 통해 푸시 알림을 전송하면 입력한 내용이 message에 담겨서 오게 됩니다.


6. MainActivity.java


import com.google.firebase.messaging.FirebaseMessaging;

onCreate 함수 안에

FirebaseMessaging.getInstance().subscribeToTopic("notice");

-> 여기서 topic은 api를 사용하여 푸시 알림 전송시 같은 토픽명 그룹 전체에 메세지를 발송 할 수 있습니다.

 

 테스트는 Firebase Console의 Notification 메뉴에서 가능합니다.

 

 

 

 

백그라운드 푸시알림 받기 :: http://trandent.com/board/Android/detail/744 

 

+ 내용 추가 

 

1. android sdk에 google play services 가 설치되어있지 않아서 오류가 발생한다면

 

android studio 사용중이시라면 tools -> android -> SDK manager -> SDK Tools 탭에 들어가셔서 Google Play services 설치해 보시기 바랍니다.

2. onTokenRefresh에서 뿐만 아니라 어느 시점에서든 

String token = FirebaseInstanceId.getInstance().getToken(); 을 사용하게 되면 사용자 기기의 고유 토큰 값을 가져 올 수 있습니다.

여기서 얻은 토큰으로 특정 사용자에게 푸시알림 전송이 가능합니다.

AD
통관알리미
2016-07-16 11:50
SHARE
댓글

FirebaseMessagingService에서 계속 오류가 발생했엇는데,

Gradle 의 app 레벨에
compile 'com.google.firebase:firebase-core:10.0.1'

이 있어야 FirebaseMessagingService에서 에러가 안나네요
김**

ㅎㅎ 저두 얼른 FCM을 자유자재로 하고싶은데 너무 안일하게 생각했나봐여 잘안풀리네여 ㅎㅎ 그래도 도움 많이 감사드려요 덕분에 조금씩 진도가 나가고있네여 ㅎㅎ
J**********

네ㅎㅎ 저같은 경우는 서버에서 보낼때 title은 사용 안하고 data 안에 제가 필요한 파라미터를 정의해서 json형식으로 사용합니다
H**

아아아아아아!!! 해결했어요!!

저혼자 이상한 말 다하고 .. ㅈㅅ합니다..

말씀하신 고급옵션에 보니깐 맞춤 데이터라고 따로 있네요 여기서 key 하고 value를 설정하니깐 되네여..

ㅠㅠ 알려주신 점들 정말 감사합니다.
J**********

쉽게 정리해서 말씀드리면 firebase console로 메시지를 보내면 Client에서는 getNotification().getTitle() 그리고 getNotification().getBody()로 메시지의 타이틀과 내용을 받을 수 있고
webserver에서 
Content-Type : application/json
Authorization : key="구글서 발급 받은 키"
body : 
{
    "to": "위에 프로젝트에서 받은 token",
    "data": {
      "title" : "푸시 타이틀",
      "message": "푸시 내용",
     }
  }

이런 형태로 메시지를 보내게되면 Client에서는 getData().get("title") 그리고 getData().get("message") 로 메시지의 타이틀과 내용을 받아올수있다.. 가 맞는가여?
J**********

아 혹시 firebase console 의 notification 항목으로 메시지를 보내게되면 getData()에는 내용이 안들어오고
firebase console 이 아닌 자체 웹서버에서 FCM 형태로 데이터를 보내면 getData() 에 내용이 떨어지는건가여???
api를 보니깐 
키	                              콘솔 필드 라벨	설명
notification.title	메시지 제목	알림 제목을 나타냅니다.
notification.body	메시지 내용	알림 본문 텍스트를 나타냅니다.
data	                        맞춤 데이터	사용자가 정의하는 키/값 쌍입니다. 앱에서 처리할 데이터 페이로드로 전송됩니다.

라고 정의가 되어있는데 data 부분은 결국 https://console.firebase.google.com/project/..  의 notification 항목에서 보내는게 아니라 webserver에  fcm으로 client에 json과 같은 형식으로 보내고 client는 해당부분을 getData().get("[정의한 키값 ex) message]") 와 같이 사용해서 내용을 얻어오는 건가여?
J**********

고급옵션에서 타이틀을 넣으면 onMessageReceived 메소드에서 remotemessage.getnotification().getTitle() 을 이용해서 타이틀을 가져올 수 있자나여?
getnotification()을 이용해서 getTitle() 하고 getBody()를 하면 타이틀하고 메시지는 잘 나와여
그런데 remotemessage.getData().get("message")를 하면 null 값이 떨어지고 getData().size()를 체크해보면 0이라고 출력이 되더라구염
말씀하신 key value는 따로 입력안했구여.
그래서 getData()는 아무런 값도 나오지않아서.. getData() 는 왜 값이 안나오는 가 여쭤본겁니다...ㅠㅠ
혹시 getData()는 메시지의 타이틀하고 내용을 가져오는 용도가 아닌가..라는 생각도 들기도 했구여..
J**********

고급옵션에서의 title, key value로 전송했을 경우를 말씀하시는건가요?
H**

감사합니다 ^^ 그런데 한가지만 더 여쭤볼께여..ㅎㅎ
우선 말씀하신 firebase console의 notification 에서 데이터를 보내고는 있는데 여전히 getData에는 데이터가 없고 (size 체크를 해보니 0이 출력..)
notification의 title 과 body에는 메시지 타이틀과 메시지 내용이 정상적으로 출력되고있습니다.
getData()에는 왜 데이터가 없는걸까요...^^;;
J**********

https://firebase.google.com/docs/notifications/android/console-device?hl=ko
여기를 참조 해 보시면 title은 notification.title로 전송된다고 되어있네요
참고하시면 될것같습니다
H**

https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/RemoteMessage
에 보시면 getData()를 통해 payload 데이터를 받을 수 있습니다.  firebase console을 통해 전송시 메세지 내용으로 입력한 부분이 들어옵니다
H**

혹시 onMessageReceived 오버라이드 메소드에서 sendPushNotification() 메소드로 보낼 때 getData가 아니라 getBody로 보내야하는 거 아닌가여?
현재 getData() 자체가 null로 나오고 getBody에 firebase에서 보낸 메시지가 나오네요 .. Title은..멀로 봐야할지...
J**********

이 다음 글을 보시면 관련한 내용이 나옵니다
통관알리미

테스트는 firebase console에서 하고 계시는 건가요?
console에서 테스트 중이시라면 앱이 백그라운드로 돌고 있을때는 설정이 적용되지 않습니다
통관알리미

NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.darak).setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.darak) )
                .setSound(defaultSoundUri).setLights(000000255,500,2000)

현재 이렇게 되어있는데 푸시는 오고 진동/알람이 오지 않습니다ㅜ 이미지도 변경이 안되고ㅜ 답답하네요ㅜㅜ
윤**

notificationBuilder.setSound(defaultSoundUri) 를 하셨는데도 진동/ 알림음이 오지 않나요?
H**

이모티콘도 다른 이미지로 변경하려고 drawable에 있는 이미지로 바꿨는데 변경이 안되네요ㅜㅜ 조언부탁드립니다ㅜ
윤**

푸시는 오는데 진동이나 알림음이 안오는건 무슨 문제일까요ㅜㅜ
윤**

이 다음 글 보시면 거기에 있는 fcm api 이용하시면 됩니다
H**

혹시 저렇게 Firebase에서 수동으로 메시지를 보내는 것 말고 자동으로 할 수는 없나요?
예를 들어서, 게시판에 글이 올라오면 메시지가 간다던가.. 하는 방법이요!
박**

답변 정말 감사합니다.  많이 배우고가요!!
박**

글쎄요 해당 오류가 발생한 적이 없어서 저도  답변 드릴수가 없네요
구글에서 비슷한 케이스를 찾아봐야 할거같습니다
통관알리미

답변 정말 감사합니다.
'(with google apis)' 붙어있는걸로 디바이스를 만들고 실행을 시키면 ''unfortunately the process com google process gapps has stopped' 계속 이런문구가 떠서 검색해보고 tool몇개를 설치했더니 애뮬레이터설정할때  '(with google apis)' 붙어있는걸로 설정하면 자동으로 '(with google apis)' 안붙어있는 target이 android6.0인 avd가 실행이 됩니다. 뭐가 잘못된건가요?ㅠㅠ
박**

에뮬레이터를 만드실때 target에 Google APIs를 해주셔야 알림이 수신됩니다.
genymotion은 2.0 이상부터 였던가 google apps를 지원하지 않아서 별도 설정을 해줘야 하는데
설정이 번거로워서 기본 에뮬레이터 AVD로 말씀드리면 디바이스를 만들때 시스템 이미지 선택화면에 
Target
Android6.0  (with Google APIs)
이런식으로 되어있는 이미지들이 있습니다. with Google APIs가 붙어있는 이미지로 만들어서 테스트하시면 됩니다
통관알리미

정말 감사합니다. 해결되었습니다.
혹시요 가상기기에서는 푸시알림 테스트가 안되나요?
안드로이드기기가 없어서 genymotion 연동해서 사용하고 있는데 notification에서 메시지보내도 반응이 없네요.
박**

이미지가 없어서 에러가 나는건데요 
제 프로젝트의  경우 app/src/main/res/drawable/noti.png 파일을 쓰고 있습니다.
그래서 사용 할 때는 R.drawable.noti 로 불러와서 쓰는거구요 
푸시알림에서 사용하실 이미지 파일을  res/drawable 경로에 넣으시고 이미지 파일이름을 바꿔주시면 됩니다.
ex) R.drawable.이미지파일명
통관알리미

안녕하세요. 선생님 글보고 푸시알림 공부하고있습니다.
5번  '.setSmallIcon(R.drawable.noti).setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher) )'  부분에서
cannot resolve symbol 'noti' 라고 빨갛게 뜨는데 어떤 문제인가요?ㅠㅠ
박**

네 빠진 부분은 추가해야 겠네요 
다음글들 보시면 어플이 백그라운드에서 돌거나 죽어있을때 알림받는거랑 알림창 설정하는 내용도 있습니다
통관알리미

와~!! 정말~! 감사합니다~! SDK Tools  에서 Google Play services 설치하고 새로 싱크랑 다 맞추니까 성공했습니다~!  푸시 알림도 테스트 해봤더니 되네요~! 정말정말 감사합니다!! 덕분에 큰도움이 되었습니다!
A**

혹시 android sdk에 google play services 가 설치되어있지 않다면 
android studio 사용중이시라면 tools -> android -> SDK manager -> SDK Tools 탭에 들어가셔서 Google Play services 설치해 보시기 바랍니다
통관알리미

그 부분에서 에러가 난다는건 라이브러리를 못 찾는다는거 같은데
혹시 1, 2번 하시고 gradle sync는 맞추셨나요? 어떤 개발툴 사용중이신가요?
통관알리미

제가 초보인데, 새프로젝트 만들고 처음부터 따라했는데 5번부터 에러가 뜹니다. 6번은 import com.google.firebase..FirebaseMessaging;

.getInstance().subscribeToTopic("notice"); <>괄호 친곳이 에러고, 5번은 RemoteMessage , getData , getSystemService , getSystemService , getResources 등등에 에러가 뜨는데 통 모르겠어서요..혹시 도와 주실수 있나 해서 질문 남겨봅니다ㅠ 아신다면 도움좀 부탁드려요~
A**

위의 내용중 빠진 내용이 있는데  String token = FirebaseInstanceId.getInstance().getToken(); 을 사용하게 되면 사용자 기기의 고유 토큰 값을 가져 올 수 있습니다.
MainActivity의 onCreate에서 사용하면 앱을 실행 시킬 때 토큰 값을 가져 올 수 있습니다.
각자 토큰값이 필요한 시점에 넣어주시면 됩니다.
통관알리미