FCM V1 API网页推送通知收不到问题及API Key生成代码需求
FCM V1 API返回200但设备无通知问题排查 + 服务账号令牌生成代码
一、设备收不到通知的核心原因及修复
你当前的代码只发送了data类型消息,而Firebase控制台发送的是notification类型消息,两者的处理逻辑完全不同:
notification消息:由FCM SDK自动处理,系统会直接弹出通知,无需客户端额外代码data消息:需要客户端代码手动解析并构建通知,否则不会自动显示
修复后的发送代码
修改$notifMessage结构,添加notification字段即可:
<?php function sendFCM() { $url = 'https://fcm.googleapis.com/v1/projects/nanagroup/messages:send'; // 注意:OAuth2 Playground的令牌是临时的,建议用服务账号生成长期令牌(见第二部分) $apiKey = "ya29.a0AfB_byB3orl0ZHoWQl_KYGObHiytKRj3WeMDmlYOuuUBVKlqHsploLlrxBExC2w5_Ux7-YgwUioFgw_F5VbQjouCDtUOGuB2y65ikUmCaMsMyYC1C8nBD4wAuSIhFSDx120BtCiSashwGC0AHZe2b9kP7lTVJc3H4WPlaCgYKATASARISFQHGX2MiX-xa0oLOMvIAiYH3thEf6w0171"; $headers = array ( 'Authorization:Bearer ' . $apiKey, 'Content-Type:application/json' ); $notifData = [ 'title' => "Test Title", 'body' => "Test notification body", ]; // 添加notification字段,让系统自动展示通知 $notifMessage = [ 'token' => "elGCwBHhSK2roeM-VysEIm:APA91bFma3hQgndwueeyIfd91acHonvGSo-T8u_VfQAfSgMGdgBYP0HTX5c9JIbvHQjMZVPv9XD0y1liuXli0K3KG6CQVbqcZrbGuM19atV2CDNvFInsxnpEkeDxJNtAQauLpS9MmgOC", 'notification' => $notifData, 'data' => $notifData, // 可选,保留data字段供客户端自定义逻辑使用 ]; $apiBody = [ 'message' => $notifMessage ]; $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_POSTFIELDS, json_encode($apiBody)); $result = curl_exec($ch); print($result); curl_close($ch); return $result; } sendFCM(); ?>
二、从Firebase服务账号JSON生成OAuth2令牌的代码
你当前用的OAuth2 Playground令牌是临时的,有效期仅1小时左右,生产环境建议用Firebase控制台下载的服务账号JSON生成长期可刷新的令牌。以下提供两种实现方式:
方法1:使用Google Client库(推荐)
先通过Composer安装依赖:
composer require google/apiclient:^2.0
然后编写代码:
<?php require __DIR__ . '/vendor/autoload.php'; // 生成FCM访问令牌 function getFCMAccessToken() { $serviceAccountPath = 'path/to/your/service-account.json'; // 替换成你的JSON文件路径 $client = new Google_Client(); $client->setAuthConfig($serviceAccountPath); $client->addScope('https://www.googleapis.com/auth/firebase.messaging'); $client->fetchAccessTokenWithAssertion(); return $client->getAccessToken()['access_token']; } // 发送FCM消息 function sendFCM() { $url = 'https://fcm.googleapis.com/v1/projects/nanagroup/messages:send'; $apiKey = getFCMAccessToken(); $headers = [ 'Authorization:Bearer ' . $apiKey, 'Content-Type:application/json' ]; $notifData = [ 'title' => "Test Title", 'body' => "Test notification body", ]; $notifMessage = [ 'token' => "elGCwBHhSK2roeM-VysEIm:APA91bFma3hQgndwueeyIfd91acHonvGSo-T8u_VfQAfSgMGdgBYP0HTX5c9JIbvHQjMZVPv9XD0y1liuXli0K3KG6CQVbqcZrbGuM19atV2CDNvFInsxnpEkeDxJNtAQauLpS9MmgOC", 'notification' => $notifData, 'data' => $notifData, ]; $apiBody = [ 'message' => $notifMessage ]; $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_POSTFIELDS, json_encode($apiBody)); $result = curl_exec($ch); print($result); curl_close($ch); return $result; } sendFCM(); ?>
方法2:手动生成JWT令牌(无需第三方库)
如果不想依赖Composer,可以手动实现JWT签名和令牌请求:
<?php // 从服务账号JSON生成FCM访问令牌 function generateFCMAccessToken($serviceAccountPath) { $serviceAccount = json_decode(file_get_contents($serviceAccountPath), true); $privateKey = $serviceAccount['private_key']; $clientEmail = $serviceAccount['client_email']; $tokenUri = $serviceAccount['token_uri']; // 构建JWT载荷 $iat = time(); $exp = $iat + 3600; // 令牌有效期1小时 $payload = [ 'iss' => $clientEmail, 'scope' => 'https://www.googleapis.com/auth/firebase.messaging', 'aud' => $tokenUri, 'iat' => $iat, 'exp' => $exp ]; // 生成JWT签名 $header = json_encode(['alg' => 'RS256', 'typ' => 'JWT']); $base64Header = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header)); $base64Payload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode(json_encode($payload))); $signatureInput = $base64Header . '.' . $base64Payload; openssl_sign($signatureInput, $signature, $privateKey, 'SHA256'); $base64Signature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature)); $jwt = $base64Header . '.' . $base64Payload . '.' . $base64Signature; // 请求获取访问令牌 $ch = curl_init($tokenUri); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([ 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $jwt ])); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); return $response['access_token']; } // 使用示例 $serviceAccountPath = 'path/to/your/service-account.json'; $apiKey = generateFCMAccessToken($serviceAccountPath); // 后续发送FCM的代码参考第一部分,记得添加notification字段 ?>
内容的提问来源于stack exchange,提问作者Witchaya Eungphinij
相关产品推荐
相关产品推荐

