端對接指南:ThinkPHP集成個推REST API V2)
簡介這是一套面向 uniapp 開發(fā)者的移動端推送功能完整后端實現(xiàn)資源核心解決 uniapp 項目中集成 unipush 與個推 SDK 的服務(wù)端接口設(shè)計問題。內(nèi)容基于 Thinkphp RestAPI V2 構(gòu)建覆蓋客戶端設(shè)備注冊、Token 上報、服務(wù)端調(diào)用個推 API 發(fā)送通知、結(jié)果反饋與異常重試完整鏈路適合具備基礎(chǔ) PHP 和 uniapp 知識、希望快速落地推送模塊的中高級開發(fā)者參考。壓縮包共 40 個文件以 37 個 PHP 源碼為主包含 GeTui.php、GTPushApi.php、GTClient.php 等 SDK 封裝與接口實現(xiàn)另有 README、license 及 composer.json 輔助說明包體僅 42KB體積小巧、結(jié)構(gòu)清晰可按模塊直接引入項目二次開發(fā)。資源已獲得 3754 人學(xué)習(xí)兼具實戰(zhàn)代碼與集成思路能幫助讀者省去排查官方文檔和聯(lián)調(diào)的時間快速理解 unipush 與個推服務(wù)端的鑒權(quán)、推送及回執(zhí)處理流程。1. uniapp 用 uniPush 做推送卡住你的往往是服務(wù)端個推SDK和ThinkPHP怎么接“前端明明拿到了cid后端卻始終推不出去”是 uniPush 接入里最典型的隱形門檻。幾乎所有人都會先在前端完成 init卻把真正的推送邏輯——個推 SDK、REST API V2 鑒權(quán)、通知和透傳的報文結(jié)構(gòu)——留到最后才碰。某開發(fā)者接推送時前后端一起寫前端半小時跑通了后端光簽名就調(diào)了一天。后來把 ThinkPHPRestAPI V2 整合成一套完整版服務(wù)端才發(fā)現(xiàn)問題不是“接入”而是“協(xié)議”。這套方案適合正在用 uniapp 做 App、后端用 PHP、想把通知欄消息和透傳消息都走通的開發(fā)者。下面按鏈路拆解到代碼落地再把排查清單放最后照著落地即可。2. 推送鏈路拆解uniPush、個推通道與 ThinkPHP 服務(wù)端的邊界2.1 一次推送從觸發(fā)到展示經(jīng)過了哪幾層先明確鏈路。App 收推送消息時不會由 uniapp 自己從業(yè)務(wù)服務(wù)器拉取而是依賴一個推送服務(wù)商的通道。uniPush 2.0 的前端能力本質(zhì)是把某個推送服務(wù)商的 SDK 封裝成了一套 uniapp 插件前端只需要拿 clientid、監(jiān)聽消息回調(diào)具體的下發(fā)、離線消息存儲、廠商通道接入全部在服務(wù)端和該推送平臺側(cè)發(fā)生。這個鏈路大致是業(yè)務(wù)后端 → 調(diào)個推的 REST API V2 → 個推服務(wù)端按設(shè)備在線狀態(tài)決定走哪條通道 → 在線設(shè)備走個推長連接離線設(shè)備走廠商離線通道比如 APNs、華為推送、小米推送等 → 客戶端收到后交給系統(tǒng)通知欄或進入監(jiān)聽回調(diào)。明白這個層級就能理解為什么“推送不顯示”不一定是你代碼寫錯而是廠商通道沒配置好。在線消息走個推長連接只要手機網(wǎng)絡(luò)通暢后臺發(fā)送幾乎即時到達(dá)熄屏后應(yīng)用進程被系統(tǒng)殺掉消息就要靠廠商通道接力這一步依賴你在個推后臺申請的廠商推送服務(wù)以及 App 打包時的證書、包名、簽名設(shè)置。這些雖然是前端工作之外的事但服務(wù)端對接哪個通道、選擇什么報文直接影響送達(dá)率。2.2 為什么不建議直接用官方 SDK 裸寫很多 PHP 后端第一次做推送會以為引入個推官方 SDK拿到 appId 和 appKey 就可以直接 new 一個客戶端推一把。實際上 SDK 封裝得再好接入時仍然要面對三個問題token 有效期管理、返回碼處理、業(yè)務(wù)側(cè)推送記錄落庫。直接在業(yè)務(wù)方法里 new 一個推送對象token 請求會重復(fù)發(fā)生往往一天下來會把當(dāng)天配額耗在半數(shù)以上。另外一個推送服務(wù)不止“發(fā)一條消息”。實際項目里通常有單推、cid 批量推、按條件推、透傳消息還要求通知點擊后有回調(diào)落地。如果所有推送邏輯都散落在 controller 里修改簽名算法或加個模板字段就要到處找。常見做法是抽出一個獨立的 PushService 類負(fù)責(zé) token 緩存、報文組裝、網(wǎng)絡(luò)請求、落庫回執(zhí)controller 只管接收參數(shù)并調(diào)用。選擇 ThinkPHPRestAPI V2 整合不是為了復(fù)用 TP 的 ORM 那么簡單。TP 自帶的命令行模式可以讓你寫一個php think push:test去手動驗證推送隊列組件可以處理大批量 cid 推送的異步分發(fā)日志組件能記錄每次推送的請求體與返回值。這些對于一個上線后“看得到回執(zhí)”的服務(wù)來說是剛需。2.3 鑒權(quán)參數(shù)與 REST API V2 的簽名規(guī)則開始寫代碼前需要先從推送平臺后臺拿到 appId、appKey、masterSecret 三項。appId 標(biāo)識應(yīng)用appKey 是開放平臺應(yīng)用標(biāo)識masterSecret 是服務(wù)端專用密鑰。注意 masterSecret 不能寫在客戶端代碼里也不能隨前端打包下發(fā)否則等于把服務(wù)器鑰匙放進用戶手機里。REST API V2 的 token 獲取過程是用 appKey、appId 和 timestamp 算出一個簽名然后 POST 到鑒權(quán)接口。簽名這里最容易出錯。我一開始用 sha1、用的是秒級時間戳、拼接順序搞錯白白調(diào)試一個多小時。正確的規(guī)則是按固定順序做字符串拼接appKey appId timestamp做 sha256timestamp 取毫秒級時間戳。這里有個玄學(xué)點有些接口文檔寫的是 timestamp 毫秒有些示例卻是秒如果服務(wù)端返回時間戳相關(guān)錯誤第一反應(yīng)就是查單位。我們后面代碼里統(tǒng)一用 13 位毫秒。token 拿到后有效期默認(rèn)是一段時間可以緩存在 think\Cache 里避免每次推送前都重新鑒權(quán)。提示masterSecret 泄露后記得去后臺重置否則任何人都能調(diào)你的接口給你的用戶發(fā)垃圾消息。3. ThinkPHPRestAPI V2 服務(wù)端實現(xiàn)從數(shù)據(jù)庫到推送報文3.1 數(shù)據(jù)庫表設(shè)計與接口約定推送服務(wù)端先要把數(shù)據(jù)模型定下來。單推要記錄 cid、標(biāo)題、內(nèi)容、taskId、推送結(jié)果批量推還要記錄任務(wù)批次、總條數(shù)、成功條數(shù)。實際項目通常建一張 push_log 表關(guān)鍵字段如下。CREATE TABLE push_log ( id int(11) NOT NULL AUTO_INCREMENT, cid varchar(64) NOT NULL DEFAULT COMMENT 客戶端唯一標(biāo)識, title varchar(128) NOT NULL DEFAULT COMMENT 通知標(biāo)題, content text COMMENT 通知內(nèi)容, payload text COMMENT 透傳數(shù)據(jù)JSON字符串, task_id varchar(64) NOT NULL DEFAULT COMMENT 個推返回的任務(wù)ID, status tinyint(1) NOT NULL DEFAULT 0 COMMENT 0處理中 1成功 2失敗, error_msg varchar(255) NOT NULL DEFAULT COMMENT 失敗原因, create_time int(11) NOT NULL, update_time int(11) NOT NULL, PRIMARY KEY (id), KEY idx_cid (cid), KEY idx_task_id (task_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT推送記錄表;cid 字段對應(yīng) uniapp 端 uni.getPushClientId 拿到的值一個 App 安裝一次會生成一個或多個 cid具體數(shù)量取決于不同端的通道注冊情況。task_id 是個推服務(wù)端返回的任務(wù)標(biāo)識用于后續(xù)查詢送達(dá)回執(zhí)。status 字段不能只存成功和失敗要加一個處理中因為批量推送是異步任務(wù)接口返回 code 為 0 不代表每條都送達(dá)。接口約定上我會設(shè)計三個 RestAPI 風(fēng)格端點單推、批量推、透傳。單推和透傳解耦開來前端業(yè)務(wù)上“點擊通知打開頁面”走通知欄消息payload“靜默更新”走透傳消息。這樣前端 onPushMessage 回調(diào)可以區(qū)分消息類型。3.2 封裝 PushServicetoken 獲取與緩存下面的 PushService 是我習(xí)慣用的結(jié)構(gòu)核心是 getAccessToken 方法和 sendSingle 方法。先看鑒權(quán)部分。?php namespace app\common\service; use think\facade\Cache; use think\facade\Log; class PushService { private $appId; private $appKey; private $masterSecret; private $baseUrl https://restapi.example.com/v2; public function __construct() { $this-appId config(push.app_id); $this-appKey config(push.app_key); $this-masterSecret config(push.master_secret); } public function getAccessToken() { $cacheKey push_token_ . $this-appId; $token Cache::get($cacheKey); if ($token) { return $token; } $timestamp (string)(time() * 1000); $sign hash(sha256, $this-appKey . $this-appId . $timestamp); $url $this-baseUrl . / . $this-appId . /auth; $body [ sign $sign, timestamp $timestamp, appkey $this-appKey ]; $result $this-httpPost($url, $body); if (isset($result[code]) $result[code] 0) { $data $result[data]; Cache::set($cacheKey, $data[token], 60 * 60); return $data[token]; } Log::error(push auth fail: . json_encode($result, JSON_UNESCAPED_UNICODE)); return null; } private function httpPost($url, $params) { $ch curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params)); curl_setopt($ch, CURLOPT_HTTPHEADER, [Content-Type: application/json]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); $response curl_exec($ch); curl_close($ch); return json_decode($response, true); } }這段代碼里 token 緩存是重點。Cache::set 往 think 的緩存通道里寫一小時有效一小時到期后重新獲取避免每個請求都觸發(fā)一次 auth。timestamp 拼接成毫秒時間戳后轉(zhuǎn)成字符串避免 PHP 整數(shù)溢出。httpPost 方法里設(shè)了 10 秒超時推送接口在弱網(wǎng)下偶發(fā)慢響應(yīng)超過 10 秒就返回。這個超時可以按業(yè)務(wù)接受度調(diào)整但不要設(shè)置成 0否則 curl 會一直等ThinkPHP 的請求隊列會積壓。auth 接口的返回結(jié)構(gòu)是 code 為 0 時data 里帶 token。如果 code 非 0通常錯誤信息里會明確提示 sign 問題還是 timestamp 問題。我第一次調(diào)通后發(fā)現(xiàn)錯誤提示簽名校驗失敗檢查后發(fā)現(xiàn)是把 appId 和 appKey 拼反了。這個接口對拼接順序高度敏感不是 sha256 算法選錯是原材料順序錯了。3.3 單推、cid 批量推與透傳消息完整請求報文token 拿到后推送才是最要命的。個推 REST API V2 的單推端點根據(jù) cid 走批量推送可以傳多個 cid這里給出我驗證過的報文組裝方式。public function sendSingle($cid, $title, $content, $payload []) { $token $this-getAccessToken(); if (!$token) { return [code -1, msg token獲取失敗]; } $requestId uniqid(, true); $url $this-baseUrl . / . $this-appId . /push/single/cid; $notification [ title $title, body $content, click_type payload, payload json_encode($payload, JSON_UNESCAPED_UNICODE) ]; $body [ request_id $requestId, audience [cid [$cid]], push_message [ notification $notification ], push_channel [ android [ ups [ notification $notification ] ], ios [ apns [ aps [ alert [ title $title, body $content ] ], payload json_encode($payload, JSON_UNESCAPED_UNICODE) ] ] ] ]; $result $this-httpPostWithToken($url, $body, $token); $this-logPush($cid, $title, $content, $payload, $result); return $result; }這里最關(guān)鍵的字段是 click_type。當(dāng)設(shè)置為 payload 后用戶點擊通知欄消息時App 會收到透傳 payload可以由此跳轉(zhuǎn)到具體頁面。如果你不設(shè)置它點擊通知只會打開 App不能拿到跳轉(zhuǎn)參數(shù)。Android 通道里我把 notification 重復(fù)放在 push_channel.android.ups 下面這是廠商通道的消息體和頂層 push_message.notification 并存。iOS 走 apns 的 alert 字段payload 作為一個自定義鍵傳給客戶端。注意 request_id 要保證每次推送唯一個推后臺會用它做消息去重和任務(wù)追蹤。遇到同一內(nèi)容重復(fù)推送時如果你沿用同一個 request_id個推可能直接丟棄。我見過一次線上重復(fù)推送查了半天才發(fā)現(xiàn)是代碼里把 request_id 寫死了。uniqid(, true) 足夠日常使用并發(fā)高時可以在后綴拼接隨機數(shù)。批量推送端點類似只是把 url 換成批量 cid 端點。批量推不要循環(huán)調(diào)用 sendSingle否則每個 cid 都會觸發(fā)一次 token 校驗和 HTTP 請求批量 1000 個 cid 就會產(chǎn)生 1000 個請求。正確做法是讓接口一次提交多 cid 到批量端點。public function sendBatch($cidList, $title, $content) { $token $this-getAccessToken(); $requestId uniqid(batch_, true); $body [ request_id $requestId, audience [cid $cidList], push_message [ notification [ title $title, body $content ] ], push_channel [ android [ups [notification [title $title, body $content]]], ios [apns [aps [alert [title $title, body $content]]]] ] ]; return $this-httpPostWithToken($this-baseUrl . / . $this-appId . /push/list/cid, $body, $token); }批量推送的返回結(jié)構(gòu)與單推一致都會返回 taskId但離線推送狀態(tài)還要等廠商回執(zhí)。批量接口一次提交的 cid 數(shù)量有上限控制我習(xí)慣每 500 個 cid 拆成一批避免單次請求體過大。拆批邏輯放在控制器層批量任務(wù)入口負(fù)責(zé)切分循環(huán)調(diào)用 sendBatch。透傳消息和通知消息的最大區(qū)別是沒有 notification 字段客戶端收到 message 后不展示系統(tǒng)通知而是直接把 payload 傳給 uniPush 回調(diào)。場景是 App 靜默更新緩存、刷新數(shù)據(jù)、狀態(tài)同步。發(fā)送方式和單推相同端點只是 push_message 里只放 transmission 字段。$body [ request_id uniqid(trans_, true), audience [cid [$cid]], push_message [ transmission json_encode($payload, JSON_UNESCAPED_UNICODE) ], push_channel [ android [ups [transmission json_encode($payload, JSON_UNESCAPED_UNICODE)]], ios [apns [aps [content-available 1]]] ] ];透傳在 iOS 端要注意content-available 設(shè)為 1 表示后臺靜默推送這種推送不一定每次都會喚醒 App蘋果對靜默推送有頻率限制。不要把關(guān)鍵業(yè)務(wù)數(shù)據(jù)完全押在靜默推送的送達(dá)上有價值的消息仍要發(fā)通知欄消息并附加 payload。3.4 推送落庫與結(jié)果判斷前面 sendSingle 方法里調(diào)用 logPush 做了落庫這個步驟不能省。推送請求返回后先用 code 判斷接口級成功再記錄 taskId狀態(tài)置為處理中。等個推的回執(zhí)回調(diào)打過來后再更新 status 為最終狀態(tài)。private function logPush($cid, $title, $content, $payload, $result) { $data [ cid $cid, title $title, content is_array($content) ? json_encode($content) : $content, payload json_encode($payload, JSON_UNESCAPED_UNICODE), task_id isset($result[data][taskId]) ? $result[data][taskId] : , status isset($result[code]) $result[code] 0 ? 0 : 2, error_msg isset($result[msg]) ? $result[msg] : , create_time time(), update_time time() ]; \think\facade\Db::name(push_log)-insert($data); }為什么接口返回成功仍然置為“處理中”這是個推的重要特點。單推時接口返回成功表示消息已接受但送達(dá)回執(zhí)是異步的尤其離線消息要等廠商通道確認(rèn)快則秒級慢則幾分鐘。如果直接把 status 置為成功你看到的是“已發(fā)送”而不是“已收到”后面排查送達(dá)率時數(shù)據(jù)全假?;貓?zhí)接口可以單獨開發(fā)通過 push_log 里的 task_id 去匹配對應(yīng)記錄。如果 code 不為 0error_msg 里會直接給失敗原因。比較常見的是 cid 不存在、應(yīng)用被卸載、token 過期。此時狀態(tài)置為 2后續(xù)腳本可以篩出這些失敗 cid 做清理。我的習(xí)慣是每天跑一次定時任務(wù)把近七天的失敗記錄按 cid 分組確認(rèn)無效 cid 就從用戶表里解綁避免每輪推送都對著無效 cid 空打。4. 前端聯(lián)調(diào)與避坑排查cid拿不到、熄屏收不到、廠商通道限制4.1 uniapp 端 cid 獲取與上報后端準(zhǔn)備好之后前端要確保 cid 正確傳到服務(wù)端。在 uniapp 的 App 生命周期里調(diào)用 uni.getPushClientId 獲取 clientid然后 POST 到我們自己的接口。代碼不復(fù)雜但要注意調(diào)用時機。要在 manifest.json 里勾選 uniPush 并配置好相關(guān)參數(shù)后再調(diào)用獲取方法否則拿到的可能是空。async function bindPush() { const res await uni.getPushClientId(); const cid res.cid; if (cid) { uni.request({ url: https://api.yourdomain.com/api/push/bindCid, method: POST, data: { cid: cid, userId: uni.getStorageSync(userId) }, success: (resp) { console.log(cid綁定成功, resp.data); } }); } } uni.onPushMessage((res) { if (res.type click) { // 用戶點擊通知欄消息payload在這里 console.log(click payload, res.payload); } else if (res.type message) { // 在線消息或透傳消息 console.log(message, res.payload); } });bindPush 方法應(yīng)在 App 啟動時調(diào)用且 cid 可能隨登錄用戶變化所以用戶切換登錄后要重新綁定一次。這里的 bindCid 接口后端要處理“一個 userId 多個 cid”的情況因為同一個用戶可能在不同設(shè)備登錄每臺設(shè)備會生成不同 cid。簡單做法是綁定表里插入一條記錄設(shè)備下線時調(diào)用 unbind。onPushMessage 回調(diào)里的 type 很關(guān)鍵。消息退了通知欄后用戶點擊回調(diào) type 是 clickApp 在前臺收到的消息走 message。有些開發(fā)者把業(yè)務(wù)跳轉(zhuǎn)邏輯全寫在 message 分支結(jié)果點擊通知時沒有任何反應(yīng)就是因為 click 分支沒處理。4.2 熄屏收不到消息廠商通道參數(shù)與簽名這是接入過程中血淚經(jīng)驗最多的地方。App 在后臺或熄屏?xí)r系統(tǒng)會殺死應(yīng)用進程長連接斷掉個推自己的通道無法直接通信必須靠華為、小米、OPPO、vivo、魅族或蘋果 APNs 的離線通道送達(dá)。個推的 REST API V2 能不能走通廠商通道取決于你在推送平臺后臺填寫的廠商推送配置以及服務(wù)端報文里 push_channel 下的 android 或 ios 內(nèi)容是否完整。從現(xiàn)象上講同一套后端代碼App 在前臺時每次都能收到鎖屏過幾分鐘再解鎖就發(fā)現(xiàn)消息不見了。這不是代碼邏輯問題是廠商通道沒申請下來或者申請下來但簽名對不上。Android 各廠商要求 App 簽名證書 sha256 值必須在廠商推送平臺登記否則廠商服務(wù)器直接拒絕下發(fā)。你的 App 打包若使用云打包需要確認(rèn)云打包用的證書與申請廠商通道時填寫的簽名一致。很多人開發(fā)階段用調(diào)試證書申請了通道后來換成正式證書打包忘記更新廠商平臺的指紋信息測試時就會出現(xiàn)這個翻車現(xiàn)場。iOS 端呢推送走 APNs 時對證書或 token 要求更嚴(yán)格。如果收不到推送先看官方的 device token 有沒有成功傳給個推后臺再看 APNs 的 p12 證書過期沒有。證書過期不會報錯只是靜默丟棄消息后端的 taskId 顯示已發(fā)送但實際沒有送達(dá)。4.3 常見問題排查清單現(xiàn)象→原因→解決以下幾條是從調(diào)通到上線過程里最常見的坑把現(xiàn)象和根因與處理辦法按固定格式整理出來方便直接對照。現(xiàn)象一前端拿到的 cid 為空。 原因manifest.json 中 uniPush 配置沒打開或 App 端還沒觸發(fā)初始化。 解決檢查 manifest 配置確認(rèn) App 端使用 apk 包調(diào)試而不是 HBuilderX 模擬器預(yù)覽重新打包后再調(diào)用 getPushClientId。現(xiàn)象二推送接口返回 code 為 0但手機收不到任何消息。 原因應(yīng)用殺進程后離線廠商通道配置缺失或簽名指紋不匹配。 解決先讓 App 處于前臺測試一次能收到說明在線通道正常再鎖屏測試仍能收到則回到廠商通道配置排查?,F(xiàn)象三Android 8.0 以上設(shè)備收不到通知但低版本手機正常。 原因Android 8.0 開始通知必須有 channelId個推在部分廠商通道需要指定 notification channel否則系統(tǒng)直接丟棄。 解決在推送報文的 android.ups.notification 里增加 channel_id 字段并在 App 端提前創(chuàng)建同名的通知渠道?,F(xiàn)象四同一臺設(shè)備登錄兩個賬號后推送綁到舊賬號。 原因cid 是設(shè)備維度賬號切換時沒有重新走 bindCid 邏輯。 解決切換登錄后前端主動調(diào)用 bindCid把新的 userId 重新綁定到同一 cid后端綁定表采用 userIdcid 聯(lián)合更新。現(xiàn)象五點擊通知沒有觸發(fā)回調(diào)App 只是被打開。 原因payload 沒有放在 click_type 對應(yīng)的字段里或 Android 廠商通道用了你自己的廣告跳轉(zhuǎn)。 解決確認(rèn)通知里 click_type 為 payloadpayload 為 JSON 字符串并在 onPushMessage 的 click 分支解析不要寫在 message 分支里。注意真正排查“送達(dá)率”問題后端 taskId 只是入口回執(zhí)回調(diào)才是出口。只盯發(fā)送成功會漏掉一半問題。5. 把推送測試變成自動化CLI命令與回執(zhí)核對習(xí)慣推送接口在開發(fā)期調(diào)試時最忌諱在 uniapp 頁面里寫一個按鈕去觸發(fā)送推送。前端剛跑起來就要啟動模擬器、登錄、綁定 cid麻煩且容易誤導(dǎo)。正確做法是在 ThinkPHP 里寫一個命令行指令直接傳 cid、標(biāo)題、內(nèi)容觸發(fā)推送服務(wù)這樣每次聯(lián)調(diào)只需一行命令。?php namespace app\command; use app\common\service\PushService; use think\console\Command; use think\console\Input; use think\console\Output; use think\console\input\Option; class PushTest extends Command { protected function configure() { $this-setName(push:test) -addOption(cid, null, Option::VALUE_REQUIRED, 設(shè)備cid) -addOption(title, null, Option::VALUE_REQUIRED, 通知標(biāo)題) -addOption(body, null, Option::VALUE_OPTIONAL, 通知內(nèi)容, test); } protected function execute(Input $input, Output $output) { $cid $input-getOption(cid); $title $input-getOption(title); $body $input-getOption(body); $pushService new PushService(); $result $pushService-sendSingle($cid, $title, $body, [page /pages/index/index]); $output-writeln(推送返回 . json_encode($result, JSON_UNESCAPED_UNICODE)); } }這個命令的方便之處在于不依賴任何登錄態(tài)拿到一個真實設(shè)備 cid 就能即刻驗證后端改動。推送結(jié)果直接顯示在終端里返回的 taskId 可以復(fù)制到推送平臺后臺的任務(wù)列表里查詢送達(dá)狀態(tài)。我平時調(diào)廠商通道參數(shù)就是靠它改一次報文跑一次命令省掉前端打點的時間。驗證“是否真的送達(dá)”還有一個習(xí)慣不要在收到 code 為 0 后就開始改下一個需求。等推送返回后我會等十秒再掃一遍 push_log主動查一下回執(zhí)狀態(tài)。如果回執(zhí)狀態(tài)遲遲不更新就去后臺看 taskId 的詳情確認(rèn)是卡在廠商通道還是已經(jīng)確認(rèn)送達(dá)。這種看起來很麻煩的流程其實能救你于上線第二天的“推送失靈”事故。從那以后我每次接入新版本 SDK 或換打包證書都會強制走一遍這個命令測試再重查一次回執(zhí)確認(rèn)回執(zhí)狀態(tài)里展示的是廠商通道的成功回執(zhí)才敢把改動提交。希望這套鏈路和排查思路幫到你。本文還有配套的精品資源點擊獲取