Hypertrack阻止Flutter中的FCM通知 [英] Hypertrack is preventing FCM notification in Flutter

查看:62
本文介绍了Hypertrack阻止Flutter中的FCM通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我使用 hypertrack_plugin 以及

When I use hypertrack_plugin along with firebase_messaging in Flutter, I am not able to receive any message in Android. However, it works fine in iOS.

hypertrack_plugin的版本:0.1.3firebase_messaging版本:7.0.3

Version of hypertrack_plugin: 0.1.3 Version of firebase_messaging: 7.0.3

推荐答案

UPDATE

此问题已在 hypertrack_plugin 版本的插件更新中得到解决:0.1.4

This issue has been fixed in the plugin update which is in the version hypertrack_plugin: 0.1.4

问题

您正面临此问题,因为从 FirebaseMessagingService 扩展了多个服务类.因此,在一个类别中收到的消息具有较高的优先级,而在另一个类别中则没有.

Problem

You are facing this issue because there is multiple service class that extends from FirebaseMessagingService. Because of this, messages are received in one class with high priority and not the other.

将以下内容添加到您的 AndroidManifest.xml 文件

Add the following to your AndroidManifest.xml file

<service android:name="io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService">
      <intent-filter android:priority="100">
            <action android:name="com.google.firebase.MESSAGING_EVENT"/>
      </intent-filter>
</service>

它如何工作?

在清单文件中为 FlutterFirebaseMessagingService 设置的优先级为零(默认),但在清单文件中为 HyperTrackMessagingService 声明的优先级为5(现在为4.8.0版)).上面的解决方案仅覆盖优先级,并允许传入消息进入 FlutterFirebaseMessagingService 而不是 HyperTrackMessagingService .

How it works?

The priority set for FlutterFirebaseMessagingService in its manifest file is zero (default) but HyperTrackMessagingService in its manifest file is declared with a priority of 5 (version 4.8.0 now). The above solution simply overrides the priority and lets incoming messages come to FlutterFirebaseMessagingService instead of HyperTrackMessagingService.

尽管HyperTrack可以正常工作,但是HyperTrack使用FCM进行设备-服务器通信以进行优化,而没有FCM则无法运行.但是,您可能不会注意到这一点.

Although HyperTrack will work fine, HyperTrack uses FCM for device-server communication for optimization which won't function without FCM. However, you might not notice this.

使用反射将 HyperTrackMessagingService 中的传入消息转发到插件 hypertrack_plugin 中的 FlutterFirebaseMessagingService 中.

Forward incoming message in HyperTrackMessagingService to FlutterFirebaseMessagingService in the plugin hypertrack_plugin using reflection.

  1. 您将需要下载 hypertrack_plugin 源代码并将其用作本地依赖项.如何?
  2. 在库 sdk-flutter/android/src/main/kotlin/com/hypertrack/sdk/flutter/MyFirebaseMessagingService.java
  3. 中创建一个新类
  1. You will need to download hypertrack_plugin source code and use it as a local dependency. How?
  2. Create a new class inside the library sdk-flutter/android/src/main/kotlin/com/hypertrack/sdk/flutter/MyFirebaseMessagingService.java

package com.hypertrack.sdk.flutter;

import android.annotation.SuppressLint;
import android.util.Log;

import com.google.firebase.messaging.RemoteMessage;
import com.hypertrack.sdk.HyperTrackMessagingService;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@SuppressLint("LongLogTag")
public class MyFirebaseMessagingService extends HyperTrackMessagingService {

    private static final String TAG = "MyFirebaseMessagingService";

    private Class<?> serviceClass;
    private Object serviceObject;

    public MyFirebaseMessagingService() {
        try {
            serviceClass = Class.forName("io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService");
            serviceObject = serviceClass.newInstance();
            injectContext();

            Log.d(TAG, "io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService is found");
        } catch (Throwable t) {
            Log.w(TAG, "Can't find the class io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService", t);
        }
    }

    @Override
    public void onNewToken(final String s) {
        super.onNewToken(s);
        injectToken(s);
    }

    @Override
    public void onMessageReceived(final RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        injectMessage(remoteMessage);
    }

    public void injectToken(String newToken) {
        if (serviceClass != null) {
            try {
                Method sendTokenRefresh = serviceClass.getMethod("onNewToken", String.class);
                sendTokenRefresh.invoke(serviceObject, newToken);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                Log.w(TAG, "Can't inject token due to error ", e);
            }
        }
    }

    public void injectMessage(RemoteMessage remoteMessage) {
        if (serviceClass != null) {
            try {
                Method sendTokenRefresh = serviceClass.getMethod("onMessageReceived", RemoteMessage.class);
                sendTokenRefresh.invoke(serviceObject, remoteMessage);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                Log.w(TAG, "Can't inject message due to error ", e);
            }
        }
    }

    private void injectContext() {
        if (serviceObject != null) {
            if (setField(serviceObject, "mBase", this)) {
                Log.d(TAG, "context is set to io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService");
            }
        }
    }

    private boolean setField(Object targetObject, String fieldName, Object fieldValue) {
        Field field;
        try {
            field = targetObject.getClass().getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            field = null;
        }
        Class<?> superClass = targetObject.getClass().getSuperclass();
        while (field == null && superClass != null) {
            try {
                field = superClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                superClass = superClass.getSuperclass();
            }
        }
        if (field == null) {
            return false;
        }
        field.setAccessible(true);
        try {
            field.set(targetObject, fieldValue);
            return true;
        } catch (IllegalAccessException e) {
            return false;
        }
    }
}

  1. 编辑清单文件 sdk-flutter/android/src/main/AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.hypertrack.sdk.flutter">

    <application>
        <service
            android:name=".MyFirebaseMessagingService"
            android:exported="false" >
            <intent-filter android:priority="100" >
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
    </application>
</manifest>

它是如何工作的?

HyperTrackMessagingService 扩展的

MyFirebaseMessagingService AndroidManifest.xml 文件中声明为具有更高的优先级(肯定高于 HyperTrackMessagingService ).这将使消息直接进入新类.这也将消除方法1中的限制.现在,我们也使用反射将消息转发到 FlutterFirebaseMessagingService .

How it works?

MyFirebaseMessagingService extended from HyperTrackMessagingService, is declared in the AndroidManifest.xml file with higher priority (definitely higher than HyperTrackMessagingService). This will allow messages directly to come to the new class. This will also remove the limitation in method 1. Now we forward the message also to FlutterFirebaseMessagingService using reflection.

没有限制,但是在更新主机库时,您需要手动更新 hypertrack_plugin .最好在插件本身中拥有此更新,而此更新目前不存在(11月13日)

No limitation, but you need to manually update the hypertrack_plugin when the host library is updated. It's good to have this update in the plugin itself which is not present now (Nov 13)

现在,我们将不触摸库中的任何代码,而是编写我们自己的代码.我们将以安全的方式提出解决方案.您不必添加 hypertrack_plugin 作为本地依赖项.

Now we will not touch any code in the library but write our own code. We will propose a solution in a safe way. You don't have to add hypertrack_plugin as local dependencies.

  1. 创建类< project_root>/android/app/src/main/< your_package_name>/MyFirebaseMessagingService.java

package com.example.myapp;

import android.annotation.SuppressLint;
import android.util.Log;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@SuppressLint("LongLogTag")
public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMessagingService";

    // put all the firebase messaging service classes used in your project here
    private String[] fcmClasses = new String[]{
            "io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService",
            "com.hypertrack.sdk.HyperTrackMessagingService"};

    @Override
    public void onNewToken(@NotNull String token) {
        Log.d(TAG, "onNewToken()");
        super.onNewToken(token);
        injectToken(token);
    }

    @Override
    public void onMessageReceived(@NotNull RemoteMessage remoteMessage) {
        Log.d(TAG, "onMessageReceived()");
        super.onMessageReceived(remoteMessage);
        injectMessage(remoteMessage);
    }

    public void injectToken(String newToken) {
        Log.d(TAG, "injectToken()");

        for (String fcmClass : fcmClasses) {
            try {
                Class<?> serviceClass = Class.forName(fcmClass);
                Object serviceObject = serviceClass.newInstance();
                injectContext(serviceClass, serviceObject);

                Method sendTokenRefresh = serviceClass.getMethod("onNewToken", String.class);
                sendTokenRefresh.invoke(serviceObject, newToken);

            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ClassNotFoundException | InstantiationException e) {
                Log.w(TAG, "Can't inject token due to error ", e);
            }
        }
    }

    public void injectMessage(RemoteMessage remoteMessage) {
        Log.d(TAG, "injectMessage()");

        for (String fcmClass : fcmClasses) {
            try {
                Class<?> serviceClass = Class.forName(fcmClass);
                Object serviceObject = serviceClass.newInstance();
                injectContext(serviceClass, serviceObject);

                Method sendTokenRefresh = serviceClass.getMethod("onMessageReceived", RemoteMessage.class);
                sendTokenRefresh.invoke(serviceObject, remoteMessage);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ClassNotFoundException | InstantiationException e) {
                Log.w(TAG, "Can't inject token due to error ", e);
            }
        }
    }

    private void injectContext(Class<?> serviceClass, Object serviceObject) {
        Log.d(TAG, "injectContext()");
        if (serviceClass != null) {
            if (setField(serviceObject, "mBase", this)) {
                Log.d(TAG, "context is set to " + serviceClass.getName());
            }
        }
    }

    private boolean setField(Object targetObject, String fieldName, Object fieldValue) {
        Log.d(TAG, "setField()");

        Field field;
        try {
            field = targetObject.getClass().getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            field = null;
        }
        Class<?> superClass = targetObject.getClass().getSuperclass();
        while (field == null && superClass != null) {
            try {
                field = superClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                superClass = superClass.getSuperclass();
            }
        }
        if (field == null) {
            return false;
        }
        field.setAccessible(true);
        try {
            field.set(targetObject, fieldValue);
            return true;
        } catch (IllegalAccessException e) {
            return false;
        }
    }
}

  1. < project_root>/couriers/android/app/src/main/AndroidManifest.xml
  2. 中声明

重要:设置优先级高于5(在HyperTrack SDK中声明的优先级)

     <service
            android:name=".MyFirebaseMessagingService"
            android:exported="false">
            <intent-filter android:priority="100">
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

它如何工作?

我们已经明确创建了 MyFirebaseMessagingService ,并从 FirebaseMessagingService 进行了扩展.我们还将优先级设置为最高100,以确保仅在此处接收传入消息,而在任何其他Firebase消息传递服务(例如HyperTrack)中均不会接收到.现在,我们可以通过反射灵活地将邮件转发到任何需要的地方.

How does it work?

We have created MyFirebaseMessagingService explicitly and extended from FirebaseMessagingService. We also have set a priority as high as 100 to make sure we are receiving incoming messages only here and not in any other firebase messaging service such as HyperTrack. Now we have the flexibility to forward this message wherever we need, using reflection.

这篇关于Hypertrack阻止Flutter中的FCM通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆