【问题标题】:Firebase Cloud Messaging - onMessageReceived not workingFirebase 云消息传递 - onMessageReceived 不起作用
【发布时间】:2018-08-04 17:31:25
【问题描述】:

我想在我的应用中创建一个简单的通知功能。我关注了 this YouTube 视频以及这两个 Firebase 文档 URL 12 以及 Android Studio 中的 Firebase 工具助手(表示我已连接到 Firebase)。出于某种原因,按照我的旧应用程序上的这些步骤和文档(代码发布在下面),它不允许我接收通知。但是,如果我在一个全新的应用程序上遵循相同的步骤,它就可以完美运行。我在后台、活动和终止状态下在相同的物理设备和环境中测试了这两个应用程序。每次我创建的新演示应用程序都可以正常工作,但我想要通知的旧应用程序不起作用。两者都在没有获得设备 ID 的情况下进行了测试。我什至没有收到任何错误日志或任何 TAG 日志。我认为我编译的项目之一有干扰,不确定到底是什么,但我可能需要看看那里。

我也已经查看了所有这些 SO 帖子:123 等等

附言。我在下面删除了我的包名称,我在 FireBase 上检查了多次,它们匹配,所以我知道这不是问题。但是,我的新演示应用程序的 FireBase 显示我的应用程序已连接,但我的旧应用程序的 FireBase 没有。另外,我之前设置了赏金,但仍然遇到同样的问题。

这是我有问题的代码:

Notification.java(它像文档要求的那样提供服务)

public class Notification extends FirebaseMessagingService {
public Notification() {
}
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    showNotification(remoteMessage.getData().get("message"));

    Log.d("FMC", "Message Notification Body: " + remoteMessage.getNotification().getBody());
}

private void showNotification(String message) {
    Intent i=new Intent(this, SplashScreen.class);
    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

    PendingIntent pendingIntent=PendingIntent.getActivity(this,0,i,PendingIntent.FLAG_UPDATE_CURRENT);
    NotificationCompat.Builder builder=new NotificationCompat.Builder(this)
            .setAutoCancel(true)
            .setContentTitle("FCM TITLE").setContentText(message)
            .setSmallIcon(R.drawable.pt_icon)
            .setDefaults(android.app.Notification.DEFAULT_ALL)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    notificationManager.notify(0,builder.build());
}
}

请注意,我什至没有在上面的 notification.java 中获得日志。

Project.gradle

buildscript {
repositories {
    jcenter()
    maven {
        url 'https://maven.google.com/'
        name 'Google'
    }
}
dependencies {
    classpath 'com.android.tools.build:gradle:3.0.1'
    classpath 'com.google.gms:google-services:3.2.0'

    // NOTE: Do not place your application dependencies here; they belong
    // in the individual module build.gradle files
}
}

allprojects {
repositories {
    jcenter()

    maven { url "https://jitpack.io" }
    maven { url 'https://maven.google.com' }
    google()
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

app.gradle

apply plugin: 'com.android.application'

android {
compileSdkVersion 26

defaultConfig {

    minSdkVersion 16
    targetSdkVersion 26
    versionCode 16
    versionName "2.6"
}
dexOptions {
    jumboMode = true
}
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
//Code below is added to fix random error ("Fix the issues identified by lint")
lintOptions {
    abortOnError false
}
productFlavors {
}
}

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
//compile project(path: ':backend', configuration: 'android-endpoints')
//Removed the 0.2.+
compile 'com.daprlabs.aaron:cardstack:0.3.1-beta0'
//noinspection GradleCompatible
compile 'com.android.support:appcompat-v7:25.4.0'
compile "com.android.support:appcompat-v7:19.0.+"
compile 'com.android.support:design:23.4.0'
compile 'com.android.support:recyclerview-v7:23.4.0'
compile 'com.android.support:cardview-v7:23.4.0'

compile 'com.github.danylovolokh:video-player-manager:0.2.0'
compile 'com.github.danylovolokh:list-visibility-utils:0.2.0'



implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.google.firebase:firebase-messaging:11.8.0'
compile 'com.google.firebase:firebase-core:11.8.0'


compile 'com.orhanobut:dialogplus:1.11@aar'


compile 'com.nineoldandroids:library:2.4.0'
compile files('libs/sinch-android-rtc-3.9.14.jar')
compile 'com.amazonaws:aws-android-sdk-s3:2.4.4'
compile 'com.github.chrisbanes:PhotoView:1.2.6'
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.5.0'
compile 'com.github.amlcurran.showcaseview:library:5.4.3'
compile 'com.github.d-max:spots-dialog:0.7@aar'
compile 'com.victor:lib:1.0.4'
compile 'com.github.bumptech.glide:glide:3.5.2'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.android.support:recyclerview-v7:23.0.0'
compile 'me.grantland:autofittextview:0.2.0'
compile 'com.wang.avi:library:1.0.5'
compile 'com.nineoldandroids:library:2.4.0'
compile 'com.braintreepayments.api:drop-in:2.3.8'
compile 'com.braintreepayments.api:braintree:2.3.9'
compile 'com.loopj.android:android-async-http:1.4.9'
compile 'com.getbase:floatingactionbutton:1.10.1'
compile 'com.mxn.soul:flowingdrawer-core:1.2.2'
compile 'com.github.rengwuxian:MaterialEditText:2.1.4'
compile 'com.github.PhilJay:MPAndroidChart:v3.0.1'
compile 'net.gotev:uploadservice:3.2.5'
compile 'in.srain.cube:ultra-ptr:1.0.11'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha9'
testCompile 'junit:junit:4.12'
//implementation 'com.android.support:appcompat-v4:23.+'
}


apply plugin: 'com.google.gms.google-services'

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-feature
    android:name="android.hardware.microphone"
    android:required="false" />

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<!--
so the app can be found on tablets Google Play

<uses-permission android:name="android.permission.CALL_PHONE" />
-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/> -->
<!-- <uses-permission android:name="android.permission.WAKE_LOCK" /> -->
<!-- <uses-permission android:name="android.permission.READ_PHONE_STATE" /> -->

<grant-uri-permission
    android:path="string"
    android:pathPattern="string"
    android:pathPrefix="string" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/_icon"
    android:label=""
    android:supportsRtl="true"
    android:theme="@style/Theme.AppCompat.Light.NoActionBar"
    tools:node="replace">
    <activity android:name=".SplashScreen">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <service android:name=".Notification">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

    <!-- &lt;!&ndash; -->
    <!-- Set custom default icon. This is used when no icon is set for incoming notification messages. -->
    <!-- See README() for more. -->
    <!-- &ndash;&gt; -->
    <!-- <meta-data -->
    <!-- android:name="com.google.firebase.messaging.default_notification_icon" -->
    <!-- android:resource="@drawable/pt_icon" /> -->
    <!-- &lt;!&ndash; -->
    <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming -->
    <!-- notification message. See README() for more. -->
    <!-- &ndash;&gt; -->
    <!-- <meta-data -->
    <!-- android:name="com.google.firebase.messaging.default_notification_color" -->
    <!-- android:resource="@color/colorAccent" /> -->

    <activity android:name=".SignInForm" />
    <activity android:name=".SignUpPage" />
    <activity android:name=".SellerFillOutForm" />
    <activity android:name=".BuyerFillOutForm" />
    <activity
        android:name=".BuyerHomePage"
        android:label="@string/title_activity_buyer_home_page" />

    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.BROWSABLE" />

    <data android:scheme="http" />

    <activity android:name=".VideoPlayerActivity" />
    <activity android:name=".BackgroundTask" />

    <service
        android:name="com.amazonaws.mobileconnectors.s3.transferutility.TransferService"
        android:enabled="true" />

    <activity android:name=".EnterCreditCard" />
    <activity android:name=".PickMeeting" />
    <activity android:name=".HowBillingWorks" />
    <activity android:name=".ReBillingPlan" />
    <activity android:name=".PayBill" />
    <activity
        android:name=".Buyer_Home_Page"
        android:configChanges="locale|orientation" />
    <activity android:name=".Seller_Home_Page" />
    <activity android:name=".ProductList" />
    <activity android:name=".EditProduct" />
    <activity android:name=".EditSellerAccount" />
    <activity android:name=".EditBuyerAccount" />
    <activity android:name=".Video_Calling.incomingVideoCall" />
    <activity android:name=".Video_Calling.CallScreenActivity" />
    <activity android:name=".SellerAnalytics" />
    <activity android:name=".Swipe_Layout.SwipeLayout" />
    <activity android:name=".Swipe_Layout.PopUpActivity" />
</application>

</manifest>

下面的工作代码(我制作的应用程序只是为了测试我的步骤并且 100% 工作):

Notifaction.java

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

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

import static android.content.ContentValues.TAG;

public class Notifaction extends FirebaseMessagingService {
public Notifaction() {
}
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    showNotification(remoteMessage.getData().get("message"));
}

private void showNotification(String message) {
    Intent i=new Intent(this,MainActivity.class);
    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

    PendingIntent pendingIntent=PendingIntent.getActivity(this,0,i,PendingIntent.FLAG_UPDATE_CURRENT);
    NotificationCompat.Builder builder=new NotificationCompat.Builder(this)
            .setAutoCancel(true)
            .setContentTitle("FCM TITLE").setContentText(message)
            .setSmallIcon(R.drawable.ic_launcher_background)
            .setDefaults(Notification.DEFAULT_ALL)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    notificationManager.notify(0,builder.build());
}
}

AndroidManiest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="">
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <service
        android:name=".Notifaction">
        <intent-filter>
            <action 
android:name="com.google.firebase.MESSAGING_EVENT"/>
        </intent-filter>
    </service>

</application>

</manifest>

app.gradle

apply plugin: 'com.android.application'

android {
compileSdkVersion 26
defaultConfig {
    applicationId ""
    minSdkVersion 14
    targetSdkVersion 26
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.google.firebase:firebase-messaging:11.8.0'
compile 'com.google.firebase:firebase-core:11.8.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}


apply plugin: 'com.google.gms.google-services'

Project.grdle

    // Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {

repositories {
    google()
    jcenter()
}
dependencies {
    classpath 'com.android.tools.build:gradle:3.0.1'
    classpath 'com.google.gms:google-services:3.2.0'

    // NOTE: Do not place your application dependencies here; they 
belong
    // in the individual module build.gradle files
}
}

allprojects {
repositories {
    google()
    jcenter()
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

另外,我将 .json 文件添加到两个项目中。这是一个屏幕截图: .

【问题讨论】:

  • 它可能是我使用的编译库之一,不允许 me 与 Firebase 交互吗?*
  • 从 Firebase 控制台发送时是否收到任何默认通知?
  • 当您运行应用程序时,您会收到“Firebase 已成功初始化”的日志消息?
  • 我没有收到任何通知,甚至没有收到“Firebase 已成功初始化”日志:/
  • 你能显示你放置 json 文件的文件夹结构的屏幕截图吗?

标签: java android firebase firebase-cloud-messaging


【解决方案1】:

如果您正在接收设备令牌并且您有服务器 api 密钥,请检查您的代码是否正常工作或没有使用 pushtry 。 如果您在代码中犯了任何错误,它将给出 Invalid Registration404 Error 等错误。 对于 FCM 的实现,你可以按照这个教程-FCM Tutorial

我在您的build.gradlefile 中注意到的另一件事是defaultConfig 中没有任何applicationId "Package Name"。 我不确定,但这是包名称,当我们在 firebase 控制台上创建项目时使用(项目名称与包)

【讨论】:

  • 我删除了包含私人信息的包名称,但我将它与 Android Studio 和 Firebase 网站上的 Firebase 助手工具连接。一切都说它是连接的。另外,我确实添加了 .json 文件。
  • 这个答案是为 +25 自动选择的。这个答案没有解决我的问题。
  • @aj0822ArpitJoshi 我还有一个问题要问你吗?我有一个项目,从 Firebase 控制台进行的测试在调试时工作正常,但带有 proguard 规则集的发布版本不起作用。我使用 pushtry 对其进行了测试,它工作正常。有什么意见可能是什么问题?
【解决方案2】:

您的通知很可能没有显示,因为 Android Oreo 新的notifications model 需要指定频道定义才能构建和显示通知。同样在您的 app.gradle 中,您的目标是 android version 26,即 Android Oreo,因此无论哪种方式,您都必须实现以下代码。

很容易采用。您需要做的就是:

1.在 YourApplicationClass.onCreate() 中定义通知通道

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            NotificationChannel chan1 = new NotificationChannel(
                YOUR_DESIRED_CHANNEL_ID_STRING,
                YOUR_DESIRED_CHANNEL_LABEL_STRING, 
                NotificationManager.IMPORTANCE_DEFAULT);

            chan1.setDescription(YOUR_DESIRED_CHANNEL_DESC_STRING);//OPTIONAL
            chan1.setLightColor(Color.BLUE);//OPTIONAL     
            chan1.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);//OPTIONAL
            chan1.setShowBadge(true);//OPTIONAL

            getManager().createNotificationChannel(chan1);
        }

2。用这个构造函数替换你的通知生成器

    NotificationCompat.Builder builder=
new NotificationCompat.Builder(this, YOUR_DESIRED_CHANNEL_ID_STRING);

很高兴知道您可以针对 Android Oreo 及更高版本定义多个具有不同属性的渠道

【讨论】:

  • 如果是这种情况,我的新应用不应该无法运行,因为它也针对 Android Oreo 并且不遵循新的通知模型吗?
  • 您可能会遇到不同类型的问题或错误,但我 100% 确定如果不指定渠道,您的应用将无法在运行 android O (26) 的设备上显示通知...您在同一设备/android 版本上测试您的两个应用程序?两个应用程序是否也具有相同的代码实现? (也许我可以提供更多帮助)
  • 我确实在同一台设备上测试了这两个应用程序,并且这两个应用程序都具有上述所有受尊重的代码
  • 2 个愚蠢的问题,但有助于调试: - 您是否在两个项目中放置了相同的 json 文件? - 您如何将通知发送到设备?火力控制台?再看一遍……你的代码看起来不错
  • 我有每个项目的 .json 文件,我正在通过 firebase 控制台发送通知。正是这就是我超级卡住的原因:/
【解决方案3】:

如果你看看这个doc 您似乎没有扩展 FirebaseInstanceIdService 来管理令牌创建/轮换的服务。 Here 是一个示例代码。您需要将推送通知发送到特定设备的令牌由此类接收。

<service
    android:name=".MyFirebaseInstanceIDService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
    </intent-filter>
</service>

编辑

好的,这个错误现在困扰着我。我查看了您的依赖关系树,发现您正在重复其中的一些。例如,您有三个版本:

compile 'com.android.support:appcompat-v7:25.4.0'

也许您应该将其清除到最新版本,或者将其与工作版本匹配。此外,您正在使用新的 gradle 插件,但在大多数情况下,您还没有更新您的依赖项以使用 implementation 而不是 compile,也许也可以尝试一下?这是why,你应该这样做。

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
//compile project(path: ':backend', configuration: 'android-endpoints')
//Removed the 0.2.+
compile 'com.daprlabs.aaron:cardstack:0.3.1-beta0'
//noinspection GradleCompatible
compile 'com.android.support:appcompat-v7:25.4.0'
compile "com.android.support:appcompat-v7:19.0.+"
compile 'com.android.support:design:23.4.0'
compile 'com.android.support:recyclerview-v7:23.4.0'
compile 'com.android.support:cardview-v7:23.4.0'

compile 'com.github.danylovolokh:video-player-manager:0.2.0'
compile 'com.github.danylovolokh:list-visibility-utils:0.2.0'



implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.google.firebase:firebase-messaging:11.8.0'
compile 'com.google.firebase:firebase-core:11.8.0'


compile 'com.orhanobut:dialogplus:1.11@aar'


compile 'com.nineoldandroids:library:2.4.0'
compile files('libs/sinch-android-rtc-3.9.14.jar')
compile 'com.amazonaws:aws-android-sdk-s3:2.4.4'
compile 'com.github.chrisbanes:PhotoView:1.2.6'
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.5.0'
compile 'com.github.amlcurran.showcaseview:library:5.4.3'
compile 'com.github.d-max:spots-dialog:0.7@aar'
compile 'com.victor:lib:1.0.4'
compile 'com.github.bumptech.glide:glide:3.5.2'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.android.support:recyclerview-v7:23.0.0'
compile 'me.grantland:autofittextview:0.2.0'
compile 'com.wang.avi:library:1.0.5'
compile 'com.nineoldandroids:library:2.4.0'
compile 'com.braintreepayments.api:drop-in:2.3.8'
compile 'com.braintreepayments.api:braintree:2.3.9'
compile 'com.loopj.android:android-async-http:1.4.9'
compile 'com.getbase:floatingactionbutton:1.10.1'
compile 'com.mxn.soul:flowingdrawer-core:1.2.2'
compile 'com.github.rengwuxian:MaterialEditText:2.1.4'
compile 'com.github.PhilJay:MPAndroidChart:v3.0.1'
compile 'net.gotev:uploadservice:3.2.5'
compile 'in.srain.cube:ultra-ptr:1.0.11'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha9'
testCompile 'junit:junit:4.12'
//implementation 'com.android.support:appcompat-v4:23.+'
}

另外,更新你的依赖并使用实现而不是编译:

implementation 'com.google.firebase:firebase-messaging:15.0.2'
implementation 'com.google.firebase:firebase-core:15.0.2'

【讨论】:

  • 我制作的快应用中没有它,它可以工作
  • 在你说你用的视频里,11:03左右,小伙子教如何创建FirebaseInstanceIdService,你是用视频做快应用的吗?
  • 没有ID服务是用来获取token订阅主题通知的,但我只是想给大家发个通知,之后我会玩主题等等
  • 好的,如果您不通过令牌向设备发送通知,您是如何发送的?
  • 因为ID服务也用于生成token发送到服务器进行通信。例如,如果我希望我的应用程序具有来自 firebase 的推送通知,我会将该令牌保存到实时数据库中,并使用它将消息定向到我的设备。
【解决方案4】:

//这有助于在手机重启时在后台启动FCM服务。

Add receiver in Manifest.xml

<uses-permission android:name="android.permission.WAKE_LOCK" />
<receiver android:name=".OnBootBroadcastReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
</receiver>

OnBootBroadcastReceiver.class

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class OnBootBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent i = new Intent("com.examle.FirebaseMessagingReceiveService");
        i.setClass(context, FirebaseMessagingReceiveService.class);
        context.startService(i);
    }
}

【讨论】:

  • 1.您是否检查了通知的类型(消息或数据),因为在您的 onMessageReceived 中您只处理数据消息。尝试在此消息中打印日志。 2.如果你在之前的项目中实现了GCM和GCM依赖,可能和fcm有些冲突。
  • 每次测试时,我都会检查日志中的“FCM”,但它从未出现过。另外,我相信我之前使用过 GCM,您能帮我指出如何摆脱它吗?
  • 当您向设备发送通知时,请尝试获取日志,这会有所帮助.. 并检查是否生成了 fcm 令牌,如果令牌有效则只有您收到通知。
  • 再次,每次我测试任何东西时,我都会检查我的日志中是否有“FMC”,我不想只向我的设备发送通知,我想向所有人发送通知。
  • 首先检查您的设备 fcm 令牌,您可以使用提前休息客户端 chrome 扩展发送通知
【解决方案5】:

从 FCM 消息中删除通知负载,以便将数据负载传送到 onMessageReceived 方法。

仔细阅读下面给出的链接。

当您的应用程序在后台时,只有在没有通知负载时才会将数据负载传递到 onMessageReceived 方法。 (标记单词)

如果两个有效负载都存在,则系统会自动处理通知部分(系统托盘),并且您的应用会在启动器 Activity 的意图的附加部分中获取数据有效负载(在用户点击通知后)。

为了能够成功地服务于 Android 和 iOS 这两个平台,您可能必须根据客户端的操作系统发送不同的 FCM 消息。

【讨论】:

  • 我通过在应用程序处于后台并从活动中删除时发送通知来进行测试。我的演示应用可以工作,而主应用不能。
  • 如果您想向所有移动设备发送通知,那么您必须将移动设备的设备 ID 存储到您的服务器,然后通知将发送到所有设备。
  • 这不是真的,因为我在一个新应用程序上重新创建了这些步骤,该应用程序在不存储设备 ID 的情况下运行良好。检查上面的更新问题。
【解决方案6】:

希望您知道通知的类型,要发送通知,您必须使用自定义服务器或 postman 之类的东西,有关更多信息,请参阅这些问题的答案:

How to handle notification when app in background in Firebase

无论如何,您必须在 FirebaseMessagingService 中调用 handleIntent(Intent intent) 方法才能调用 onMessageReceived() 方法..

这是我的完整工作代码,notification-when-app-in-background-in-firebase。

build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    buildToolsVersion '26.0.3'
    defaultConfig {
        applicationId "com.abc.xyz"
        minSdkVersion 17
        targetSdkVersion 26
        multiDexEnabled true
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    dexOptions {
        javaMaxHeapSize "4g"
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation 'com.android.support:support-v4:26.1.0'
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support:design:26.1.0'
    implementation 'com.android.support:recyclerview-v7:26.1.0'
    implementation 'com.android.support:cardview-v7:26.1.0'
    //firebase analytics and ads
    implementation 'com.google.firebase:firebase-ads:11.4.2'
    implementation 'com.google.firebase:firebase-core:11.4.2'
    implementation 'com.google.firebase:firebase-messaging:11.4.2'
    implementation 'com.firebase:firebase-jobdispatcher:0.8.5'
}

apply plugin: 'com.google.gms.google-services'

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.abc.xyz">

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>


        <!-- [START fcm_default_icon] -->

        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@drawable/ic_stat_ic_notification" />

        <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:resource="@color/colorAccent" />
        <!-- [END fcm_default_icon] -->
        <!-- [START fcm_default_channel] -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="@string/default_notification_channel_id" />
        <!-- [END fcm_default_channel] -->

        <service
            android:name=".services.MyFirebaseMessagingService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        <service android:name=".services.MyFirebaseInstanceIDService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
            </intent-filter>
        </service>
        <service
            android:name=".services.MyJobService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
            </intent-filter>
        </service>

    </application>

</manifest>

MyFirebaseMessagingService.java:

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private static final String TAG = "MyFirebaseMsgService";

    @Override
    public void handleIntent(Intent intent) {

        Log.e(TAG, "handleIntent");
        try
        {
            if (intent.getExtras() != null)
            {
                RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

                for (String key : intent.getExtras().keySet())
                {
                    builder.addData(key, intent.getExtras().get(key).toString());
                }

                onMessageReceived(builder.build());
            }
            else
            {
                super.handleIntent(intent);
            }
        }
        catch (Exception e)
        {
            super.handleIntent(intent);
        }
    }

    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // [START_EXCLUDE]
        // There are two types of messages data messages and notification messages. Data messages are handled
        // here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
        // traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
        // is in the foreground. When the app is in the background an automatically generated notification is displayed.
        // When the user taps on the notification they are returned to the app. Messages containing both notification
        // and data payloads are treated as notification messages. The Firebase console always sends notification
        // messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
        // [END_EXCLUDE]

        // TODO(developer): Handle FCM messages here.
        // Not getting messages here? See why this may be:
        Log.e(TAG, "Notification received Successfully");
        Log.e(TAG, "From: " + remoteMessage.getFrom());

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.e(TAG, "Message data payload: " + remoteMessage.getData());

            if (/* Check if data needs to be processed by long running job */ true) {
                // For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
                scheduleJob();
            } else {
                // Handle message within 10 seconds
                handleNow();
            }

        }

        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            Log.e(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
        }

        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated. See sendNotification method below.
    }
    // [END receive_message]

    /**
     * Schedule a job using FirebaseJobDispatcher.
     */
    private void scheduleJob() {
        // [START dispatch_job]
        FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));
        Job myJob = dispatcher.newJobBuilder()
                .setService(MyJobService.class)
                .setTag("my-job-tag")
                .build();
        dispatcher.schedule(myJob);
        // [END dispatch_job]
    }

    /**
     * Handle time allotted to BroadcastReceivers.
     */
    private void handleNow() {
        Log.e(TAG, "Short lived task is done.");
    }

    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param messageBody FCM message body received.
     */
    private void sendNotification(String messageBody) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);

        String channelId = getString(R.string.default_notification_channel_id);
        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(this, channelId)
                        .setSmallIcon(R.drawable.ic_stat_ic_notification)
                        .setContentTitle("FCM Message")
                        .setContentText(messageBody)
                        .setAutoCancel(true)
                        .setSound(defaultSoundUri)
                        .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
}

MyFirebaseInstanceIDService.java:

public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
    private static final String TAG = "MyFirebaseIIDService";

    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the InstanceID token
     * is initially generated so this is where you would retrieve the token.
     */
    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        Log.e(TAG, "onTokenRefresh");
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.e(TAG, "Refreshed token: " + refreshedToken);

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        sendRegistrationToServer(refreshedToken);
    }
    // [END refresh_token]

    /**
     * Persist token to third-party servers.
     *
     * Modify this method to associate the user's FCM InstanceID token with any server-side account
     * maintained by your application.
     *
     * @param token The new token.
     */
    private void sendRegistrationToServer(String token) {
        // TODO: Implement this method to send token to your app server.
    }
}

MyJobService.java

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class MyJobService extends JobService {

    private static final String TAG = "MyJobService";

    @Override
    public boolean onStartJob(JobParameters job) {
        // Do some work here
        Log.e(TAG, "Inside MyJobService");
        return false; // Answers the question: "Is there still work going on?"
    }

    @Override
    public boolean onStopJob(JobParameters job) {
        Log.e(TAG, "Inside MyJobService");
        return false; // Answers the question: "Should this job be retried?"
    }
}

MyApplication.java:

public class MyApplication extends MultiDexApplication {

    @Override
    public void onCreate() {
        super.onCreate();

        // active JobSchedulerReceiver
        Intent intent = new Intent();
        intent.setAction(getPackageName() + ".receiver.JobSchedulerReceiver");
        sendBroadcast(intent);
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.e(TAG, "Inside MainActivity");

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Create channel to show notifications.
            String channelId = getString(R.string.default_notification_channel_id);
            String channelName = getString(R.string.default_notification_channel_name);
            NotificationManager notificationManager =
                    getSystemService(NotificationManager.class);
            assert notificationManager != null;
            notificationManager.createNotificationChannel(new NotificationChannel(channelId,
                    channelName, NotificationManager.IMPORTANCE_LOW));
        }

        // If a notification message is tapped, any data accompanying the notification
        // message is available in the intent extras. In this sample the launcher
        // intent is fired when the notification is tapped, so any accompanying data would
        // be handled here. If you want a different intent fired, set the click_action
        // field of the notification message to the desired intent. The launcher intent
        // is used when no click_action is specified.
        //
        // Handle possible data accompanying notification message.
        // [START handle_data_extras]
        if (getIntent().getExtras() != null) {
            for (String key : getIntent().getExtras().keySet()) {
                Object value = getIntent().getExtras().get(key);
                Log.e(TAG, "Key: " + key + " Value: " + value);
            }
        }
        // [END handle_data_extras]

        Button subscribeButton = findViewById(R.id.subscribeButton);
        subscribeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // [START subscribe_topics]
                FirebaseMessaging.getInstance().subscribeToTopic("news");
                // [END subscribe_topics]

                // Log and toast
                String msg = getString(R.string.msg_subscribed);
                Log.e(TAG, msg);
                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
            }
        });

        Button logTokenButton = findViewById(R.id.logTokenButton);
        logTokenButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Get token
                String token = FirebaseInstanceId.getInstance().getToken();

                // Log and toast
                String msg = getString(R.string.msg_token_fmt, token);
                Log.e(TAG, msg);
                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
            }
        });

    }
}

【讨论】:

    【解决方案7】:

    即使我遇到了同样的问题,也可以通过在 AndroidManifest.xml 中添加完整路径 android:name 服务来解决

    <service android:name="com.testapp.Notifaction">
         <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT"/>
        </intent-filter>
    </service>
    

    尝试一次,如果您有任何问题,请告诉我。

    【讨论】:

      【解决方案8】:

      由于您没有从 Firebase 收到任何日志事件,请检查以下步骤:

      • 转到您的 Firebase 项目控制台,输入项目设置并检查包名称是否正确。
      • 再次下载JSON文件并将其复制到app/模块(将项目视角从Android更改为项目),确保文件名 google-services.json
      • 运行你的项目,去logcat搜索关键字Firebase,如果成功你会看到消息:

      I/FirebaseInitProvider:FirebaseApp 初始化成功

      【讨论】:

        【解决方案9】:

        让我们一步一步地检查你的所有代码,并与我的实际项目进行比较,该项目正在生产中使用最新版本的 Firebase 消息服务:

        • 你对 gradle 的依赖看起来不错,但你只需要 implementation "com.google.firebase:firebase-messaging:15.0.2"

        • 您可以尝试将您的课程重命名为不同的名称吗? Notification 名称可能是它与自己的 Android 通知类的交互。还要记住它应该有一个 Empty 构造函数(但我在你的代码中看到你有它)

        例如,将其命名为 MessagingController 并将其放在 &lt;application&gt; 内的清单中,例如:

           <!--Service to control messaging requests-->
                <service
                    android:name=".messaging.controller.MessagingController"
                    android:exported="false">
                    <intent-filter>
                        <action android:name="com.google.firebase.MESSAGING_EVENT" />
                    </intent-filter>
                </service>
            </application>
        

        另外,别忘了你需要一个FirebaseInstanceService 的实例,就像Official Doc says 一样需要:

        扩展 FirebaseInstanceIdService 以处理注册令牌的创建、轮换和更新的服务。这是发送到特定设备或创建设备组所必需的。

        <!--Firebase instance service to renew messaging tokens-->
                <service
                    android:name=".messaging.service.FirebaseInstanceService"
                    android:exported="false">
                    <intent-filter>
                        <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
                    </intent-filter>
                </service>
        
        • 您是否从 Firebase 控制台发送通知?还是使用 Firebase Cloud 功能?在这两种情况下,您是否引入了正确的令牌?如果您放置一个超时令牌 Firebase 控制台会向您显示错误,您应该像这样添加通知:

        • 好的,此时,您的代码应该至少可以接收日志中的通知,

        • 如果您愿意,您可以查看下一个项目,即应用程序 Skeleton 来构建通知系统。也许它也会对您有所帮助:https://github.com/FrangSierra/PushNotificationSkeleton

        • 最后如果你想查看一些关于如何从服务器发送通知的云函数代码,我建议你看看This repository

        【讨论】:

          【解决方案10】:

          让应用监听 firebase 数据库中的某个值,并将其更改为您想要的消息。 我对我的应用程序这样做,它的工作就像魅力一样。

          【讨论】:

            【解决方案11】:

            您是否在 FCM 控制台上注册了您的应用程序?并在您的应用程序中添加了 .json 文件?

            【讨论】:

            • 我创建了 Firebase 项目,添加了 .json,然后通过 Assistant Tool 连接了我的项目
            【解决方案12】:

            有两种类型的通知数据 1)通知有效载荷 2)数据有效载荷 如果您在通知有效负载中从服务器发送数据意味着。有可能没有从 FirbaseMessagingService 调用 onMessageRecieved() 看看this link

            【讨论】:

              【解决方案13】:

              这只是一个简单的建议,但几周前对我造成类似错误的原因是我发送了错误的通知形式。 我发送了无声通知,即使我应该大声发送。检查您的服务器如何发送消息。我还弄乱了 FCM API 期望密钥的顺序。

              这是我的工作大声通知代码,由 Django Python 服务器发送:

              def _build_loud_message(not_id, data):
                  """Construct loud notifiation message.
                  Loud means that this message will show up in the notifications hub
                  of the app.
                  """
                  return {
                      'message': {
                          'notification': {
                              'title': 'New activity',
                              'body': 'Hey you have some new activity!'
                          },
                          'data': {"data": data},
                          'apns': {
                              'payload': {
                                  "notId": not_id,  # notId HAS TO BE FIRST!!!
                                  'aps': {
                                      'badge': 1,
                                      'sound': 'default',
                                      'content-available': 1
                                  }
                              },
                              'headers': {
                                  'apns-priority': '10',
                                  'apns-collapse-id': 'myid-1'
                              }
                          },
                          'android': {
                              'priority': "high",
                              'data': {
                                  "androidData": data
                              },
                              'notification': {
                                  'sound': 'default',
                                  'tag': 'mytag-1'
                              }
                          }
                      }
                  }
              

              还要密切注意提到 dic 键的顺序。更改它们可能会导致消息无法从 FCM 成功发送到设备,即使 FCM api 说它已成功发送。

              【讨论】:

                猜你喜欢
                • 2016-10-09
                • 1970-01-01
                • 2018-12-15
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2022-08-19
                • 2018-01-09
                相关资源
                最近更新 更多