代码之家  ›  专栏  ›  技术社区  ›  Stephen McCormick

带可选数据的Android FireBase通知,使用v1 api,不用于后台

  •  0
  • Stephen McCormick  · 技术社区  · 6 年前

    我肯定有答案,但我似乎找不到。大多数例子都是使用传统的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"
            }
         }
      }
    }
    

    请注意上述消息-我尝试了“单击”操作的各种组合,例如“StartActivity”“.StartActivity”“.SplashActivity”“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 . 这有点复杂,因为我已经实现了一些deeplink,我更愿意为此重用相同的活动,但是如果我需要创建一个新的deeplink,就这样吧。目前我有两个主要的入口点活动。一个用于被调用的发射器 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>
    

    我把第二部分放在两个前导活动的创建中,试图从创建活动的额外意图中提取数据。我没有看到任何数据通过这个机制进入,许多其他stackoverflows都建议它应该(它们通常超过一年,可能不适用于API的v1?)。以下是它的示例:

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

    在这个问题上,我已经看到了无数其他的堆积如山的东西,但都没有成功。如果你想的话,我可以列出来-也许我错过了什么?点击率最高的人(224000)没有帮助。

    事先谢谢!

    更新

    感谢鲍勃的帮助。只是想标记这些变化,这样其他人就不会以Android处理这种奇怪的方式丢失(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() . 只需要检查一下 Intent 对于 extras 如果应用程序没有运行或不在后台。在前景中时 public void onMessageReceived(RemoteMessage remoteMessage) 只有消息中有通知时才会调用。如果您只是数据,或者像我一样,使用额外数据通知,则必须同时实现 OnCuto() 意图和 onMessageReceived() 在上面的FireBase服务中。

    新消息如下:

    {
      "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();
    }
    

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

    令我惊讶的是,在谷歌产品(Android)上使用谷歌产品(FireBase)有多么困难,而在iOS(我被告知)上,这一切都很容易建立起来。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Bob Snyder    6 年前

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

    如果你想要 SplashActivity 要接收消息中的数据值,请更改 点击动作 在信息中 com.mycompany.USER_CLICK 并在下面添加另一个意向过滤器 飞溅活性 使用默认类别和匹配的操作名称:

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

    注意,操作名可以是任何有效字符串,但应该是 prefixed with your package name to ensure uniqueness . 虽然很多相关的帖子上都使用了活动名称,但这是不必要的。

    另外,如果你想的话 飞溅活性 要处理用户单击和动态链接,您需要检查接收到的意图中的操作,并将其分支到适当的处理。