Android 的 GcmReceiver/GcmListenerService 在接收时强制将应用程序置于前台
Android's GcmReceiver/GcmListenerService Forces Application to Foreground on receive
我 运行 在 Android 上实施 GCM 时遇到问题,最小 SDK 15。我完全能够从 GCM 和我的 GcmListenerService
接收推送通知实现有一个正常运行的 onMessageReceived(...)
回调。不过,我的问题是,每当一个或另一个执行接收时,它会强制应用程序进入前台!
我的预期行为是,无论应用程序是否在后台,我都能收到这些推送通知,然后在托盘中创建一个通知,启动 activity 应该有效负载需要它。
导致问题的流程是(物理设备,Motorola Razr M xt907):
1. 启动应用程序。设备密钥从 GCM instanceID 验证。
2. 在 Android.
上按主页
3.按最近的应用程序键;轻扫应用程序;稍等几秒
4. 通过 GCM
手动向设备发送推送通知
5. 应用收到通知,应用强行回到前台
如果有帮助,我将主应用程序和接收器放入单独的进程中,以了解后台实际发生的事情,下面是截断版本:
NotificationsProcess I/MultiDex﹕ VM with version 1.6.0 does not have multidex support
NotificationsProcess I/MultiDex﹕ install
NotificationsProcess I/MultiDex﹕ MultiDexExtractor.load(/data/app/com.MyApp.MyAppmobile.alpha-1.apk, false)
NotificationsProcess I/MultiDex﹕ loading existing secondary dex files
NotificationsProcess I/MultiDex﹕ load found 1 secondary dex files
NotificationsProcess I/MultiDex﹕ install done
...
[... Main Application Code ... ]
...
PrivateProcess I/MultiDex﹕ VM with version 1.6.0 does not have multidex support
PrivateProcess I/MultiDex﹕ install
PrivateProcess I/MultiDex﹕ MultiDexExtractor.load(/data/app/com.MyApp.MyAppmobile.alpha-1.apk, false)
PrivateProcess I/MultiDex﹕ loading existing secondary dex files
PrivateProcess I/MultiDex﹕ load found 1 secondary dex files
PrivateProcess I/MultiDex﹕ install done
NotificationsProcess D/MyApp﹕ Network is connected via WIFI
NotificationsProcess D/MyApp﹕ Executing networkWentOnline() callbacks
NotificationsProcess D/MyApp﹕ Successfully connected to GoogleApiServices for Location Awareness.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GcmListenerService finally comes alive
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NotificationsProcess D/GCMMessageHandler﹕ From: 149994375514
NotificationsProcess D/GCMMessageHandler﹕ Message: null
NotificationsProcess D/GCMMessageHandler﹕ Data: Bundle[{gcm.notification.body=Hey there dude, I like text =), collapse_key=com.MyApp.MyAppmobile.alpha}]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GcmListenerService is finished
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NotificationsProcess D/MyApp﹕ [... Main Application Code ... ]
NotificationsProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess V/TDCollateJSON﹕ SQLite3 handle is 1417181168
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
我的 Android 清单是这样设置的,在主 <application>
标签下找到以下项目:
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:process="NotificationsProcess"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter
android:process="NotificationsProcess">
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
</intent-filter>
</receiver>
<service
android:name=".GCMMessageHandler"
android:process="NotificationsProcess"
android:exported="false">
<intent-filter
android:process="NotificationsProcess">
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name=".GCMInstanceIDListenerService"
android:process="NotificationsProcess"
android:exported="false">
<intent-filter
android:process="NotificationsProcess">
<action android:name="com.google.android.gms.iid.InstanceID"/>
</intent-filter>
</service>
<service
android:name=".RegistrationIntentService"
android:process="NotificationsProcess"
android:exported="false">
</service>
[... Other app activities ...]
<activity
android:name=".activities.SyncActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.NoActionBar"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
我有一种明显的感觉,就像这是一个简单的明显问题,但如果这是一个更微妙的问题,我也不会感到惊讶。如果我能提供更多的应用程序输出,请告诉我!
非常感谢为此尝试的任何经验、智慧或途径!
编辑:
我包括 GcmListenerService 实现。请注意,我唯一做的就是创建一个通知并 post 它。 没有来自用户的交互,应用程序直接进入前台 - 没有点击,没有滑动,只是 poof 前台。
@Override
public void onMessageReceived(String from, Bundle data) {
String message = data.getString("gcm.notification.body");
Log.d("GCMMessageHandler", "From: " + from);
Log.d("GCMMessageHandler", "Message: " + message);
MyApp.WAS_STARTED_FROM_NOTIFICATION = true;
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Hello from MyApp")
.setContentText(message);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(MY_APP_NOTIFICATION_ID, mBuilder.build());
}
感谢问题评论历史记录中的@petey,我走上了正确的道路,弄清楚了应用程序中发生了什么。
他的评论提出查看应用程序启动,以确保流程中的其他内容不会强制启动 Activity 意图。我没有意识到Android(作为一个初出茅庐的开发者)是应用程序class的完整生命周期,以及它与意图接收器和过滤器的关系。
简而言之,我的问题是 MyApplication class(从应用程序扩展)包含根据应用程序的其他一些已保存状态触发 Intent 的逻辑 - 应该没有任何防范措施过滤器强制打开应用程序,并且这些接收器是第一次以设备启动器以外的任何方式启动应用程序。
对于遇到类似问题的任何其他人:
Intent 过滤器,为了发挥作用, 将始终 触发您显示的应用程序,按照标准 android 行为。 确保您的核心逻辑流程能够处理这样一个事实,即您的启动可能来自 其他 而不是点击您的用户!
P.S.: 对于任何对此非常明显的开发人员,请保持温和,并帮助向您的同行解释大概览 Android 应用程序生命周期概念 ;)
我 运行 在 Android 上实施 GCM 时遇到问题,最小 SDK 15。我完全能够从 GCM 和我的 GcmListenerService
接收推送通知实现有一个正常运行的 onMessageReceived(...)
回调。不过,我的问题是,每当一个或另一个执行接收时,它会强制应用程序进入前台!
我的预期行为是,无论应用程序是否在后台,我都能收到这些推送通知,然后在托盘中创建一个通知,启动 activity 应该有效负载需要它。
导致问题的流程是(物理设备,Motorola Razr M xt907):
1. 启动应用程序。设备密钥从 GCM instanceID 验证。
2. 在 Android.
上按主页
3.按最近的应用程序键;轻扫应用程序;稍等几秒
4. 通过 GCM
手动向设备发送推送通知
5. 应用收到通知,应用强行回到前台
如果有帮助,我将主应用程序和接收器放入单独的进程中,以了解后台实际发生的事情,下面是截断版本:
NotificationsProcess I/MultiDex﹕ VM with version 1.6.0 does not have multidex support
NotificationsProcess I/MultiDex﹕ install
NotificationsProcess I/MultiDex﹕ MultiDexExtractor.load(/data/app/com.MyApp.MyAppmobile.alpha-1.apk, false)
NotificationsProcess I/MultiDex﹕ loading existing secondary dex files
NotificationsProcess I/MultiDex﹕ load found 1 secondary dex files
NotificationsProcess I/MultiDex﹕ install done
...
[... Main Application Code ... ]
...
PrivateProcess I/MultiDex﹕ VM with version 1.6.0 does not have multidex support
PrivateProcess I/MultiDex﹕ install
PrivateProcess I/MultiDex﹕ MultiDexExtractor.load(/data/app/com.MyApp.MyAppmobile.alpha-1.apk, false)
PrivateProcess I/MultiDex﹕ loading existing secondary dex files
PrivateProcess I/MultiDex﹕ load found 1 secondary dex files
PrivateProcess I/MultiDex﹕ install done
NotificationsProcess D/MyApp﹕ Network is connected via WIFI
NotificationsProcess D/MyApp﹕ Executing networkWentOnline() callbacks
NotificationsProcess D/MyApp﹕ Successfully connected to GoogleApiServices for Location Awareness.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GcmListenerService finally comes alive
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NotificationsProcess D/GCMMessageHandler﹕ From: 149994375514
NotificationsProcess D/GCMMessageHandler﹕ Message: null
NotificationsProcess D/GCMMessageHandler﹕ Data: Bundle[{gcm.notification.body=Hey there dude, I like text =), collapse_key=com.MyApp.MyAppmobile.alpha}]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GcmListenerService is finished
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NotificationsProcess D/MyApp﹕ [... Main Application Code ... ]
NotificationsProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess V/TDCollateJSON﹕ SQLite3 handle is 1417181168
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
PrivateProcess D/MyApp﹕ [... Main Application Code ... ]
我的 Android 清单是这样设置的,在主 <application>
标签下找到以下项目:
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:process="NotificationsProcess"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter
android:process="NotificationsProcess">
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
</intent-filter>
</receiver>
<service
android:name=".GCMMessageHandler"
android:process="NotificationsProcess"
android:exported="false">
<intent-filter
android:process="NotificationsProcess">
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name=".GCMInstanceIDListenerService"
android:process="NotificationsProcess"
android:exported="false">
<intent-filter
android:process="NotificationsProcess">
<action android:name="com.google.android.gms.iid.InstanceID"/>
</intent-filter>
</service>
<service
android:name=".RegistrationIntentService"
android:process="NotificationsProcess"
android:exported="false">
</service>
[... Other app activities ...]
<activity
android:name=".activities.SyncActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.NoActionBar"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
我有一种明显的感觉,就像这是一个简单的明显问题,但如果这是一个更微妙的问题,我也不会感到惊讶。如果我能提供更多的应用程序输出,请告诉我!
非常感谢为此尝试的任何经验、智慧或途径!
编辑:
我包括 GcmListenerService 实现。请注意,我唯一做的就是创建一个通知并 post 它。 没有来自用户的交互,应用程序直接进入前台 - 没有点击,没有滑动,只是 poof 前台。
@Override
public void onMessageReceived(String from, Bundle data) {
String message = data.getString("gcm.notification.body");
Log.d("GCMMessageHandler", "From: " + from);
Log.d("GCMMessageHandler", "Message: " + message);
MyApp.WAS_STARTED_FROM_NOTIFICATION = true;
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Hello from MyApp")
.setContentText(message);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(MY_APP_NOTIFICATION_ID, mBuilder.build());
}
感谢问题评论历史记录中的@petey,我走上了正确的道路,弄清楚了应用程序中发生了什么。
他的评论提出查看应用程序启动,以确保流程中的其他内容不会强制启动 Activity 意图。我没有意识到Android(作为一个初出茅庐的开发者)是应用程序class的完整生命周期,以及它与意图接收器和过滤器的关系。
简而言之,我的问题是 MyApplication class(从应用程序扩展)包含根据应用程序的其他一些已保存状态触发 Intent 的逻辑 - 应该没有任何防范措施过滤器强制打开应用程序,并且这些接收器是第一次以设备启动器以外的任何方式启动应用程序。
对于遇到类似问题的任何其他人: Intent 过滤器,为了发挥作用, 将始终 触发您显示的应用程序,按照标准 android 行为。 确保您的核心逻辑流程能够处理这样一个事实,即您的启动可能来自 其他 而不是点击您的用户!
P.S.: 对于任何对此非常明显的开发人员,请保持温和,并帮助向您的同行解释大概览 Android 应用程序生命周期概念 ;)