dootask/app/Services/DooPushClient.php
kuaifan 9151939ba5 feat(push): 移动端推送从友盟替换为 DooPush 通道
新移动端 (Expo App) 使用 doopush-react-native-sdk 完成设备注册;服务端
按 userid 标签 OR 并集定向推送,替代原友盟 alias 链路。

- 新增 app/Services/DooPushClient.php:DooPush 服务端 HTTP 客户端
  POST /apps/{appId}/push(按 tags 定向)
  POST /apps/{appId}/device-tags/{deviceToken}(绑定 userid 标签)
  DELETE 同上(解绑)
  X-API-Key 鉴权
- 新增 app/Module/Push/PushService.php:推送业务编排
  按 badge(未读数)分组合并下发,减少 HTTP 次数
- 新增 app/Http/Controllers/Api/PushController.php:设备注册/解绑接口
  api/push/register、api/push/unregister
- 修改 app/Models/UmengAlias.php:pushMsgToUserid 入口在
  DooPushClient::enabled() 时委托新通道,否则保留旧友盟链路
- 修改 config/dootask.php:新增 doopush 段(appId/apiKey/baseURL/tag_name)
- 修改 routes/web.php:注册 api/push/{method} 路由
- 同步 routes/api-map.md(doc:api-map 自动生成)

旧 EEUI App 推送链路完全不动;新 App 通过 .env 的 DOOPUSH_ENABLED=yes 启用。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-17 06:55:07 +00:00

113 lines
3.6 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Services;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
/**
* DooPush 服务端 HTTP 客户端封装:
*
* - 发推送POST /apps/{appId}/push
* - 设设备标签POST /apps/{appId}/device-tags/{deviceToken}
* - 删设备标签DELETE /apps/{appId}/device-tags/{deviceToken}/{tagName}
*
* 鉴权使用 X-API-KeyDooPush 文档推荐 Header 方式)。
* 配置来源config('dootask.doopush')。未启用或未配置时由调用方判断;本类不做静默降级。
*/
class DooPushClient
{
public static function enabled(): bool
{
$cfg = (array) config('dootask.doopush', []);
return ($cfg['enabled'] ?? false)
&& !empty($cfg['app_id'])
&& !empty($cfg['api_key']);
}
/**
* 推送给若干 userid按 userid 标签 OR 并集定向)。
*
* @param array<int> $userids
* @param array{title:string, body?:string, badge?:int, extra?:array} $msg
*/
public static function pushToUserids(array $userids, array $msg, ?string $platform = null): Response
{
$cfg = (array) config('dootask.doopush', []);
$tagName = (string) ($cfg['tag_name'] ?? 'userid');
$tags = [];
foreach (array_unique($userids) as $uid) {
$tags[] = ['tag_name' => $tagName, 'tag_value' => (string) $uid];
}
$target = ['type' => 'tags', 'tags' => $tags];
if ($platform !== null) {
$target['platform'] = $platform;
}
$payload = [
'title' => (string) ($msg['title'] ?? ''),
'content' => (string) ($msg['body'] ?? ''),
'target' => $target,
];
if (isset($msg['badge'])) {
$payload['badge'] = (int) $msg['badge'];
}
// 自定义载荷:保留 extra 中的 dialog_id / msg_id 等点击跳转字段
$extra = (array) ($msg['extra'] ?? []);
if (!empty($extra)) {
$payload['payload'] = [
'action' => 'open_dialog',
'data' => json_encode($extra, JSON_UNESCAPED_UNICODE),
];
}
return self::http()->post(self::url('/push'), $payload);
}
/**
* 给指定设备 token 绑定 userid 标签App SDK 注册后由客户端→DooTask 后端→本接口完成)。
*/
public static function setUserTag(string $deviceToken, int $userid): Response
{
$cfg = (array) config('dootask.doopush', []);
$tagName = (string) ($cfg['tag_name'] ?? 'userid');
return self::http()->post(self::url("/device-tags/{$deviceToken}"), [
'tag_name' => $tagName,
'tag_value' => (string) $userid,
]);
}
/**
* 解除设备的 userid 标签(用户登出/换号时调用)。
*/
public static function unsetUserTag(string $deviceToken): Response
{
$cfg = (array) config('dootask.doopush', []);
$tagName = (string) ($cfg['tag_name'] ?? 'userid');
return self::http()->delete(self::url("/device-tags/{$deviceToken}/{$tagName}"));
}
private static function http()
{
$cfg = (array) config('dootask.doopush', []);
return Http::withHeaders([
'X-API-Key' => (string) ($cfg['api_key'] ?? ''),
'Content-Type' => 'application/json',
])->timeout(10);
}
private static function url(string $path): string
{
$cfg = (array) config('dootask.doopush', []);
$baseUrl = rtrim((string) ($cfg['base_url'] ?? 'https://doopush.com/api/v1'), '/');
$appId = (string) ($cfg['app_id'] ?? '');
return $baseUrl . '/apps/' . $appId . $path;
}
}