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}"); } /** * 获取设备 AI Brain 状态 */ public function getAIBrainStatus(string $deviceId): array { return $this->get("/api/v3/devices/{$deviceId}/ai/status"); } /** * 推送 AI 任务(排队执行) */ public function pushAITask(string $deviceId, string $instruction, int $priority = 5): array { return $this->post("/api/v3/devices/{$deviceId}/ai/task", [ 'instruction' => $instruction, 'priority' => $priority, ]); } /** * 推送 AI 常驻指令 */ public function pushAIStandingOrder(string $deviceId, string $order): array { return $this->post("/api/v3/devices/{$deviceId}/ai/standing-order", [ 'order' => $order, ]); } /** * 同步执行 AI 自然语言任务 */ public function executeAITask(string $deviceId, string $task, int $timeout = 60): array { $query = http_build_query(['task' => $task, 'timeout' => $timeout]); return $this->post("/api/v3/devices/{$deviceId}/ai/execute?{$query}"); } // ========== 设备管理接口 ========== /** * 获取设备列表 * * @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; } }