- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
因此,我尝试在我的虚幻项目中使用 Firebase c++ 库,但我遇到了一些非常一致的崩溃:在新卸载后我第一次运行它时它崩溃了,之后工作正常
这是我从 firebase 崩溃日志记录中获得的堆栈跟踪:
E/art ( 7271): No implementation found for void com.google.firebase.messaging.cpp.RegistrationIntentService.nativeOnTokenReceived(java.lang.String) (tried Java_com_google_firebase_messaging_cpp_RegistrationIntentService_nativeOnTokenReceived and Java_com_google_firebase_messaging_cpp_RegistrationIntentService_nativeOnTokenReceived__Ljava_lang_String_2)
E/UncaughtException( 7271):
E/UncaughtException( 7271): java.lang.UnsatisfiedLinkError: No implementation found for void com.google.firebase.messaging.cpp.RegistrationIntentService.nativeOnTokenReceived(java.lang.String) (tried Java_com_google_firebase_messaging_cpp_RegistrationIntentService_nativeOnTokenReceived and Java_com_google_firebase_messaging_cpp_RegistrationIntentService_nativeOnTokenReceived__Ljava_lang_String_2)
E/UncaughtException( 7271): at com.google.firebase.messaging.cpp.RegistrationIntentService.nativeOnTokenReceived(Native Method)
E/UncaughtException( 7271): at com.google.firebase.messaging.cpp.RegistrationIntentService.onHandleIntent(RegistrationIntentService.java:31)
E/UncaughtException( 7271): at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
E/UncaughtException( 7271): at android.os.Handler.dispatchMessage(Handler.java:102)
E/UncaughtException( 7271): at android.os.Looper.loop(Looper.java:145)
E/UncaughtException( 7271): at android.os.HandlerThread.run(HandlerThread.java:61)
它说没有 nativeOnTokenReceived 的实现,但它是在 firebase c++ sdk 库中实现的。当 RegistrationIntentService 从 FcmInstanceIDListenerService 发送一个 Intent 时会发生崩溃,当 firebase 给出一个新 token 时会发生崩溃,这总是在重新安装或清除它的应用程序数据后在应用程序启动时发生(我不确定是否有可能让它发生在与启动时间不同)。
但是,RegistrationIntentService 已激活 onHandleIntent,并且在应用程序运行期间初始化我的 c++ 监听器类时调用 nativeOnTokenReceived 没有任何问题。有谁知道可能导致这次崩溃的原因是什么?
在使用 ndk-build 之前,Unreal 的构建过程可能会将 sdk 中的静态 .a 库打包到单个 .so 中,这可能是相关的。
下面是从 sdk 的 libmessaging_java.jar 中提取的 RegistrationIntentService 和 FcmInstanceIDListenerService 的代码
FcmInstanceIDListenerService.java
package com.google.firebase.messaging.cpp;
import android.content.Intent;
import com.google.firebase.iid.FirebaseInstanceIdService;
public class FcmInstanceIDListenerService
extends FirebaseInstanceIdService
{
public void onTokenRefresh()
{
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
}
RegistrationIntentService.java
package com.google.firebase.messaging.cpp;
import android.app.IntentService;
import android.content.Intent;
import com.google.firebase.iid.FirebaseInstanceId;
public class RegistrationIntentService
extends IntentService
{
private static final String TAG = "FirebaseRegService";
public RegistrationIntentService()
{
super("FirebaseRegService");
}
protected void onHandleIntent(Intent intent)
{
DebugLogging.log("FirebaseRegService", String.format("onHandleIntent token=%s", new Object[] {
FirebaseInstanceId.getInstance().getToken() }));
String token = FirebaseInstanceId.getInstance().getToken();
if (token != null) {
nativeOnTokenReceived(token);
}
}
private static native void nativeOnTokenReceived(String paramString);
}
最佳答案
所以,我想我在这里发布了我对这个问题的解决方案..
首先,我真的不知道为什么会出现问题,但我感觉这与 Unreal 的构建系统有关。(有趣的事实:当我尝试在虚幻引擎中使用 Google 的 Protobuf 库时,我也遇到了无法解释的错误。)
因为 JNI 找不到它需要的库定义函数,所以我编写了自己的函数来替换它。
基本上,当您使用 Firebase Messaging C++ SDK 时,您的项目中需要包含两个组件:C++ 静态库和 header ,以及一个 Java 库 libmessaging_java.jar
jar文件定义了几个类,大部分都很好,但有几个需要编辑,反编译就可以了(我用了 this tool )
因此,在 RegistrationIntentService
中我声明了
private static native void nativeOnNewToken(String paramString);
并用它替换了对 nativeOnTokenReceived
的调用
在 ListenerService
中声明
private static native void nativeOnNewMessage(String paramString1, String paramString2, String paramString3, Map<String, String> paramMap);
并将其添加到 writeMessageToInternalStorage()
private void writeMessageToInternalStorage(String from, String msgId, String error, Map<String, String> data)
{
//Added code
nativeOnNewMessage(from, msgId, error, data);
//I'm passing the message directly to the C++ code, rather than storing
//it in a buffer, and processing every once in a while
//like the sdk normally does; so surround this crap with if(false)
if(false){
//end added code
try
{
JSONObject json = messageToJson(from, msgId, error, data);
DebugLogging.log("FIREBASE_LISTENER", json.toString());
writeStorageFile(json.toString());
} catch (JSONException e) {
e.printStackTrace();
}
//added code
}
///end added code
}
现在,消息和 token 正在发送到我的函数,所以我需要声明它们:
#include "FirebaseMessageListener.h"
#include "stdio.h"
#include <string>
#include <map>
#if PLATFORM_ANDROID
//jni calls from the listener services
extern "C" void Java_com_google_firebase_messaging_cpp_ListenerService_nativeOnNewMessage(JNIEnv* jenv, jobject thiz, jstring from, jstring mssgID, jstring error, jobject data) {
UE_LOG(FirebaseLog, Log, TEXT("Entering nativeOnNewMessage *****"));
printf("Entering nativeOnNewMessage *****");
std::map<std::string, std::string> data_out;
std::string messageID;
std::string fromID;
//code iterating through map from java, based off code from here:https://android.googlesource.com/platform/frameworks/base.git/+/a3804cf77f0edd93f6247a055cdafb856b117eec/media/jni/android_media_MediaMetadataRetriever.cpp
// data is a Map<String, String>.
if (data) {
// Get the Map's entry Set.
jclass mapClass = jenv->FindClass("java/util/Map");
if (mapClass == NULL) {
return;
}
jmethodID entrySet =
jenv->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
if (entrySet == NULL) {
return;
}
jobject set = jenv->CallObjectMethod(data, entrySet);
if (set == NULL) {
return;
}
// Obtain an iterator over the Set
jclass setClass = jenv->FindClass("java/util/Set");
if (setClass == NULL) {
return;
}
jmethodID iterator =
jenv->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
if (iterator == NULL) {
return;
}
jobject iter = jenv->CallObjectMethod(set, iterator);
if (iter == NULL) {
return;
}
// Get the Iterator method IDs
jclass iteratorClass = jenv->FindClass("java/util/Iterator");
if (iteratorClass == NULL) {
return;
}
jmethodID hasNext = jenv->GetMethodID(iteratorClass, "hasNext", "()Z");
if (hasNext == NULL) {
return;
}
jmethodID next =
jenv->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
if (next == NULL) {
return;
}
// Get the Entry class method IDs
jclass entryClass = jenv->FindClass("java/util/Map$Entry");
if (entryClass == NULL) {
return;
}
jmethodID getKey =
jenv->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
if (getKey == NULL) {
return;
}
jmethodID getValue =
jenv->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
if (getValue == NULL) {
return;
}
// Iterate over the entry Set
while (jenv->CallBooleanMethod(iter, hasNext)) {
jobject entry = jenv->CallObjectMethod(iter, next);
jstring key = (jstring)jenv->CallObjectMethod(entry, getKey);
jstring value = (jstring)jenv->CallObjectMethod(entry, getValue);
const char* keyStr = jenv->GetStringUTFChars(key, NULL);
if (!keyStr) { // Out of memory
return;
}
const char* valueStr = jenv->GetStringUTFChars(value, NULL);
if (!valueStr) { // Out of memory
jenv->ReleaseStringUTFChars(key, keyStr);
return;
}
data_out.insert(std::pair<std::string, std::string>(std::string(keyStr), std::string(valueStr)));
jenv->DeleteLocalRef(entry);
jenv->ReleaseStringUTFChars(key, keyStr);
jenv->DeleteLocalRef(key);
jenv->ReleaseStringUTFChars(value, valueStr);
jenv->DeleteLocalRef(value);
}
}
if (from != nullptr) {
const char* valueStr = jenv->GetStringUTFChars(from, NULL);
if (!valueStr) { // Out of memory
return;
}
fromID = std::string(valueStr);
jenv->ReleaseStringUTFChars(from, valueStr);
}
if (mssgID != nullptr) {
const char* valueStr = jenv->GetStringUTFChars(mssgID, NULL);
if (!valueStr) { // Out of memory
return;
}
messageID = std::string(valueStr);
jenv->ReleaseStringUTFChars(mssgID, valueStr);
}
FirebaseMessageListener::Get()->onNewMessage(fromID, messageID, data_out);
}
extern "C" void Java_com_google_firebase_messaging_cpp_RegistrationIntentService_nativeOnNewToken(JNIEnv* jenv, jobject thiz, jstring inJNIStr) {
UE_LOG(FirebaseLog, Log, TEXT("Entering nativeOnNewToken *****"));
printf("Entering nativeOnNewToken *****");
//first, put the token into a c string
jboolean isCopy;
const char* token = jenv->GetStringUTFChars(inJNIStr, &isCopy);
FirebaseMessageListener::Get()->onNewToken(token);
}
#endif
这些将消息传递到我创建的单例类。你可以在这里做任何你想做的事,但我将它们传递给 firebase::messaging::Listener reference
,以尝试保持与 Firebase SDK 的兼容性(以防我让它正常工作)
class RIFT411_API FirebaseMessageListener
{
private:
static FirebaseMessageListener* self;
//private so that new instance can only be made through call to Get()
FirebaseMessageListener();
#if PLATFORM_ANDROID
JNIEnv * env = FAndroidApplication::GetJavaEnv();
jobject activity = FAndroidApplication::GetGameActivityThis();
#endif
//signals to return the key
void getToken();
//send the messages to the firebase sdk implemented listener, so we'll have an easier time if we ever want to move back
firebase::messaging::Listener *listener = nullptr;
public:
static FirebaseMessageListener* Get();
void onNewToken(const char* token);
void onNewMessage(std::string, std::string, std::map<std::string, std::string> &data);
void Init(firebase::messaging::Listener *listener);
~FirebaseMessageListener();
};
//
FirebaseMessageListener* FirebaseMessageListener::self = nullptr;
FirebaseMessageListener* FirebaseMessageListener::Get()
{
if (self == nullptr) {
self = new FirebaseMessageListener();
}
return self;
}
void FirebaseMessageListener::getToken() {
#if PLATFORM_ANDROID
//This has to happen in the main thread, or some of the FindClass() calls will fail
UE_LOG(FirebaseLog, Log, TEXT("Trying to grab token *****"));
printf("Trying to grab token *****");
env = FAndroidApplication::GetJavaEnv();
activity = FAndroidApplication::GetGameActivityThis();
jclass cls_intent = (env)->FindClass("android/content/Intent");
if (NULL == cls_intent) { UE_LOG(FirebaseLog, Error, TEXT("Failure getting cls_intent")); return; }
jclass cls_service = FAndroidApplication::FindJavaClass("com/google/firebase/messaging/cpp/RegistrationIntentService");
//jclass cls_service = (env)->FindClass("com/google/firebase/messaging/cpp/RegistrationIntentService");
if (NULL == cls_service) { UE_LOG(FirebaseLog, Error, TEXT("Failure getting cls_service")); }
// Get the Method ID of the constructor which takes an int
jmethodID mid_Init = (env)->GetMethodID(cls_intent, "<init>", "(Landroid/content/Context;Ljava/lang/Class;)V");
if (NULL == mid_Init) { UE_LOG(FirebaseLog, Error, TEXT("Failure getting mid_Init")); return;}
// Call back constructor to allocate a new instance, with an int argument
jobject obj_intent = (env)->NewObject(cls_intent, mid_Init, activity, cls_service);
if (NULL == obj_intent) { UE_LOG(FirebaseLog, Error, TEXT("Failure getting obj_intent")); return; }
if (NULL == activity) { UE_LOG(FirebaseLog, Error, TEXT("Failure getting activity")); return; }
jclass cls_activity = (env)->GetObjectClass(activity);
if (NULL == cls_activity) { UE_LOG(FirebaseLog, Error, TEXT("Failure getting cls_activity")); return; }
jmethodID mid_start = (env)->GetMethodID(cls_activity, "startService", "(Landroid/content/Intent;)Landroid/content/ComponentName;");
if (NULL == mid_start) { UE_LOG(FirebaseLog, Error, TEXT("Failure getting mid_start")); return; }
UE_LOG(FirebaseLog, Log, TEXT("MADE IT TO THE END!"));
(env)->CallObjectMethod(activity, mid_start, obj_intent);
#endif
}
void FirebaseMessageListener::onNewToken(const char* token) {
UE_LOG(FirebaseLog, Log, TEXT("Recieving new token in Unreal! Hooray! ***** %s"), *FString(token));
printf("Recieving new Message in Unreal! Hooray! *****\n");
if (listener != nullptr) {
listener->OnTokenReceived(token);
}
}
void FirebaseMessageListener::onNewMessage(std::string from, std::string MessageID, std::map<std::string, std::string> &data) {
UE_LOG(FirebaseLog, Log, TEXT("Recieving new Message in Unreal! Hooray! *****"));
printf("Recieving new Message in Unreal! Hooray! *****\n");
if (!data.empty()) {
UE_LOG(FirebaseLog, Log, TEXT("data:"));
typedef std::map<std::string, std::string>::const_iterator MapIter;
for (MapIter it = data.begin(); it != data.end(); ++it) {
FString s1 = FString(it->first.c_str());
FString s2 = FString(it->second.c_str());
UE_LOG(FirebaseLog, Log, TEXT(" %s: %s"), *s1, *s2);
}
}
::firebase::messaging::Message message;
message.data = data;
message.from = from;
message.message_id = MessageID;
if (listener != nullptr) {
listener->OnMessage(message);
}
}
void FirebaseMessageListener::Init(firebase::messaging::Listener *newlistener) {
this->listener = newlistener;
FGraphEventRef Task = FFunctionGraphTask::CreateAndDispatchWhenReady([=]()
{
getToken();
}, TStatId(), NULL, ENamedThreads::GameThread);
}
FirebaseMessageListener::FirebaseMessageListener()
{
self = this;
}
FirebaseMessageListener::~FirebaseMessageListener()
{
}
与此相关的一件事是,您不会从应用关闭时收到的通知中获取数据。这些数据打包在 Intent 中,我几乎找到了获取它的好方法,我可能会在完成后发布
关于android - Firebase C++ 消息在启动时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38982916/
我一直在读到,如果一个集合“被释放”,它也会释放它的所有对象。另一方面,我还读到,一旦集合被释放,集合就会释放它的对象。 但最后一件事可能并不总是发生,正如苹果所说。系统决定是否取消分配。在大多数情况
我有一个客户端-服务器应用程序,它使用 WCF 进行通信,并使用 NetDataContractSerializer 序列化对象图。 由于服务器和客户端之间传输了大量数据,因此我尝试通过微调数据成员的
我需要有关 JMS 队列和消息处理的帮助。 我有一个场景,需要针对特定属性组同步处理消息,但可以在不同属性组之间同时处理消息。 我了解了特定于每个属性的消息组和队列的一些知识。我的想法是,我想针对
我最近开始使用 C++,并且有一种强烈的冲动 #define print(msg) std::cout void print(T const& msg) { std::cout void
我已经为使用 JGroups 编写了简单的测试。有两个像这样的简单应用程序 import org.jgroups.*; import org.jgroups.conf.ConfiguratorFact
这个问题在这里已经有了答案: Firebase messaging is not supported in your browser how to solve this? (3 个回答) 7 个月前关
在我的 C# 控制台应用程序中,我正在尝试更新 CRM 2016 中的帐户。IsFaulted 不断返回 true。当我向下钻取时它返回的错误消息如下: EntityState must be set
我正在尝试通过 tcp 将以下 json 写入 graylog 服务器: {"facility":"GELF","file":"","full_message":"Test Message Tcp",
我正在使用 Django 的消息框架来指示成功的操作和失败的操作。 如何排除帐户登录和注销消息?目前,登录后登陆页面显示 已成功登录为“用户名”。我不希望显示此消息,但应显示所有其他成功消息。我的尝试
我通过编写禁用qDebug()消息 CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT 在.pro文件中。这很好。我想知道是否可以
我正在使用 ThrottleRequest 来限制登录尝试。 在 Kendler.php 我有 'throttle' => \Illuminate\Routing\Middleware\Throttl
我有一个脚本,它通过die引发异常。捕获异常时,我想输出不附加位置信息的消息。 该脚本: #! /usr/bin/perl -w use strict; eval { die "My erro
允许的消息类型有哪些(字符串、字节、整数等)? 消息的最大大小是多少? 队列和交换器的最大数量是多少? 最佳答案 理论上任何东西都可以作为消息存储/发送。实际上您不想在队列上存储任何内容。如果队列大部
基本上,我正在尝试创建一个简单的 GUI 来与 Robocopy 一起使用。我正在使用进程打开 Robocopy 并将输出重定向到文本框,如下所示: With MyProcess.StartI
我想将进入 MQ 队列的消息记录到数据库/文件或其他日志队列,并且我无法修改现有代码。是否有任何方法可以实现某种类似于 HTTP 嗅探器的消息记录实用程序?或者也许 MQ 有一些内置的功能来记录消息?
我得到了一个带有 single_selection 数据表和一个命令按钮的页面。命令按钮调用一个 bean 方法来验证是否进行了选择。如果不是,它应该显示一条消息警告用户。如果进行了选择,它将导航到另
我知道 MSVC 可以通过 pragma 消息做到这一点 -> http://support.microsoft.com/kb/155196 gcc 是否有办法打印用户创建的警告或消息? (我找不到谷
当存在大量节点或二进制数据时, native Erlang 消息能否提供合理的性能? 情况 1:有一个大约 50-200 台机器的动态池(erlang 节点)。它在不断变化,每 10 分钟大约添加或删
我想知道如何在用户登录后显示“欢迎用户,您已登录”的问候消息,并且该消息应在 5 秒内消失。 该消息将在用户成功登录后显示一次,但在同一 session 期间连续访问主页时不会再次显示。因为我在 ho
如果我仅使用Welcome消息,我的代码可以正常工作,但是当打印p->client_name指针时,消息不居中。 所以我的问题是如何将消息和客户端名称居中,就像它是一条消息一样。为什么它目前仅将消
我是一名优秀的程序员,十分优秀!