Some checks failed
SDK CI / python-compile (push) Has been cancelled
- 新增 sdk/app/agent(Hook/Skills/Anti-ban 等)及 NAS/ADB 脚本 - 更新 Android 端、unified、PHP SDK、Docker Compose - Soul 文档迁移至 Soul调研/;移除资料目录内 APK - .gitignore 排除 sdk/tmp、sdk/logs、sdk/tmp_rom Co-authored-by: Cursor <cursoragent@cursor.com>
1144 lines
31 KiB
PHP
1144 lines
31 KiB
PHP
<?php
|
||
/**
|
||
* 工作手机SDK v3.0 - PHP客户端
|
||
*
|
||
* 存客宝后端直接使用此类调用SDK
|
||
*
|
||
* 功能模块:
|
||
* 1. 消息管理 - 发送/获取消息、批量发送
|
||
* 2. 好友管理 - 添加/通过好友、设置备注、删除好友
|
||
* 3. 群聊管理 - 创建群/邀请入群/群发消息/设置群欢迎语
|
||
* 4. 标签管理 - 添加/删除/查询标签
|
||
* 5. 朋友圈管理 - 发布/点赞/评论
|
||
* 6. 设备管理 - 获取设备列表/截图/控制
|
||
* 7. AI Agent - 自然语言任务执行
|
||
*
|
||
* @author 卡若
|
||
* @version 3.0.0
|
||
*
|
||
* @example
|
||
* // 初始化
|
||
* $sdk = new WorkPhoneClient('https://workphone.example.com', 'your-api-key');
|
||
*
|
||
* // 发送微信消息
|
||
* $result = $sdk->sendMessage('device-001', 'wechat', '张三', '你好!');
|
||
*
|
||
* // AI Agent模式
|
||
* $result = $sdk->executeTask('device-001', '打开微信给张三发消息:下午开会');
|
||
*/
|
||
|
||
namespace Cunkebao\WorkPhone;
|
||
|
||
class WorkPhoneClient
|
||
{
|
||
/** @var string SDK服务器地址 */
|
||
private string $baseUrl;
|
||
|
||
/** @var string API密钥 */
|
||
private string $apiKey;
|
||
|
||
/** @var int 超时时间(秒) */
|
||
private int $timeout;
|
||
|
||
/** @var bool 是否开启调试日志 */
|
||
private bool $debug = false;
|
||
|
||
/**
|
||
* 构造函数
|
||
*
|
||
* @param string $baseUrl SDK服务器地址
|
||
* @param string $apiKey API密钥
|
||
* @param int $timeout 超时时间(秒)
|
||
*/
|
||
public function __construct(string $baseUrl, string $apiKey, int $timeout = 30)
|
||
{
|
||
$this->baseUrl = rtrim($baseUrl, '/');
|
||
$this->apiKey = $apiKey;
|
||
$this->timeout = $timeout;
|
||
}
|
||
|
||
/**
|
||
* 开启/关闭调试模式
|
||
*/
|
||
public function setDebug(bool $debug): self
|
||
{
|
||
$this->debug = $debug;
|
||
return $this;
|
||
}
|
||
|
||
// ==========================================================================
|
||
// 一、消息管理接口
|
||
// ==========================================================================
|
||
|
||
/**
|
||
* 发送消息(统一接口,默认走 Frida Hook 主控通道,失败自动降级 SDK/ADB)
|
||
*
|
||
* channel 取值(与 sdk/app/routers/unified.py Channel 枚举一致):
|
||
* - hook : Frida Hook(推荐 / 默认)
|
||
* - sdk_control : ADB / WebSocket Agent UI 自动化
|
||
* - ai_agent : AI 自然语言任务
|
||
* - official_api : 官方开放平台 API
|
||
*
|
||
* @param string $deviceId
|
||
* @param string $platform wechat/douyin/xhs/xianyu
|
||
* @param string $toId
|
||
* @param string $content
|
||
* @param string $msgType text/image/video
|
||
* @param string|null $mediaUrl
|
||
* @param array|null $atList
|
||
* @param int|null $timeoutSeconds
|
||
* @param string $channel 强制通道,默认 hook
|
||
* @param array|null $hookConfig Hook 配置:['script_id'=>..., 'method'=>...]
|
||
* @return array
|
||
*/
|
||
public function sendMessage(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $toId,
|
||
string $content,
|
||
string $msgType = 'text',
|
||
?string $mediaUrl = null,
|
||
?array $atList = null,
|
||
?int $timeoutSeconds = null,
|
||
string $channel = 'hook',
|
||
?array $hookConfig = null
|
||
): array {
|
||
$body = [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'to_id' => $toId,
|
||
'content' => $content,
|
||
'msg_type' => $msgType,
|
||
'media_url' => $mediaUrl,
|
||
'channel' => $channel,
|
||
];
|
||
if ($atList !== null) {
|
||
$body['at_list'] = $atList;
|
||
}
|
||
if ($timeoutSeconds !== null) {
|
||
$body['timeout_seconds'] = $timeoutSeconds;
|
||
}
|
||
if ($hookConfig !== null) {
|
||
$body['hook_config'] = $hookConfig;
|
||
}
|
||
return $this->post('/api/v3/message/send', $body);
|
||
}
|
||
|
||
// ==========================================================================
|
||
// 〇、Frida Hook 直控接口(存客宝主用:channel=hook 单端点驱动 110 RPC / 24 模块)
|
||
// ==========================================================================
|
||
|
||
/**
|
||
* Frida Hook 探测 — 服务端附着微信进程并 ping,结果写入 device_modules
|
||
* 对应:GET /api/v3/hook/probe/{device_id}
|
||
*/
|
||
public function hookProbe(string $deviceId): array
|
||
{
|
||
return $this->get("/api/v3/hook/probe/{$deviceId}");
|
||
}
|
||
|
||
/**
|
||
* Frida Hook 一次取数 — profile/contacts/groups/messages/labels/moments…
|
||
* 对应:GET /api/v3/hook/data/{device_id}?modules=...
|
||
*/
|
||
public function hookData(
|
||
string $deviceId,
|
||
array $modules = ['profile', 'contacts', 'groups', 'messages', 'labels']
|
||
): array {
|
||
return $this->get("/api/v3/hook/data/{$deviceId}", [
|
||
'modules' => implode(',', $modules),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Frida Hook 通用执行 — 单端点驱动 110 个 RPC 操作
|
||
* 对应:POST /api/v3/hook/execute
|
||
*
|
||
* @param string $deviceId 设备序列号 / device_id
|
||
* @param string $platform 'wechat'
|
||
* @param string $action 动作名(与 hook_executor.py ACTION_TO_RPC 一致)
|
||
* @param array $params 动作参数
|
||
* @param bool $hookOnly true=仅 Frida Hook,失败不降级;false=失败降级 ADB
|
||
*/
|
||
public function hookExecute(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $action,
|
||
array $params = [],
|
||
bool $hookOnly = true
|
||
): array {
|
||
return $this->post('/api/v3/hook/execute', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'action' => $action,
|
||
'params' => $params,
|
||
'hook_only' => $hookOnly,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Frida Hook 全部支持动作清单 — 24 模块 / 110 操作
|
||
* 对应:GET /api/v3/hook/actions
|
||
*/
|
||
public function hookActions(): array
|
||
{
|
||
return $this->get('/api/v3/hook/actions');
|
||
}
|
||
|
||
// —— Frida Hook 快捷调用(存客宝调用示例)——
|
||
|
||
/**
|
||
* 通过 Frida Hook 直控发微信消息(不干扰屏幕,最稳定)
|
||
*/
|
||
public function wechatSendByHook(
|
||
string $deviceId,
|
||
string $toIdOrName,
|
||
string $content
|
||
): array {
|
||
return $this->hookExecute($deviceId, 'wechat', 'send_message', [
|
||
'to_id' => $toIdOrName,
|
||
'content' => $content,
|
||
'msg_type' => 'text',
|
||
], true);
|
||
}
|
||
|
||
/**
|
||
* 通过 Frida Hook 直读联系人(零打扰,不滚动 UI)
|
||
*/
|
||
public function wechatGetContactsByHook(string $deviceId, int $limit = 200): array
|
||
{
|
||
return $this->hookExecute($deviceId, 'wechat', 'get_contacts', ['limit' => $limit], true);
|
||
}
|
||
|
||
/**
|
||
* 获取消息列表
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $platform 平台
|
||
* @param int $limit 数量限制
|
||
* @param string|null $conversationId 会话ID
|
||
* @param int|null $sinceTime 时间戳,只取该时间之后的消息
|
||
* @return array
|
||
*/
|
||
public function getMessages(
|
||
string $deviceId,
|
||
string $platform,
|
||
int $limit = 20,
|
||
?string $conversationId = null,
|
||
?int $sinceTime = null
|
||
): array {
|
||
$body = [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'limit' => $limit,
|
||
'conversation_id' => $conversationId,
|
||
];
|
||
if ($sinceTime !== null) {
|
||
$body['since_time'] = $sinceTime;
|
||
}
|
||
return $this->post('/api/v3/message/list', $body);
|
||
}
|
||
|
||
/**
|
||
* 回复评论(抖音/小红书等)
|
||
*/
|
||
public function replyComment(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $commentId,
|
||
string $content,
|
||
?string $videoId = null
|
||
): array {
|
||
return $this->post('/api/v3/comment/reply', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'comment_id' => $commentId,
|
||
'content' => $content,
|
||
'video_id' => $videoId,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 添加好友
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $platform 平台
|
||
* @param string $userId 用户ID
|
||
* @param string $message 验证消息
|
||
* @return array
|
||
*/
|
||
public function addFriend(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $userId,
|
||
string $message = ''
|
||
): array {
|
||
return $this->post('/api/v3/friend/add', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'user_id' => $userId,
|
||
'message' => $message,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 通过好友请求
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $platform 平台
|
||
* @param string $userId 用户ID
|
||
* @return array
|
||
*/
|
||
public function acceptFriend(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $userId
|
||
): array {
|
||
return $this->post('/api/v3/friend/accept', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'user_id' => $userId,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取联系人列表
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $platform 平台
|
||
* @param int $limit 数量限制
|
||
* @return array
|
||
*/
|
||
public function getContacts(
|
||
string $deviceId,
|
||
string $platform,
|
||
int $limit = 100
|
||
): array {
|
||
return $this->get('/api/v3/contacts', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'limit' => $limit,
|
||
]);
|
||
}
|
||
|
||
// ========== AI Agent接口 ==========
|
||
|
||
/**
|
||
* 执行自然语言任务(AI Agent模式)
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $task 任务描述
|
||
* @param string $llmProvider LLM提供商:deepseek/openai
|
||
* @param int $maxSteps 最大步数
|
||
* @return array
|
||
*/
|
||
public function executeTask(
|
||
string $deviceId,
|
||
string $task,
|
||
string $llmProvider = 'deepseek',
|
||
int $maxSteps = 30
|
||
): array {
|
||
return $this->post('/api/v3/agent/execute', [
|
||
'device_id' => $deviceId,
|
||
'task' => $task,
|
||
'llm_provider' => $llmProvider,
|
||
'max_steps' => $maxSteps,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取Agent状态
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @return array
|
||
*/
|
||
public function getAgentStatus(string $deviceId): array
|
||
{
|
||
return $this->get("/api/v3/agent/status/{$deviceId}");
|
||
}
|
||
|
||
/**
|
||
* 停止Agent任务
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @return array
|
||
*/
|
||
public function stopAgent(string $deviceId): array
|
||
{
|
||
return $this->post("/api/v3/agent/stop/{$deviceId}");
|
||
}
|
||
|
||
// ========== 设备管理接口 ==========
|
||
|
||
/**
|
||
* 获取设备列表
|
||
*
|
||
* @return array
|
||
*/
|
||
public function getDevices(): array
|
||
{
|
||
return $this->get('/api/v3/devices');
|
||
}
|
||
|
||
/**
|
||
* 获取设备详情
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @return array
|
||
*/
|
||
public function getDevice(string $deviceId): array
|
||
{
|
||
return $this->get("/api/v3/devices/{$deviceId}");
|
||
}
|
||
|
||
/**
|
||
* 设备截图
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @return array
|
||
*/
|
||
public function screenshot(string $deviceId): array
|
||
{
|
||
return $this->post("/api/v3/devices/{$deviceId}/screenshot");
|
||
}
|
||
|
||
/**
|
||
* 获取UI树
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @return array
|
||
*/
|
||
public function getUiTree(string $deviceId): array
|
||
{
|
||
return $this->get("/api/v3/devices/{$deviceId}/ui-tree");
|
||
}
|
||
|
||
// ========== 底层控制接口 ==========
|
||
|
||
/**
|
||
* 点击坐标
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param int $x X坐标
|
||
* @param int $y Y坐标
|
||
* @return array
|
||
*/
|
||
public function click(string $deviceId, int $x, int $y): array
|
||
{
|
||
return $this->post("/api/v3/devices/{$deviceId}/click", [
|
||
'x' => $x,
|
||
'y' => $y,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 点击文字
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $text 文字内容
|
||
* @param int $timeout 超时时间
|
||
* @return array
|
||
*/
|
||
public function clickText(string $deviceId, string $text, int $timeout = 10): array
|
||
{
|
||
return $this->post("/api/v3/devices/{$deviceId}/click-text", [
|
||
'text' => $text,
|
||
'timeout' => $timeout,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 输入文字
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $text 文字内容
|
||
* @param bool $clear 是否清空
|
||
* @return array
|
||
*/
|
||
public function input(string $deviceId, string $text, bool $clear = true): array
|
||
{
|
||
return $this->post("/api/v3/devices/{$deviceId}/input", [
|
||
'text' => $text,
|
||
'clear' => $clear,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 滑动
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $direction 方向:up/down/left/right
|
||
* @param float $scale 幅度
|
||
* @return array
|
||
*/
|
||
public function swipe(string $deviceId, string $direction, float $scale = 0.8): array
|
||
{
|
||
return $this->post("/api/v3/devices/{$deviceId}/swipe", [
|
||
'direction' => $direction,
|
||
'scale' => $scale,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 执行脚本
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $script 脚本名称
|
||
* @param string $action 动作名称
|
||
* @param array $params 参数
|
||
* @param int $timeout 超时时间
|
||
* @return array
|
||
*/
|
||
public function execute(
|
||
string $deviceId,
|
||
string $script,
|
||
string $action,
|
||
array $params = [],
|
||
int $timeout = 30
|
||
): array {
|
||
return $this->post("/api/v3/devices/{$deviceId}/execute", [
|
||
'script' => $script,
|
||
'action' => $action,
|
||
'params' => $params,
|
||
'timeout' => $timeout,
|
||
]);
|
||
}
|
||
|
||
// ==========================================================================
|
||
// 三、群聊管理接口
|
||
// ==========================================================================
|
||
|
||
/**
|
||
* 创建群聊
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $platform 平台
|
||
* @param string $groupName 群名
|
||
* @param array $memberIds 成员ID列表
|
||
* @return array
|
||
*/
|
||
public function createGroup(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $groupName,
|
||
array $memberIds
|
||
): array {
|
||
return $this->post('/api/v3/group/create', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'group_name' => $groupName,
|
||
'member_ids' => $memberIds,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 邀请入群
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $platform 平台
|
||
* @param string $groupId 群ID或群名
|
||
* @param array $memberIds 邀请的成员ID
|
||
* @return array
|
||
*/
|
||
public function inviteToGroup(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $groupId,
|
||
array $memberIds
|
||
): array {
|
||
return $this->post('/api/v3/group/invite', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'group_id' => $groupId,
|
||
'member_ids' => $memberIds,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 移出群聊
|
||
*/
|
||
public function removeFromGroup(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $groupId,
|
||
array $memberIds
|
||
): array {
|
||
return $this->post('/api/v3/group/remove', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'group_id' => $groupId,
|
||
'member_ids' => $memberIds,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 设置群公告
|
||
*/
|
||
public function setGroupNotice(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $groupId,
|
||
string $notice
|
||
): array {
|
||
return $this->post('/api/v3/group/set-notice', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'group_id' => $groupId,
|
||
'notice' => $notice,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 设置群名
|
||
*/
|
||
public function setGroupName(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $groupId,
|
||
string $groupName
|
||
): array {
|
||
return $this->post('/api/v3/group/set-name', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'group_id' => $groupId,
|
||
'group_name' => $groupName,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 发送群消息
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $platform 平台
|
||
* @param string $groupId 群ID
|
||
* @param string $content 消息内容
|
||
* @param string $msgType 消息类型
|
||
* @param bool $atAll 是否@所有人
|
||
* @param array|null $atList @列表
|
||
* @return array
|
||
*/
|
||
public function sendGroupMessage(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $groupId,
|
||
string $content,
|
||
string $msgType = 'text',
|
||
bool $atAll = false,
|
||
?array $atList = null
|
||
): array {
|
||
return $this->post('/api/v3/group/send-message', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'group_id' => $groupId,
|
||
'content' => $content,
|
||
'msg_type' => $msgType,
|
||
'at_all' => $atAll,
|
||
'at_list' => $atList,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 设置群欢迎语
|
||
*/
|
||
public function setGroupWelcome(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $groupId,
|
||
string $welcomeText,
|
||
?string $welcomeImage = null
|
||
): array {
|
||
return $this->post('/api/v3/group/set-welcome', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'group_id' => $groupId,
|
||
'welcome_text' => $welcomeText,
|
||
'welcome_image' => $welcomeImage,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取群聊列表
|
||
*/
|
||
public function getGroups(string $deviceId, string $platform, int $limit = 100): array
|
||
{
|
||
return $this->get('/api/v3/group/list', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'limit' => $limit,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取群成员列表
|
||
*/
|
||
public function getGroupMembers(string $deviceId, string $platform, string $groupId): array
|
||
{
|
||
return $this->get('/api/v3/group/members', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'group_id' => $groupId,
|
||
]);
|
||
}
|
||
|
||
// ==========================================================================
|
||
// 四、标签管理接口
|
||
// ==========================================================================
|
||
|
||
/**
|
||
* 给好友添加标签
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $platform 平台
|
||
* @param string $userId 用户ID
|
||
* @param array $tags 标签列表
|
||
* @return array
|
||
*/
|
||
public function addTag(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $userId,
|
||
array $tags
|
||
): array {
|
||
return $this->post('/api/v3/tag/add', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'user_id' => $userId,
|
||
'tags' => $tags,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 移除好友标签
|
||
*/
|
||
public function removeTag(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $userId,
|
||
array $tags
|
||
): array {
|
||
return $this->post('/api/v3/tag/remove', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'user_id' => $userId,
|
||
'tags' => $tags,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 创建标签
|
||
*/
|
||
public function createTag(string $deviceId, string $platform, string $tagName): array
|
||
{
|
||
return $this->post('/api/v3/tag/create', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'tag_name' => $tagName,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 删除标签
|
||
*/
|
||
public function deleteTag(string $deviceId, string $platform, string $tagName): array
|
||
{
|
||
return $this->post('/api/v3/tag/delete', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'tag_name' => $tagName,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取标签列表
|
||
*/
|
||
public function getTags(string $deviceId, string $platform): array
|
||
{
|
||
return $this->get('/api/v3/tag/list', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 根据标签获取好友列表
|
||
*/
|
||
public function getUsersByTag(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $tagName,
|
||
int $limit = 100
|
||
): array {
|
||
return $this->post('/api/v3/tag/users', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'tag_name' => $tagName,
|
||
'limit' => $limit,
|
||
]);
|
||
}
|
||
|
||
// ==========================================================================
|
||
// 五、朋友圈管理接口
|
||
// ==========================================================================
|
||
|
||
/**
|
||
* 发布朋友圈
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $platform 平台
|
||
* @param string $content 内容
|
||
* @param array|null $images 图片URL列表
|
||
* @param string|null $videoUrl 视频URL
|
||
* @param string|null $location 位置
|
||
* @param array|null $visibleList 可见名单
|
||
* @param array|null $invisibleList 不可见名单
|
||
* @return array
|
||
*/
|
||
public function postMoments(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $content,
|
||
?array $images = null,
|
||
?string $videoUrl = null,
|
||
?string $location = null,
|
||
?array $visibleList = null,
|
||
?array $invisibleList = null
|
||
): array {
|
||
return $this->post('/api/v3/moments/post', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'content' => $content,
|
||
'images' => $images,
|
||
'video_url' => $videoUrl,
|
||
'location' => $location,
|
||
'visible_list' => $visibleList,
|
||
'invisible_list' => $invisibleList,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 点赞朋友圈
|
||
*/
|
||
public function likeMoments(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $userId,
|
||
int $postIndex = 0
|
||
): array {
|
||
return $this->post('/api/v3/moments/like', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'user_id' => $userId,
|
||
'post_index' => $postIndex,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 评论朋友圈
|
||
*/
|
||
public function commentMoments(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $userId,
|
||
string $comment,
|
||
int $postIndex = 0,
|
||
?string $replyTo = null
|
||
): array {
|
||
return $this->post('/api/v3/moments/comment', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'user_id' => $userId,
|
||
'post_index' => $postIndex,
|
||
'comment' => $comment,
|
||
'reply_to' => $replyTo,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取朋友圈列表
|
||
*/
|
||
public function getMoments(
|
||
string $deviceId,
|
||
string $platform,
|
||
?string $userId = null,
|
||
int $limit = 10
|
||
): array {
|
||
return $this->post('/api/v3/moments/list', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'user_id' => $userId,
|
||
'limit' => $limit,
|
||
]);
|
||
}
|
||
|
||
// ==========================================================================
|
||
// 六、批量操作接口
|
||
// ==========================================================================
|
||
|
||
/**
|
||
* 批量发送消息
|
||
*
|
||
* @param string $deviceId 设备ID
|
||
* @param string $platform 平台
|
||
* @param array $toIds 接收者ID列表
|
||
* @param string $content 消息内容
|
||
* @param string $msgType 消息类型
|
||
* @param float $interval 发送间隔(秒)
|
||
* @return array
|
||
*/
|
||
public function batchSendMessage(
|
||
string $deviceId,
|
||
string $platform,
|
||
array $toIds,
|
||
string $content,
|
||
string $msgType = 'text',
|
||
float $interval = 2.0
|
||
): array {
|
||
return $this->post('/api/v3/message/batch-send', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'to_ids' => $toIds,
|
||
'content' => $content,
|
||
'msg_type' => $msgType,
|
||
'interval' => $interval,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 批量添加好友
|
||
*/
|
||
public function batchAddFriend(
|
||
string $deviceId,
|
||
string $platform,
|
||
array $userIds,
|
||
string $message = '',
|
||
float $interval = 5.0
|
||
): array {
|
||
return $this->post('/api/v3/friend/batch-add', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'user_ids' => $userIds,
|
||
'message' => $message,
|
||
'interval' => $interval,
|
||
]);
|
||
}
|
||
|
||
// ==========================================================================
|
||
// 七、好友管理扩展接口
|
||
// ==========================================================================
|
||
|
||
/**
|
||
* 设置好友备注
|
||
*/
|
||
public function setFriendRemark(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $userId,
|
||
string $remark
|
||
): array {
|
||
return $this->post('/api/v3/friend/set-remark', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'user_id' => $userId,
|
||
'remark' => $remark,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 删除好友
|
||
*/
|
||
public function deleteFriend(
|
||
string $deviceId,
|
||
string $platform,
|
||
string $userId
|
||
): array {
|
||
return $this->post('/api/v3/friend/delete', [
|
||
'device_id' => $deviceId,
|
||
'platform' => $platform,
|
||
'user_id' => $userId,
|
||
]);
|
||
}
|
||
|
||
// ==========================================================================
|
||
// 八、快捷方法
|
||
// ==========================================================================
|
||
|
||
/**
|
||
* 发送微信消息
|
||
*/
|
||
public function wechatSend(string $deviceId, string $wxid, string $content): array
|
||
{
|
||
return $this->sendMessage($deviceId, 'wechat', $wxid, $content);
|
||
}
|
||
|
||
/**
|
||
* 发送抖音私信
|
||
*/
|
||
public function douyinSend(string $deviceId, string $uid, string $content): array
|
||
{
|
||
return $this->sendMessage($deviceId, 'douyin', $uid, $content);
|
||
}
|
||
|
||
/**
|
||
* 发送小红书私信
|
||
*/
|
||
public function xhsSend(string $deviceId, string $uid, string $content): array
|
||
{
|
||
return $this->sendMessage($deviceId, 'xhs', $uid, $content);
|
||
}
|
||
|
||
/**
|
||
* 发送闲鱼消息
|
||
*/
|
||
public function xianyuSend(string $deviceId, string $uid, string $content): array
|
||
{
|
||
return $this->sendMessage($deviceId, 'xianyu', $uid, $content);
|
||
}
|
||
|
||
/**
|
||
* 发送Soul消息
|
||
*/
|
||
public function soulSend(string $deviceId, string $uid, string $content): array
|
||
{
|
||
return $this->sendMessage($deviceId, 'soul', $uid, $content);
|
||
}
|
||
|
||
/**
|
||
* 微信创建群聊
|
||
*/
|
||
public function wechatCreateGroup(string $deviceId, string $groupName, array $memberIds): array
|
||
{
|
||
return $this->createGroup($deviceId, 'wechat', $groupName, $memberIds);
|
||
}
|
||
|
||
/**
|
||
* 微信发送群消息
|
||
*/
|
||
public function wechatGroupSend(string $deviceId, string $groupId, string $content, bool $atAll = false): array
|
||
{
|
||
return $this->sendGroupMessage($deviceId, 'wechat', $groupId, $content, 'text', $atAll);
|
||
}
|
||
|
||
/**
|
||
* 微信添加标签
|
||
*/
|
||
public function wechatAddTag(string $deviceId, string $userId, array $tags): array
|
||
{
|
||
return $this->addTag($deviceId, 'wechat', $userId, $tags);
|
||
}
|
||
|
||
/**
|
||
* 微信发朋友圈
|
||
*/
|
||
public function wechatPostMoments(string $deviceId, string $content, ?array $images = null): array
|
||
{
|
||
return $this->postMoments($deviceId, 'wechat', $content, $images);
|
||
}
|
||
|
||
/**
|
||
* 检查设备是否在线
|
||
*/
|
||
public function isOnline(string $deviceId): bool
|
||
{
|
||
$result = $this->getDevice($deviceId);
|
||
return ($result['code'] ?? 0) === 200 && ($result['data']['status'] ?? '') === 'online';
|
||
}
|
||
|
||
/**
|
||
* 获取在线设备列表
|
||
*/
|
||
public function getOnlineDevices(): array
|
||
{
|
||
$result = $this->getDevices();
|
||
if (($result['code'] ?? 0) !== 200) {
|
||
return [];
|
||
}
|
||
|
||
return array_filter($result['data'] ?? [], function($device) {
|
||
return ($device['status'] ?? '') === 'online';
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 健康检查
|
||
*/
|
||
public function healthCheck(): array
|
||
{
|
||
return $this->get('/health');
|
||
}
|
||
|
||
// ==========================================================================
|
||
// HTTP请求方法
|
||
// ==========================================================================
|
||
|
||
/**
|
||
* GET请求
|
||
*/
|
||
private function get(string $path, array $params = []): array
|
||
{
|
||
$url = $this->baseUrl . $path;
|
||
if ($params) {
|
||
$url .= '?' . http_build_query($params);
|
||
}
|
||
|
||
return $this->request('GET', $url);
|
||
}
|
||
|
||
/**
|
||
* POST请求
|
||
*/
|
||
private function post(string $path, array $data = []): array
|
||
{
|
||
return $this->request('POST', $this->baseUrl . $path, $data);
|
||
}
|
||
|
||
/**
|
||
* 发送HTTP请求
|
||
*/
|
||
private function request(string $method, string $url, array $data = []): array
|
||
{
|
||
$ch = curl_init();
|
||
|
||
$options = [
|
||
CURLOPT_URL => $url,
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_TIMEOUT => $this->timeout,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Content-Type: application/json',
|
||
'Authorization: Bearer ' . $this->apiKey,
|
||
],
|
||
];
|
||
|
||
if ($method === 'POST') {
|
||
$options[CURLOPT_POST] = true;
|
||
$options[CURLOPT_POSTFIELDS] = json_encode($data);
|
||
}
|
||
|
||
curl_setopt_array($ch, $options);
|
||
|
||
$response = curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
$error = curl_error($ch);
|
||
|
||
curl_close($ch);
|
||
|
||
if ($error) {
|
||
return [
|
||
'code' => 500,
|
||
'message' => 'CURL错误: ' . $error,
|
||
];
|
||
}
|
||
|
||
$result = json_decode($response, true);
|
||
|
||
if ($result === null) {
|
||
return [
|
||
'code' => 500,
|
||
'message' => '响应解析失败',
|
||
'raw' => $response,
|
||
];
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
}
|