基于自有后端实现Flutter推送通知的方案及设备ID获取咨询
自有后端实现App推送:设备ID传递与完整方案
核心实现思路
要实现自有后端直接推送,核心是获取平台专属推送令牌并同步到后端,再通过对应平台的官方推送API发送通知,流程如下:
- 客户端向系统申请通知权限,获取推送令牌(iOS为APNs Device Token,Android为各厂商Push Token)
- 将令牌与用户身份(若有)绑定,通过API发送到后端存储
- 后端根据存储的令牌,调用对应平台的推送API下发通知
客户端代码示例
iOS(Swift)获取APNs令牌并同步到后端
import UIKit import UserNotifications class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 请求通知权限 UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, _ in if granted { DispatchQueue.main.async { application.registerForRemoteNotifications() } } } UNUserNotificationCenter.current().delegate = self return true } // 成功获取APNs令牌 func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { // 转换为字符串格式 let tokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() // 同步到后端 syncTokenToBackend(token: tokenString, platform: "iOS") } // 获取令牌失败处理 func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print("APNs令牌获取失败: \(error.localizedDescription)") } // 向后端发送令牌的网络请求 private func syncTokenToBackend(token: String, platform: String) { guard let url = URL(string: "https://your-api-domain.com/api/device-tokens") else { return } var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") let payload = [ "device_token": token, "platform": platform, "user_id": "当前用户ID(如果有)" ] request.httpBody = try? JSONSerialization.data(withJSONObject: payload) URLSession.shared.dataTask(with: request) { _, response, error in if let error = error { print("令牌同步失败: \(error)") return } // 可根据后端响应处理成功逻辑 }.resume() } }
Android(Kotlin)获取厂商推送令牌(以华为为例)并同步到后端
如果不用Firebase,推荐使用Android厂商自带推送通道(华为、小米、OPPO等),以下是华为Push Token的获取示例:
import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.huawei.hms.push.HmsMessaging import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody class MainActivity : AppCompatActivity() { private val client = OkHttpClient() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 获取华为Push Token HmsMessaging.getInstance(this).token.addOnCompleteListener { task -> if (task.isSuccessful) { task.result?.let { token -> syncTokenToBackend(token, "Android-Huawei") } } else { print("华为Push Token获取失败: ${task.exception?.localizedDescription}") } } } // 同步令牌到后端 private fun syncTokenToBackend(token: String, platform: String) { val url = "https://your-api-domain.com/api/device-tokens" val mediaType = "application/json; charset=utf-8".toMediaType() val payload = """ { "device_token": "$token", "platform": "$platform", "user_id": "当前用户ID(如果有)" } """.trimIndent() val requestBody = payload.toRequestBody(mediaType) val request = Request.Builder() .url(url) .post(requestBody) .build() client.newCall(request).enqueue(object : okhttp3.Callback { override fun onFailure(call: okhttp3.Call, e: java.io.IOException) { e.printStackTrace() } override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) { response.close() // 处理成功响应 } }) } }
后端关键处理逻辑
- 令牌存储:提供POST接口接收客户端发送的令牌,将其与用户ID(若有)、平台类型关联,存入数据库(注意令牌可能更新,需覆盖旧值)
- 推送发送:
- iOS:调用APNs HTTP/2 API,需提前在苹果开发者平台申请APNs证书或密钥,请求示例(Node.js):
const axios = require('axios'); const jwt = require('jsonwebtoken'); const fs = require('fs'); // 生成APNs JWT令牌 const generateAPNsToken = () => { const privateKey = fs.readFileSync('apns-private-key.p8'); return jwt.sign({}, privateKey, { algorithm: 'ES256', issuer: '你的Team ID', header: { kid: '你的Key ID' } }); }; // 发送APNs通知 const sendAPNsNotification = async (deviceToken, title, content) => { const apnsToken = generateAPNsToken(); await axios.post(`https://api.push.apple.com/3/device/${deviceToken}`, { aps: { alert: { title, body: content }, sound: 'default' } }, { headers: { 'Authorization': `bearer ${apnsToken}`, 'apns-topic': '你的App Bundle ID' } }); }; - Android厂商通道:调用对应厂商的推送API(如华为Push API、小米Push API),需在厂商开发者平台申请API密钥,按文档构造请求即可
- iOS:调用APNs HTTP/2 API,需提前在苹果开发者平台申请APNs证书或密钥,请求示例(Node.js):
注意事项
- 令牌可能因用户重装App、系统更新、设备重置等情况变更,客户端需在每次获取到新令牌时重新同步到后端
- 处理用户拒绝通知权限的场景,可引导用户前往设置开启
- 后端需监听推送API的错误响应(如令牌失效),及时从数据库移除无效令牌,避免无效推送请求
内容的提问来源于stack exchange,提问作者Ilian Gion Häsler
相关产品推荐
相关产品推荐

