web-dev-qa-db-ja.com

アプリケーションがバックグラウンドにあるときにGcmListenerServiceが呼び出されない

アプリケーションがバックグラウンドにあるとき、または電話がロックされているとき、またはスリープモードにあるときにGcmListenerServiceは呼び出されませんが、通知は発生します。アプリがフォアグラウンドで動作しているときに、これがどのように呼び出されるかが理想的です。 GcmListenerServiceのコードは次のとおりです

  public class MyGcmListenerService extends GcmListenerService {

    private static final String TAG = "MyGcmListenerService";
    LocalDataBaseManager mDbManager;
    String message;
    Random randomNumber;
    long ID;
    /**
     * Called when message is received.
     *
     * @param from SenderID of the sender.
     * @param data Data bundle containing message data as key/value pairs.
     *             For Set of keys use data.keySet().
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(String from, Bundle data) {
        String message ;
        String title;
//        ID = Utils.getIDForPush("pushId",this);
//        if(ID == 0){
//            ID = 1;
//        }else {
//            ID += 1;
//        }
//        Utils.saveIDForPush("pushId",ID,this);
        Bundle bundle = data.getBundle("notification");
        if(bundle!= null){
        message = bundle.getString("body");
        title = bundle.getString("title");
            Log.d(TAG, "From: " + from);
            Log.d(TAG, "Message: " + message);}
        else {
            message ="";
            title = "NCMS";
        }

        mDbManager = LocalDataBaseManager.getInstance(this);
        if (from.startsWith("/topics/")) {
            Calendar c = Calendar.getInstance();
            SimpleDateFormat s = new SimpleDateFormat("ddMMyyyyhhmmss");
            String format = s.format(new Date());
            ID = Long.parseLong(format);
            String date = new SimpleDateFormat("dd-MM-yyyy HH:mm", Locale.ENGLISH).format(new Date());
            Warnings warnings = new Warnings();
            warnings.setWARNING_ID(ID);
            warnings.setWARNING_EN(message);
            warnings.setWARNING_AR(message);
            warnings.setSTART_DATE_TIME(date);
            warnings.setNotification_type(String.valueOf(Constant.NotificationType.Push));
            warnings.setSEVERITY("");
            warnings.setEND_DATE_TIME("");
            warnings.setUPDATE_NO("");
            mDbManager.insertNotificationInfo(warnings);
            // message received from some topic.
        } else {
            // normal downstream message.
        }

        // [START_EXCLUDE]
        /**
         * Production applications would usually process the message here.
         * Eg: - Syncing with server.
         *     - Store message in local database.
         *     - Update UI.
         */

        /**
         * In some cases it may be useful to show a notification indicating to the user
         * that a message was received.
         */
//        KeyguardManager km = (KeyguardManager) this.getSystemService(Context.KEYGUARD_SERVICE);
//        boolean locked = km.inKeyguardRestrictedInputMode();
//
//        String release = Android.os.Build.VERSION.RELEASE;
//
//
//        if (Integer.parseInt(String.valueOf(release.charAt(0))) < 5 && locked) {
//
//            this.stopService(new Intent(this, NotificationService.class));
//            Intent serviceIntent = new Intent(this, NotificationService.class);
//            this.startService(serviceIntent);
//
//        }
        sendNotification(title,message);
        // [END_EXCLUDE]
    }
    // [END receive_message]

    /**
     * Create and show a simple notification containing the received GCM message.
     *
     * @param message GCM message received.
     */
    private void sendNotification(String title,String message) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtra("message",message);
        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.ncms_launcher)
                .setContentTitle(title)
                .setContentText(message)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

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

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

このサービスのマニフェスト情報は次のとおりです

 <service
        Android:name=".gcm.MyGcmListenerService"
        Android:exported="false" >
        <intent-filter>
            <action Android:name="com.google.Android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>

ここで欠けているもの。

12
Usman Kurd

私が直面していた問題は、アプリケーションがバックグラウンドまたは強制的に閉じられている場合に通知が発生するが、GcmListenServiceではなくGCMReceiverを介して通知されるため、アプリケーションがフォアグラウンドまたはバックグラウンドにあるか、強制的に強制終了された場合、GCMReceiverを拡張して、このようにしました。変更後はGCMListenerServiceと呼ばれます。

 public class MyGcmListenerService extends GcmListenerService {

    private static final String TAG = "MyGcmListenerService";
    LocalDataBaseManager mDbManager;
    String message;
    Random randomNumber;
    long ID;
    /**
     * Called when message is received.
     *
     * @param from SenderID of the sender.
     * @param data Data bundle containing message data as key/value pairs.
     *             For Set of keys use data.keySet().
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(String from, Bundle data) {
        String message ;
        String title;
//        ID = Utils.getIDForPush("pushId",this);
//        if(ID == 0){
//            ID = 1;
//        }else {
//            ID += 1;
//        }
//        Utils.saveIDForPush("pushId",ID,this);
        Bundle bundle = data.getBundle("notification");
        if(bundle!= null){
        message = bundle.getString("body");
        title = bundle.getString("title");
            Log.d(TAG, "From: " + from);
            Log.d(TAG, "Message: " + message);}
        else {
            message ="";
            title = "NCMS";
        }

        mDbManager = LocalDataBaseManager.getInstance(this);
        if (from.startsWith("/topics/")) {
            Calendar c = Calendar.getInstance();
            SimpleDateFormat s = new SimpleDateFormat("ddMMyyyyhhmmss");
            String format = s.format(new Date());
            ID = Long.parseLong(format);
            String date = new SimpleDateFormat("dd-MM-yyyy HH:mm", Locale.ENGLISH).format(new Date());
            Warnings warnings = new Warnings();
            warnings.setWARNING_ID(ID);
            warnings.setWARNING_EN(message);
            warnings.setWARNING_AR(message);
            warnings.setSTART_DATE_TIME(date);
            warnings.setNotification_type(String.valueOf(Constant.NotificationType.Push));
            warnings.setSEVERITY("");
            warnings.setEND_DATE_TIME("");
            warnings.setUPDATE_NO("");
            mDbManager.insertNotificationInfo(warnings);
            // message received from some topic.
        } else {
            // normal downstream message.
        }

        // [START_EXCLUDE]
        /**
         * Production applications would usually process the message here.
         * Eg: - Syncing with server.
         *     - Store message in local database.
         *     - Update UI.
         */

        /**
         * In some cases it may be useful to show a notification indicating to the user
         * that a message was received.
         */
//        KeyguardManager km = (KeyguardManager) this.getSystemService(Context.KEYGUARD_SERVICE);
//        boolean locked = km.inKeyguardRestrictedInputMode();
//
//        String release = Android.os.Build.VERSION.RELEASE;
//
//
//        if (Integer.parseInt(String.valueOf(release.charAt(0))) < 5 && locked) {
//
//            this.stopService(new Intent(this, NotificationService.class));
//            Intent serviceIntent = new Intent(this, NotificationService.class);
//            this.startService(serviceIntent);
//
//        }
        sendNotification(title,message);
        // [END_EXCLUDE]
    }
    // [END receive_message]

    /**
     * Create and show a simple notification containing the received GCM message.
     *
     * @param message GCM message received.
     */
    private void sendNotification(String title,String message) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtra("message",message);
        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.ncms_launcher)
                .setContentTitle(title)
                .setContentText(message)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

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

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

gCMレシーバーは次のとおりです

   public class GcmBroadcastReceiver extends GcmReceiver {

    LocalDataBaseManager mDbManager;
    @Override
    public void onReceive(Context context, Intent intent) {
        mDbManager = LocalDataBaseManager.getInstance(context);
        Bundle bundle = intent.getExtras();
        bundle.keySet();
        Set<String> keySet = bundle.keySet();
        if(keySet != null && keySet.isEmpty() == false) {
            Iterator<String> it = keySet.iterator();
           int i = 0;
            while(it.hasNext()){
               String  key = it.next();
               String  desc = bundle.getString(key);
               Log.d("BroadCast Values",key +"  "+desc);
            }
        }
        Log.d("", "In Receive Method of Broadcast Receiver");

        if (bundle != null && bundle.containsKey("gcm.notification.body")) {
            String message = bundle.getString("gcm.notification.body","");
            Long ID = new Date().getTime();
            String date = new SimpleDateFormat("dd-MM-yyyy HH:mm", Locale.ENGLISH).format(new Date());
            Warnings warnings = new Warnings();
            warnings.setWARNING_ID(ID);
            warnings.setWARNING_EN(message);
            warnings.setWARNING_AR(message);
            warnings.setSTART_DATE_TIME(date);
            warnings.setNotification_type(String.valueOf(Constant.NotificationType.Push));
            warnings.setSEVERITY("");
            warnings.setEND_DATE_TIME("");
            warnings.setUPDATE_NO("");
            mDbManager.insertNotificationInfo(warnings);
            // message received from some topic.
        }

        super.onReceive(context, intent);
//        ComponentName cn = new ComponentName(context.getPackageName(), RegistrationIntentService.class.getName());
//        startWakefulService(context, intent.setComponent(cn));
//        setResultCode(Activity.RESULT_OK);
    }
}

GCMReceiverのマニフェストの変更は次のとおりです

   <receiver
            Android:name=".gcm.GcmBroadcastReceiver"
            Android:exported="true"
            Android:permission="com.google.Android.c2dm.permission.SEND" >
            <intent-filter>
                <action Android:name="com.google.Android.c2dm.intent.RECEIVE" />
                <category Android:name="com.uae.ncms" />
            </intent-filter>
        </receiver>
<service
        Android:name=".gcm.MyGcmListenerService"
        Android:exported="false" >
        <intent-filter>
            <action Android:name="com.google.Android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>
12
Usman Kurd

この問題の中心は実際にはサーバー側の問題であるようです。サーバーがnotificationメッセージを送信している場合、アプリがバックグラウンドにある場合、onMessageReceivedは呼び出されません。サーバーは実際にdataメッセージを送信しているはずです。

GCM Docs 違いについて話し合います。

基本的に、メッセージのペイロードには次のようなdataキーが必要です

{
   "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
   "data" : {
     "Nick" : "Mario",
     "body" : "great match!",
     "Room" : "PortugalVSDenmark"
   },
 }

などの通知キーではありません

{
    "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "notification" : {
      "body" : "great match!",
      "title" : "Portugal vs. Denmark",
      "icon" : "myicon"
    }
  }

より具体的には、GCMドキュメントでは、datanotificationペイロードの両方を含む送信メッセージは、アプリがフォアグラウンドまたはバックグラウンドで:

通知とデータペイロードの両方を含むメッセージを受信したときのアプリの動作は、アプリがバックグラウンドにあるかフォアグラウンドにあるか、つまり、受信時にアプリがアクティブかどうかに依存します。

  • バックグラウンドでは、アプリは通知トレイで通知ペイロードを受信し、ユーザーが通知をタップしたときにのみデータペイロードを処理します。
  • フォアグラウンドでは、アプリは両方のペイロードが利用可能なバンドルを受け取ります。

このgithubスレッド にも良い説明があります:

したがって、GCMメッセージには次の2種類があります。

  • 通知メッセージ-これらは、アプリケーションによる中間処理なしで通知を生成することを目的としています。アプリが実行されている場合にのみ、onMessageReceivedをヒットします。

  • データメッセージ-アプリのメッセージングサービスにデータを通知なしで渡すことを目的としています。アプリがバックグラウンドにある場合でも、onMessageReceivedをヒットします。次に、サービスは、通常のシステム通知APIを使用して通知を生成することを選択するか、メッセージをサイレントに処理することを選択できます。

32
Adam Johns