Programming

Firebase에서 백그라운드에서 앱을 사용할 때 알림을 처리하는 방법

procodes 2020. 2. 27. 22:31
반응형

Firebase에서 백그라운드에서 앱을 사용할 때 알림을 처리하는 방법


여기 내 매니페스트

    <service android:name=".fcm.PshycoFirebaseMessagingServices">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

    <service android:name=".fcm.PshycoFirebaseInstanceIDService">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>

앱이 백그라운드에 있고 알림이 도착하면 기본 알림이 표시되고 코드가 실행되지 않습니다 onMessageReceived.

여기 내 onMessageReceived코드가 있습니다. 백그라운드에서 앱이 아닌 앱이 포 그라운드에서 실행중인 경우 호출합니다. 앱이 백그라운드에있을 때이 코드를 실행하는 방법은 무엇입니까?

// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // If the application is in the foreground handle both data and notification messages here.
    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
    data = remoteMessage.getData();
    String title = remoteMessage.getNotification().getTitle();
    String message = remoteMessage.getNotification().getBody();
    String imageUrl = (String) data.get("image");
    String action = (String) data.get("action");
    Log.i(TAG, "onMessageReceived: title : "+title);
    Log.i(TAG, "onMessageReceived: message : "+message);
    Log.i(TAG, "onMessageReceived: imageUrl : "+imageUrl);
    Log.i(TAG, "onMessageReceived: action : "+action);

    if (imageUrl == null) {
        sendNotification(title,message,action);
    } else {
        new BigPictureNotification(this,title,message,imageUrl,action);
    }
}
// [END receive_message]

1. 왜 이런 일이 발생합니까?

FCM에는 두 가지 유형의 메시지 (Firebase Cloud Messaging)가 있습니다.

  1. 메시지 표시 :이 메시지 onMessageReceived()는 앱이 포 그라운드에 있을 때만 콜백을 트리거합니다
  2. 데이터 메시지 :이 메시지 는 앱이 포 그라운드 / 백그라운드 /onMessageReceived() 킬링 상태 인 경우 에도 콜백을 트리거합니다.

Firebase 팀은 data-messages아직 기기 로 보낼 UI를 개발하지 않았습니다.

2. 어떻게?

이를 위해서는 POST다음 URL에 대한 요청을 수행해야합니다 .

POST https://fcm.googleapis.com/fcm/send

헤더

  • 키 : Content-Type , 값 : application/json
  • 키 : Authorization , 값 : key=<your-server-key>

주제를 사용하는 본문

{
    "to": "/topics/my_topic",
    "data": {
        "my_custom_key": "my_custom_value",
        "my_custom_key2": true
     }
}

또는 특정 기기로 보내려면

{
    "data": {
        "my_custom_key": "my_custom_value",
        "my_custom_key2": true
     },
    "registration_ids": ["{device-token}","{device2-token}","{device3-token}"]
}


참고 : 당신이있어 반드시 추가하지 JSON 키 notification
: 참고 는 중포 기지 콘솔에서 찾을 수 있습니다, 서버 키를 얻으려면 :Your project -> settings -> Project settings -> Cloud messaging -> Server Key

3. 푸시 알림 메시지를 처리하는 방법은 무엇입니까?

수신 된 메시지를 처리하는 방법은 다음과 같습니다.

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();
     String myCustomKey = data.get("my_custom_key");

     // Manage data
}

다음과 같은 경우 firebase 라이브러리가 onMessageReceived () 를 호출하도록하려면

  1. 포 그라운드의 앱
  2. 백그라운드의 앱
  3. 앱이 종료되었습니다

firebase API 요청에 JSON 키 '알림'을 넣지 말고 대신 '데이터'를 사용해야합니다 (아래 참조).

앱이 백그라운드에 있거나 종료 된 경우 다음 메시지는 onMessageReceived ()를 호출 하지 않으며 알림을 사용자 정의 할 수 없습니다.

{
   "to": "/topics/journal",
   "notification": {
   "title" : "title",
   "text": "data!",
   "icon": "ic_notification"
    }
}

그러나 대신 이것을 사용하면 효과가 있습니다.

{
  "to": "/topics/dev_journal",
   "data": {
       "text":"text",
       "title":"",
       "line1":"Journal",
       "line2":"刊物"
   }
} 

기본적으로 메시지는 데이터 객체와 함께 RemoteMessage 인수에 Map으로 전송되며 여기의 스 니펫에서와 같이 onMessageReceived에서 알림을 관리 할 수 ​​있습니다.

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();

     //you can get your text message here.
     String text= data.get("text");


     NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
        // optional, this is to make beautiful icon
             .setLargeIcon(BitmapFactory.decodeResource(
                                    getResources(), R.mipmap.ic_launcher))  
        .setSmallIcon(smallIcon)  //mandatory
      .......
    /*You can read more on notification here:
    https://developer.android.com/training/notify-user/build-notification.html
    https://www.youtube.com/watch?v=-iog_fmm6mE
    */
}

모든 응답이 불완전한 것처럼 느껴지지만 앱이 백그라운드에있을 때 데이터가있는 알림을 처리 해야하는 것이 있습니다.

이 단계를 수행하면 앱이 백그라운드에있을 때 알림을 처리 할 수 ​​있습니다.

1. 다음과 같이 인 텐트 필터를 추가하십시오.

<activity android:name=".MainActivity">
      <intent-filter>
           <action android:name=".MainActivity" />
           <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
</activity>

알림 데이터를 처리하려는 활동에

  1. 다음 형식으로 알림을 보내십시오.

    { 
     "notification" : {
            "click_action" : ".MainActivity", 
            "body" : "new Symulti update !", 
            "title" : "new Symulti update !", 
            "icon" : "ic_notif_symulti" }, 
     "data": { ... },
     "to" : "c9Vaa3ReGdk:APA91bH-AuXgg3lDN2WMcBrNhJZoFtYF9" }
    

여기서 핵심은 추가

"click_action" : ".MainActivity"

여기서 .MainActivity는 1 단계에서 추가 한 의도 필터가있는 활동입니다.

  1. ".MainActivity"의 onCreate에있는 알림에서 "데이터"정보를 가져옵니다.

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //get notification data info
        Bundle bundle = getIntent().getExtras();
        if (bundle != null) {
           //bundle must contain all info sent in "data" field of the notification
        }
    }
    

그리고 그게 당신이해야 할 모든 것입니다. 나는 이것이 누군가를 돕기를 바랍니다 :)


firebase를 사용하여 다운 스트림 보내기 의 firebase 문서에 따르면 두 가지 유형의 페이로드가 있습니다.

  1. 데이터

    이 매개 변수는 메시지 페이로드의 사용자 정의 키-값 쌍을 지정합니다. 클라이언트 앱은 데이터 메시지 처리를 담당합니다. 데이터 메시지에는 사용자 정의 키-값 쌍만 있습니다.

  2. 공고

    이 매개 변수는 사전 정의되고 사용자가 볼 수있는 알림 페이로드의 키-값 쌍을 지정합니다. FCM은 클라이언트 앱 대신 최종 사용자 장치에 메시지를 자동으로 표시합니다. 알림 메시지에는 사전 정의 된 사용자 표시 키 세트가 있습니다.

포 그라운드에있을 때 onMessageReceived ()를 사용하여 FCM 내부 의 데이터를 가져올 수 있으며 데이터 페이로드 에서 데이터를 가져올 수 있습니다 .

data = remoteMessage.getData();
String customData = (String) data.get("customData");

백그라운드에있을 때 FCM은 알림 페이로드 의 정보를 기반으로 시스템 트레이에 알림을 표시 합니다. 시스템 트레이의 알림에 사용 된 제목, 메시지 및 아이콘은 알림 페이로드 에서 가져옵니다 .

{
  "notification": {
        "title" : "title",
        "body"  : "body text",
        "icon"  : "ic_notification",
        "click_action" : "OPEN_ACTIVITY_1"
       }
}

알림 페이로드는 앱이 백그라운드에있을 때 시스템 트레이에 알림을 자동으로 표시하려는 경우에 사용됩니다. 앱이 백그라운드에있을 때 알림 데이터를 얻으려면 알림 페이로드 내에 click_action을 추가해야합니다 .

앱을 열고 백그라운드에서 특정 작업을 수행하려면 알림 페이로드에서 click_action을 설정하고 시작하려는 활동의 인 텐트 필터에 매핑하십시오. 예를 들어 click_action을 OPEN_ACTIVITY_1로 설정하여 다음과 같이 인 텐트 필터를 트리거하십시오.

<intent-filter>
  <action android:name="OPEN_ACTIVITY_1" />
  <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

해당 인 텐트 필터를 활동 태그 중 하나의 매니페스트에 배치하십시오. 알림을 클릭하면 앱이 열리고 click_action에서 정의한 활동 (이 경우 "OPEN_ACTIVTY_1")으로 바로 이동합니다. 그리고 그 활동 안에서 다음과 같이 데이터를 얻을 수 있습니다.

Bundle b = getIntent().getExtras();
String someData = b.getString("someData");

내 안드로이드 앱에 FCM을 사용하고 있으며 두 페이로드를 모두 사용하고 있습니다. 다음은 사용중인 JSON 예제입니다.

{
  "to": "FCM registration ID",
  "notification": {
    "title" : "title",
    "body"  : "body text",
    "icon"  : "ic_notification",
    "click_action" : "OPEN_ACTIVITY_1"
   },
   "data": {
     "someData"  : "This is some data",
     "someData2" : "etc"
   }
}

문서 에 따르면

백그라운드 앱에서 메시지 처리

앱이 백그라운드에 있으면 Android는 알림 메시지를 시스템 트레이로 보냅니다. 알림을 사용자가 누르면 기본적으로 앱 실행기가 열립니다.

여기에는 알림 및 데이터 페이로드가 모두 포함 된 메시지가 포함됩니다. 이 경우 알림은 장치의 시스템 트레이에 전달되고 데이터 페이로드는 런처 활동의 의도에 따라 추가로 전달됩니다.

앱을 열고 특정 작업을 수행하려면 알림 페이로드에서 click_action을 설정하고 시작하려는 활동의 인 텐트 필터에 매핑하십시오. 예를 들어 click_action을 OPEN_ACTIVITY_1로 설정하여 다음과 같이 인 텐트 필터를 트리거하십시오.

 <intent-filter>   <action android:name="OPEN_ACTIVITY_1" />  
 <category android:name="android.intent.category.DEFAULT" />
 </intent-filter>

편집하다 :

스레드를 기반으로 :

Firebase 콘솔을 사용하여 click_action 페이로드를 설정할 수 없습니다. curl 명령 또는 사용자 정의 http 서버로 테스트를 시도 할 수 있습니다.

curl --header "Authorization: key=<YOUR_KEY_GOES_HERE>" 
     --header Content-Type:"application/json" https://fcm.googleapis.com/fcm/send  
     -d "{\"to\":\"/topics/news\",\"notification\": 
         {\"title\": \"Click Action Message\",\"text\": \"Sample message\",
            \"click_action\":\"OPEN_ACTIVITY_1\"}}"

때문에 display-messages어떤 앱이 포 그라운드에있는 경우에만 작동 중포 기지 알림 UI에서 전송됩니다. 의 경우 FCM에data-messages POST 호출을해야합니다.

단계

  1. 고급 휴식 클라이언트 Google 크롬 확장 프로그램 설치 여기에 이미지 설명을 입력하십시오

  2. 다음 헤더를 추가하십시오

    : Content-Type, Value : application / json

    : 인증, : key = "사용자 서버 키"여기에 이미지 설명을 입력하십시오

  3. 몸을 추가

    • 주제를 사용하는 경우 :

      {
          "to" : "/topics/topic_name",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
          }
      }
      
    • 등록 ID를 사용하는 경우 :

      {
          "registration_ids" : "[{"id"},{id1}]",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
           }
      }
      

그게 다야!. 이제 onMessageReceived평소와 같이 콜백을 듣습니다 .

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();
     String value1 = data.get("key1");
     String value2 = data.get("key2");
}

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

}

앱이 forground에있을 때만 호출 될 때마다 호출되지 않습니다.

포 그라운드 또는 백그라운드 또는 종료 된 앱에 관계없이이 메소드는 매번 호출되는 재정의 메소드가 하나 있지만이 메소드는이 Firebase API 버전에서 사용할 수 있습니다.

이것은 gradle에서 가져와야하는 버전입니다.

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

이것은 방법입니다

@Override
public void handleIntent(Intent intent) {
    super.handleIntent(intent);

    // you can get ur data here 
    //intent.getExtras().get("your_data_key") 


}

이전 firebase api를 사용하면이 방법이 없었습니다.이 경우 응용 프로그램이 백그라운드에있을 때 fire base handle 자체가 .... 이제 u 원하는 방법을 가지고 있습니다 ... u이 방법으로 여기에서 할 수 있습니다 .. ...

이전 버전을 사용하는 경우 기본 활동보다 시작됩니다.이 경우 u는 동일한 방식으로 데이터를 얻을 수 있습니다.

if(getIntent().getExtras() != null && getIntent().getExtras().get("your_data_key") != null) {
String strNotificaiton = getIntent().getExtras().get("your_data_key").toString();

// 원하는 것을하십시오 ....}

일반적으로 이것은 우리가 알림을받는 서버의 구조입니다.

{
    "notification": {
        "body": "Cool offers. Get them before expiring!",
        "title": "Flat 80% discount",
        "icon": "appicon",
        "click_action": "activity name" //optional if required.....
    },
    "data": {
        "product_id": 11,
        "product_details": "details.....",
        "other_info": "......."
    }
}

u가 그 데이터 키를주고 싶거나 u가 줄 수있는 모든 것을 통지하고 싶을 때 u에게 달려 있습니다 ....... 같은 키로 u를 줄 것이라면 그 데이터를 얻을 것입니다. .

u가 알림을 클릭 할 때 클릭 동작을 보내지 않으면 기본 활동이 열리지 만 응용 프로그램이 백그라운드에있을 때 특정 활동을 열려면 u가 handleIntent 메소드에서 활동을 호출 할 수 있습니다. 매번 호출


백그라운드에서 메시지를 캡처하려면 BroadcastReceiver

import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.legacy.content.WakefulBroadcastReceiver
import com.google.firebase.messaging.RemoteMessage

class FirebaseBroadcastReceiver : WakefulBroadcastReceiver() {

    val TAG: String = FirebaseBroadcastReceiver::class.java.simpleName

    override fun onReceive(context: Context, intent: Intent) {

        val dataBundle = intent.extras
        if (dataBundle != null)
            for (key in dataBundle.keySet()) {
                Log.d(TAG, "dataBundle: " + key + " : " + dataBundle.get(key))
            }
        val remoteMessage = RemoteMessage(dataBundle)
        }
    }

이것을 매니페스트에 추가하십시오.

<receiver
      android:name="MY_PACKAGE_NAME.FirebaseBroadcastReceiver"
      android:exported="true"
      android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
</receiver>

다음은 firebase 메시지에 대한보다 명확한 개념입니다. 지원팀에서 찾았습니다.

Firebase에는 세 가지 메시지 유형이 있습니다 .

알림 메시지 : 알림 메시지는 배경 또는 전경에서 작동합니다. 앱이 백그라운드에 있으면 알림 메시지가 시스템 트레이로 전달됩니다. 앱이 포 그라운드에있는 경우, 메시지가 처리 onMessageReceived()또는 didReceiveRemoteNotification콜백. 기본적으로 디스플레이 메시지라고합니다.

데이터 메시지 : Android 플랫폼에서 데이터 메시지는 배경 및 전경에서 작동 할 수 있습니다. 데이터 메시지는 onMessageReceived ()에 의해 처리됩니다. 플랫폼 별 참고 사항은 다음과 같습니다. Android에서는 활동을 시작하는 데 사용 된 의도로 데이터 페이로드를 검색 할 수 있습니다. 당신이있을 경우 정교하게하려면 "click_action":"launch_Activity_1", 당신이 의도를 통해 검색 할 수 있습니다 getIntent()만에서 Activity_1.

알림 및 데이터 페이로드가 모두 포함 된 메시지 : 백그라운드에서 앱은 알림 트레이에 알림 페이로드를 수신하고 사용자가 알림을 누를 때만 데이터 페이로드를 처리합니다. 포 그라운드에있을 때 앱은 두 페이로드를 모두 사용할 수있는 메시지 객체를받습니다. 둘째, click_action매개 변수는 종종 데이터 페이로드가 아닌 알림 페이로드에 사용됩니다. 데이터 페이로드 내에서 사용되는 경우이 매개 변수는 사용자 정의 키-값 쌍으로 취급되므로 의도 한대로 작동하도록 사용자 정의 논리를 구현해야합니다.

또한 onMessageReceived방법 (데이터 메시지 참조)을 사용하여 데이터 번들을 추출하는 것이 좋습니다 . 논리에서 번들 객체를 확인했지만 예상되는 데이터 내용을 찾지 못했습니다. 다음은 더 명확성을 제공 할 수있는 유사한 사례에 대한 참조입니다.

자세한 내용은 내 스레드를 방문하십시오.


문서에 따르면 : 2017 년 5 월 17 일

앱이 백그라운드 에 있으면 Android는 알림 메시지를 시스템 트레이로 보냅니다. 알림을 사용자가 누르면 기본적으로 앱 실행기 가 열립니다 .

여기에는 알림 및 데이터 페이로드와 알림 콘솔에서 보낸 모든 메시지가 포함 된 메시지가 포함 됩니다. 이 경우 알림은 장치의 시스템 트레이로 전달되고 데이터 페이로드는 런처 활동의 의도를 제외하고 전달됩니다.

따라서 페이로드 알림 + 데이터를 모두 사용해야합니다.

{
  "to": "FCM registration ID",
  "notification": {
    "title" : "title",
    "body"  : "body text",
    "icon"  : "ic_notification"
   },
   "data": {
     "someData"  : "This is some data",
     "someData2" : "etc"
   }
}

click_action을 사용할 필요가 없습니다. LAUNCHER 액티비티 에 대한 의도만으로 시험을 받아야 합니다.

<activity android:name=".MainActivity">
        <intent-filter>
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>

Java 코드는 MainActivity의 onCreate 메소드에 있어야합니다.

Intent intent = getIntent();
if (intent != null && intent.getExtras() != null) {
    Bundle extras = intent.getExtras();
    String someData= extras.getString("someData");
    String someData2 = extras.getString("someData2");
}

Firebase Notifications Console 에서 페이로드 알림 + 데이터를 모두 테스트 할 수 있습니다 . 고급 옵션 섹션에서 사용자 정의 데이터 필드를 채우는 것을 잊지 마십시오


2017 업데이트 답변

여기 에 관한 문서 에서 명확한 대답 이 있습니다.

여기에 이미지 설명을 입력하십시오


이와 같은 간단한 요약

  • 앱이 실행중인 경우

    onMessageReceived()
    

트리거입니다.

  • 앱이 실행 중이 아닌 경우 (스 와이프하여 종료);

    onMessageReceived()
    

direclty에 의해 트리거되고 전달되지 않습니다. 특수 키-값 쌍이있는 경우 onMessageReceived ()가 작동하지 않아 작동하지 않습니다.

나는이 방법을 찾았다.

런처 활동에서이 논리를

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState, R.layout.activity_splash);

    if (getIntent().getExtras() != null && getIntent().getExtras().containsKey("PACKAGE_NAME")) {

        // do what you want

        // and this for killing app if we dont want to start
        android.os.Process.killProcess(android.os.Process.myPid());

    } else {

        //continue to app
    }
}

이 if 블록에서 firebase UI에 따라 키를 검색하십시오.

이 예에서 위의 키와 값은 다음과 같습니다. (언어 = 죄송합니다)여기에 이미지 설명을 입력하십시오

내 코드가 작동하면 "com.rda.note"가 나타납니다.

android.os.Process.killProcess(android.os.Process.myPid());

이 코드 줄을 사용하여 응용 프로그램을 닫고 Google Play 마켓을 열었습니다.

행복한 코딩 =)


시나리오를 알아 냈습니다.

애플 리케이션에있을 때 전경 , onMessageReceived () 메소드가 호출되는 FirebaseService 낭포 pendingIntent 호출되는 서비스 클래스에 정의.

응용 프로그램이있을 때 그리고 배경 , 첫 번째 활동 이라고합니다.

당신이 사용하는 경우 이제 시작 활동을 하고 있어야 마음에 계속 splashactivity가 다음 첫 번째 활동이 무엇이든, 호출됩니다 더 splashActivity이 존재하지 않는 경우는 다른, 호출됩니다.

그런 다음 확인해야합니다 () getIntent을firstActivity 는 어떤이 있는지 번들 은 번들이 채워 값이 나타납니다 확실히 모든 잎파리. 만약에 값 데이터 태그 이 같은 서버 외모에서 전송,

"data": {
    "user_name": "arefin sajib",
    "value": "user name notification"
  }

그런 다음 첫 번째 활동에서 유효한 intent ( getIntent ()가 null이 아님 ), 유효한 번들 및 내부 번들이 있고 위에서 언급 한 전체 JSON이 datakey 로 표시 됩니다 .

이 시나리오의 경우 값 추출 코드는 다음과 같습니다.

    if(getIntent()!=null){
            Bundle bundle = getIntent().getExtras();
            if (bundle != null) {
                try {
                   JSONObject object = new JSONObject(bundle.getStringExtra("data"));
String user_name = object.optString("user_name");

                } catch (JSONException e) {
                    e.printStackTrace();
                }


            }
        }

2019 년 7 월 현재

Android compileSdkVersion 28, buildToolsVersion 28.0.3 및 firebase-messaging : 19.0.1

다른 모든 StackOverflow 질문과 답변을 조사하고 수많은 구식 솔루션을 시도한 후이 솔루션은 다음 세 가지 시나리오에서 알림을 표시했습니다.

-앱이 포 그라운드에 있음 :
MyFirebaseMessagingService 클래스의 onMessageReceived 메소드가 알림을받습니다 .

-앱이 종료되었습니다 (백그라운드에서 실행되지 않음). FCM에 의해 알림이 알림 트레이로 자동 전송됩니다. 사용자가 알림을 터치하면 매니페스트에 android.intent.category.LAUNCHER가있는 활동을 호출하여 앱이 시작됩니다. onCreate () 메소드에서 getIntent (). getExtras ()를 사용하여 알림의 데이터 부분을 가져올 수 있습니다.

-앱이 백그라운드에 있음 : FCM에 의해 알림이 알림 트레이로 자동 전송됩니다. 사용자가 알림을 터치하면 매니페스트에 android.intent.category.LAUNCHER가있는 활동을 시작하여 앱이 포 그라운드로 이동합니다. 내 응용 프로그램에 해당 활동에 launchMode = "singleTop"가 있으므로 동일한 클래스의 활동 하나가 이미 작성되어 있기 때문에 onCreate () 메소드가 호출되지 않고 해당 클래스의 onNewIntent () 메소드가 호출되어 데이터의 일부를 가져옵니다 intent.getExtras ()를 사용하여 알림.

단계 : 1- 앱의 주요 활동을 다음과 같이 정의한 경우 :

<activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:screenOrientation="portrait"
    android:launchMode="singleTop">
    <intent-filter>
        <action android:name=".MainActivity" />
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

2- MainActivity.class의 onCreate () 메소드에서이 행을 추가하십시오.

Intent i = getIntent();
Bundle extras = i.getExtras();
if (extras != null) {
    for (String key : extras.keySet()) {
        Object value = extras.get(key);
        Log.d(Application.APPTAG, "Extras received at onCreate:  Key: " + key + " Value: " + value);
    }
    String title = extras.getString("title");
    String message = extras.getString("body");
    if (message!=null && message.length()>0) {
        getIntent().removeExtra("body");
        showNotificationInADialog(title, message);
    }
}

그리고 같은 MainActivity.class에 대한 메소드 :

@Override
public void onNewIntent(Intent intent){
    //called when a new intent for this class is created.
    // The main case is when the app was in background, a notification arrives to the tray, and the user touches the notification

    super.onNewIntent(intent);

    Log.d(Application.APPTAG, "onNewIntent - starting");
    Bundle extras = intent.getExtras();
    if (extras != null) {
        for (String key : extras.keySet()) {
            Object value = extras.get(key);
            Log.d(Application.APPTAG, "Extras received at onNewIntent:  Key: " + key + " Value: " + value);
        }
        String title = extras.getString("title");
        String message = extras.getString("body");
        if (message!=null && message.length()>0) {
            getIntent().removeExtra("body");
            showNotificationInADialog(title, message);
        }
    }
}


private void showNotificationInADialog(String title, String message) {

    // show a dialog with the provided title and message
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(title);
    builder.setMessage(message);
    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            dialog.cancel();
        }
    });
    AlertDialog alert = builder.create();
    alert.show();
}

3- 다음과 같이 MyFirebase 클래스를 만듭니다.

package com.yourcompany.app;

import android.content.Intent;
import android.util.Log;

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

public class MyFirebaseMessagingService extends FirebaseMessagingService {


    public MyFirebaseMessagingService() {
        super();
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        Log.d(Application.APPTAG, "myFirebaseMessagingService - onMessageReceived - message: " + remoteMessage);

        Intent dialogIntent = new Intent(this, NotificationActivity.class);
        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        dialogIntent.putExtra("msg", remoteMessage);
        startActivity(dialogIntent);

    }

}

4- 다음과 같이 새 클래스 NotificationActivity.class를 작성하십시오.

package com.yourcompany.app;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ContextThemeWrapper;

import com.google.firebase.messaging.RemoteMessage;

public class NotificationActivity extends AppCompatActivity {

private Activity context;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    context = this;
    Bundle extras = getIntent().getExtras();

    Log.d(Application.APPTAG, "NotificationActivity - onCreate - extras: " + extras);

    if (extras == null) {
        context.finish();
        return;
    }

    RemoteMessage msg = (RemoteMessage) extras.get("msg");

    if (msg == null) {
        context.finish();
        return;
    }

    RemoteMessage.Notification notification = msg.getNotification();

    if (notification == null) {
        context.finish();
        return;
    }

    String dialogMessage;
    try {
        dialogMessage = notification.getBody();
    } catch (Exception e){
        context.finish();
        return;
    }
    String dialogTitle = notification.getTitle();
    if (dialogTitle == null || dialogTitle.length() == 0) {
        dialogTitle = "";
    }

    AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(context, R.style.myDialog));
    builder.setTitle(dialogTitle);
    builder.setMessage(dialogMessage);
    builder.setPositiveButton(getResources().getString(R.string.accept), new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            dialog.cancel();
        }
    });
    AlertDialog alert = builder.create();
    alert.show();

}

}

5- 태그 내에서 앱 매니페스트에이 줄을 추가하십시오.

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

    <meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/default_notification_channel_id"/>

    <activity android:name=".NotificationActivity"
        android:theme="@style/myDialog"> </activity>

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/notification_icon"/>

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/color_accent" />

6- Application.java onCreate () 메소드 또는 MainActivity.class onCreate () 메소드에 다음 행을 추가하십시오.

      // notifications channel creation
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      // Create channel to show notifications.
      String channelId = getResources().getString("default_channel_id");
      String channelName = getResources().getString("General announcements");
      NotificationManager notificationManager = getSystemService(NotificationManager.class);
      notificationManager.createNotificationChannel(new NotificationChannel(channelId,
              channelName, NotificationManager.IMPORTANCE_LOW));
  }

끝난.

위에서 언급 한 3 가지 시나리오에서이 기능이 제대로 작동하려면 다음과 같은 방식으로 Firebase 웹 콘솔에서 알림을 보내야합니다.

알림 섹션에서 : 알림 제목 = 알림 대화 상자에 표시 할 제목 (선택 사항) 알림 텍스트 = 사용자에게 표시 할 메시지 (필수) 그런 다음 대상 섹션에서 : App = Android 앱 및 추가 옵션 섹션 : Android 알림 채널 = default_channel_id 맞춤 데이터 키 : 제목 값 : (알림 섹션의 제목 필드에있는 동일한 텍스트) 키 : 본문 값 : (알림 섹션의 메시지 필드에있는 동일한 텍스트) 키 : click_action 값 : .MainActivity Sound = 사용 안함
만료 = 4 주

Google Play API 28의 에뮬레이터에서 디버깅 할 수 있습니다.

행복한 코딩!


답변 해 주셔서 감사합니다. 그러나 Notification 을 보내는 대신 데이터 메시지보내서이 문제를 해결했습니다 . 서버 코드

<?php
$url = "https://fcm.googleapis.com/fcm/send";
$token = "C-l6T_a7HouUK****";
$serverKey = "AAAAaOcKS00:********";
define( 'API_ACCESS_KEY', $serverKey );
$registrationIds = array($token);
// prep the bundle

$msg = array

(
 'message'  => 'here is a message. message',
 'title'        => 'This is a title. title',
 'subtitle' => 'This is a subtitle. subtitle',
 'tickerText'   => 'Ticker text here...Ticker text here...Ticker text 
 here',
 'vibrate'  => 1,
 'sound'        => 1,
 'largeIcon'    => 'large_icon',
 'smallIcon'    => 'small_icon'

);

$fields = array

(
  'registration_ids'    => $registrationIds,
  'data'            => $msg

);
$headers = array

(
  'Authorization: key=' . API_ACCESS_KEY,
 'Content-Type: application/json'

);


$ch = curl_init();

curl_setopt( $ch,CURLOPT_URL, 'https://android.googleapis.com/gcm/send' 
);

curl_setopt( $ch,CURLOPT_POST, true );

curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );

curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );

curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );

curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) );

$result = curl_exec($ch );

curl_close( $ch );

echo $result;

?>

그리고 onMessageReceived의 데이터를 잡았습니다.

public class MyFirebaseMessagingService extends FirebaseMessagingService     {

  private static final String TAG = "MyFirebaseMsgService";

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    Log.d(TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());

      sendNotification(remoteMessage.getData().get("message"));
     }
   // Check if message contains a notification payload.
    else if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    sendNotification(remoteMessage.getNotification().getBody());
    }


}
   private void sendNotification(String messageBody) {
    Intent intent = new Intent(this, Notify.class).putExtra("msg",messageBody);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT);

    String channelId = "idddd";
    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder =
            new NotificationCompat.Builder(MyFirebaseMessagingService.this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentTitle("FCM Message")
                    .setContentText(messageBody)
                    .setAutoCancel(true)
                    .setSound(defaultSoundUri)
                    .setContentIntent(pendingIntent);

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

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

서버 요청에서 알림 페이로드를 완전히 제거하십시오 . 전송 데이터 만 하고 그것을 처리 onMessageReceived()그렇지 않으면, onMessageReceived뜻이 응용 프로그램은 배경 또는 사망에있을 때 트리거 할 수 없습니다.

다음은 서버에서 보내는 것입니다.

{
  "data":{
    "id": 1,
    "missedRequests": 5
    "addAnyDataHere": 123
  },
  "to": "fhiT7evmZk8:APA91bFJq7Tkly4BtLRXdYvqHno2vHCRkzpJT8QZy0TlIGs......"
}

따라서 다음 onMessageReceived(RemoteMessage message)과 같이 데이터를 수신 할 수 있습니다 (ID를 가져와야한다고 가정 해 봅시다)

Object obj = message.getData().get("id");
        if (obj != null) {
            int id = Integer.valueOf(obj.toString());
        }

마찬가지로 서버 내에서 보낸 모든 데이터를 얻을 수 있습니다 onMessageReceived().


앱이 백그라운드 및 포 그라운드에있는 경우에도 다음과 같이 메시지를 보내는 쉬운 방법 :-API를 사용하여 메시지를 보내려면 크롬 확장명 인 AdvancedREST 클라이언트라는 도구를 사용하고 다음 매개 변수를 사용하여 메시지를 보낼 수 있습니다.

나머지 클라이언트 도구 링크 : https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo

이 URL을 사용하십시오 : https://fcm.googleapis.com/fcm/send Content-Type : application / json Authorization : key = 귀하의 서버 키 또는 Authoization 키 (아래 참조 참조)

{ "data": {
    "image": "https://static.pexels.com/photos/4825/red-love-romantic-flowers.jpg",
    "message": "Firebase Push Message Using API"
    "AnotherActivity": "True"
     },
  "to" : "device id Or Device token"
}

인증 키는 Google 개발자 콘솔을 방문하여 프로젝트 왼쪽 메뉴에서 자격 증명 버튼을 클릭하여 얻을 수 있습니다. 나열된 API 키 중 서버 키는 인증 키입니다.

그리고 API를 사용하여 보낸 POST 요청의 "to"섹션에 수신자의 tokenID를 넣어야합니다.


2018 년 6 월 답변-

메시지에 "알림"키워드가 없는지 확인해야합니다. "데이터"만 포함하면 앱이 백그라운드에서 또는 종료 된 경우에도 onMessageReceived의 메시지를 처리 ​​할 수 ​​있습니다.

클라우드 기능 사용 :

const message = {
    token: token_id,   // obtain device token id by querying data in firebase
    data: {
       title: "my_custom_title",
       body:  "my_custom_body_message"
       }
    }


return admin.messaging().send(message).then(response => {
    // handle response
});

그런 다음 onMessageReceived ()에서 com.google.firebase.messaging.FirebaseMessagingService를 확장하는 클래스에서 :

if (data != null) {
  Log.d(TAG, "data title is: " + data.get("title");
  Log.d(TAG, "data body is: " + data.get("body");
}

// build notification using the body, title, and whatever else you want.

OAUTH 2.0에 따르면 :

FAUC가 OAUTH 2를 사용하고 있으므로이 경우 인증 문제가 발생합니다.

그래서 나는 firebase 문서를 읽고 문서에 따르면 데이터 메시지를 게시하는 새로운 방법은 다음과 같습니다.

POST: https://fcm.googleapis.com/v1/projects/YOUR_FIREBASEDB_ID/messages:send

헤더

Key: Content-Type, Value: application/json

인증

Bearer YOUR_TOKEN 

본문 예

{
   "message":{
    "topic" : "xxx",
    "data" : {
         "body" : "This is a Firebase Cloud Messaging Topic Message!",
         "title" : "FCM Message"
          }
      }
 }

URL에는 Firebase 콘솔에서 찾을 수있는 데이터베이스 ID가 있습니다. (프로젝트 설정 이동)

이제 토큰을 가져갑니다 (1 시간 만 유효).

먼저 Firebase 콘솔에서 설정> 서비스 계정을 엽니 다 . 새 개인 키 생성을 클릭 하고 키가 포함 된 JSON 파일을 안전하게 저장하십시오. 서버 요청을 수동으로 승인하려면이 JSON 파일이 필요했습니다. 다운로드했습니다.

그런 다음 node.js 프로젝트를 만들고이 함수를 사용하여 토큰을 얻습니다.

var PROJECT_ID = 'YOUR_PROJECT_ID';
var HOST = 'fcm.googleapis.com';
var PATH = '/v1/projects/' + PROJECT_ID + '/messages:send';
var MESSAGING_SCOPE = 'https://www.googleapis.com/auth/firebase.messaging';
var SCOPES = [MESSAGING_SCOPE];

  router.get('/', function(req, res, next) {
      res.render('index', { title: 'Express' });
      getAccessToken().then(function(accessToken) {
        console.log("TOKEN: "+accessToken)
      })

    });

function getAccessToken() {
return new Promise(function(resolve, reject) {
    var key = require('./YOUR_DOWNLOADED_JSON_FILE.json');
    var jwtClient = new google.auth.JWT(
        key.client_email,
        null,
        key.private_key,
        SCOPES,
        null
    );
    jwtClient.authorize(function(err, tokens) {
        if (err) {
            reject(err);
            return;
        }
        resolve(tokens.access_token);
    });
});
}

이제 게시물 요청에이 토큰을 사용할 수 있습니다. 그런 다음 데이터 메시지를 게시하면 이제 내 앱 onMessageReceived 함수에서 처리합니다.


백그라운드에서 데이터 부분 알림 부분에서만 onMessageReceived (RemoteMessage remoteMessage)를 작업하려고합니다.

"data":    "image": "",    "message": "Firebase Push Message Using API", 

"AnotherActivity": "True", "to": "장치 ID 또는 장치 토큰"

이 onMessageRecivied는 호출 배경 및 포 그라운드이므로 실행기 활동에서 알림 트레이를 사용하여 알림을 처리 할 필요가 없습니다. 이것을 사용하여 데이터 페이로드를 처리하십시오.

  public void onMessageReceived(RemoteMessage remoteMessage)
    if (remoteMessage.getData().size() > 0) 
    Log.d(TAG, "Message data payload: " + remoteMessage.getData());      

위의 답변 외에도 FCM console을 사용하여 푸시 알림을 테스트하는 경우 '데이터'키와 객체가 푸시 알림 번들에 추가 되지 않습니다 . 따라서 앱이 백그라운드이거나 종료 된 경우 자세한 푸시 알림을받지 않습니다.

이 경우 앱 백그라운드 시나리오를 테스트하려면 백엔드 관리 콘솔을 선택해야합니다.

여기에서 푸시 번들에 '데이터'키를 추가했습니다. 자세한 푸시가 예상대로 표시됩니다. 이것이 도움이되기를 바랍니다.


이 코드를 사용하면 백그라운드 / 전경에서 알림을 받고 조치를 취할 수 있습니다.

//Data should come in this format from the notification
{
  "to": "/xyz/Notifications",
  "data": {
      "key1": "title notification",
      "key2": "description notification"
  }
}

인앱은 다음 코드를 사용합니다.

  @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
      String key1Data = remoteMessage.getData().get("key1");
      // use key1Data to according to your need
    }

Since 2019, Google Firebase has a big change in their APIs I mean: 'com.google.firebase:firebase-messaging:18.0.0'

in 18.0.0 they removed MyFirebaseInstanceIDService and you need to get token in MyFirebaseMessagingService so you just need to write :

@Override
public void onNewToken(String token) {
    Log.d(TAG, "Refreshed token: " + token);

}

and also in your AndroidManifest.xml, you have to remove :

<service android:name=".service.MyFirebaseInstanceIDService">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>

Also, you're recommended to set default values to customize the appearance of notifications. You can specify a custom default icon and a custom default color that are applied whenever equivalent values are not set in the notification payload.

Add these lines inside the application tag to set the custom default icon and custom color:

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/ic_notification" />

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/colorAccent" />

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_channel_id"
        android:value="@string/push_channel" />

now to handle notification messages in a backgrounded app you should define an Intent in your first Activity even if it is SplashScreen, When your app is in the background, Android directs notification messages to the system tray. A user tap on the notification opens the app launcher by default.

for example, if your Json is like this:

 "data": {
"message": "2",
"title": "1",
"pushType" : "banner",
"bannerLink": "http://www.google.com",
"image" : "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"}

you just need to write a simple intent to get those values:

        Bundle extras = intent.getExtras();
        String bannerLink = extras.getString("bannerLink");
        ...
        String channelId = extras.getString("channelId");

  // Place this code on your MainActivity,then you will get your payload
  // Handle possible data accompanying notification message.
    // [START handle_data_extras]
    if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d(TAG, "Key: " + key + " Value: " + value);
        }
    }

There will be two types of notifications

  1. Display Notification - Only display notifications, will be shown only app is not open and its in the app stack.
  2. Data Notification - callback will go into onMessageReceived method of firebasemessagingservice and it works when the app is in background, foreground or killed state.

You must use Data Notifications to handle the notification when app is in background.


동일한 문제가 발생하여 Firebase 라이브러리를 다시 컴파일하여 애플리케이션이 백그라운드에있을 때 알림을 보내지 못했습니다.

* 라이브러리 https://github.com/erdalceylan/com-google-firebase-messaging

 dependencies {
        compile 'com.google.firebase:firebase-core:11.2.0'
        compile 'com.github.erdalceylan:com-google-firebase-messaging:v1-11.2.0'
    }

*

@WorkerThread
public void onMessageReceived(RemoteMessage var1) {
  //your app is in background or foreground all time calling
}

희망이 도움이됩니다. 행운을 빕니다

참고 URL : https://stackoverflow.com/questions/37711082/how-to-hand-notification-when-app-in-background-in-firebase



반응형