You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android App后台接收FCM通知无振动及图标异常问题求助

解决FCM后台通知无振动、图标异常问题

这个问题的核心原因是FCM消息的两种处理机制差异:当你的App处于后台时,notification类型的消息会由Android系统直接展示,不会触发App内的onMessageReceived方法,所以你在MyNotificationManager里设置的振动、自定义图标等配置完全不会生效;只有当App在前台时,notification消息才会传递到App,让你自己的代码处理通知。

你的PHP代码同时发送了notificationdata字段,后台时系统优先处理notification字段,导致自定义配置失效。下面是两种解决方案,推荐第一种更可靠的方式:

方案一:改用纯Data消息,统一前后台通知逻辑

这种方式下,无论App在前台还是后台,FCM都会把消息传递到你的FirebaseMessagingService,让App自己处理通知,这样振动、图标等配置就能统一生效。

1. 修改PHP推送代码

移除notification字段,只保留data字段,把通知需要的标题、内容都放在data里:

function send_notification ($token, $message, $Raum, $Notruf) {
    $url = 'https://fcm.googleapis.com/fcm/send';
    // 只保留data字段,把通知内容都放在这里
    $fields = array(
        'to' => $token,
        'data' => array(
            'title' => '紧急通知', // 可以自定义通知标题
            'body' => "Raum ".$Raum.", Notruf ".$Notruf,
            'message' => $message
        )
    );
    $headers = array (
        'Authorization:key = (HERE IS MY AUTH KEY)',
        'Content-Type: application/json'
    );
    $ch = curl_init ();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
    $result = curl_exec($ch);
    if ($result == FALSE) {
        die ('Curl failed: ' . curl_error($ch));
    }
    curl_close($ch);
    return $result;
}

2. 实现FirebaseMessagingService

创建一个继承自FirebaseMessagingService的类,用来接收所有FCM消息(包括后台),然后调用你的MyNotificationManager展示通知:

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        
        // 从data中取出通知内容
        String title = remoteMessage.getData().get("title");
        String body = remoteMessage.getData().get("body");
        
        // 调用自定义通知管理器展示通知
        MyNotificationManager.getInstance(this).displayNotification(title, body);
    }
}

3. 在Manifest中注册服务

AndroidManifest.xml里添加这个服务的注册,确保FCM能找到它:

<application ...>
    <!-- 其他组件 -->
    <service
        android:name=".MyFirebaseMessagingService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
</application>

方案二:在Notification字段中添加系统级配置

如果你坚持要保留notification字段,可以在PHP的notification里直接指定振动、图标等参数,让系统后台展示时使用这些配置:

'notification' => array(
    'body' => "Raum ".$Raum.", Notruf ".$Notruf,
    'icon' => "sirenlight", // 这里是drawable资源的名称(不带扩展名),必须符合通知图标规范
    'vibrate' => array(0, 5000, 100, 5000, 100, 5000, 100, 5000, 100, 5000, 100, 5000),
    'sound' => "default" // 可选:添加默认通知声音
)

⚠️ 注意:这种方式下,App前台时可能会收到两次通知(系统一次,你的代码一次),需要额外处理重复通知的问题;另外通知图标必须是白色透明背景的符合Android规范的图标,否则系统会自动替换成默认图标,导致显示异常。

额外注意事项

  • 通知图标规范:Android要求通知图标必须是白色图形+透明背景,否则在Android 8.0+的系统上会显示异常,建议你检查R.drawable.sirenlight是否符合这个要求。
  • 通知渠道:你的代码里用了Constants.CHANNEL_ID,确保已经在App启动时创建了对应的通知渠道,并且渠道的振动、声音等配置是开启的,否则Android 8.0+系统可能会限制通知的振动和声音。

内容的提问来源于stack exchange,提问作者Mario0933

火山引擎 最新活动