[英]Hypertrack is preventing FCM notification in Flutter
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.当我在 Flutter 中使用hypertrack_plugin和firebase_messaging时,我无法在 Android 中收到任何消息。但是,它在 iOS 中工作正常。
Version of hypertrack_plugin: 0.1.3 Version of firebase_messaging: 7.0.3 hypertrack_plugin 版本:0.1.3 firebase_messaging 版本:7.0.3
This issue has been fixed in the plugin update which is in the version hypertrack_plugin : 0.1.4
此问题已在hypertrack_plugin版本的插件更新中修复:0.1.4
You are facing this issue because there is multiple service class that extends from FirebaseMessagingService
.您遇到此问题是因为有多个服务 class 从
FirebaseMessagingService
扩展而来。 Because of this, messages are received in one class with high priority and not the other.因此,消息在一个 class 中以高优先级接收,而不是另一个。
Add the following to your AndroidManifest.xml
file将以下内容添加到您的
AndroidManifest.xml
文件中
<service android:name="io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService">
<intent-filter android:priority="100">
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
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).在其清单文件中为
FlutterFirebaseMessagingService
设置的优先级为零(默认),但在其清单文件中为HyperTrackMessagingService
声明的优先级为 5(现在为 4.8.0 版)。 The above solution simply overrides the priority and lets incoming messages come to FlutterFirebaseMessagingService
instead of HyperTrackMessagingService
.上面的解决方案只是简单地覆盖了优先级,让传入的消息到达
FlutterFirebaseMessagingService
而不是HyperTrackMessagingService
。
Although HyperTrack will work fine, HyperTrack uses FCM for device-server communication for optimization which won't function without FCM.尽管 HyperTrack 可以正常工作,但 HyperTrack 使用 FCM 进行设备-服务器通信以进行优化,如果没有 FCM,则不会 function。 However, you might not notice this.
但是,您可能没有注意到这一点。
Forward incoming message in HyperTrackMessagingService
to FlutterFirebaseMessagingService
in the plugin hypertrack_plugin
using reflection.使用反射将
HyperTrackMessagingService
中的传入消息转发到插件FlutterFirebaseMessagingService
中的hypertrack_plugin
。
sdk-flutter/android/src/main/kotlin/com/hypertrack/sdk/flutter/MyFirebaseMessagingService.java
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;
}
}
}
sdk-flutter/android/src/main/AndroidManifest.xml
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>
MyFirebaseMessagingService
extended from HyperTrackMessagingService
, is declared in the AndroidManifest.xml
file with higher priority (definitely higher than HyperTrackMessagingService
). MyFirebaseMessagingService
扩展自HyperTrackMessagingService
,在AndroidManifest.xml
文件中声明了更高的优先级(肯定高于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.这将允许消息直接到达新的 class。这也将消除方法 1 中的限制。现在我们也使用反射将消息转发到
FlutterFirebaseMessagingService
。
No limitation, but you need to manually update the hypertrack_plugin
when the host library is updated.不限,但需要在宿主库更新时手动更新
hypertrack_plugin
。 It's good to have this update in the plugin itself which is not present now (Nov 13)很高兴在现在不存在的插件本身中进行此更新(11 月 13 日)
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.您不必将
hypertrack_plugin
添加为本地依赖项。
<project_root>/android/app/src/main/<your_package_name>/MyFirebaseMessagingService.java
<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;
}
}
}
<project_root>/couriers/android/app/src/main/AndroidManifest.xml
<project_root>/couriers/android/app/src/main/AndroidManifest.xml
声明 <service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter android:priority="100">
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
We have created MyFirebaseMessagingService
explicitly and extended from FirebaseMessagingService
.我们明确地创建了
MyFirebaseMessagingService
并从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.我们还设置了高达 100 的优先级,以确保我们只在此处接收传入消息,而不会在任何其他 firebase 消息服务(例如 HyperTrack)中接收传入消息。 Now we have the flexibility to forward this message wherever we need, using reflection.
现在我们可以灵活地使用反射将此消息转发到我们需要的任何地方。
None没有任何
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.