npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

wuin-cloud-phone

v0.1.0

Published

Framework-independent cloud phone player with Vue, React and isolated vendor runtimes

Readme

wuin-cloud-phone

云手机播放器组件,支持 Vue 3 和 React,提供设备画面、导航键、工具栏、连接状态和事件接口。

安装

npm install wuin-cloud-phone

按项目选择 Vue 3.5.2+ 或 React 18/19。包使用 ESM,运行于现代浏览器。使用组件时需引入样式:

import 'wuin-cloud-phone/style.css'

准备连接配置

Vue 和 React 使用相同的 CloudPhoneOptions。先在业务项目中创建 phone-options.ts:

import type { CloudPhoneOptions, PhoneSession } from 'wuin-cloud-phone'

export const phoneOptions: CloudPhoneOptions = {
  phoneId: 'your-phone-id',
  vendor: 'your-runtime-key',
  runtimeUrl: 'https://your-domain.example/cloud-phone/runtime.html',
  sessionProvider: async ({ phoneId, vendor, reason, signal }) => {
    const response = await fetch('/api/cloud-phone/session', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ phoneId, vendor, reason }),
      signal,
    })
    if (!response.ok) throw new Error('获取云手机会话失败')
    const session: PhoneSession = await response.json()
    return session
  },
}

将示例中的设备 ID、运行配置标识和 URL 替换为业务实际值:

| 配置 | 说明 | | --- | --- | | phoneId | 当前云手机的设备 ID | | vendor | 运行配置标识,须与已部署的 runtime 配置一致 | | runtimeUrl | 业务已部署的 runtime 页面的完整 HTTP(S) 地址;本包不提供托管地址 | | sessionProvider | 获取连接会话的异步函数,首次连接和重连时调用 |

/api/cloud-phone/session 需要由业务提供,返回 { credentials, expiresAt? }。credentials 为 runtime 所需的短期凭证对象,必须可结构化克隆;可选的 expiresAt 为到期时间的毫秒时间戳。请将 signal 传给网络请求,以便取消已过期的连接请求。

Vue 使用

<script setup lang="ts">
import { useTemplateRef } from 'vue'
import { WuinCloudPhone } from 'wuin-cloud-phone/vue'
import type { PhoneEvent } from 'wuin-cloud-phone'
import { phoneOptions } from './phone-options'
import 'wuin-cloud-phone/style.css'

const phone = useTemplateRef<InstanceType<typeof WuinCloudPhone>>('phone')

function onEvent(event: PhoneEvent) {
  if (event.type === 'error') console.error(event.data.message)
}

function reconnect() {
  void phone.value?.getClient()?.reconnect().catch(console.error)
}
</script>

<template>
  <WuinCloudPhone
    ref="phone"
    :options="phoneOptions"
    title="我的云手机"
    @event="onEvent"
  />
  <button type="button" @click="reconnect">重新连接</button>
</template>

React 使用

import { useRef } from 'react'
import { WuinCloudPhone } from 'wuin-cloud-phone/react'
import type { WuinCloudPhoneRef } from 'wuin-cloud-phone/react'
import type { PhoneEvent } from 'wuin-cloud-phone'
import { phoneOptions } from './phone-options'
import 'wuin-cloud-phone/style.css'

export function PhonePanel() {
  const phoneRef = useRef<WuinCloudPhoneRef>(null)

  function onEvent(event: PhoneEvent) {
    if (event.type === 'error') console.error(event.data.message)
  }

  function reconnect() {
    void phoneRef.current?.getClient()?.reconnect().catch(console.error)
  }

  return (
    <>
      <WuinCloudPhone
        ref={phoneRef}
        options={phoneOptions}
        title="我的云手机"
        onEvent={onEvent}
      />
      <button type="button" onClick={reconnect}>重新连接</button>
    </>
  )
}

组件挂载后会自动连接,卸载时自动清理。保持 options 对象引用稳定;React 中动态生成配置时可使用 useMemo。切换设备或连接配置时传入新的 options 对象,组件会重建实例,不要仅修改原对象的字段。

组件配置

Vue 和 React 支持以下通用属性;Vue 模板中使用 :toolbar-layout 等短横线写法。

| 属性 | 默认值 | 说明 | | --- | --- | --- | | options | 必填 | 连接配置与业务操作 | | toolbar | true | 显示右侧工具栏 | | navigation | true | 显示返回、主页、最近任务按钮 | | locale | 'zh-CN' | 支持 'zh-CN'、'en-US' | | title | 随语言设置 | 播放器标题 | | showUnsupported | false | 显示暂不支持的工具按钮,按钮保持禁用 | | toolbarLayout | 内置布局 | 自定义工具栏顺序 |

工具栏顺序

import type { ToolbarLayout } from 'wuin-cloud-phone/ui'

const toolbarLayout: ToolbarLayout = {
  main: ['file.open', 'quality.set', 'volume.up', 'volume.down', 'more'],
  more: ['live.open', 'device.restart', 'device.powerOff'],
  bottom: ['apps.open'],
}

Vue 传入 :toolbar-layout="toolbarLayout",React 传入 toolbarLayout={toolbarLayout}。main 为主菜单,more 为更多菜单,bottom 为底部菜单;三个数组均需提供。未列出的内置菜单会补入更多菜单,不支持的操作默认隐藏。更新布局时替换整个布局对象即可,不会重新连接。

业务操作

通过 options.services 为文件、应用、直播及设备管理等菜单配置业务回调。以下路径和接口均需由业务项目提供:

import type { CloudPhoneOptions, ServiceHandlers } from 'wuin-cloud-phone'
import { phoneOptions } from './phone-options'

const services: ServiceHandlers = {
  'file.open': async (_, { phoneId }) => {
    window.open(`/phones/${encodeURIComponent(phoneId)}/files`, '_blank', 'noopener')
  },
  'device.restart': async (_, { phoneId, vendor, signal }) => {
    const response = await fetch('/api/cloud-phone/restart', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ phoneId, vendor }),
      signal,
    })
    if (!response.ok) throw new Error('重启请求失败')
  },
}

const options: CloudPhoneOptions = { ...phoneOptions, services }

将这里的 options 传给组件。其他常用键包括 apps.open、live.open、scan.open、device.powerOff、device.reset、device.new。回调接收当前设备信息和 AbortSignal,返回的 Promise 应覆盖实际业务请求;失败时抛出 Error,工具栏会显示错误信息。文件、应用和直播页面的内容由业务自行实现。

工具栏执行设备管理操作时会弹出确认框;通过代码调用 execute() 时需自行确认。已配置的关机、重启、重置和新机操作可在断开状态执行。可通过 options.permissions 禁用指定命令,例如 { 'device.reset': false }。

事件和实例方法

Vue 使用 @event、@ready、@error,React 使用 onEvent、onReady、onError。通用事件包含 type、instanceId、phoneId、vendor、timestamp 和对应的 data。

| 事件 | 用途 | | --- | --- | | stateChange | 读取 data.state,跟踪连接状态 | | ready | 连接就绪,读取 data.capabilities 获取可用操作 | | firstFrame | 首帧到达,读取画面 width、height | | metrics | 读取延迟、帧率、码率等可用指标 | | capabilitiesChange | 更新可用操作和权限状态 | | reconnecting / reconnected | 跟踪连接恢复过程 | | error / warning | 读取错误信息及 retryable | | closed | 连接关闭,读取 data.reason |

通过 Vue 的 phone.value?.getClient() 或 React 的 phoneRef.current?.getClient() 获取 CloudPhone 实例。组件尚未完成初始化时可能返回 undefined。

| 方法 / 属性 | 用途 | | --- | --- | | connect() | 建立连接;已就绪时直接返回 | | reconnect() | 重新获取会话并连接 | | disconnect() | 断开当前连接,不执行设备关机 | | destroy() | 销毁实例;再次使用需重新挂载组件 | | execute(command, payload?) | 执行当前可用的操作 | | state / capabilities | 当前状态和能力 | | on(name, handler) / onEvent(handler) | 订阅指定或全部事件,返回取消订阅函数 |

例如,在连接就绪后切换画质:

import type { CloudPhone } from 'wuin-cloud-phone'

async function setHighQuality(client: CloudPhone) {
  const capability = client.capabilities['quality.set']
  if (client.state === 'ready' && capability?.supported && capability.enabled) {
    await client.execute('quality.set', { level: 'hd' })
  }
}

画质支持 smooth、standard、hd。其他常见调用包括 execute('navigation.home')、execute('volume.up') 和 execute('clipboard.write', { text: '内容' }),是否可用以当前 capabilities 为准。调用方法时应处理 Promise 拒绝。会话不会自动定时刷新,业务可在需要时调用 reconnect() 获取新会话。

本地开发

npm install
npm run dev          # 启动 Vue / React 演示
npm run check        # 类型、测试、构建及消费端类型检查
npm run build:demo   # 构建演示页面到 demo-dist
npm pack             # 生成可在其他项目安装的 npm 包