当我在Flutter中使用hypertrack_plugin和firebase_messaging时,我无法在Android中接收任何消息。然而,它在iOS中运行良好。
hypertrack_plugin版本:0.1.3firebase_messaging版本:7.0.3
更新
此问题已在hypertrack_plugin:0.1.4版本的插件更新中修复
问题
您正面临这个问题,因为存在从FirebaseMessagingService
扩展而来的多个服务类。因此,消息是在一个具有高优先级的类中接收的,而不是在另一个类中。
解决方案
方法1
将以下内容添加到您的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>
它是如何工作的
为清单文件中的FlutterFirebaseMessagingService
设置的优先级为零(默认值(,但清单文件中HyperTrackMessagingService
的优先级声明为5(现在版本4.8.0(。上述解决方案只是覆盖优先级,并允许传入消息到达FlutterFirebaseMessagingService
而不是HyperTrackMessagingService
。
限制:
尽管HyperTrack可以很好地工作,但HyperTrack使用FCM进行设备服务器通信以进行优化,如果没有FCM,这将无法正常工作。然而,您可能没有注意到这一点。
方法2
使用反射将HyperTrackMessagingService
中的传入消息转发到插件hypertrack_plugin
中的FlutterFirebaseMessagingService
。
步骤:
- 您需要下载hypertrack_plugin源代码并将其用作本地依赖项。如何
- 在库
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
<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
在具有更高优先级(肯定高于HyperTrackMessagingService
(的AndroidManifest.xml
文件中声明。这将允许消息直接进入新类。这也将消除方法1中的限制。现在,我们也使用反射将消息转发到FlutterFirebaseMessagingService
。
限制:
没有限制,但在更新主机库时,您需要手动更新hypertrack_plugin
插件本身有这个更新是很好的,现在还没有(11月13日(
方法3
现在我们不会接触库中的任何代码,而是编写自己的代码。我们将以安全的方式提出解决方案。您不必将hypertrack_plugin
添加为本地依赖项。
- 创建类
<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
中声明
重要提示:设置高于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的优先级,以确保我们只在这里接收传入消息,而不是在HyperTrack等任何其他firebase消息服务中接收传入消息。现在,我们可以灵活地通过反思将这一信息传递到任何需要的地方。
限制:
无