带有可选数据的Android FireBase通知,使用V1 API,不适用于后台



我确信有答案,但我似乎找不到。大多数示例都使用传统的HTTP FireBase调用(以及2年前),但我希望使用新的V1HTTP API。当应用程序在前台运行时(谁没有),我可以让它工作,但不能在后台或应用程序不运行时。更复杂的是,我们也在支持IOS,所以同样的信息必须对两者都有效。

其他一些项目需要非常清楚我正在尝试做什么:

  1. 如果应用程序在前台,FireBase服务工作正常,我会收到通知并获取数据。稍后我将显示该代码
  2. 如果应用程序没有运行,当我单击系统托盘中的通知时,我希望能够从通知中获取数据并进行处理。不工作
  3. 如果应用程序在后台运行,当我单击系统托盘中的通知时,我希望能够从通知中获取数据并进行处理。不工作

我怀疑AndroidManifest.xml和/或实际消息中的安装程序有问题,但我尝试了很多变体,但都没有成功。

首先,我目前从FireBase发布到设备的消息:

{
"message":{
"token":"mynastylongdevicetoken...",
"data":{
"State":"Whatever",
},
"notification":{
"title":"New Info",
"body":"A new info has been dispatched to you"
},
"android": {
"notification": {
"click_action": ".StartActivity"
}
}
}
}

关于以上消息的注意事项-我已经尝试了"click_action"的各种组合,如"StartActivity".StartActivity".splishActivity"SplashActivity"。

这是基于FireBase:的最新文档

https://firebase.google.com/docs/cloud-messaging/migrate-v1

https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#AndroidNotification

现在是我的AndroidManifest.xml。这有点复杂,因为我已经实现了一些深度链接,我更喜欢重用相同的"活动",但如果我需要创建一个新的,那就顺其自然吧。目前我有两个主要的入口点"活动"。一个用于名为SplashActivity的启动器,用于抛出飞溅图像,另一个用于称为StartActivity的深度链接。以下是两者的XML:

<activity
android:name="com.mycompany.SplashActivity"
android:configChanges="orientation|keyboardHidden|screenSize|keyboard|navigation"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.Splash" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.mycompany.StartActivity"
android:configChanges="orientation|keyboardHidden|screenSize|keyboard|navigation"
android:label="StartActivity"
android:launchMode="singleTask"
android:windowSoftInputMode="stateHidden" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="@string/launch_protocol" android:host="deeplink1"/>
<data android:scheme="@string/launch_protocol" android:host="deeplink2"/>
<data android:scheme="@string/launch_protocol" android:host="deeplink3"/>
<data android:scheme="@string/launch_protocol" android:host="deeplink4"/>
</intent-filter>
</activity>

现在是源代码。我有两个主要的代码块。第一个是你的标准FireBase消息服务代码,当应用程序在前台时,它可以工作:

public class MyCompanyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
String test = remoteMessage.getData().get("State");
}
}

public class MyCompanyInstanceIDService extends FirebaseInstanceIdService {
public void sendNotification ( ) {
String token = FirebaseInstanceId.getInstance().getToken();
if (!Utilities.stringIsBlank(token)) {
// Register with our server
}
}
}

和AndroidManifest.xml参考:

<service android:name="com.mycompany.MyCompanyMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name="com.mycompany.MyCompanyInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>

我将第二块放入前面提到的两个Activities的OnCreate中,试图从Activities的OnCreate中的Intent extra中提取数据。我没有看到任何数据通过该机制进入,而许多其他StackOverflow都建议它应该这样做(它们通常已有一年多的历史,可能不适用于API的V1?)。下面是一个例子:

protected void onCreate(Bundle savedInstanceState) 
{
if (getIntent().getExtras() != null) {
String test = getIntent().getExtras().getString("State", "");
}
}

我研究过无数其他关于这个主题的StackaoverFlow,但都没有成功。如果你愿意,我可以列出它们——也许我错过了什么?命中率最高的一个(224000)也于事无补。

提前感谢!

更新

感谢鲍勃的帮助。只是想标记这些变化,这样其他人就不会以安卓处理这件事的奇怪方式丢失(IOS似乎没有这样的问题,幸运的是他们)。

首先是答案中所示的AndroidManifest.xml,现在有了一个新的意图过滤器:

<activity
android:name="com.mycompany.SplashActivity"
android:configChanges="orientation|keyboardHidden|screenSize|keyboard|navigation"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.Splash" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="com.mycompany.NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.mycompany.StartActivity"
android:configChanges="orientation|keyboardHidden|screenSize|keyboard|navigation"
android:label="StartActivity"
android:launchMode="singleTask"
android:windowSoftInputMode="stateHidden" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="@string/launch_protocol" android:host="deeplink1"/>
<data android:scheme="@string/launch_protocol" android:host="deeplink2"/>
<data android:scheme="@string/launch_protocol" android:host="deeplink3"/>
<data android:scheme="@string/launch_protocol" android:host="deeplink4"/>
</intent-filter>
</activity>

代码在onCreate()中非常正确。如果应用程序没有运行或在后台,只需要检查extrasIntent。在前台时,仅当消息中有Notification时,才会调用public void onMessageReceived(RemoteMessage remoteMessage)。如果您只是数据,或者像我一样,是具有额外数据的Notification,则必须在上面的Firebase服务中同时实现onCreate()Intent和onMessageReceived()

新消息如下:

{
"message":{
"token":"mynastylongdevicetoken...",
"data":{
"State":"Whatever",
},
"notification":{
"title":"New Info",
"body":"A new info has been dispatched to you"
},
"android": {
"notification": {
"click_action": "com.mycompany.NOTIFICATION_CLICK"
}
}
}
}

最后,如果应用程序还没有运行,我永远无法通过从工具栏中选择应用程序(当它有通知指示时)来获取通知。不确定这是否是我想要的行为,或者我只是在某个地方搞砸了。

最后,如果应用程序已经在前台或后台运行,我想调出当前运行的Activity,如果没有,我想启动应用程序。为此,我必须将以下内容添加到接收通知的活动的onCreate()中:

protected void onCreate(Bundle savedInstanceState) 
{
if (getIntent().getExtras() != null) {
String test = getIntent().getExtras().getString("State", "");
}
// If this activity is the root activity of the task, the app is not running
if (isTaskRoot()) {
setContentView(R.layout.activity_splash);
}
else
finish();
}

基本上,它会检查SplashActivity是否是根,这意味着它是唯一的活动(新启动)或不是(应用程序已经运行)。如果是这样的话,它就会完成并向前拉动应用程序。

令我惊讶的是,使用谷歌产品(Firebase)和谷歌产品(Android)是多么困难,而与IOS(我被告知)一样,这一切都很容易,而且都是建立起来的。

在消息中为click_action指定的字符串必须与应用程序清单中为目标活动定义的意图过滤器中的操作名称匹配。

如果您希望SplashActivity接收消息中的数据值,请将消息中的click_action更改为类似com.mycompany.USER_CLICK的内容,并在SplashActivity下添加另一个具有DEFAULT类别和匹配操作名称的意向过滤器:

<intent-filter>
<action android:name="com.mycompany.USER_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

请注意,操作名称可以是任何有效的字符串,但应以包名称为前缀,以确保唯一性。尽管SO上的许多相关帖子都使用活动名称,但这并不是必须的。

此外,如果您希望SplashActivity同时处理用户点击和动态链接,则需要检查接收到的意图中的操作并分支到适当的处理。

最新更新