OPPO 推送补新消息分类(channel_id/category/notify_level)
2024-11-20 后创建的 OPPO 应用发送通知必须携带 category(新规), 配置项 OPPO_PUSH_CHANNEL_ID / OPPO_PUSH_CATEGORY / OPPO_PUSH_NOTIFY_LEVEL(0=不传), 均留空时 payload 与原先完全一致。凭据已到位:荣耀/小米(含 channel 154219)/OPPO/vivo 四家配齐(.env,不入库),仅剩华为待补。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -69,6 +69,11 @@ OPPO_PUSH_APP_KEY=
|
|||||||
OPPO_PUSH_MASTER_SECRET=
|
OPPO_PUSH_MASTER_SECRET=
|
||||||
OPPO_PUSH_AUTH_ENDPOINT=https://api.push.oppomobile.com/server/v1/auth
|
OPPO_PUSH_AUTH_ENDPOINT=https://api.push.oppomobile.com/server/v1/auth
|
||||||
OPPO_PUSH_SEND_ENDPOINT=https://api.push.oppomobile.com/server/v1/message/notification/unicast
|
OPPO_PUSH_SEND_ENDPOINT=https://api.push.oppomobile.com/server/v1/message/notification/unicast
|
||||||
|
# OPPO 新消息分类(2024-11-20 后创建的应用必须携带 category;channel_id 为后台「通道ID」;
|
||||||
|
# notify_level 0=不传走默认,内容营销类仅支持 1/2)
|
||||||
|
OPPO_PUSH_CHANNEL_ID=
|
||||||
|
OPPO_PUSH_CATEGORY=
|
||||||
|
OPPO_PUSH_NOTIFY_LEVEL=0
|
||||||
|
|
||||||
# ===== 无障碍保护存活监控(推送 + pull 后置兜底)=====
|
# ===== 无障碍保护存活监控(推送 + pull 后置兜底)=====
|
||||||
HEARTBEAT_MONITOR_ENABLED=true
|
HEARTBEAT_MONITOR_ENABLED=true
|
||||||
|
|||||||
@@ -111,6 +111,12 @@ class Settings(BaseSettings):
|
|||||||
OPPO_PUSH_SEND_ENDPOINT: str = (
|
OPPO_PUSH_SEND_ENDPOINT: str = (
|
||||||
"https://api.push.oppomobile.com/server/v1/message/notification/unicast"
|
"https://api.push.oppomobile.com/server/v1/message/notification/unicast"
|
||||||
)
|
)
|
||||||
|
# OPPO 新消息分类(2024-11-20 后创建的应用必须携带,否则可能被拒/限):
|
||||||
|
# channel_id=通知栏通道(OPPO 后台「通道ID」),category=消息分类 code(如 MARKETING 内容营销)。
|
||||||
|
# notify_level=提醒方式(0=不传走 OPPO 默认;内容营销类仅支持 1 通知栏/2 通知栏+锁屏)。
|
||||||
|
OPPO_PUSH_CHANNEL_ID: str = ""
|
||||||
|
OPPO_PUSH_CATEGORY: str = ""
|
||||||
|
OPPO_PUSH_NOTIFY_LEVEL: int = 0
|
||||||
|
|
||||||
# 无障碍保护存活监控后台任务(推送 + pull 后置兜底)
|
# 无障碍保护存活监控后台任务(推送 + pull 后置兜底)
|
||||||
HEARTBEAT_MONITOR_ENABLED: bool = True # 总开关
|
HEARTBEAT_MONITOR_ENABLED: bool = True # 总开关
|
||||||
|
|||||||
@@ -484,18 +484,26 @@ def _oppo_auth_token() -> str:
|
|||||||
def _send_oppo(token: str, title: str, body: str, extras: dict[str, str]) -> dict[str, Any]:
|
def _send_oppo(token: str, title: str, body: str, extras: dict[str, str]) -> dict[str, Any]:
|
||||||
auth_token = _oppo_auth_token()
|
auth_token = _oppo_auth_token()
|
||||||
ttl_hours = max(1, min(72, settings.PUSH_TIME_TO_LIVE_SEC // 3600))
|
ttl_hours = max(1, min(72, settings.PUSH_TIME_TO_LIVE_SEC // 3600))
|
||||||
|
notification: dict[str, Any] = {
|
||||||
|
"app_message_id": f"{extras.get('type', 'notify')}_{uuid.uuid4().hex}",
|
||||||
|
"title": title,
|
||||||
|
"content": body,
|
||||||
|
"click_action_type": 0,
|
||||||
|
"off_line": True,
|
||||||
|
"off_line_ttl": ttl_hours,
|
||||||
|
"action_parameters": json.dumps(extras, ensure_ascii=False),
|
||||||
|
}
|
||||||
|
# 新消息分类(2024-11-20 后创建的 OPPO 应用必须带 category,否则可能被拒收/降级)
|
||||||
|
if settings.OPPO_PUSH_CHANNEL_ID.strip():
|
||||||
|
notification["channel_id"] = settings.OPPO_PUSH_CHANNEL_ID.strip()
|
||||||
|
if settings.OPPO_PUSH_CATEGORY.strip():
|
||||||
|
notification["category"] = settings.OPPO_PUSH_CATEGORY.strip()
|
||||||
|
if settings.OPPO_PUSH_NOTIFY_LEVEL:
|
||||||
|
notification["notify_level"] = settings.OPPO_PUSH_NOTIFY_LEVEL
|
||||||
message = {
|
message = {
|
||||||
"target_type": 2,
|
"target_type": 2,
|
||||||
"target_value": token,
|
"target_value": token,
|
||||||
"notification": {
|
"notification": notification,
|
||||||
"app_message_id": f"{extras.get('type', 'notify')}_{uuid.uuid4().hex}",
|
|
||||||
"title": title,
|
|
||||||
"content": body,
|
|
||||||
"click_action_type": 0,
|
|
||||||
"off_line": True,
|
|
||||||
"off_line_ttl": ttl_hours,
|
|
||||||
"action_parameters": json.dumps(extras, ensure_ascii=False),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
data = _request_form(
|
data = _request_form(
|
||||||
"POST",
|
"POST",
|
||||||
|
|||||||
@@ -155,6 +155,60 @@ def test_accessibility_wrapper_keeps_legacy_extras(monkeypatch) -> None:
|
|||||||
assert json.loads(captured["data"]["payload"]) == {"type": "accessibility_disabled"}
|
assert json.loads(captured["data"]["payload"]) == {"type": "accessibility_disabled"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_oppo_payload_includes_new_message_category(monkeypatch) -> None:
|
||||||
|
"""OPPO 新消息分类:配置了 channel_id/category 时随通知体下发(2024-11 新规必带)。"""
|
||||||
|
vendor_push._token_cache.clear()
|
||||||
|
calls: list[dict] = []
|
||||||
|
|
||||||
|
def _fake_request(method, url, **kwargs): # noqa: ANN001
|
||||||
|
calls.append({"method": method, "url": url, **kwargs})
|
||||||
|
if url == vendor_push.settings.OPPO_PUSH_AUTH_ENDPOINT:
|
||||||
|
return _Resp({"code": 0, "data": {"auth_token": "oppo-auth"}})
|
||||||
|
return _Resp({"code": 0, "data": {"message_id": "oppo-msg"}})
|
||||||
|
|
||||||
|
monkeypatch.setattr(vendor_push.settings, "OPPO_PUSH_APP_KEY", "oppo-key")
|
||||||
|
monkeypatch.setattr(vendor_push.settings, "OPPO_PUSH_MASTER_SECRET", "oppo-master")
|
||||||
|
monkeypatch.setattr(vendor_push.settings, "OPPO_PUSH_CHANNEL_ID", "push_oplus_category_content")
|
||||||
|
monkeypatch.setattr(vendor_push.settings, "OPPO_PUSH_CATEGORY", "MARKETING")
|
||||||
|
monkeypatch.setattr(vendor_push.settings, "OPPO_PUSH_NOTIFY_LEVEL", 0)
|
||||||
|
monkeypatch.setattr(vendor_push.httpx, "request", _fake_request)
|
||||||
|
|
||||||
|
vendor_push.send_notification(
|
||||||
|
"oppo", "oppo-regid", title="标题", body="正文", extras={"type": "push_test"}
|
||||||
|
)
|
||||||
|
|
||||||
|
notification = json.loads(calls[1]["data"]["message"])["notification"]
|
||||||
|
assert notification["channel_id"] == "push_oplus_category_content"
|
||||||
|
assert notification["category"] == "MARKETING"
|
||||||
|
assert "notify_level" not in notification # 0=不传,走 OPPO 默认
|
||||||
|
|
||||||
|
|
||||||
|
def test_oppo_payload_omits_category_when_unconfigured(monkeypatch) -> None:
|
||||||
|
vendor_push._token_cache.clear()
|
||||||
|
calls: list[dict] = []
|
||||||
|
|
||||||
|
def _fake_request(method, url, **kwargs): # noqa: ANN001
|
||||||
|
calls.append({"method": method, "url": url, **kwargs})
|
||||||
|
if url == vendor_push.settings.OPPO_PUSH_AUTH_ENDPOINT:
|
||||||
|
return _Resp({"code": 0, "data": {"auth_token": "oppo-auth"}})
|
||||||
|
return _Resp({"code": 0, "data": {"message_id": "oppo-msg"}})
|
||||||
|
|
||||||
|
monkeypatch.setattr(vendor_push.settings, "OPPO_PUSH_APP_KEY", "oppo-key")
|
||||||
|
monkeypatch.setattr(vendor_push.settings, "OPPO_PUSH_MASTER_SECRET", "oppo-master")
|
||||||
|
monkeypatch.setattr(vendor_push.settings, "OPPO_PUSH_CHANNEL_ID", "")
|
||||||
|
monkeypatch.setattr(vendor_push.settings, "OPPO_PUSH_CATEGORY", "")
|
||||||
|
monkeypatch.setattr(vendor_push.settings, "OPPO_PUSH_NOTIFY_LEVEL", 0)
|
||||||
|
monkeypatch.setattr(vendor_push.httpx, "request", _fake_request)
|
||||||
|
|
||||||
|
vendor_push.send_notification(
|
||||||
|
"oppo", "oppo-regid", title="标题", body="正文", extras={"type": "push_test"}
|
||||||
|
)
|
||||||
|
|
||||||
|
notification = json.loads(calls[1]["data"]["message"])["notification"]
|
||||||
|
assert "channel_id" not in notification
|
||||||
|
assert "category" not in notification
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# /api/v1/push 三件套
|
# /api/v1/push 三件套
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user