android - Firebase onMessageReceived जब पृष्ठभूमि में app नहीं कहा जाता है




messaging firebase-cloud-messaging (16)

मैं फायरबेस के साथ काम कर रहा हूं और ऐप को पृष्ठभूमि में होने के दौरान अपने सर्वर से अपने ऐप पर सूचनाएं भेजने का परीक्षण कर रहा हूं। अधिसूचना सफलतापूर्वक भेजी जाती है, यह डिवाइस के सूचना केंद्र पर भी दिखाई देती है, लेकिन जब अधिसूचना दिखाई देती है या यहां तक ​​कि अगर मैं इस पर क्लिक करता हूं, तो मेरे FCMessagingService के अंदर ऑनमैसेजेज विधि कभी नहीं कहा जाता है।

जब मैंने अपने ऐप को अग्रभूमि में रखा था, तब मैंने इसका परीक्षण किया था। समस्या तब होती है जब ऐप पृष्ठभूमि में चल रहा होता है।

क्या यह इच्छित व्यवहार है, या ऐसा कोई तरीका है जिससे मैं इसे ठीक कर सकता हूं?

यहाँ मेरा FBMessagingService है:

import android.util.Log;

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

public class FBMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.i("PVL", "MESSAGE RECEIVED!!");
        if (remoteMessage.getNotification().getBody() != null) {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getNotification().getBody());
        } else {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getData().get("message"));
        }
    }
}

t3h exi से समाधान के अनुसार मैं यहाँ स्वच्छ कोड पोस्ट करना चाहूंगा। अगर एप्लिकेशन बैकग्राउंड मोड में है तो बस इसे MyFirebaseMessagingService में डालें और सब कुछ ठीक चले। आपको कम से कम com.google.firebase: फायरबेस-मैसेजिंग: 10.2.1 संकलित करने की आवश्यकता है

public void handleIntent(Intent intent) {
    try {
        if (intent.getExtras() != null) {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");
            for (String key : intent.getExtras().keySet()) {
            builder.addData(key, intent.getExtras().get(key).toString());
        }
            onMessageReceived(builder.build());
        } else {
            super.handleIntent(intent);
        }
    } catch (Exception e) {
        super.handleIntent(intent);
    }
}

अगर आपकी समस्या बिग इमेज दिखाने से संबंधित है यानी अगर आप फायरबेस कंसोल से इमेज के साथ पुश नोटिफिकेशन भेज रहे हैं और यह इमेज तभी प्रदर्शित करता है जब ऐप अग्रभूमि में हो। इस समस्या का हल केवल डेटा फ़ील्ड के साथ एक पुश संदेश भेजना है। कुछ इस तरह:

{ "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" }

इस विधि को संभालता है () मूल्यह्रास किया गया है, इसलिए एक अधिसूचना को संभालना नीचे दिया जा सकता है:

  1. फ़ॉरग्राउंड स्टेट: अधिसूचना का क्लिक लंबित इरादे की गतिविधि पर जाएगा, जिसे आप प्रो-व्याकरणिक रूप से एक अधिसूचना बनाते समय प्रदान कर रहे हैं क्योंकि यह आमतौर पर अधिसूचना के डेटा पेलोड के साथ बनाया जाता है।

  2. बैकग्राउंड / किल्ड स्टेट - यहां, सिस्टम खुद ही नोटिफिकेशन पेलोड के आधार पर एक नोटिफिकेशन बनाता है और उस नोटिफिकेशन पर क्लिक करने पर आपको एप्लिकेशन की लॉन्चर एक्टिविटी में ले जाएगा, जहां आप अपने किसी भी लाइफ-साइकल मेथड में इंटेंट डेटा आसानी से ले सकते हैं।


इसे इस्तेमाल करे:

 private void sendNotification(Bitmap bitmap,  String title, String 
    message, PendingIntent resultPendingIntent) {

    NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
    style.bigPicture(bitmap);

    Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

    NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    String NOTIFICATION_CHANNEL_ID = mContext.getString(R.string.default_notification_channel_id);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);

        notificationManager.createNotificationChannel(notificationChannel);
    }
    Bitmap iconLarge = BitmapFactory.decodeResource(mContext.getResources(),
            R.drawable.mdmlogo);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID)
            .setSmallIcon(R.drawable.mdmlogo)
            .setContentTitle(title)
            .setAutoCancel(true)
            .setSound(defaultSound)
            .setContentText(message)
            .setContentIntent(resultPendingIntent)
            .setStyle(style)
            .setLargeIcon(iconLarge)
            .setWhen(System.currentTimeMillis())
            .setPriority(Notification.PRIORITY_MAX)
            .setChannelId(NOTIFICATION_CHANNEL_ID);


    notificationManager.notify(1, notificationBuilder.build());


}

जो बिंदु हाइलाइटिंग के योग्य है, वह यह है कि आपको डेटा संदेश - डेटा कुंजी का उपयोग करना है - onMessageReceived हैंडलर प्राप्त करने के लिए जब ऐप पृष्ठभूमि में हो। आपके पेलोड में आपके पास कोई अन्य सूचना संदेश कुंजी नहीं होनी चाहिए, अन्यथा ऐप पृष्ठभूमि में होने पर हैंडलर ट्रिगर नहीं होगा।

यह उल्लेख किया गया है (लेकिन FCM प्रलेखन में इतना जोर नहीं दिया गया है):

https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

अपने ऐप सर्वर और FCM सर्वर API का उपयोग करें: डेटा कुंजी केवल सेट करें। संकुचित या गैर-बंधनेवाला हो सकता है।


डिफ़ॉल्ट रूप से आपके ऐप में लॉन्चर एक्टिविटी लॉन्च हो जाएगी जब आपका ऐप बैकग्राउंड में होगा और आप नोटिफिकेशन पर क्लिक करेंगे, अगर आपके पास नोटिफिकेशन के साथ कोई डेटा पार्ट है तो आप इसे उसी एक्टिविटी में निम्न प्रकार से हैंडल कर सकते हैं,

if(getIntent().getExtras()! = null){
  //do your stuff
}else{
  //do that you normally do
}

फायरबेस क्लाउड मैसेजिंग डॉक्यूमेंटेशन के अनुसार-यदि एक्टिविटी अग्रभूमि में है, तो ऑनमैसेजेज को कॉल किया जाएगा। यदि गतिविधि पृष्ठभूमि या बंद है, तो एप्लिकेशन लॉन्चर गतिविधि के लिए अधिसूचना केंद्र में अधिसूचना संदेश दिखाया जाता है। अगर आपका ऐप फायरबेस मैसेजिंग के लिए रेस्ट सर्विस एपीआई कॉल करके पृष्ठभूमि में है, तो आप अपनी अनुकूलित गतिविधि को नोटिफिकेशन पर क्लिक कर सकते हैं:

URL- https://fcm.googleapis.com/fcm/send

विधि प्रकार- POST

Header- Content-Type:application/json
Authorization:key=your api key

शारीरिक / पेलोड:

{ "notification": {
    "title": "Your Title",
    "text": "Your Text",
     "click_action": "OPEN_ACTIVITY_1" // should match to your intent filter
  },
    "data": {
    "keyname": "any value " //you can get this data as extras in your activity and this data is optional
    },
  "to" : "to_id(firebase refreshedToken)"
} 

और इसके साथ अपने ऐप में आप नीचे दी गई कोड को अपनी गतिविधि में जोड़ सकते हैं:

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

बस FirebaseMessagingService की OnCreate विधि को ओवरराइड करें। यह तब कहा जाता है जब आपका ऐप पृष्ठभूमि में हो:

public override void OnCreate()
{
    // your code
    base.OnCreate();
}

मुझे भी यही समस्या थी। 'सूचना' के बजाय 'डेटा संदेश' का उपयोग करना अधिक आसान है। डेटा संदेश हमेशा कक्षा को लोड करता है।

उस क्लास में आप नोटिफिकेशन के साथ अपना नोटिफिकेशन बना सकते हैं।

उदाहरण:

 @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        sendNotification(remoteMessage.getData().get("title"),remoteMessage.getData().get("body"));
    }

    private void sendNotification(String messageTitle,String messageBody) {
        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_UPDATE_CURRENT);

        long[] pattern = {500,500,500,500,500};

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

        NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_stat_name)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setVibrate(pattern)
                .setLights(Color.BLUE,1,1)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }

मुझे यही मुद्दा मिला। यदि एप्लिकेशन अग्रभूमि है - यह मेरी पृष्ठभूमि सेवा को चलाता है जहां मैं अधिसूचना प्रकार के आधार पर अपने डेटाबेस को अपडेट कर सकता हूं। लेकिन, ऐप पृष्ठभूमि में जाता है - उपयोगकर्ता को अधिसूचना दिखाने के लिए डिफ़ॉल्ट अधिसूचना सेवा का ध्यान रखा जाएगा।

यहाँ पृष्ठभूमि में ऐप की पहचान करने और अपनी पृष्ठभूमि सेवा को ट्रिगर करने का मेरा समाधान है,

public class FirebaseBackgroundService extends WakefulBroadcastReceiver {

  private static final String TAG = "FirebaseService";

  @Override
  public void onReceive(Context context, Intent intent) {
    Log.d(TAG, "I'm in!!!");

    if (intent.getExtras() != null) {
      for (String key : intent.getExtras().keySet()) {
        Object value = intent.getExtras().get(key);
        Log.e("FirebaseDataReceiver", "Key: " + key + " Value: " + value);
        if(key.equalsIgnoreCase("gcm.notification.body") && value != null) {
          Bundle bundle = new Bundle();
          Intent backgroundIntent = new Intent(context, BackgroundSyncJobService.class);
          bundle.putString("push_message", value + "");
          backgroundIntent.putExtras(bundle);
          context.startService(backgroundIntent);
        }
      }
    }
  }
}

मेनिफेस्ट में .xml

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

नवीनतम Android 8.0 संस्करण में इस समाधान का परीक्षण किया। धन्यवाद


मेरे लिए FirebaseMessageService के handleIntent की handleIntent विधि को ओवरराइड करें।

यहाँ C # (Xamarin) में कोड

public override void HandleIntent(Intent intent)
{
    try
    {
        if (intent.Extras != null)
        {
            var builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            foreach (string key in intent.Extras.KeySet())
            {
                builder.AddData(key, intent.Extras.Get(key).ToString());
            }

            this.OnMessageReceived(builder.Build());
        }
        else
        {
            base.HandleIntent(intent);
        }
    }
    catch (Exception)
    {
        base.HandleIntent(intent);
    }
}

और जावा में कोड है

public void handleIntent(Intent intent)
{
    try
    {
        if (intent.getExtras() != null)
        {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            for (String key : intent.getExtras().keySet())
            {
                builder.addData(key, intent.getExtras().get(key).toString());
            }

            onMessageReceived(builder.build());
        }
        else
        {
            super.handleIntent(intent);
        }
    }
    catch (Exception e)
    {
        super.handleIntent(intent);
    }
}

मैं एक ही मुद्दा रहा था और इस पर कुछ और खुदाई किया था। जब एप्लिकेशन बैकग्राउंड में होता है, तो सिस्टम ट्रे में एक सूचना संदेश भेजा जाता है, लेकिन एक डेटा संदेश onMessageReceived() भेजा जाता है
https://firebase.google.com/docs/cloud-messaging/downstream#monitor-token-generation_3 देखें
और https://github.com/firebase/quickstart-android/blob/master/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/MyFirebaseMessagingService.java

यह सुनिश्चित करने के लिए कि आप जो संदेश भेज रहे हैं, डॉक्स कहते हैं, " अपने ऐप सर्वर और FCM सर्वर API का उपयोग करें: डेटा कुंजी केवल सेट करें। या तो समाप्‍त या गैर-बंधनेवाला हो सकता है। "
https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages देखें


यदि एप्लिकेशन पृष्ठभूमि में है तो फायर-बेस डिफॉल्ट हैंडलिंग नोटिफिकेशन से लेकिन अगर हम अपने कस्टम नोटिफिकेशन से चाहते हैं कि हमें अपना सर्वर साइड बदलना है, जो हमारे कस्टम डेटा (डेटा पेलोड) को भेजने के लिए जिम्मेदार है

अपने सर्वर अनुरोध से पूरी तरह से अधिसूचना पेलोड निकालें। केवल डेटा भेजें और इसे onMessageReceived () में संभालें अन्यथा जब आपका बैकग्राउंड या मारे गए ऐप पर आपके OnMessageReceived को ट्रिगर नहीं किया जाएगा।

अब, आपका सर्वर साइड कोड प्रारूप जैसा दिखता है,

{
  "collapse_key": "CHAT_MESSAGE_CONTACT",
  "data": {
    "loc_key": "CHAT_MESSAGE_CONTACT",
    "loc_args": ["John Doe", "Contact Exchange"],
    "text": "John Doe shared a contact in the group Contact Exchange",
    "custom": {
      "chat_id": 241233,
      "msg_id": 123
    },
    "badge": 1,
    "sound": "sound1.mp3",
    "mute": true
  }
}

नोट : इस लाइन को उपरोक्त कोड में देखें
"टेक्स्ट": "जॉन डो ने डेटा पेलोड में ग्रुप कॉन्टैक्ट एक्सचेंज में एक कॉन्टैक्ट शेयर किया है। आपको मैसेज डिस्क्रिप्शन के लिए" बॉडी "या" मैसेज "पैरामीटर के बजाय" टेक्स्ट "पैरामीटर का उपयोग करना चाहिए या जो भी आप टेक्स्ट का उपयोग करना चाहते हैं।

onMessageReceived ()

@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.e(TAG, "From: " + remoteMessage.getData().toString());

        if (remoteMessage == null)
            return;

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
           /* Log.e(TAG, "Data Payload: " + remoteMessage.getData().toString());*/
            Log.e(TAG, "Data Payload: " + remoteMessage);

            try {

                Map<String, String> params = remoteMessage.getData();
                JSONObject json = new JSONObject(params);
                Log.e("JSON_OBJECT", json.toString());


                Log.e(TAG, "onMessageReceived: " + json.toString());

                handleDataMessage(json);
            } catch (Exception e) {
                Log.e(TAG, "Exception: " + e.getMessage());
            }
        }
    }

यदि एप्लिकेशन पृष्ठभूमि मोड या निष्क्रिय (मार डाला) में है, और आप अधिसूचना पर क्लिक करते हैं, तो आपको लॉन्चस्क्रीन में पेलोड के लिए जांच करनी चाहिए (मेरे मामले में लॉन्च स्क्रीन MainActivity.java है)।

तो MainActivity.java में एक्स्ट्रा कलाकार के लिए onCreate चेक पर:

    if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d("MainActivity: ", "Key: " + key + " Value: " + value);
        }
    }

यहां फायरबेस संदेश के बारे में अधिक स्पष्ट अवधारणाएं हैं। मुझे यह उनकी सपोर्ट टीम से मिला।

फायरबेस के तीन संदेश प्रकार हैं :

अधिसूचना संदेश : अधिसूचना संदेश पृष्ठभूमि या अग्रभूमि पर काम करता है। जब ऐप बैकग्राउंड में होता है, तो नोटिफिकेशन मैसेज सिस्टम ट्रे में डिलीवर हो जाते हैं। यदि एप्लिकेशन अग्रभूमि में है, तो संदेश onMessageReceived() या didReceiveRemoteNotification कॉलबैक द्वारा नियंत्रित किए onMessageReceived() । ये अनिवार्य रूप से प्रदर्शन संदेश के रूप में संदर्भित होते हैं।

डेटा संदेश : एंड्रॉइड प्लेटफॉर्म पर, डेटा संदेश पृष्ठभूमि और अग्रभूमि पर काम कर सकता है। डेटा संदेश onMessageReceived () द्वारा नियंत्रित किया जाएगा। यहां एक प्लेटफ़ॉर्म विशिष्ट नोट होगा: एंड्रॉइड पर, डेटा पेलोड को आपकी गतिविधि लॉन्च करने के लिए उपयोग किए जाने वाले इरादे में प्राप्त किया जा सकता है। विस्तृत करने के लिए, यदि आपके पास "click_action":"launch_Activity_1" , तो आप केवल getIntent() से getIntent() माध्यम से इस आशय को पुनः प्राप्त कर सकते हैं।

अधिसूचना और डेटा पेलोड दोनों के साथ संदेश : जब पृष्ठभूमि में, एप्लिकेशन अधिसूचना ट्रे में सूचना पेलोड प्राप्त करते हैं, और उपयोगकर्ता द्वारा अधिसूचना पर टैप करने पर केवल डेटा पेलोड को संभालते हैं। अग्रभूमि में होने पर, आपके एप्लिकेशन को उपलब्ध दोनों पेलोड के साथ एक संदेश ऑब्जेक्ट प्राप्त होता है। दूसरे, click_action पैरामीटर अक्सर सूचना पेलोड में उपयोग किया जाता है और डेटा पेलोड में नहीं। यदि डेटा पेलोड के अंदर उपयोग किया जाता है, तो इस पैरामीटर को कस्टम की-वैल्यू पेयर के रूप में माना जाएगा और इसलिए आपको इसके लिए कस्टम लॉजिक को लागू करने की आवश्यकता होगी।

इसके अलावा, मैं आपको डेटा बंडल निकालने के लिए onMessageReceived विधि (डेटा संदेश देखें) का उपयोग करने की सलाह देता हूं। आपके तर्क से, मैंने बंडल ऑब्जेक्ट की जाँच की और अपेक्षित डेटा सामग्री नहीं पाई। यहां एक ऐसे ही मामले का संदर्भ दिया गया है जो अधिक स्पष्टता प्रदान कर सकता है।

अधिक जानकारी के लिए मेरे इस धागे और इस धागे पर जाएँ


फायरबेस पुश-नोटिफिकेशन के 2 प्रकार हैं:

1- अधिसूचना संदेश (प्रदर्शन संदेश) -> - 1.1 यदि आप इस संस्करण को चुनते हैं, तो ओएस इसे स्वयं अधिसूचना बना देगा यदि ऐप पृष्ठभूमि में है और intent में डेटा पास करेगा। फिर इस डेटा को संभालने के लिए क्लाइंट पर निर्भर है।

- 1.2 यदि ऐप फ़ॉरग्राउंड में है तो यह नोटिफिकेशन FirebaseMessagingService में callback-function माध्यम से प्राप्त होगा और इसे संभालने के लिए क्लाइंट पर निर्भर है।

2- डेटा संदेश (4k डेटा तक) -> इन संदेशों का उपयोग क्लाइंट को केवल डेटा भेजने के लिए किया जाता है (चुपचाप) और यह क्लाइंट के लिए है कि वह दोनों मामलों के लिए इसे हैंडल कर सकता है बैकग्राउंड / फोरग्राउंड कॉलबैक-फंक्शन के माध्यम से FirebaseMessagingService

यह आधिकारिक डॉक्स के अनुसार है: https://firebase.google.com/docs/cloud-messaging/concept-options





firebase-cloud-messaging