在前台

时间:2016-09-06 22:41:47

标签: android firebase firebase-cloud-messaging firebase-notifications

当我的应用程序打开并收到通知时,我希望能够立即打开相关活动,而无需用户点击通知。

这个问题非常相似:Open app on firebase notification received (FCM)

但它在后台打开应用程序时,我需要在应用程序处于前台时执行此操作。

来自firebase documentation

  

您的应用在后台时发送的通知。在这   如果是,通知将传送到设备的系统托盘。一个   用户点按通知会默认打开应用启动器。消息   同时具有通知和数据有效负载,背景和   前景。在这种情况下,通知将传递给   设备的系统托盘,数据有效负载在附加功能中提供   您的启动器活动的意图。

这是我对onMessageReceived

的暗示
@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

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

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

    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param remoteMessage FCM message message received.
     */
    private void sendNotification(RemoteMessage remoteMessage) {
        Intent intent = new Intent(this, MyActivity.class);

        Map<String, String> hmap ;
        hmap = remoteMessage.getData();
        hmap.get("data_info");
        intent.putExtra("data_info", hmap.get("data_info"));
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);


        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);

    }

我能够正确收到通知,但只有在我点击系统托盘上的通知后,活动才会开始。

有没有办法在不在前台点击通知的情况下启动活动?

来自班级onMessageReceived()的方法MyFirebaseMessagingService extends FirebaseMessagingService在前台正确调用,但活动未开始。我也试过了旗帜FLAG_ACTIVITY_NEW_TASK也没有运气。提前谢谢。

9 个答案:

答案 0 :(得分:4)

您可以在前台活动中注册广播接收器并从onReceiveMessage()方法发送广播。

ForegroundActivity

mReceiver = new BroadcastReceiver() {
 @Override
 public void onReceive(Context context, Intent intent) {
     Intent myNewActivity = new Intent(this, MyActivity.class);
     startActivity(myNewActivity);
   }
 };

mIntentFilter=new IntentFilter("OPEN_NEW_ACTIVITY");

@Override
protected void onResume() {
     super.onResume();
     registerReceiver(mReceiver, mIntentFilter);
}



@Override
protected void onPause() {
     if(mReceiver != null) 
            unregisterReceiver(mReceiver);
            mReceiver = null;
     }
     super.onPause();
   }

FirebaseNotificationReceiver

@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

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

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

        Intent broadcast = new Intent();
        broadcast.setAction("OPEN_NEW_ACTIVITY);
        sendBroadcast(broadcast);
    }     
}

您可以添加一项检查,以了解app is in foreground是否选择发送通知或发送广播。

答案 1 :(得分:1)

(kotlin) 如果要检查应用程序是前台还是后台,请在onMessageReceived中使用此代码

    var foreground = false

    try {
        foreground = ForegroundCheckTask().execute(this).get()
    } catch (e: InterruptedException) {
        e.printStackTrace()
    } catch (e: ExecutionException) {
        e.printStackTrace()
    }

然后使用“ foreground”变量根据需要执行操作

 if (foregroud) { //app in foreground
            intent = Intent(this, ChatAdminActivity::class.java)
            intent.putExtra("intent_backchat", 1)
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK)
            pendingIntent = PendingIntent.getActivity(this, Integer.valueOf(random) /* Request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT)
            startActivity(intent)      // to directly open activity if app is foreground
        } else { //app in background
            intent = Intent(this, ChatAdminActivity::class.java)
            intent.putExtra("intent_backchat", 1)
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
            pendingIntent = PendingIntent.getActivity(this, Integer.valueOf(random) /* Request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        }
.....

希望有帮助。

您会看到我的完整FCMService code

答案 2 :(得分:0)

我能够通过在pendingIntent:

上调用send()来实现这一点
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);
try {
       pendingIntent.send();
        } catch (PendingIntent.CanceledException e) {
            e.printStackTrace();
    }

答案 3 :(得分:0)

public class MyFirebaseMessagingService extends FirebaseMessagingService {
 private static final String TAG = "FCM Service";
 @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // TODO: 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.
//     IntentFilter filter = new IntentFilter("OPEN_NEW_ACTIVITY");
//        registerReceiver(new BroadcastNotification(),filter);
//     showNotification(remoteMessage.getNotification().getBody());

        Log.d(TAG, "From: " + remoteMessage.getFrom());
        Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
     Log.e("Myname","shdjhfghgh");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Intent in= new Intent(this,MainActivity.class);
        in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(in);
    }
}

答案 4 :(得分:0)

创建 BroadcastReceiver 是处理场景的最佳方式。但您需要知道用户正在使用哪个活动。

在每个活动中创建 BroadcastReceiver 会产生奇怪的外观。因此,创建一个扩展Activity的BaseActivityBaseActivity将包含BroadcastReceiver代码,而所有其他活动都会延伸BaseActivity

open class BaseActivity : AppCompatActivity() {

private lateinit var broadcastReceiver: BroadcastReceiver

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(p0: Context?, p1: Intent?) {
            if (p1 != null) {
                handleBroadcastActions(p1)
            }
        }

    }
}

private fun handleBroadcastActions(intent: Intent) {
    when (intent.action) {
        Constants.ACTIVITY_STUFF -> {
            onHandleActivity()
        }
    }
}

protected open fun onHandleActivity() {
    startActivity(intentFor<YourActivity>())
}

override fun onResume() {
    super.onResume()
    registerReceiver(broadcastReceiver, IntentFilter(Constants.ACTIVITY_STUFF))

}

override fun onPause() {
    super.onPause()
    unregisterReceiver(broadcastReceiver)
}}

我添加了我的kotlin代码。希望你能理解:)

最后,您可以在BroadcastReceiver中的onMessageReceived()拨打此FirebaseMessagingService

override fun onMessageReceived(message: RemoteMessage) {
    sendBroadcast(Intent(Constants.ACTIVITY_STUFF))
}

答案 5 :(得分:0)

根据Google page about Broadcasts

  

如果您不需要向应用程序外部的组件发送广播,请使用支持库中提供的LocalBroadcastManager发送和接收本地广播。 LocalBroadcastManager效率更高(无需进程间通信),并允许您避免考虑与其他应用程序能够接收或发送您的广播相关的任何安全问题。本地广播可以在您的应用中用作通用发布/子事件总线,而不会产生系统广播的任何开销。

因此,请使用 LocalBroadcastManager 而不是 BroadcastReceiver

在FirebaseMessagingService类中,您会收到来自FCM(Firebase云消息传递)的通知并使用:

LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

向MainActivity发送消息:

public class AppFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        try {
            String messageFrom = remoteMessage.getFrom();
            String messageBody = (remoteMessage.getNotification() != null ? remoteMessage.getNotification().getBody() : null);
            Map<String, String> messageData = remoteMessage.getData();

            NotificationInfo notificationInfo = new NotificationInfo(messageData.get(message));
            notifyMainActivity(notificationInfo);
            showNotification(notificationInfo);
    }

    private void notifyMainActivity(NotificationInfo notificationInfo) {
        Intent intent = new Intent();
        intent.setAction(Constants.BROADCAST_MESSAGE_NOTIFICATION_RECEIVED);
        intent.putExtra(Constants.PARAM_NOTIFICATION_INFO, notificationInfo);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void showNotification(NotificationInfo notificationInfo) {

        Intent intentNotificationClicked = new Intent(this, MainActivity.class);
        intentNotificationClicked.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intentNotificationClicked.putExtra(Constants.PARAM_NOTIFICATION_INFO, notificationInfo);
        PendingIntent resultIntentNotificationClicked = PendingIntent.getActivity(this, 0, intentNotificationClicked, PendingIntent.FLAG_ONE_SHOT);

        String title = "MY APPLICATION";
        String message = notificationInfo.message;

        Uri notificationSoundURI = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder mNotificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_notification_icon)
                .setContentTitle(title)
                .setContentText(message)
                .setAutoCancel(true)
                .setSound(notificationSoundURI)
                .setContentIntent(resultIntentNotificationClicked);

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

        int notificationID = Integer.parseInt(new SimpleDateFormat("HHmmssSSS").format(new Date()));
        notificationManager.notify(notificationID, mNotificationBuilder.build());
    }
}

在MainActivity中,您创建BroadcastReceiver以接收消息:

public class MainActivity extends AppCompatActivity {
    private NotificationBroadcastReceiver mNotificationBroadcastReceiver = null;
    private IntentFilter mIntentFilter = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        this.mNotificationBroadcastReceiver = new NotificationBroadcastReceiver(this);
        this.mIntentFilter = new IntentFilter(Constants.BROADCAST_MESSAGE_NOTIFICATION_RECEIVED);
    }

    @Override
    protected void onResume() {
        super.onResume();
        LocalBroadcastManager.getInstance(this).registerReceiver(this.mNotificationBroadcastReceiver, this.mIntentFilter);
    }

    @Override
    protected void onPause() {
        if (this.mNotificationBroadcastReceiver != null) {
            unregisterReceiver(mNotificationBroadcastReceiver);
            this.mNotificationBroadcastReceiver = null;
        }

        super.onPause();
    }

    private class NotificationBroadcastReceiver extends BroadcastReceiver {

        WeakReference<MainActivity> mMainActivity;

        public NotificationBroadcastReceiver(MainActivity mainActivity) {
            this.mMainActivity = new WeakReference<>(mainActivity);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            MainActivity mainActivity = mMainActivity.get();
            if (mainActivity != null) {
                Bundle extras = intent.getExtras();
                if (extras != null && extras.containsKey(Constants.PARAM_NOTIFICATION_INFO)) {
                    NotificationInfo notificationInfo = (NotificationInfo) extras.getSerializable(Constants.PARAM_NOTIFICATION_INFO);
                    mainActivity.notificationReceived(notificationInfo);
                }
            }
        }
    }

    public void notificationReceived(@NonNull final NotificationInfo notificationInfo)
    {
        //handle the notification in MainActivity
    }
}

在代码中引用的类下面:

public class Constants {
    public static final String NOTIFICATION_BROADCAST_RECEIVER_MESSAGE_RECEIVED = "com.mycompany.myapp.NOTIFICATION_RECEIVED";
    public static final String PARAM_NOTIFICATION_INFO = "NotificationContent";
}

public class NotificationInfo implements Serializable {
    public String message;
    public NotificationInfo() { }
    public NotificationInfo(String message) { this.message = message; }
}

那就是它!

答案 6 :(得分:0)

您需要获取有关设备中当前前景应用的信息。在此基础上,您可以决定是否开始活动或发送通知。

为了做到这一点,我会建议这样的事情:

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

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

private void handleNotification(RemoteMessage remoteMessage){
    Intent intent = new Intent(this, MyActivity.class);
    Map<String, String> hmap ;
    hmap = remoteMessage.getData();
    hmap.get("data_info");

    intent.putExtra("data_info", hmap.get("data_info"));
    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

    Context context = getApplicationContext();

    //CHECK IF THIS APP IS IN FOREGROUND
    ActivityManager am = (ActivityManager)
    AppService.this.getSystemService(ACTIVITY_SERVICE);

    // The first in the list of RunningTasks is always the foreground task.
    RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
    String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName();

    if(foregroundTaskPackageName.equals(context.getPackageName()){
        //THIS STARTS MAINACTIVITY DIRECTLY IF THE FOREGROUND APP IS THIS APP
        startActivity(intent);
    }else{
        //IF THE FOREGROUND APP ISN'T THIS APP THEN SEND A PENDING INTENT TO OPEN MAIACTIVITY WHEN USER TAP ON NOTIFICATION
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT);
        //CREATE A NOTIFICATION IN THE SYSTEM TRAY
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
                .setContentTitle("TITLE")
                .setContentText("SUBMESSAGE")
                .setPriority(Notification.PRIORITY_MAX)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .setContentIntent(pendingIntent)
                .setAutoCancel(true);
        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);

        // notificationId is a unique int for each notification that you must define
        notificationManager.notify(notificationId, mBuilder.build());
    }
}

您必须设置通知中显示的通知ID,标题和子消息。

您还需要在应用清单中添加<uses-permission android:name="android.permission.GET_TASKS" />权限。

答案 7 :(得分:0)

我通常要做的是发送数据消息并从中创建意图。

public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
    super.onMessageReceived(remoteMessage);
    Log.d(TAG, "onMessageReceived: called");

    Log.d(TAG, "onMessageReceived: Message received from: " + remoteMessage.getFrom());

    if (remoteMessage.getNotification() != null) {
        String title = remoteMessage.getNotification().getTitle();
        String body = remoteMessage.getNotification().getBody();
        Log.d(TAG, "onMessageReceived: "+title+" "+body);

        Notification notification = new NotificationCompat.Builder(this, FCM_CHANNEL_ID)
                .setSmallIcon(R.mipmap.ridersquare)
                        .setContentTitle(title)
                .setContentText(body)
                .setColor(Color.BLUE)
                .setSubText("KKKK")
                .build();

        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(FCM_CHANNEL_ID, "Default channel", NotificationManager.IMPORTANCE_HIGH);
            manager.createNotificationChannel(channel);
        }
        manager.notify(1002, notification);
    }

    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "onMessageReceived: Data: " + remoteMessage.getData().toString());
        if (remoteMessage.getData().toString().length()>0){
            Notification notification = new NotificationCompat.Builder(this, FCM_CHANNEL_ID)
                    .setSmallIcon(R.mipmap.ridersquare)
                    .setContentTitle("New Order")
                    .setContentText("New order received from"+remoteMessage.getData().get("restaurant_name"))
                    .setSound(App.soundUri)
                    .setLights(Color.RED, 3000, 3000)
                    .setAutoCancel(true)
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setVibrate(new long[]{0,1000, 500, 1000})
                    .build();

            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationChannel channel = new NotificationChannel(FCM_CHANNEL_ID, "Default channel", NotificationManager.IMPORTANCE_HIGH);
                manager.createNotificationChannel(channel);
            }
            manager.notify(50, notification);
            Intent intent=new Intent(getApplicationContext(), NewOrderNoti.class);
            intent.putExtra("username",remoteMessage.getData().get("username"));
            startActivity(intent);

        }


    }

这基本上会创建一个通知并调用打开新活动的意图

答案 8 :(得分:-1)

如果您只想设置通知,可以更改此设置(Clinet示例),

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

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

然后服务器发送这样的消息(例子),只发送数据(不是通知)

var message = { //this may vary according to the message type (single recipient, multicast, topic, et cetera)
to: token,     
priority: 'high',
content_available: true,    
data: {  
    //you can send only notification or only data(or include both)
    message: 'news'
}};

REF)

  

FCM中有两种类型的消息:
   - display-messages:仅当您的应用处于前台时,这些消息才会触发onMessageReceived()回调    - 数据消息:即使您的应用程序处于后台,这些消息也会触发onMessageReceived()回调

Two types of messages in FCM