<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Macos on Armstrong Yan</title><link>https://yanqian.github.io/zh/topics/macos/</link><description>Recent content in Macos on Armstrong Yan</description><generator>Hugo</generator><language>zh-CN</language><lastBuildDate>Thu, 13 Aug 2026 14:08:41 +0800</lastBuildDate><atom:link href="https://yanqian.github.io/zh/topics/macos/index.xml" rel="self" type="application/rss+xml"/><item><title>Hey Jarvis 的困难 II：从 Demo 到 Mac 产品</title><link>https://yanqian.github.io/zh/posts/publish/building-hey-jarvis-mac-product/</link><pubDate>Thu, 13 Aug 2026 14:08:41 +0800</pubDate><guid>https://yanqian.github.io/zh/posts/publish/building-hey-jarvis-mac-product/</guid><description>&lt;p&gt;在 &lt;a href="https://yanqian.github.io/zh/posts/publish/building-hey-jarvis-voice-interaction/" &gt;上一篇&lt;/a&gt; 里，我写了 Hey Jarvis 怎样处理确认音、回声、打断和麦克风交接。&lt;/p&gt;
&lt;p&gt;当这些能力在终端和浏览器里跑通时，我一度觉得产品最困难的部分已经完成了。&lt;/p&gt;
&lt;p&gt;后来我才意识到，那只是证明了一条语音流程可以工作。&lt;/p&gt;
&lt;p&gt;一个 Demo 只需要在我准备好的环境里成功一次。一个产品则必须面对第一次安装、权限拒绝、窗口切换、电脑锁屏、系统睡眠、子进程崩溃和应用退出。它不但要成功，还要在无法成功时停在一个安全、诚实、可以恢复的状态。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Demo 证明一件事能发生。产品必须决定其他所有事情发生时怎么办。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="产品化不是给-python-加一个窗口"&gt;
 产品化不是给 Python 加一个窗口
 &lt;a class="heading-link" href="#%e4%ba%a7%e5%93%81%e5%8c%96%e4%b8%8d%e6%98%af%e7%bb%99-python-%e5%8a%a0%e4%b8%80%e4%b8%aa%e7%aa%97%e5%8f%a3"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="链接到标题"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;链接到标题&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;最早的 Hey Jarvis 由 Python 启动。Realtime 模式还需要打开一个 Chrome 页面，让浏览器负责 WebRTC 的麦克风和语音播放。&lt;/p&gt;
&lt;p&gt;这个结构适合开发，因为每一层都可以单独观察和调试。但如果把它直接包装成一个窗口，很多只存在于我电脑里的前提仍然没有消失：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;系统里已经安装了正确版本的 Python 和依赖；&lt;/li&gt;
&lt;li&gt;项目目录和 &lt;code&gt;.env&lt;/code&gt; 文件位于预期位置；&lt;/li&gt;
&lt;li&gt;Chrome 页面没有被重复打开；&lt;/li&gt;
&lt;li&gt;API Key 可以由开发环境读取；&lt;/li&gt;
&lt;li&gt;进程异常时，我知道应该去哪里看日志和怎样重新启动。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些都不是产品应该交给使用者理解的事情。&lt;/p&gt;
&lt;p&gt;在正式搭建 Mac App 之前，我先做了一个完全隔离的 Tauri 实验。它只回答一个问题：WKWebView 能不能在真实的 Apple Silicon Mac 上完成麦克风授权、Realtime 播放、自然打断、媒体释放，以及把麦克风还给 Python？&lt;/p&gt;
&lt;p&gt;实验成功以后，我没有继续在这份实验代码上追加功能，而是重新建立产品自己的应用外壳。&lt;/p&gt;
&lt;p&gt;这个选择看起来多走了一步，却帮我区分了两个很不一样的问题：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;实验：这条技术路线可不可行？
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;产品：它能否保护秘密、正确失败、恢复运行，并在另一台电脑上重现？
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="三种运行环境三种责任"&gt;
 三种运行环境，三种责任
 &lt;a class="heading-link" href="#%e4%b8%89%e7%a7%8d%e8%bf%90%e8%a1%8c%e7%8e%af%e5%a2%83%e4%b8%89%e7%a7%8d%e8%b4%a3%e4%bb%bb"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="链接到标题"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;链接到标题&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;最终的 Hey Jarvis Mac App 分成三部分：&lt;/p&gt;</description></item></channel></rss>