服务集
这个 npx serve 苹果模拟器.
将模拟器挂在本地局域网上,或挂在任何地方的远程mac和地道上.
npx @expo/serve-sim
# → Preview at http://localhost:3200
https://github.com/user-attachments/assets/fbf890f4-c8c7-4684-82be-d677b8a188f8
serve-sim 通过进程内 Swift addon 捕捉到模拟器的 IOSurface,在 HTTP 或 WebRTC 上曝光,并服务一个带有模拟器输入的 React 预览 UI. 它与任何被启动的iOS模拟器工作——没有Xcode插件,也没有在你的应用中安装仪器.
特征
- 低纬度模拟Kit捕捉以60 Hz IOSurface种子投票和可配置的WebRTC cadence.
- 从下取取出出家.
- 手势如按住选项键来缩放.
- 模拟日志存在于预览中的日志抽屉中,以及
serve-sim(单位:千美元) 给他们服务/.sim/logs用于发送会话无记名符号的工具. 将这个高容量流转发到浏览器控制台中选择: 附加?logs=1到预览 URL. - 浏览器工具面板和
serve-sim event-log。 。 。 . - 拖放视频和图像以添加到模拟器设备中.
- 键盘命令和热键被转发到模拟器,包括CMD+SHIFT+ 回家去 回家去 回家去 回家去 H to go home.
- 苹果卫视,iPad,和iOS支持.
- 网络抓取:解密并检查模拟器的HTTPS流量(参见 网络抓取) (中文(简体) ).
日志范围
/logs (或中间的软件) /.sim/logs)保持其全过程默认值.
过 scope=user-apps 仅接收其排放量
可执行性在已安装的应用容器中存在,包括应用扩展.
包括背景和随后安装的应用程序,而不仅仅是前台
app. 仅提及一个app的系统消息不在此列.
过滤器适用于SSE,快照,再播放. 响应头
X-Serve-Sim-Log-Scope 承认选定的范围; 仅需要应用程序的呼叫者
日志应该检查它,因为旧服务器可能会忽略参数.
重放光标属于一个设备,范围和服务器寿命. 不重复使用一个
用于用户应用程序流的全部进程光标。 每个范围都有单独的界限
缓冲和日志流进程,按需要启动,闲置时停止.
此选项无法捕获收藏开始前的日志或替换崩溃报告 .
为什么?
主机模拟器可能很难测试, serve-sim 允许您先在本地测试主机, 以更快的重迭 。 当你准备好远程托管一个模拟器时,简单的是隧道,服务过的URL和用户可以和模拟器交互,仿佛它在当地运行在他们的设备上一样.
我开发了"博览会"框架,但这个工具完全不可知,可以回溯原生,并可用于任何需要的iOS交互.
安装
需要一个苹果硅 (arm64带有Xcode命令行工具的Mac(xcrun simctl)和a 数据 维持节点Js LTS发布 (目前为节点20+). 旧的或报废的节点版本不支持. bun 实值 没有 需要运行 CLI。 相机注射使用为macOS 14+所建的主机侧辅助器.
被捆绑的本地添加器,模拟工具,以及主机帮助器都是arm64-只使用.
IPhone Duo模拟器支持被折叠的封面屏幕和半开或全开的内屏幕上的触摸输入,滚动和触摸手势. 框架和输入遵循活性显示及其取向;一个应用程序仍然可以限制其支持取向.
手机下方有3个快捷键选择了Fully折叠,部分打开,并Fully打开.
在工具侧边栏的模拟器设置上方, Fold 摆放
增加了笔记本电脑和帐篷。 下一行提供 0–180° 链条滑动器
十进制角输入和表格模式,使用与其他设置相同的控件.
部分开放用途 Book:它和笔记本电脑使用不同角度的90°链角
物理取向; 帐篷使用80°.
Duo默认为3D,使用Apple的模型从主机的Xcode安装,
与活的显示和平滑的折叠,走出,并摆出过渡.
显示像素保留在其上
物理面板随着模型的移动。 直接关闭和打开观众面孔,
与屏幕的肖像或地貌布局相接合的开放式模型. 手提电脑
腾讯提供外部封面屏幕。 原画 V68.usdz
在本地装入,而不捆绑苹果的模型或下载. 观点
尊重浏览器的减动偏好. 模拟器 — 预览模式
2D到3D之间的开关; AX检查也使用平面视图. 见 控件和显示
选择 用于隐藏设备枢纽
控制及其后面的模拟 API .
国 际
serve-sim [device...] Start preview server (default: localhost:3200)
serve-sim --no-preview [device...] Stream in foreground without a preview server
serve-sim --disable-share [device...] Hide only the preview's Share button
serve-sim gesture '<json>' [-d udid] Send a touch gesture
serve-sim button [name] [-d udid] Send a button press (default: home)
serve-sim type <text> [-d udid] Type text via the simulator keyboard
(US keyboard only; also --stdin / --file <path>)
serve-sim rotate <orientation> [-d udid]
portrait | portrait_upside_down |
landscape_left | landscape_right
serve-sim hinge <fold|half|unfold|degrees> [-d udid]
Set the hinge angle (0° folded, 180° unfolded)
serve-sim ca-debug <option> <on|off> [-d udid]
Toggle a CoreAnimation debug flag
(blended|copies|misaligned|offscreen|slow-animations)
serve-sim memory-warning [-d udid] Simulate a memory warning
serve-sim software-keyboard [-d udid] Show or hide the on-screen keyboard
serve-sim event-log [-d udid] Show recent simulator events
serve-sim capture har -o <path> [-d udid]
Follow a live capture into HAR + JSON files
serve-sim camera <bundle-id> [-d udid] [source-options]
Inject a synthetic camera feed and (re)launch the app
serve-sim camera switch <placeholder|webcam|file> [arg] [-d udid]
Hot-swap the running helper's source (no relaunch)
serve-sim camera mirror <auto|on|off> [-d udid]
Hot-swap preview-layer mirror mode
serve-sim camera status [-d udid] Print helper state as JSON ({alive, source, ...})
serve-sim camera --list-webcams List host camera devices
serve-sim camera --stop-webcam [-d udid]
Stop the camera helper for a device
Options:
-p, --port <port> Starting port (preview default: 3200; helper default: 3100)
--detach Spawn server and exit (daemon mode)
-q, --quiet JSON-only output
--no-preview Skip the web UI; stream in foreground only
--network-capture
Record HTTP(S) for selected devices, including already booted ones
(requires mitmproxy; see Network capture below)
--network-capture-proxy <url>
Forward captured traffic through an HTTP proxy (default: direct)
--network-capture-field <field>
What to keep beyond metadata: header | query |
request-body | response-body (repeatable or
comma-separated; default: none)
--codec <codec> HTTP stream codec: 'auto', 'h264', or 'mjpeg'
--transport <http|webrtc>
Stream transport (default: http)
--webrtc-codec <vp8|vp9|h264>
WebRTC video codec (default: h264)
--stun-url <url[,url...]>
STUN URL(s) for WebRTC ICE
--turn-url <url[,url...]>
TURN URL(s) for WebRTC ICE
--turn-username <username>
TURN username
--turn-credential <credential>
TURN credential
--mjpeg-fps <fps>
MJPEG frame rate (1-120)
--mjpeg-quality <quality>
MJPEG quality (0.05-1)
--max-dimension <pixels>
Maximum captured width or height; 0 keeps native resolution
--video-bitrate <bits-per-second>
H.264/WebRTC target bitrate
--video-fps <fps>
H.264/WebRTC frame rate (1-140)
--install-app-path <path>
Install a local .app after boot, before any requested launch
--launch-app-identifier <id>
Bundle identifier of the app to launch once the
simulator boots
--launch-arg <arg>
Argument passed to the app when it launches (repeatable)
--open-url <url>
URL to open in the app after it launches
--enable <capability>
Turn on a capability that is off by default (repeatable)
--disable <capability>
Turn off a capability that is on by default (repeatable).
Capabilities: clipboard (on), networkCapture (off)
--list [device] List running streams
--kill [device] Kill running stream(s)
Camera options (used with `serve-sim camera <bundle-id>`):
-f, --file <path> Image or video file (kind auto-detected from
extension/magic bytes; videos loop at native FPS)
--webcam [name] Live host webcam (defaults to the built-in
front camera when [name] is omitted)
--mirror [on|off|auto] Override preview-layer mirroring (default: auto =
front mirrored, back not). Data-output buffers
are never auto-mirrored, matching AVF defaults.
--no-mirror Shortcut for --mirror off
--build Rebuild the dylib + helper from source
WebRTC使用HTTP进行SDP信号和RTP进行视频. 模拟输入和屏幕
元数据在已有的帮助 WebSocket 上继续。 ICE 更喜欢直接 UDP
可到达时的路径,即使通过隧道 URL 装入页面;
当直接/STUN候选人失败时,TURN被用作倒计时.
从开始 --transport webrtc 将预览锁定到 WebRTC 终生
服务器。 UI只曝光WebRTC编码器和编码器控制器
设置 API 拒绝 HTTP 唯一的控制, MJPEG/ AVCC 端点返回
409 stream_transport_locked 而不是打开有隧道的屏幕流.
当一个对等点被连接起来时,一个出版商在它到达时发送每个新框架,
最多1.5倍配置 --video-fps,并重复最新框架
--video-fps 而屏幕不变。 模拟 Kit 更改
以60个Hz IOSurface种子民调补充回调
倒下 Cadence 不是捕捉出FPS天花板 自由网络c
源适配器使用1 000个FPS安全天花板,RTP发送器没有单独的
FPS帽,所以也不能相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相.
多个WebRTC的取景者可以同时使用相同的模拟器. 他们分享
一个模拟 Kit 捕获源,对于 H.264, 一个共享 VideoToolbox 编码器.
每个取景器保留自己的对等连接,拥堵控制器, RTP 流,
和帮助WebSocket。 VP8倒计时保留了每端编码器. HTTP 流线
继续支持多个观众.
见 WebRTC 架构 用于信号和 控制,和 视频管道和录音 用于抓捕, 缩放,硬件编码,录音合同,和测量的限度.
见 API 密码 hTTP 路径、认证、 CORS 和 WebSocket端点.
录像
启动模拟器的服务图像, 然后运行 :
serve-sim record-video --udid <udid> --output <empty-dir>
发送SIGINT完成录音. 命令打印路径
session.json,输出目录包含 recording.mp4会议
开始于 --require-token 使用其无记名标志记录控制;
没有符号的会话 .
实例
serve-sim # auto-detect booted sim, open preview
serve-sim "iPhone 16 Pro" # target a specific device
serve-sim --detach # start a background helper, return JSON
serve-sim --list # show running streams
serve-sim --kill # stop all helpers
# Type text into the focused field
serve-sim type "Hello, world!"
echo "from stdin" | serve-sim type --stdin
serve-sim type --file ./snippet.txt
# Camera injection
serve-sim camera com.acme.MyApp # animated placeholder
serve-sim camera com.acme.MyApp --webcam # default webcam
serve-sim camera com.acme.MyApp --webcam "MacBook Pro Camera"
serve-sim camera com.acme.MyApp --file ~/Pictures/face.png # static image
serve-sim camera com.acme.MyApp --file ~/Movies/loop.mp4 # looping video
# Hot-swap source on a running helper (no app relaunch)
serve-sim camera switch placeholder
serve-sim camera switch webcam
serve-sim camera switch ~/Movies/loop.mp4 # auto-detects file kind
# Other helpers
serve-sim camera mirror on
serve-sim camera status # JSON: alive, source, mirror
serve-sim camera --list-webcams
serve-sim camera --stop-webcam
多个被启动的模拟器通过通过多个设备名称支持. 在没有设备参数的情况下,service-sim会选择一个已存在的流,一个被启动的模拟器,或者一个默认的模拟器来启动.
监工可以调查 GET /healthz 确认预览服务器是
倾听和 GET /readyz 以等待到选中的模拟器和本地
捕捉会话准备好了 两个端点都返回JSON并禁用缓存.
额外的模拟 dylibs
设定 SERVE_SIM_ADDITIONAL_DYLIBS 至以冒号分隔的绝对去向路径列表:
SERVE_SIM_ADDITIONAL_DYLIBS=/path/to/egress-guard.dylib serve-sim <udid>
启动在设备操作前拒绝相对,缺失或非文件路径. 路径保留了白空间 。 此验证文件存在, 而非库兼容性 ; 拨打者必须保留用于会话的图书馆.
这些库被传送到模拟器启动器中,并加入能力 用于随后的应用程序发射的加载器. 要影响启动时启动的进程, 请开始 用一个关闭模拟器。 已运行的进程保留其当前图像 . 启动插件中包括 service-sim 的加载器和不活动抓取图像, 因此启动 能力继续发挥作用;仍需要通过控制来进行捕获. 呼叫者拥有这些库;会话拆分保留了它们的插入.
安装和启动应用程序
--launch-app-identifier <bundle-id> 等待模拟启动完成, 然后发射
在预览准备好前已安装的应用程序 。 要安装已下载
先建,再通过 --install-app-path /path/to/Example.app旗帜是
独立:您可以不发射而安装,也可以安装一个应用程序并启动
其它已安装的应用程序。如果启动、安装、启动或启动失败
打开 URL 失败 。 没有安装旗号,就事先安装应用程序.
serve-sim --launch-app-identifier host.exp.Exponent \
--launch-arg -EXDevMenuIsOnboardingFinished --launch-arg 1 \
--open-url exp://127.0.0.1:8081
--launch-arg 可重复和地图 simctl launch 进程参数. --open-url
运行 simctl openurl 在应用程序启动后, 并预先批准自定义 URL 方案, 因此
模拟器不要求确认. 这事关 exp:// 无头主机的深层链接.
从 serve-sim 而不是事前的紧要 因为一秒 simctl launch
在运行的应用程序上, 它是一个不开放的: 它既不重新启动该应用程序, 也不应用新的参数 。 拥有
发射是允许的 serve-sim 从开始就附于进程.
见 会话启动 用于启动命令、准备边界和拆卸所有权.
相机
serve-sim camera <bundle-id> 将模拟器的相机种子替换为单一的应用程序. 一个小主机侧帮助将 BGRA 框架写入 POSIX 共享记忆区域; 被注入的 dilib ()DYLD_INSERT_LIBRARIES)将AVFoundation打入了模拟器过程内部,所以应用从那个区域读取,而不是模拟器的相机.
帮助器是每台一台,超过任何一台应用程序的启动,所以同一模拟器上的多台应用程序可以共享种子——只运行 serve-sim camera <other-bundle-id> 重新重新启动下一个应用,并附带了 dilib 。 资料来源的变化(camera switch)和镜像变化(camera mirror)通过帮助器的控制套接字流出,而不要重启应用程序.
资料来源:
- 占位符 ——动画程序框架(默认).
- 文件 ——影像 (PNG/JPEG/HEIC/.)或视频 (mp4/mov/m4v/webm/.). CLI从扩展名中嗅出这种类型,并倒回魔法字节用于没有扩展名的文件.
- 网络相机 现场直播
AVCaptureDevice(内建,相续,外出).
网络抓取
在模拟器上解密第三方应用的HTTPS(本地的mitmproxy +可信赖的 CA). Safari等Apple系统应用被置之不近. 证书被绑定的应用程序在抓取时会失败 。 抓取开始时已经运行的 App 可能会错过请求, 或者需要重新启动, 如果它们继续使用现有的网络会话 .
# Metadata only (default). Headers and bodies are opt-in.
serve-sim --network-capture
# Include request and/or response bodies
serve-sim --network-capture --network-capture-field header,request-body,response-body
# Optional: follow the live stream into files you keep
serve-sim capture har -o ./capture.har
| 旗帜/ 命令 | 它会做什么 |
|---|---|
--network-capture | 在选定的设备上开始抓取,包括已经启动的设备 |
--network-capture-proxy <url> | 通过一个HTTP代理将捕获到的流量转发,可选地带有Basic credits; none 选择直接 |
--network-capture-field <field> | 保留 header, (中文(简体) ), query, (中文(简体) ), request-body,和(或) response-body 超过元数据(可重复或逗号分隔)。 默认: 无 |
serve-sim capture har -o <path> | 复制会话录制的请求,然后跟随直播流进入HAR(和JSON相邻). 保存最新的一万份申请 |
使用 启用抓取 在工具面板中启动而不重新启动。 关闭抓取重新启动模拟器,因此运行的应用程序不能继续使用被停止的代理.
工具小组在抓取时列出请求。 会话文件运行在 $TMPDIR/serve-sim/capture-<udid>/ 并被移除 当捕获停止。 抓取 HTTP 路由需要预览会话 Bearer 令牌 .
要求数 闪存 {\fn华文楷体\fs16\1cHE0E0E0}在主机上 启用后重新启动应用程序, 这样他们就可以拾取代理 。 关于编辑和风险的细节: 网络抓取。 。 。 .
除非 --network-capture-proxy http://host:port 命名上游 HTTP
代理服务器。 支持基本代理认证
--network-capture-proxy http://user:password@host:port设置 none 发送俘虏的交通直接.
配置的上游需要预览服务器, 所以 --detach 财务报告和审定财务报表 --no-preview 拒绝.
选择选项或使用 none 这些模式中仍然允许.
macOS 代理设置, PAC 文件和自动发现不读取 .
嵌入式中件挂载每个进程共享一个捕获运行时间和上游政策. 创建一个
挂载用于新抓取会话的策略; 省略 networkCaptureProxy 重装为直接.
现有会话保持其上游,直到重新启动抓取。 当
挂载需要不同的代理.
连接器
serve-sim 可以和dev服务器,浏览器,以及AI编辑器一起用于更无缝的集成.
特工技能
一个 特工技能 船舶在 skills/serve-sim ——它教AI编码代理(Claude Code, Cursor, Codex CLI,双子座CLI,以及任何执行开放代理技能标准的主机)如何通过CLI来驱动一个模拟器: 水龙头,手势,硬件按钮,旋转,相机注射,以及将流线交给主机的预览面板.
bunx add-skill expo/serve-sim
见 skills/serve-sim/README.md 全部能力清单.
Claude 代码桌面
创建一个 .claude/launch.json 并定义服务器 :
{
"version": "0.0.1",
"configurations": [
{
"name": "Apple",
"runtimeExecutable": "npx",
"runtimeArgs": ["serve-sim"],
"port": 3200
}
]
}
博览
博览会的应用不需要触摸 metro.config.js - 那个 expo-device-hub 插件使用 serve-sim 并设置设备 流给你.
npx expo install expo-device-hub
然后运行 npx expo start 并打开模拟器预览 :
http://localhost:8081/_expo/plugins/expo-device-hub
不需要其他配置 .
将会话限制在一个模拟器内
npx @expo/serve-sim --single-device <simulator-udid>
这靴子把预览锁到那个模拟器上 设备侧边栏
它的切换被移除。 HTTP 路由、 助手套接字和控制动作
拒绝其他设备目标,包括 all 财务报告和审定财务报表 booted。同样的模拟器
可以在不改变会话设备的情况下重启或重新连接. 此选项
需要预览服务器,不能与 --detach, (中文(简体) ), --orphan, (中文(简体) ),
--no-preview, (中文(简体) ), --list,或 --kill它可以伴随 --adopt 当它的UDID
匹配请求的任务设备。 私人交接可以选择另一个设备
或启动到同一服务器,然后在成功前应用限制.
嵌入式主机可以设置 simMiddleware({ singleDevice: udid })。这也使得
同源助手代理; 前进WebSocket升级如下所描述.
WebKit DevTools 已禁用,因为桥无法可靠地连接其
目标带有模拟器UDID。 此限制适用于此服务器的路径;
它并不妨碍主机工具或单独运行的服务器使用设备.
基于路径 file.readBase64 财务报告和审定财务报表 app.infoPlist 动作仍为主机范围
其现存被允许的根. 他们可以读取属于另一个模拟器的文件;
单设备模式不是一个文件系统沙盒.
任务前先温暖服务器
npx @expo/serve-sim <default-udid> <optional-second-udid> --orphan --port 3200 --require-token --transport webrtc
npx @expo/serve-sim <device-udid> --adopt --port 3200 --single-device <device-udid> --require-token --transport webrtc
第一种装置在背景中加热后再准备就绪. 在收养成功之前,孤儿只接受健康、准备和鉴定 状态探测器; 预览动作, 输入和订阅等其私人所有者 . 采用时保持服务器 PID 和端口,选择或粘贴精确的工作设备,以及 等待其本土流并请求抓取/记录设置 。 索赔停止 未来背景热身。 此进程已经准备好的设备在之后移交 启动状态检查;采用第一个设备不会等待其他设备的暖和. 未使用设备在发售前未公布,在发售后背景关闭 使用与UI相同的内部设备生命周期;会话停止 等待他们。 一个失败的索赔被消耗,需要停止服务器 在寒冷的开始之前.
嵌入您的 dev 服务器
@expo/serve-sim/middleware 是一个 获取样式 中间软件. simMiddleware(options) 返回带有 Web 标准的处理器 .handleWebSocket 钩子,所以它挂在任何服务器上 Request编号 :Response ("本","德诺","浩诺","节点适配器",". 运行 serve-sim --detach 然后电线连接两个入口:
import { simMiddleware } from "@expo/serve-sim/middleware";
const middleware = simMiddleware({ basePath: "/.sim" });
// `server` is a stand-in for your runtime (Bun.serve, node:http + ws, Deno, …).
// HTTP — run every request through the middleware. It returns a Response for
// serve-sim's own routes (preview at /.sim, state at /.sim/api, SSE logs at
// /.sim/logs), or `undefined` — meaning "not mine", so fall through.
server.onRequest(async (request) => {
return (await middleware(request)) ?? new Response("Not found", { status: 404 });
});
// WebSocket — the preview client runs execs, simulator settings, and the SSE
// side-channels over one socket at `<basePath>/exec-ws`, with no HTTP fallback.
// On upgrade, hand the request + accepted socket to handleWebSocket; it returns
// true once it owns the socket. `socket` is a `ws`-style WebSocket (Node's `ws`
// works as-is; other runtimes need a small adapter).
server.onUpgrade((request, socket) => {
if (!middleware.handleWebSocket?.(request, socket)) socket.close();
});
中间软件读取 帮助者状态从 $TMPDIR/serve-sim/ ,并将浏览器指向帮助器的流,交互WebSocket,以及WebKit DevTools端点. 默认情况下,这些 URL 直接针对帮助者自己的端口( 帮助者回答回回回源), 所以一个 plain app.use(...) 不触摸服务器的 WebSocket 处理而挂载工作 .
打开一个设备通过容量加载器设置剪贴板读取器,在挂载中间软件的过程中. 设定 clipboard: false 删除该读取器,或者 clipboard: "unmanaged" 把它留给拥有设备的 service-sim 会话。 等着 middleware.dispose() 当主机服务器关闭时, 释放它拥有的剪贴板设置 。 剪贴板读取从不重启应用程序;设置前已经运行的应用程序可能需要明确重启.
在CLI和中间软件,何时 simctl pbpaste 失败, 读取的剪贴板可以询问应用程序中的剪贴板阅读器 。 在它问之前,它允许应用贴板访问 simctl privacy. 在补助金离开之后失效的读数。 补助金留在模拟器的隐私(TCC)数据库中,同样是在重启之后. 它取代了一个拒绝 simctl privacy revoke 存储。 在它停留期间,应用程序没有得到"Allow Paste"的提示. iOS仍然可以在一个读取上显示一面横幅,如"从service-sim-pasteboard上贴出". 要将应用程序还原为即时, 请运行 xcrun simctl privacy <udid> reset pasteboard <bundle-id>。稍后通过剪贴板阅读器再次允许访问。 不使用 revoke。它存储一个 Deny,贴板在应用程序中读取,然后获得空文本,而不迅速. clipboard: false (单位:千美元)--disable clipboard (c) 禁止发放补助金。 上面的赠与,即时,横幅,和撤销的结果来自一个有Xcode 26.4的iOS 26.4模拟器. 剪贴板 提供细节.
复制到预览工具栏中 (POST /api/pasteboard?copy=1)安装 ServeSimPasteboard.app 在模拟器上,并授予它粘贴板访问权限。 应用程序和补助金暂住 应用程序在家庭屏幕上显示. clipboard: false (单位:千美元)--disable clipboard (c) 国家行动倡议没有阻止这种情况。 要删除应用程序, 请运行 xcrun simctl uninstall <udid> com.expo.serve-sim-pasteboard。下一次复制安装并再次授予它.
单端口/ 远程代理
将预览曝光给单个端口( 独立的方式) 后面的远程观看者 serve-sim 执行),通过 proxyHelpers: true。浏览器然后通过同一来源到达流、控制套接字和 DevTools /.sim/helper/<device> 财务报告和审定财务报表 /.sim/devtools URL,因此每个设备的助手端口和检查-webkit桥可以留在本地到主机. 此路由 WebSockets 通过中间软件, 所以您必须转发您的服务器的 upgrade 事件改为 handleUpgrade数字 :
const middleware = simMiddleware({ basePath: "/.sim", proxyHelpers: true });
// Route HTTP requests through `middleware(request)` as above, and also forward
// raw upgrade events for helper and DevTools proxy sockets.
const server = listen();
server.on("upgrade", (req, socket, head) => middleware.handleUpgrade(req, socket, head));
如果您启用 proxyHelpers 但不要电线 upgrade,页面仍然在 HTTP 上加载视频,但丢失了模拟器输入和 DevTools(他们的套接字从未到达代理) 。 当逆向代理终止 TLS 时, 转发 X-Forwarded-Proto 因此帮助者 URL 使用 https编号 :wss 并避免混合成分块.
如何运作
┌──────────────┐ IOSurface ┌──────────────────────┐ HTTP / WebRTC ┌─────────┐
│ iOS Simulator│ ────────────► │ serve-sim process │ ──────────────► │ Browser │
└──────────────┘ │ Swift N-API capture │ └─────────┘
│ + Node middleware │
└──────────────────────┘
▲
state files in
$TMPDIR/serve-sim/
Npm 软件包将本地捕获附加物和LiveKit WebRTC框架与Node CLI并列. bun 需要用于构建软件包,但不需要运行已发布的CLI.
发展
单曲 发布工作流程 建筑和测试
@expo/serve-sim 在 GitHub 时 macos-latest 发布前运行 。 它检查
跑步者为 arm64 在开始建造之前.
bun install
bun run packages/serve-sim/build.ts # full production build
bash packages/serve-sim/Sources/build-test-fixtures.sh # simulator test fixtures
packages/serve-sim/Sources/SimNative/build.sh # native addon only
bun run --filter @expo/serve-sim dev # watch mode
bun run --filter @expo/serve-sim tart-dev # guest preview at localhost:3200
bun run --filter @expo/serve-sim tart-test -- <files> # bun test on the guest
烂客
运行服务图像 编号 贱货 macOS VM 软件 而不是主持人。 SSH 作为 Unix 用户 expo (无) tart exec 作为管理员),它与EAS形状的VMs的实际运行方式相匹配.
需要一个 tart CLI,带有 Xcode 的 VM (默认名称) tahoe-xcode),以及一个已建成的土生土长.
bun run packages/serve-sim/build.ts
bun run --filter @expo/serve-sim tart-dev
# → Preview at http://localhost:3200
tart-dev 如果需要, 启动 VM, 启动 iPhone 17, 运行 bun run dev.ts 和隧道的来宾 :3200 给主机。 主机端口 3200 必须自由。 Ctrl-C停止地道和来宾服务器.
tart-test 使用同一个客人,但运行 bun test 在这里。 它分级将套件 src 装入 VM , 将 iPhone 装入 iPhone , 执行您通过 SSH 的文件 expo。通过文件;没有文件可以退出,而不是运行整个宾馆.
bun run --filter @expo/serve-sim tart-test -- src/__tests__/foo.test.ts
bun run --filter @expo/serve-sim tart -- test src/__tests__/foo.test.ts
第一次运行创建 expo 用户和复制包放在来宾上(bun run --filter @expo/serve-sim tart -- setup 如果你想单独走一步的话.
VM 挂载此退出 /Volumes/My Shared Files/serve-sim。如果VM是从不同的工作树开始的,请停止它,从这个重新运行.
bun run --filter @expo/serve-sim tart -- ssh # shell as expo
tart 还有 up, (中文(简体) ), boot,以及 stage 如果你需要 分开的棋子.
信封( 所有可选) : TART_VM=tahoe-xcode, (中文(简体) ), TART_USER=expo, (中文(简体) ), TART_SHARE_NAME=serve-sim, (中文(简体) ), PORT=3200。 。 。 .
CI 包的 EAS 预览
--package-version 针头只服务于 --type web-preview-only。其他会话类型则使用旗子作为自己的软件包(agent-device, (中文(简体) ), appium, (中文(简体) ), argent并总是运行服务-sim at latest,所以一个 serv-sim tarball URL 打破它们.
埃及艾滋病协会 测试工作流程 包装
serve-sim.tgz 更改的拉动请求 packages/serve-sim 上传为
serve-sim-npm-package它在试验开始前就打包了 所以即使当
他们失败了。 从运行中复制下载 URL, 然后以 --package-version。 。 。 .
从 Expo 工程目录中运行这些命令 .
npx --yes eas-cli@latest workflow:runs --workflow sim-test.yml --limit 5
npx --yes eas-cli@latest workflow:view <workflow-run-id> --non-interactive --json \
| jq -er '.jobs[].artifacts[]? | select(.name == "serve-sim-npm-package") | .downloadUrl'
--non-interactive 需要运行的ID作为参数。 没有它, workflow:view 运行提示 。 无 --json它在博览会仪表盘上打印一个运行的日志URL,每个工作都用下载URL来列出其文物.
下载 URL 签名并将于1小时后到期 workflow:view 返回它。 工人在会话开始后几分钟安装包,因此复制每个会话的新鲜URL. 工作日志中已过期的 URL 失败 。 URL也出现在了该日志中,因此任何能读取跑道的人都可以下载文物直到URL过期.
npx --yes eas-cli@latest simulator:start --platform ios --type web-preview-only --non-interactive \
--name "serve-sim preview" \
--package-version '<download-url>'
EAS 运行 npx @expo/serve-sim@<value>,因此旗子需要任何 npm 规格:一个版本,一个标签,或者一个柏油球 URL. 引用 URL .
从其中之一开始安装和启动应用程序 --build-id, (中文(简体) ), --application-archive-url,或 --expo-go。 。 。 . --launch-arg 财务报告和审定财务报表 --open-url 需要其中一个. --sdk-version 需求 --expo-go。 。 。 .
npx --yes eas-cli@latest simulator:start --platform ios --type web-preview-only --non-interactive \
--name "serve-sim preview" \
--package-version '<download-url>' \
--expo-go
EAS在服务-sim启动前安装并启动应用程序. 预览开始后, 放下一个 .ipa 在页面上安装另一个应用程序。 页面需要 .ipa 或媒体,不是 .app 捆绑或构建归档,通过 --build-id 或者说 --application-archive-url 这些。 停下来 npx --yes eas-cli@latest simulator:stop。 。 。 .
起源和归属
serve-sim 创建和开源 埃文·培根 输入 原始服务项目。这个寄存器是保存在世博会的分叉。 我们感谢埃文创建了这个项目,并向社区开放.
见 通知 关于归属细节.
许可证
阿帕奇 - 2.0