Laravel集成Firebase实现安卓应用推送的设备token获取与实现问题
FCM设备token获取与存储流程
- 安卓端集成FCM SDK后,首次启动应用会自动向FCM服务器请求生成唯一的设备token,该token与当前设备+安装的应用绑定
- 安卓端拿到token后,在用户注册/登录接口的请求参数中携带该token,传递给Laravel后端
- 后端接收token后,直接更新到对应用户的
device_key字段即可 - 注意FCM token不是永久有效,应用重装、系统重置、FCM主动刷新等场景都会触发token变更,安卓端需要监听token刷新事件,每次更新后都要调用后端接口同步更新数据库中存储的token值
现有发送代码的优化建议
你当前的代码是给所有存储了device_key的用户群发通知,和你给指定任务对应用户发通知的需求不匹配,可按以下方向调整:
- 不要全量拉取用户的device_key,在创建任务的业务逻辑中,直接获取任务所属的用户ID,单独查询该用户的device_key,将
registration_ids字段替换为to字段传递单个用户的token,资源消耗更低逻辑也更精准 - 当前代码中通知标题取的是第一个有device_key的用户姓名,群发时所有用户看到的都是同一个姓名,逻辑存在问题,改为单发后直接取目标用户的name即可正常显示
- 生产环境不要禁用SSL校验,将
CURLOPT_SSL_VERIFYPEER和CURLOPT_SSL_VERIFYHOST参数改为有效值,避免安全风险 - 敏感的serverKey不要硬编码在业务代码中,写入
.env配置文件,通过config('services.fcm.server_key')的方式读取,避免密钥泄露 - 可额外处理FCM返回的响应结果,识别无效/过期的token,自动清空对应用户的device_key字段,减少后续无效请求
以下是调整后的单用户任务通知发送示例代码:
// 创建任务后调用该方法,传入目标用户和任务信息 public function sendTaskNotification(User $user, string $taskTitle, $taskId) { $url = 'https://fcm.googleapis.com/fcm/send'; // 提前在config/services.php中配置fcm.server_key对应.env里的FCM_SERVER_KEY参数 $serverKey = config('services.fcm.server_key'); $data = [ "to" => $user->device_key, "notification" => [ "title" => "你有新的任务:{$taskTitle}", "body" => "请及时登录应用查看处理", ], // 额外携带业务参数,安卓端接收后可直接跳转到对应任务详情页 "data" => [ "type" => "new_task", "task_id" => $taskId ] ]; $encodedData = json_encode($data); $headers = [ 'Authorization:key=' . $serverKey, '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_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_POSTFIELDS, $encodedData); $result = curl_exec($ch); if ($result === FALSE) { \Log::error('FCM推送失败: ' . curl_error($ch)); } curl_close($ch); // 处理失效token $response = json_decode($result, true); if (isset($response['failure']) && $response['failure'] > 0) { foreach ($response['results'] as $resultItem) { if (isset($resultItem['error']) && in_array($resultItem['error'], ['InvalidRegistration', 'NotRegistered'])) { $user->update(['device_key' => null]); } } } return $result; }
内容的提问来源于stack exchange,提问作者Cideinit
相关产品推荐
相关产品推荐

