Firebase (FCM): открывать активность и передавать данные при нажатии на уведомление. андроид

Должна быть четкая реализация того, как работать с уведомлениями и данными Firebase. Я прочитал много ответов, но, похоже, не могу заставить его работать. вот мои шаги:

1.) Я передаю уведомление и данные на android в PHP, и вроде все в порядке:

$msg = array
    (
         "body" => $body,
         "title" => $title,
         "sound" => "mySound"
    );

    $data = array
    (

         "user_id" => $res_id,
         "date" => $date,
         "hal_id" => $hal_id,
         "M_view" => $M_view
    );

    $fields = array
    (
        'registration_ids' => $registrationIds,
        'notification' => $msg,
        'data' => $data
    );



    $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 );

2.) при получении уведомления и данных в Android отображается уведомление. Когда я нажимаю на это уведомление, открывается приложение. Но я не могу понять, как обрабатывать данные при открытии приложения. Есть пара различий, когда приложение находится на переднем и заднем плане. Код, который у меня есть сейчас, следующий:

public class MyFirebaseMessagingService extends FirebaseMessagingService {

private static final String TAG = "MyFirebaseMsgService";

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

    String user_id = "0";
    String date = "0";
    String cal_id = "0";
    String M_view = "0";

    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());
        user_id = remoteMessage.getData().get("user_id");
        date = remoteMessage.getData().get("date");
        hal_id = remoteMessage.getData().get("hal_id");
        M_view = remoteMessage.getData().get("M_view");
    }

    //Calling method to generate notification
    sendNotification(remoteMessage.getNotification().getBody(), user_id, date, hal_id, M_view);
}

private void sendNotification(String messageBody, String user_id, String date, String hal_id, String M_view) {
    Intent intent = new Intent(this, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);

    intent.putExtra("fcm_notification", "Y");
    intent.putExtra("user_id", user_id);
    intent.putExtra("date", date);
    intent.putExtra("hal_id", hal_id);
    intent.putExtra("M_view", M_view);
    int uniqueInt = (int) (System.currentTimeMillis() & 0xff);
    PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), uniqueInt, intent,
            PendingIntent.FLAG_UPDATE_CURRENT);

    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
    notificationBuilder.setSmallIcon(R.drawable.ic_launcher)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(0, notificationBuilder.build());
}}

3.) Когда я использую приведенный выше код, и когда я нажимаю на уведомление обо всем, что он делает, он открывает приложение, если оно находится в фоновом режиме. Если приложение на переднем плане, то при нажатии на уведомление оно просто отклоняет уведомление. Однако я хочу получать данные и открывать определенные действия в обоих сценариях (фоновом и переднем плане). У меня в MainActivity есть следующий код, но я не могу получить данные. fcm_notification, date, hal_id возвращает null.

public class MainActivity extends Activity {
 UserFunctions userFunctions;

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

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
    Intent intent_o = getIntent();
}

@Override
protected void onResume() {
    super.onResume();
    userFunctions = new UserFunctions();
    if(userFunctions.isUserLoggedIn(getApplicationContext())){
        Intent intent_o = getIntent();
        String fcm_notification = intent_o.getStringExtra("fcm_notification") ;
        String user_id = intent_o.getStringExtra("user_id");
        String date = intent_o.getStringExtra("date");
        String hal_id = intent_o.getStringExtra("hal_id");
        String M_view = intent_o.getStringExtra("M_view");
        Intent intent = new Intent(this, JobList.class);

        // THIS RETURNS NULL, user_id = null
        System.out.print("FCM" + user_id);
        startActivity(intent);
        finish();
    }else{
        // user is not logged in show login screen
        Intent login = new Intent(this, LoginActivity.class);
        startActivity(login);
        // Closing dashboard screen
        finish();
    }
}}

ЕСЛИ кто-нибудь может направить или посоветовать, как я могу получить данные в MainActivity.java из Firebase в любом сценарии (передний план или фон), это было бы фантастически.




Ответы (5)


Итак, прежде всего я подробно расскажу о деталях, упомянутых в документах Обработка сообщений.

В сводке под строкой Оба показано, что, когда приложение находится на переднем плане, полезная нагрузка будет обрабатываться в вашем onMessageReceived().

Чтобы открыть действие из onMessageReceived(), вы должны проверить, находятся ли нужные вам данные в полезной нагрузке, если это так, вызовите конкретное действие, а затем передайте все другие необходимые данные через намерение.

Теперь, если приложение находится в фоновом режиме, в документации упоминается, что уведомление поступает на панель задач Android и что полезная нагрузка data может быть получена из дополнений намерения. < / em>

Просто добавив детали из моего ответа здесь, который в значительной степени просто дает инструкцию docs и ссылку на образец:

Обработка уведомлений в фоновом приложении

Когда ваше приложение работает в фоновом режиме, Android направляет уведомления на панель задач. При нажатии пользователем на уведомление по умолчанию открывается панель запуска приложений.

Сюда входят сообщения, содержащие как уведомление, так и полезные данные (и все сообщения, отправленные из консоли уведомлений). В этих случаях уведомление доставляется на панель задач устройства, а полезные данные доставляются в дополнение к цели вашей активности запуска.

Я думаю, что этот ответ @ArthurThompson очень хорошо объясняет это:

Когда вы отправляете уведомление с полезными данными (уведомление и данные), а приложение находится в фоновом режиме, вы можете получить данные из дополнительных компонентов намерения, которое запускается в результате нажатия пользователем на уведомление.

Из пример FCM, который запускает MainActivity при нажатии на уведомление:

if (getIntent().getExtras() != null) {
    for (String key : getIntent().getExtras().keySet()) {
        String value = getIntent().getExtras().getString(key);
        Log.d(TAG, "Key: " + key + " Value: " + value);
    }
}
person AL.    schedule 21.10.2016
comment
Я получаю только полезную нагрузку в своих дополнительных услугах. любая идея, как я могу получить текст и заголовок уведомления при запуске, когда приложение даже не в фоновом режиме? - person Syeda Zunaira; 24.03.2017
comment
Ссылка на образец FCM не работает. - person Red M; 02.01.2019
comment
@RedM Похоже, Google обновил свое репо, добавив в пакет для kotlin. Исправил ссылку. Спасибо, что указали на это. - person AL.; 02.01.2019
comment
@SyedaZunaira один из вариантов - также отправить title и body как атрибуты data, чтобы вы могли читать их как дополнительные. - person Awi; 28.02.2020
comment
большое спасибо! это работа со мной! и это было очень полезно! - person Haya Akkad; 18.03.2020
comment
Большое спасибо за разъяснение - person sohel yadav; 11.06.2020

Перепробовав все ответы и блоги, придумал решение. если кому-то нужно, используйте это видео как ссылку

https://www.youtube.com/watch?v=hi8IPLNq59o

ДОПОЛНИТЕЛЬНО к видео для добавления намерений выполните в MyFirebaseMessagingService:

public class MyFirebaseMessagingService extends FirebaseMessagingService {

private static final String TAG = "MyFirebaseMsgService";

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

    String user_id = "0";
    String date = "0";
    String hal_id = "0";
    String M_view = "0";

    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());
        user_id = remoteMessage.getData().get("user_id");
        date = remoteMessage.getData().get("date");
        cal_id = remoteMessage.getData().get("hal_id");
        M_view = remoteMessage.getData().get("M_view");
    }

    String click_action = remoteMessage.getNotification().getClickAction();

    //Calling method to generate notification
    sendNotification(remoteMessage.getNotification().getBody(), remoteMessage.getNotification().getTitle(), user_id, date, hal_id, M_view, click_action);
}

private void sendNotification(String messageBody, String messageTitle, String user_id, String date, String hal_id, String M_view, String click_action) {
    Intent intent = new Intent(click_action);
    intent.putExtra("user_id", user_id);
    intent.putExtra("date", date);
    intent.putExtra("hal_id", hal_id);
    intent.putExtra("M_view", M_view);

    PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent,
            PendingIntent.FLAG_ONE_SHOT);

    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
    notificationBuilder.setSmallIcon(R.drawable.ic_launcher)
            .setContentTitle(messageTitle)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(0, notificationBuilder.build());
}}

и в новой активности NotificationReceive в onCreate или onResume добавьте это

    notification_Y_N = (TextView) findViewById(R.id.notification_Y_N);
    user_id_text = (TextView) findViewById(R.id.user_id_text);

    Intent intent_o = getIntent();
    String user_id = intent_o.getStringExtra("user_id");
    String date = intent_o.getStringExtra("date");
    String hal_id = intent_o.getStringExtra("hal_id");
    String M_view = intent_o.getStringExtra("M_view");

    notification_Y_N.setText(date);
    user_id_text.setText(hal_id);
person Vaidas    schedule 21.10.2016
comment
Я не заметил, что вы уже добавили в ответ. На 8 минут позже. Ха-ха - person AL.; 22.10.2016
comment
Спасибо за ответ, AL. Провел дополнительные исследования и наконец нашел решение. - person Vaidas; 22.10.2016
comment
Пожалуйста. Примите ваш ответ как правильный, чтобы ваше сообщение было правильно помечено. Ваше здоровье! - person AL.; 23.10.2016
comment
не уверен в этом. вам следует уточнить у производителя видео, так как я просто использовал эту ссылку в качестве примера видео на YouTube .. - person Vaidas; 01.04.2018
comment
новый NotificationCompat.Builder (это); устарела в Android Oreo, проверьте документацию и используйте реализацию канала уведомлений. - person TapanHP; 26.04.2018
comment
Привет! Ваш код работает на переднем плане, но как указать активность, когда приложение находится в фоновом режиме? - person E-Place; 03.05.2018

Чтобы вызвать метод onMessageReceived(), вам нужно будет использовать другой метод для отправки уведомлений (например, создание веб-API для отправки уведомлений). Затем, используя его,

удалите полезную нагрузку уведомления из ваших сообщений FCM, чтобы полезная нагрузка данных была доставлена ​​onMessageReceived() методу.

Когда ваше приложение работает в фоновом режиме, полезная нагрузка данных доставляется методу onMessageReceived только в том случае, если полезная нагрузка уведомления отсутствует.

В случае, если существуют обе полезные нагрузки, система автоматически обрабатывает часть уведомления (системный трей), и ваше приложение получает полезные данные в дополнительных функциях действия запуска (после того, как пользователь нажмет на уведомление).

Для получения дополнительной информации перейдите по следующим ссылкам:

person Ashu    schedule 07.09.2017

Вам не нужно реализовывать sendNotification и onMessageReceived самостоятельно.

При отправке:

$data = array
(
    "user_id" => $res_id
    //whatever fields you want to include
);

$msg = array
(
     "body" => $body,
     "title" => $title,
     "data" => $data
     // more fields
);

сторона Android (на вашем MainACtivity:

private void handleIntent(Intent intent) {
    String user_id= intent.getStringExtra("user_id");
    if(user_id!= null)
        Log.d(TAG, user_id);
}

и конечно:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    handleIntent(intent);
}

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

    handleIntent(getIntent());
}

любые поля, которые вы укажете data, будут отправлены по вашему намерению extra.

person Ohad Cohen    schedule 07.05.2018

во-первых, если у вас есть объект данных и объект уведомления в ответ. затем попросите внутреннего разработчика удалить объект уведомления. Я надеюсь, что мой собственный класс поможет.

public class MyFirebaseService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseService";

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

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

      
        sendNotification(remoteMessage.getData().get("body"),
                remoteMessage.getData().get("mode_id"), remoteMessage.getData().get("click_action"));
        
    }
}

private void sendNotification(String messageBody, String id, String clickAction) {
    Intent intent = new Intent(clickAction);
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    stackBuilder.addNextIntentWithParentStack(intent);
    intent.putExtra("id", id);
    intent.putExtra("body", messageBody);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
            | Intent.FLAG_ACTIVITY_CLEAR_TASK);

    PendingIntent pendingIntent =
            stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "111")
            .setSmallIcon(R.drawable.venus_logo)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setVibrate(new long[]{1000, 1000, 1000, 1000, 1000})
            .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
            .setContentIntent(pendingIntent)
            .setLights(Color.GREEN, 3000, 3000);

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        int importance = NotificationManager.IMPORTANCE_HIGH;
        NotificationChannel notificationChannel = new NotificationChannel("111", "NOTIFICATION_CHANNEL_NAME", importance);
        notificationChannel.enableLights(true);
        notificationChannel.setLightColor(Color.RED);
        notificationChannel.enableVibration(true);
        notificationChannel.setShowBadge(false);
        notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
        assert notificationManager != null;
        notificationBuilder.setChannelId("111");
        notificationManager.createNotificationChannel(notificationChannel);
        notificationManager.notify(0, notificationBuilder.build());
    } else {
        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
        notificationManager.notify(0, notificationBuilder.build());
    }
  }
}

затем добавьте это в свой файл манифеста.

    <service
        android:name=".data.services.MyFirebaseService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
    <activity
        android:name=".ui.notifications.NotificationsDetailsActivity"
        android:excludeFromRecents="true"
        android:launchMode="singleTask"
        android:parentActivityName=".ui.home.HomeActivity"
        android:taskAffinity="">
        <intent-filter>
            <action android:name="co.example.yourApp.ui.notifications_TARGET_NOTIFICATION" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>
person dev saad    schedule 08.10.2020