<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans">
  <generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator>
  <link href="https://zh-hans.zhgchg.li/feed.xml" rel="self" type="application/atom+xml" />
  <link href="https://zh-hans.zhgchg.li/" rel="alternate" type="text/html" hreflang="zh-Hans" />
  <updated>2026-08-11T11:54:29+08:00</updated>
  <id>https://zh-hans.zhgchg.li/feed.xml</id>
  <title type="html">ZhgChgLi 技术与旅行</title>
  <subtitle>记录程序开发、科技观察与旅途生活。</subtitle><author>
    <name>ZhgChgLi</name><email>zhgchgli@gmail.com</email>
  </author><entry>
    <title type="html">AI 协作设计 Rangeable RFC｜资料结构演算法与多语言实作详解</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/ai-%E5%8D%8F%E4%BD%9C%E8%AE%BE%E8%AE%A1-rangeable-rfc-%E8%B5%84%E6%96%99%E7%BB%93%E6%9E%84%E6%BC%94%E7%AE%97%E6%B3%95%E4%B8%8E%E5%A4%9A%E8%AF%AD%E8%A8%80%E5%AE%9E%E4%BD%9C%E8%AF%A6%E8%A7%A3-f7bec8f79c08/" rel="alternate" type="text/html" title="AI 协作设计 Rangeable RFC｜资料结构演算法与多语言实作详解" />
    <published>2026-05-10T15:01:01+08:00</published>
    <updated>2026-05-10T15:28:40+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/f7bec8f79c08</id><summary type="html">针对 Medium Markup 与 AVPlayer Cache 区间问题，揭露 AI 如何从抽象问题、演算法选型到 Ruby、Swift 等多语言实作 Rangeable RFC，带来最高效区间合并与查询解决方案，令 Markdown 渲染效能提升超过 2 倍。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="ios-app-development" /><category term="leetcode" /><category term="claude-code" /><category term="ai-agent" /><category term="algorithms" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/f7bec8f79c08/1*H5MBf1d1kEqBQnqtG9-zgg.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/ai-%E5%8D%8F%E4%BD%9C%E8%AE%BE%E8%AE%A1-rangeable-rfc-%E8%B5%84%E6%96%99%E7%BB%93%E6%9E%84%E6%BC%94%E7%AE%97%E6%B3%95%E4%B8%8E%E5%A4%9A%E8%AF%AD%E8%A8%80%E5%AE%9E%E4%BD%9C%E8%AF%A6%E8%A7%A3-f7bec8f79c08/"><![CDATA[<h3 id="ai-不只会做应用用-ai-协作完成一份资料结构-rfc-与多语言实作"><strong>AI 不只会做应用：用 AI 协作完成一份资料结构 RFC 与多语言实作</strong></h3>

<p>以 Rangeable RFC 为例，从问题抽象、演算法选型、语意定义到 Ruby / Swift 参考实作，记录 AI 如何参与更深入的技术研究与设计。</p>

<p><img src="/assets/f7bec8f79c08/1*H5MBf1d1kEqBQnqtG9-zgg.webp" alt="" loading="lazy" decoding="async" width="1536" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjEwMjQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/f7bec8f79c08/1*H5MBf1d1kEqBQnqtG9-zgg.jpeg" /></p>

<h3 id="背景">背景</h3>

<p>前几周为了 Re-Design 我的 <a href="https://zhgchg.li/" target="_blank">个人网站</a> ，直上了 Claude Code Max 后来又用 AI x Google Apps Script 做了一个个人桌上 Dashboard Deck 把旧的 iPhone 变废为宝；这周开始把目标转向之前做的开源专案，用 AI 重构原本手搓的程式码，优化效率、补充文件、补足测试。</p>

<blockquote>
  <p><strong><em>TL;DR</em></strong></p>
</blockquote>

<blockquote>
  <p><em>先用 AI 重构了几个开源专案的应用层面，因而得到启发也让他做做深入的 Foundation 资料结构设计。</em></p>
</blockquote>

<h4 id="linkyee-your-own-link-page"><a href="https://github.com/ZhgChgLi/linkyee" target="_blank">Linkyee— Your Own Link Page</a></h4>

<p>A fully customized, 100% free, open-source LinkTree alternative — deployed straight to GitHub Pages.</p>

<p><a href="https://github.com/ZhgChgLi/linkyee" target="_blank"><img src="https://repository-images.githubusercontent.com/877945203/333b5db1-e5e7-4d71-8b53-986a60e75033" alt="" /></a></p>

<p>第一个优化的是之前做的 类 — Linktree 免费开源自架版，用 AI 重整了一下架构、多设计几个主题、多做几个内建 Plugin、新增 Design AI Skill 让使用者方便客制化、补充本地测试环境。</p>

<h4 id="zmediumtomarkdown"><a href="https://github.com/ZhgChgLi/ZMediumToMarkdown" target="_blank">ZMediumToMarkdown</a></h4>

<p>Download Medium posts as clean Markdown, preserving structure, images, links, code blocks, and common embeds for plain Markdown or Jekyll workflows.</p>

<p>帮你把文章的所有内容包含图片、内嵌程式码、Youtube 连结…全部下载转换成 Markdown、图片也会一起下载放到 <code class="language-plaintext highlighter-rouge">./assets</code> 。</p>

<p><a href="https://github.com/ZhgChgLi/ZMediumToMarkdown" target="_blank"><img src="https://repository-images.githubusercontent.com/493527574/9b5b7025-cc95-4e81-84a9-b38706093c27" alt="" /></a></p>

<p>第二个是我一直在使用、维护了四年多的专案 — 「下载并转换 Medium 文章成 Markdown 格式」的工具，因为后期我几乎只把 Medium 当成文章编辑器后台，主力是透过这工具把原文下载转换后传到我的 <a href="https://zhgchg.li/" target="_blank">自架网站</a> 。</p>

<p>这个专案是我的网站跟 Medium 之间的重要桥梁，不能断；当初第一版开发的时候花了我大量的时间跟精力，这几年也都在修修补补一些小问题，但是很久没有整个重新检视设计与优化了。</p>

<p>一样是先从 AI 优化应用开始，除了请他重构＋补测试原本手搓的渲染逻辑外；还有补强 Medium Cloudflare Anti-bot 流程，让使用者可以在遇到 Medium 阻挡爬虫时能优雅地从 Chrome 登入后自动获取 Cookies 然后自动执行。</p>

<h4 id="mcp-medium-reader"><a href="https://github.com/ZhgChgLi/mcp-medium-reader" target="_blank">mcp-medium-reader</a></h4>

<p>最后还请 AI 建了 Medium.com 文章 Reader MCP 服务。</p>

<p><a href="https://github.com/ZhgChgLi/mcp-medium-reader" target="_blank"><img src="https://opengraph.githubassets.com/be5c8e0489d9add1b623ab52d36b56df26fe36b6d911ba3df2be6bf6c03fe966/ZhgChgLi/mcp-medium-reader" alt="" /></a></p>

<p>主要是基础的转换服务 <a href="https://github.com/ZhgChgLi/ZMediumToMarkdown" target="_blank">ZMediumToMarkdown</a> 都做好了，MCP 只是一层 Wrapper 呼叫它来做就能达成。</p>

<p>解决的问题是 AI 如 ChatGPT, Codex, Claude, Claude Code 贴给他 Medium 文章时很容易被 Medium 的 Cloudflare Anti-bot 阻挡爬取内容，以至于 AI 无法直接读取文章，就算能也是读取 HTML，不是 AI 友善的 Markdown。</p>

<blockquote>
  <p><a href="https://github.com/ZhgChgLi/mcp-medium-reader" target="*blank"><em>mcp-medium-reader</em></a> _能让你的 AI 穿透封锁并且读取 Markdown 版本的 Medium 文章，节省 Token 的同时又能提升 AI 理解性。*</p>
</blockquote>

<h3 id="带标签区间集合问题"><strong>带标签区间集合问题</strong></h3>

<blockquote>
  <p><em>当年在做 <a href="https://github.com/ZhgChgLi/ZMediumToMarkdown" target="_blank">ZMediumToMarkdown</a> 的时候有遇到 <strong>这个 Foundation 资料结构设计(算法)问题</strong> ，那时候没有多余的精力也没有能力解决，但现在有 AI 了，想想可以尝试用 AI 解决这个问题。</em></p>
</blockquote>

<h4 id="案例一--medium-渲染问题">案例一 — Medium 渲染问题</h4>

<p><strong>Medium.com 的 GraphQL API 回传的文章内容资料如下格式：</strong></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"text"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."</span><span class="p">,</span><span class="w">
  </span><span class="nl">"markups"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"A"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"start"</span><span class="p">:</span><span class="w"> </span><span class="mi">169</span><span class="p">,</span><span class="w">
      </span><span class="nl">"end"</span><span class="p">:</span><span class="w"> </span><span class="mi">207</span><span class="p">,</span><span class="w">
      </span><span class="nl">"href"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://zhgchg.li/posts/f6713ba3fee3/"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"anchorType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"LINK"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"userId"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"linkMetadata"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"__typename"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Markup"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"STRONG"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"start"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
      </span><span class="nl">"end"</span><span class="p">:</span><span class="w"> </span><span class="mi">29</span><span class="p">,</span><span class="w">
      </span><span class="nl">"href"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"anchorType"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"userId"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"linkMetadata"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"__typename"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Markup"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"EM"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"start"</span><span class="p">:</span><span class="w"> </span><span class="mi">15</span><span class="p">,</span><span class="w">
      </span><span class="nl">"end"</span><span class="p">:</span><span class="w"> </span><span class="mi">55</span><span class="p">,</span><span class="w">
      </span><span class="nl">"href"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"anchorType"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"userId"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"linkMetadata"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"__typename"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Markup"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"STRONG"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"start"</span><span class="p">:</span><span class="w"> </span><span class="mi">69</span><span class="p">,</span><span class="w">
      </span><span class="nl">"end"</span><span class="p">:</span><span class="w"> </span><span class="mi">88</span><span class="p">,</span><span class="w">
      </span><span class="nl">"href"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"anchorType"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"userId"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"linkMetadata"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"__typename"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Markup"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p><strong>翻译成白话文：</strong></p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="m">0</span><span class="p">,</span><span class="m">14</span><span class="p">]</span>    <span class="n">STRONG</span>       <span class="p">=</span> <span class="n">Lorem</span> <span class="n">ipsum</span> <span class="n">dol</span>
<span class="p">[</span><span class="m">15</span><span class="p">,</span><span class="m">29</span><span class="p">]</span>   <span class="n">STRONG</span> <span class="p">+</span> <span class="n">EM</span>  <span class="p">=</span> <span class="n">or</span> <span class="n">sit</span> <span class="n">amet</span><span class="p">,</span> <span class="n">co</span>
<span class="p">[</span><span class="m">30</span><span class="p">,</span><span class="m">55</span><span class="p">]</span>   <span class="n">EM</span>           <span class="p">=</span> <span class="n">nsectetur</span> <span class="n">adipiscing</span> <span class="n">elit</span><span class="p">,</span>
<span class="p">[</span><span class="m">56</span><span class="p">,</span><span class="m">68</span><span class="p">]</span>   <span class="n">normal</span>       <span class="p">=</span>  <span class="n">sed</span> <span class="k">do</span> <span class="n">eiusm</span>
<span class="p">[</span><span class="m">69</span><span class="p">,</span><span class="m">88</span><span class="p">]</span>   <span class="n">STRONG</span>       <span class="p">=</span> <span class="n">od</span> <span class="n">tempor</span> <span class="n">incididunt</span>
<span class="p">[</span><span class="m">89</span><span class="p">,</span><span class="m">168</span><span class="p">]</span>  <span class="n">normal</span>       <span class="p">=</span>  <span class="n">ut</span> <span class="n">labore</span> <span class="n">et</span> <span class="n">dolore</span> <span class="n">magna</span> <span class="n">aliqua</span><span class="p">.</span> <span class="n">Ut</span> <span class="n">enim</span> <span class="n">ad</span> <span class="n">minim</span> <span class="n">veniam</span><span class="p">,</span> <span class="n">quis</span> <span class="n">nostrud</span> <span class="n">exercit</span>
<span class="p">[</span><span class="m">169</span><span class="p">,</span><span class="m">207</span><span class="p">]</span> <span class="n">A</span>            <span class="p">=</span> <span class="n">ation</span> <span class="n">ullamco</span> <span class="n">laboris</span> <span class="n">nisi</span> <span class="n">ut</span> <span class="n">aliquip</span> <span class="n">e</span>
</code></pre></div></div>

<p><strong>预期渲染结果：</strong></p>

<p><img src="/assets/f7bec8f79c08/1*0cOIQ8YgvcrBZKUdCEaxGw.webp" alt="" loading="lazy" decoding="async" width="652" height="99" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NTIiIGhlaWdodD0iOTkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/f7bec8f79c08/1*0cOIQ8YgvcrBZKUdCEaxGw.png" /></p>

<blockquote>
  <p><em>注意：Medium 原始资料的 end 语意需依实际 API 定义转换；本文后续以 Rangeable RFC 的 closed interval 语意说明。</em></p>
</blockquote>

<h4 id="问题">问题</h4>

<ul>
  <li>
    <p><strong>区间叠加</strong>
同一区间可以是多个状态叠加，例如 [15,29] 是 STRONG + EM</p>
  </li>
  <li>
    <p><strong>区间交错</strong>
极端状况下使用者可能设定交错的样式，[0,29] 是 STRONG / [15,55] 是 EM</p>
  </li>
</ul>

<p><img src="/assets/f7bec8f79c08/1*nagAmJcFkHpMSdbELnT7Mg.webp" alt="" loading="lazy" decoding="async" width="386" height="77" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzODYiIGhlaWdodD0iNzciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/f7bec8f79c08/1*nagAmJcFkHpMSdbELnT7Mg.png" /></p>

<ul>
  <li><strong>区间连续合并</strong>
资料可能给 [0,12] 是 STRONG / [12,29] 是 STRONG 需要合并成 [0,29] 是 STRONG</li>
</ul>

<p>区间叠加、区间连续合并还算好处理，最麻烦的是区间交错闭合处理，不能直接照 index 渲染，会变成 <code class="language-plaintext highlighter-rouge">**AA_AA**BBB_</code> ，需要自己处理开闭变成 <code class="language-plaintext highlighter-rouge">**AA_AA_**_BBB_</code> 才会是正确的 Markdown。</p>

<p>iOS 开发者如果有用过 <code class="language-plaintext highlighter-rouge">NSAttributedString attributes</code> 也是一样的问题，只是 Apple Foundation 帮我们做好区间合并跟叠加处理了。</p>

<blockquote>
  <p><em>当时也是搞了很久想了老半天，书到用时方恨少，平时刷题太少遇到实际要用的时候没武器可用；那时候是用最暴力的 walkthrough 解决，结果正确只是效能跟程式码很可怕。</em></p>
</blockquote>

<h4 id="关联的-leetcode-题型">关联的 LeetCode 题型</h4>

<ul>
  <li><strong>Merge Intervals</strong></li>
</ul>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">56</span><span class="p">.</span> <span class="n">Merge</span> <span class="n">Intervals</span>
<span class="mi">57</span><span class="p">.</span> <span class="k">Insert</span> <span class="n">Interval</span>
</code></pre></div></div>

<p><strong>用途：</strong> 合并 STRONG [0,12], STRONG [13,29] -&gt; STRONG [0,29]。</p>

<ul>
  <li><strong>Sweep Line</strong></li>
</ul>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">253.</span> Meeting Rooms II
<span class="p">731.</span> My Calendar II
<span class="p">732.</span> My Calendar III
<span class="p">1094.</span> Car Pooling
<span class="p">1851.</span> Minimum Interval to Include Each Query
</code></pre></div></div>

<p><strong>用途：</strong></p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">STRONG</span> <span class="o">[</span><span class="err">0</span><span class="o">,</span><span class="err">29</span><span class="o">]</span>
<span class="nt">EM</span>     <span class="o">[</span><span class="err">15</span><span class="o">,</span><span class="err">55</span><span class="o">]</span>
<span class="nt">A</span>      <span class="o">[</span><span class="err">169</span><span class="o">,</span><span class="err">207</span><span class="o">]</span>
</code></pre></div></div>

<p>to</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">0</span>    <span class="nt">open</span> <span class="nt">STRONG</span>
<span class="err">15</span>   <span class="nt">open</span> <span class="nt">EM</span>
<span class="err">30</span>   <span class="nt">close</span> <span class="nt">STRONG</span>
<span class="err">56</span>   <span class="nt">close</span> <span class="nt">EM</span>
<span class="err">169</span>  <span class="nt">open</span> <span class="nt">A</span>
<span class="err">208</span>  <span class="nt">close</span> <span class="nt">A</span>
</code></pre></div></div>

<ul>
  <li><strong>Difference Array，但不是纯数字差分</strong></li>
</ul>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">370.</span> Range Addition
<span class="p">1109.</span> Corporate Flight Bookings
<span class="p">1094.</span> Car Pooling
</code></pre></div></div>

<p><strong>用途：</strong> 维护 active markup set</p>

<ul>
  <li><strong>Interval Split / Segment Construction</strong></li>
</ul>

<p><strong>用途：</strong></p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">STRONG</span> <span class="o">[</span><span class="err">0</span><span class="o">,</span><span class="err">29</span><span class="o">]</span>
<span class="nt">EM</span>     <span class="o">[</span><span class="err">15</span><span class="o">,</span><span class="err">55</span><span class="o">]</span>
</code></pre></div></div>

<p>to</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span><span class="err">0</span><span class="o">,</span><span class="err">14</span><span class="o">]</span>   <span class="nt">STRONG</span>
<span class="o">[</span><span class="err">15</span><span class="o">,</span><span class="err">29</span><span class="o">]</span>  <span class="nt">STRONG</span> <span class="o">+</span> <span class="nt">EM</span>
<span class="o">[</span><span class="err">30</span><span class="o">,</span><span class="err">55</span><span class="o">]</span>  <span class="nt">EM</span>
</code></pre></div></div>

<p><strong>其他用到的题型、资料结构：</strong></p>

<ul>
  <li>
    <p>Event Sorting</p>
  </li>
  <li>
    <p>Interval Partition / Segment Split</p>
  </li>
  <li>
    <p>Stack / Parentheses Matching</p>
  </li>
  <li>
    <p>Binary Search</p>
  </li>
  <li>
    <p>Ordered Set / LinkedHashSet</p>
  </li>
  <li>
    <p>Canonicalization</p>
  </li>
</ul>

<h4 id="案例二--avplayer-cache-区段问题">案例二 — AVPlayer Cache 区段问题</h4>

<p>上面 Medium 遇到的区间问题其实我之前也遇过类似的，在开发「 <a href="/posts/zrealm-dev/avplayer-本地-cache-实作攻略-使用-avassetresourceloaderdelegate-节省-ios-音乐串流流量-6ce488898003/">AVPlayer 本地边播边 Cache 时</a> 」也有遇到。</p>

<p>因为串流资料是不连续的，一份 Size: 1000 的 Data，AVPlayer 可能会要求 <code class="language-plaintext highlighter-rouge">[0,100] [300–500] [150, 200]…</code> 之间的不连续或是交错资料。</p>

<p><img src="/assets/f7bec8f79c08/1*9cNp02AnTbilWCpadldfBw.webp" alt="" loading="lazy" decoding="async" width="1189" height="801" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTg5IiBoZWlnaHQ9IjgwMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/f7bec8f79c08/1*9cNp02AnTbilWCpadldfBw.png" /></p>

<p>以上图为例，假设 <strong>目前已有资料区段：</strong> <code class="language-plaintext highlighter-rouge">[250,566] [850,959]</code> ，理想上：</p>

<ul>
  <li>
    <p><strong>AVPlayer 询问 [0,300] 时：</strong> [0,249] 从远端拿、[250,300] 从本地拿</p>
  </li>
  <li>
    <p><strong>AVPlayer 询问 [350, 920] 时：</strong> [350,566] 从本地拿、[567,849] 从远端拿、[850,920] 从本地拿</p>
  </li>
</ul>

<p>当时一样遇到区间计算问题 — <strong>Covered / Uncovered Interval Query</strong> ，不过比 Medium 问题简单因为这边是 Binary Data 0 跟 1 的区别而已，只需要计算结果。</p>

<blockquote>
  <p><em>当时也是暂时没解，因为光开发 AVPlayer 边播放边缓存的功能就花大半时间了；加上当时场景是音讯，档案本身就不大； <strong>直接先走区间没资料就全拿覆盖的方式 — 细节请参考原文章「 <a href="/posts/zrealm-dev/avplayer-本地-cache-实作攻略-使用-avassetresourceloaderdelegate-节省-ios-音乐串流流量-6ce488898003/">AVPlayer 本地 Cache 实作攻略｜使用 AVAssetResourceLoaderDelegate 节省 iOS 音乐串流流量</a> 」</strong> 。</em></p>
</blockquote>

<h3 id="整体协作流程">整体协作流程</h3>

<p><img src="/assets/f7bec8f79c08/1*t1oXXy1czhI_yV0LKBVf0Q.webp" alt="" loading="lazy" decoding="async" width="1672" height="941" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjcyIiBoZWlnaHQ9Ijk0MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/f7bec8f79c08/1*t1oXXy1czhI_yV0LKBVf0Q.jpeg" /></p>

<h3 id="用-ai-实现-foundation-资料结构设计">用 AI 实现 Foundation 资料结构设计</h3>

<h4 id="工具">工具</h4>

<ul>
  <li>
    <p>Claude Code Max</p>
  </li>
  <li>
    <p>Effort: Max</p>
  </li>
  <li>
    <p>Model: Opus 4.7</p>
  </li>
</ul>

<h4 id="流程">流程</h4>

<ul>
  <li>
    <p>先请 AI Plan Mode 起草研究 RFC 撰写方案</p>
  </li>
  <li>
    <p>请 AI 开始研究并且有两个 Agent 身份：一位是研究生专门负责研究与撰写 RFC、另一位是教授只负责专注在 Review 算法效率与合理性。(Review 直到 Approve)</p>
  </li>
  <li>
    <p>研究生可以先以 Medium 案例为实验、用 Ruby 开发看看</p>
  </li>
  <li>
    <p>最终产出 RFC.md 文件</p>
  </li>
  <li>
    <p>交由其他 Agent 实现到各种语言 (我 ZMediumToMarkdown 是 Ruby / AVPlayer 是 iOS Swift 问题)</p>
  </li>
</ul>

<h4 id="1-ai-研拟资料结构-rfc--rangeable-rfc">1. AI 研拟资料结构 RFC — Rangeable RFC</h4>

<p><strong>Prompt (Plan Mode):</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/plan

請使用英文，參考英文論文研究，研擬一份 RFC 實作文件，之後會交付讓其他語言可以遵循這份文件實現，研擬期間可以使用 Ruby 作為實驗語言。
你需要研究所有資料結構與演算法，找出一套時間與空間效率最平衡的算法達成需求。
工具名稱：Rangeable
功能：計算泛型物件組合的連續與不連續集合。
範例：
var strings:Rangeable&lt;String&gt; <span class="o">=</span> <span class="o">[]</span>
strings.insert<span class="o">(</span>Strong<span class="o">()</span>, start: 2, end: 5<span class="o">)</span> // 2-5 Strong
strings.insert<span class="o">(</span>Strong<span class="o">()</span>, start: 3, end: 7<span class="o">)</span> // 3-7 Strong
strings.insert<span class="o">(</span>Strong<span class="o">()</span>, start: 9, end: 11<span class="o">)</span> // 9-11 Strong
strings.insert<span class="o">(</span>Italic<span class="o">()</span>, start: 3, end: 8 <span class="o">)</span> // 3-8 Italic

// Usage:
Strong<span class="o">()</span>.getRange<span class="o">(</span>from: strings<span class="o">)</span> -&gt; <span class="o">[{</span>2,7<span class="o">}</span>,<span class="o">{</span>9-11<span class="o">}]</span>
Italic<span class="o">()</span>.getRange<span class="o">(</span>from strings<span class="o">)</span> -&gt; <span class="o">[{</span>3,8<span class="o">}]</span>
//
strings[4].objs -&gt; <span class="o">[</span>Strong<span class="o">()</span>, Italic<span class="o">()]</span>
strings[8].objs -&gt; <span class="o">[</span>Italic<span class="o">()]</span>
strings[10].objs -&gt; <span class="o">[</span>Strong<span class="o">()]</span>
//
請注意 Strong, Italic 本身也是泛型，這裡只是舉例
//

實際研擬 RFC 時請用 sub-agent 一個是研究生負責研究人實現方式與撰寫 RFC、另一個是教授以學術或更深入的演算法為主回頭 Review 研究生 Agent 的產出；如果被教授 Agent 駁回就重新研究撰寫 RFC。
可以先建立 ./RubyRangeable Ruby 的實現 和 ./SwiftRangeable Swift 的實現
你可以盡情消耗 Token 與花費資源做研究。
//
提供一個實際應用場景：../ZMediumToMarkdown 中的 MarkupStyleRender.rb
目前會解析 Medium GraphQL 回傳的 Paragraphs
<span class="o">{</span><span class="s2">"id"</span>: <span class="s2">"f30dc1c4fe6c_19"</span>, <span class="s2">"name"</span>: <span class="s2">"b2ba"</span>, <span class="s2">"type"</span>: <span class="s2">"BQ"</span>, <span class="s2">"href"</span>: null, <span class="s2">"layout"</span>: null, <span class="s2">"metadata"</span>: null, <span class="s2">"text"</span>: <span class="s2">"A notification webhook is an endpoint you create on your server.</span><span class="se">\n</span><span class="s2">通知型 Webhook 是你在自己伺服器上建立的一個端點(endpoint)。"</span>, <span class="s2">"hasDropCap"</span>: null, <span class="s2">"dropCapImage"</span>: null, <span class="s2">"markups"</span>: <span class="o">[{</span><span class="s2">"type"</span>: <span class="s2">"EM"</span>, <span class="s2">"start"</span>: 0, <span class="s2">"end"</span>: 104, <span class="s2">"href"</span>: null, <span class="s2">"anchorType"</span>: null, <span class="s2">"userId"</span>: null, <span class="s2">"linkMetadata"</span>: null, <span class="s2">"__typename"</span>: <span class="s2">"Markup"</span><span class="o">}]</span>, <span class="s2">"__typename"</span>: <span class="s2">"Paragraph"</span>, <span class="s2">"codeBlockMetadata"</span>: null, <span class="s2">"iframe"</span>: null, <span class="s2">"mixtapeMetadata"</span>: null<span class="o">}</span>,
<span class="o">{</span><span class="s2">"id"</span>: <span class="s2">"f30dc1c4fe6c_20"</span>, <span class="s2">"name"</span>: <span class="s2">"f2e8"</span>, <span class="s2">"type"</span>: <span class="s2">"BQ"</span>, <span class="s2">"href"</span>: null, <span class="s2">"layout"</span>: null, <span class="s2">"metadata"</span>: null, <span class="s2">"text"</span>: <span class="s2">"This webhook endpoint receives HTTP POST requests from App Store Connect.</span><span class="se">\n</span><span class="s2">這個 Webhook 端點會接收來自 App Store Connect 的 HTTP POST 請求。"</span>, <span class="s2">"hasDropCap"</span>: null, <span class="s2">"dropCapImage"</span>: null, <span class="s2">"markups"</span>: <span class="o">[{</span><span class="s2">"type"</span>: <span class="s2">"EM"</span>, <span class="s2">"start"</span>: 0, <span class="s2">"end"</span>: 126, <span class="s2">"href"</span>: null, <span class="s2">"anchorType"</span>: null, <span class="s2">"userId"</span>: null, <span class="s2">"linkMetadata"</span>: null, <span class="s2">"__typename"</span>: <span class="s2">"Markup"</span><span class="o">}]</span>, <span class="s2">"__typename"</span>: <span class="s2">"Paragraph"</span>, <span class="s2">"codeBlockMetadata"</span>: null, <span class="s2">"iframe"</span>: null, <span class="s2">"mixtapeMetadata"</span>: null<span class="o">}</span>,
<span class="o">{</span><span class="s2">"id"</span>: <span class="s2">"f30dc1c4fe6c_21"</span>, <span class="s2">"name"</span>: <span class="s2">"1725"</span>, <span class="s2">"type"</span>: <span class="s2">"BQ"</span>, <span class="s2">"href"</span>: null, <span class="s2">"layout"</span>: null, <span class="s2">"metadata"</span>: null, <span class="s2">"text"</span>: <span class="s2">"The POST requests describe important events about your app.</span><span class="se">\n</span><span class="s2">這些 POST 請求會描述與你的 App 相關的重要事件。"</span>, <span class="s2">"hasDropCap"</span>: null, <span class="s2">"dropCapImage"</span>: null, <span class="s2">"markups"</span>: <span class="o">[{</span><span class="s2">"type"</span>: <span class="s2">"EM"</span>, <span class="s2">"start"</span>: 0, <span class="s2">"end"</span>: 89, <span class="s2">"href"</span>: null, <span class="s2">"anchorType"</span>: null, <span class="s2">"userId"</span>: null, <span class="s2">"linkMetadata"</span>: null, <span class="s2">"__typename"</span>: <span class="s2">"Markup"</span><span class="o">}]</span>, <span class="s2">"__typename"</span>: <span class="s2">"Paragraph"</span>, <span class="s2">"codeBlockMetadata"</span>: null, <span class="s2">"iframe"</span>: null, <span class="s2">"mixtapeMetadata"</span>: null<span class="o">}</span>,
<span class="o">{</span><span class="s2">"id"</span>: <span class="s2">"f30dc1c4fe6c_22"</span>, <span class="s2">"name"</span>: <span class="s2">"3e9d"</span>, <span class="s2">"type"</span>: <span class="s2">"BQ"</span>, <span class="s2">"href"</span>: null, <span class="s2">"layout"</span>: null, <span class="s2">"metadata"</span>: null, <span class="s2">"text"</span>: <span class="s2">"Use the webhooks notifications endpoint to configure the notifications for events happening to your apps.</span><span class="se">\n</span><span class="s2">你可以使用 Webhook 通知端點，來設定當你的 App 發生各種事件時所要接收的通知。"</span>, <span class="s2">"hasDropCap"</span>: null, <span class="s2">"dropCapImage"</span>: null, <span class="s2">"markups"</span>: <span class="o">[{</span><span class="s2">"type"</span>: <span class="s2">"EM"</span>, <span class="s2">"start"</span>: 0, <span class="s2">"end"</span>: 151, <span class="s2">"href"</span>: null, <span class="s2">"anchorType"</span>: null, <span class="s2">"userId"</span>: null, <span class="s2">"linkMetadata"</span>: null, <span class="s2">"__typename"</span>: <span class="s2">"Markup"</span><span class="o">}]</span>, <span class="s2">"__typename"</span>: <span class="s2">"Paragraph"</span>, <span class="s2">"codeBlockMetadata"</span>: null, <span class="s2">"iframe"</span>: null, <span class="s2">"mixtapeMetadata"</span>: null<span class="o">}</span>,
然後依照 start, end 渲染出 Markdown，可是目前沒有算法所以是用巡迴填補的方法。
</code></pre></div></div>

<h4 id="2-方案确定后研究生-agent-开始研究---产出第一版-rfc">2. 方案确定后研究生 Agent 开始研究 -&gt; 产出第一版 RFC</h4>

<h4 id="3-教授-agent-开始-review---rejected">3. 教授 Agent 开始 Review -&gt; REJECTED</h4>

<p>主因是教授认为 RFC 还有 <strong>6 个 MUST-FIX</strong> ，也就是不修不能通过的规格/演算法正确性问题。</p>

<p><img src="/assets/f7bec8f79c08/1*wJuWgRv0aQqpDWkjORt1nw.webp" alt="" loading="lazy" decoding="async" width="967" height="469" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjciIGhlaWdodD0iNDY5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/f7bec8f79c08/1*wJuWgRv0aQqpDWkjORt1nw.png" /></p>

<h4 id="4-研究生-agent-回头研究修改---产出第二版-rfc">4. 研究生 Agent 回头研究修改 -&gt; 产出第二版 RFC</h4>

<h4 id="5-教授-agent-重新-review---approved">5. 教授 Agent 重新 Review -&gt; APPROVED</h4>

<h4 id="6-done">6. Done</h4>

<ul>
  <li>
    <p>花费时间：约 1 hr 30 mins</p>
  </li>
  <li>
    <p>花费 Token：178K (约占 Claude Code Max 5 hr 可用额度的 30%)</p>
  </li>
</ul>

<h3 id="rangeable-rfc">Rangeable RFC</h3>

<p><a href="https://github.com/ZhgChgLi/RangeableRFC/blob/main/RFC.md" target="_blank"><img src="https://opengraph.githubassets.com/c1bbe414aeed52b95e22e3420b934b9cc8d1b4fc8feb04da559f7d9b381f7f0f/ZhgChgLi/RangeableRFC" alt="" /></a></p>

<h4 id="tldr">TL;DR</h4>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">Rangeable&lt;Element&gt;</code> <em>是一个用来管理「元素在哪些整数闭区间内生效」的通用资料结构。它可以把同一元素重叠或相邻的区间自动合并，并支援查询某个 index 上有哪些元素 active，以及输出某段范围内的 open / close transition events。它原本是为了解决 Medium Markdown markup render 问题，例如判断某个字元同时套用了 <code class="language-plaintext highlighter-rouge">STRONG</code> 、 <code class="language-plaintext highlighter-rouge">EM</code> 、 <code class="language-plaintext highlighter-rouge">LINK</code> 哪些样式；但同样 <strong>也能套用在 Calendar、游戏状态、Genome annotation、AVPlayer byte-range cache 等场景</strong> 。核心价值是把「区间合并、active set 查询、边界事件产生」抽象成一个 deterministic、跨语言一致、适合 Ruby / Swift 实作的规格。</em></p>
</blockquote>

<blockquote>
  <p>以下 RFC 细节除非很有兴趣不然可以直接略过。这边也是直接用 AI 翻译总结的。</p>
</blockquote>

<p><code class="language-plaintext highlighter-rouge">Rangeable&lt;Element&gt;</code> 是一个「 <strong>把元素对应到多段整数闭区间，并能快速查询某个位置有哪些元素生效</strong> 」的通用资料结构。</p>

<p>它解的不是单纯的 <code class="language-plaintext highlighter-rouge">Range</code> 问题，而是给我很多个 <code class="language-plaintext highlighter-rouge">(元素, start, end)</code> ，我要能：</p>

<ol>
  <li>
    <p>查某个元素有哪些合并后的区间</p>
  </li>
  <li>
    <p>查某个 index 上有哪些元素 active</p>
  </li>
  <li>
    <p>查某段范围内有哪些 open / close 边界事件</p>
  </li>
</ol>

<p>RFC 明确定义 <code class="language-plaintext highlighter-rouge">Rangeable</code> 是一个 language-neutral、generic、integer-coordinate、closed-interval set container，元素必须可 Hash，比对以 value equality 为准。它支援 <code class="language-plaintext highlighter-rouge">getRange</code> 、 <code class="language-plaintext highlighter-rouge">r[i].objs</code> 、 <code class="language-plaintext highlighter-rouge">transitions</code> 三种查询。</p>

<h4 id="主要动机">主要动机</h4>

<p>这份 RFC 起源于 <code class="language-plaintext highlighter-rouge">ZMediumToMarkdown</code> 的 Medium markup render 问题。</p>

<p>Medium paragraph 内会有像这样的 markups：</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">STRONG</span><span class="o">:</span> <span class="nf">[2</span><span class="p">,</span><span class="nf"> 5]</span>
<span class="nl">STRONG</span><span class="o">:</span> <span class="nf">[3</span><span class="p">,</span><span class="nf"> 7]</span>
<span class="nl">EM</span><span class="o">:</span>     <span class="nf">[4</span><span class="p">,</span><span class="nf"> 10]</span>
</code></pre></div></div>

<p>目前 render 时需要逐字扫描，判断每个字元上有哪些 tag active，例如 bold、italic、link、code 等。RFC 里提到原本做法会把 markups 转成 <code class="language-plaintext highlighter-rouge">TagChar</code> ，依照 <code class="language-plaintext highlighter-rouge">startIndex</code> 排序，然后每个字元线性扫过所有 tags，最坏会到 <code class="language-plaintext highlighter-rouge">O(L · m)</code> 。 <code class="language-plaintext highlighter-rouge">Rangeable</code> 想把这件事抽象化成通用容器，让 renderer 只要 insert markups，再用 <code class="language-plaintext highlighter-rouge">r[i].objs</code> 或 <code class="language-plaintext highlighter-rouge">transitions</code> 查询即可。</p>

<p>RFC 也把这个问题扩展到其他场景，例如：</p>

<p><img src="/assets/f7bec8f79c08/1*AWs90nwJGkKee9iEzLwexQ.webp" alt="" loading="lazy" decoding="async" width="611" height="275" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MTEiIGhlaWdodD0iMjc1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/f7bec8f79c08/1*AWs90nwJGkKee9iEzLwexQ.png" /></p>

<p>RFC 明确指出共通问题是：给定很多 <code class="language-plaintext highlighter-rouge">(eᵢ, lᵢ, hᵢ)</code> ，查某个位置 <code class="language-plaintext highlighter-rouge">i</code> 时，要回传所有满足 <code class="language-plaintext highlighter-rouge">l ≤ i ≤ h</code> 的元素。</p>

<h4 id="核心概念翻译">核心概念翻译</h4>

<h4 id="1-rangeableelement">1. <code class="language-plaintext highlighter-rouge">Rangeable&lt;Element&gt;</code></h4>

<p>可以想成：</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">Element</span> <span class="nt">-</span><span class="o">&gt;</span> <span class="o">[</span><span class="nt">ClosedRange</span><span class="o">&lt;</span><span class="nt">Int</span><span class="o">&gt;]</span>
</code></pre></div></div>

<p>但它不是普通 Dictionary，因为它会：</p>

<ol>
  <li>
    <p>自动合并同一元素的重叠区间</p>
  </li>
  <li>
    <p>自动合并相邻区间</p>
  </li>
  <li>
    <p>保留元素第一次插入顺序</p>
  </li>
  <li>
    <p>支援快速查询某个 index 上 active 的 elements</p>
  </li>
  <li>
    <p>支援输出 open / close transition events</p>
  </li>
</ol>

<p>例如：</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">insert</span><span class="o">(</span><span class="nt">STRONG</span><span class="o">,</span> <span class="nt">2</span><span class="o">,</span> <span class="nt">5</span><span class="o">)</span>
<span class="nt">insert</span><span class="o">(</span><span class="nt">STRONG</span><span class="o">,</span> <span class="nt">3</span><span class="o">,</span> <span class="nt">7</span><span class="o">)</span>
</code></pre></div></div>

<p>最后会变成：</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">STRONG</span> <span class="nt">-</span><span class="o">&gt;</span> <span class="o">[(</span><span class="err">2</span><span class="o">,</span> <span class="err">7</span><span class="o">)]</span>
</code></pre></div></div>

<p>因为 <code class="language-plaintext highlighter-rouge">[2,5]</code> 和 <code class="language-plaintext highlighter-rouge">[3,7]</code> 重叠。</p>

<h4 id="api-重点">API 重点</h4>

<p>RFC 定义的主要 API 如下。</p>

<h4 id="inserte-start-end"><code class="language-plaintext highlighter-rouge">insert(e, start, end)</code></h4>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">insert</span><span class="p">(</span><span class="n">e</span><span class="p">:</span> <span class="n">Element</span><span class="p">,</span> <span class="k">start</span><span class="p">:</span> <span class="nb">Int</span><span class="p">,</span> <span class="k">end</span><span class="p">:</span> <span class="nb">Int</span><span class="p">)</span>
</code></pre></div></div>

<p>效果是：</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">R</span><span class="p">(</span><span class="n">e</span><span class="p">)</span> <span class="o">=</span> <span class="n">canonicalize</span><span class="p">(</span><span class="n">R</span><span class="p">(</span><span class="n">e</span><span class="p">)</span> <span class="err">∪</span> <span class="p">[</span><span class="k">start</span><span class="p">,</span> <span class="k">end</span><span class="p">])</span>
</code></pre></div></div>

<p>也就是把新区间加入元素 <code class="language-plaintext highlighter-rouge">e</code> 的既有区间集合，然后做 canonicalize：合并所有重叠或相邻的区间并排序。 <code class="language-plaintext highlighter-rouge">start &gt; end</code> 必须丢出 <code class="language-plaintext highlighter-rouge">InvalidIntervalError</code> ；重复 insert 相同内容是 idempotent，不应改变结果，也不应增加 version。</p>

<h4 id="riobjs--activeatindex"><code class="language-plaintext highlighter-rouge">r[i].objs</code> / <code class="language-plaintext highlighter-rouge">activeAt(index:)</code></h4>

<pre><code class="language-less">r[i] -&gt; Slot
r.activeAt(index: i) -&gt; Slot
</code></pre>

<p>回传某个 index 上 active 的 elements。</p>

<p>例如：</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">insert</span><span class="o">(</span><span class="nt">Strong</span><span class="o">,</span> <span class="nt">2</span><span class="o">,</span> <span class="nt">5</span><span class="o">)</span>
<span class="nt">insert</span><span class="o">(</span><span class="nt">Italic</span><span class="o">,</span> <span class="nt">3</span><span class="o">,</span> <span class="nt">7</span><span class="o">)</span>
</code></pre></div></div>

<p>查询：</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">r</span><span class="o">[</span><span class="err">3</span><span class="o">]</span><span class="nc">.objs</span>
</code></pre></div></div>

<p>结果是：</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">Strong</span><span class="p">,</span> <span class="n">Italic</span><span class="p">]</span>
</code></pre></div></div>

<p>查询复杂度目标是：</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">O</span><span class="o">(</span><span class="nt">log</span> <span class="nt">M</span> <span class="o">+</span> <span class="nt">r</span><span class="o">)</span>
</code></pre></div></div>

<p>其中 <code class="language-plaintext highlighter-rouge">M</code> 是所有元素合并后的 interval 数量总和， <code class="language-plaintext highlighter-rouge">r</code> 是该位置实际回传的元素数。</p>

<h4 id="getrangeof"><code class="language-plaintext highlighter-rouge">getRange(of:)</code></h4>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">getRange</span><span class="o">(</span><span class="nt">of</span> <span class="nt">e</span><span class="o">)</span> <span class="nt">-</span><span class="o">&gt;</span> <span class="o">[(</span><span class="nt">Int</span><span class="o">,</span> <span class="nt">Int</span><span class="o">)]</span>
</code></pre></div></div>

<p>回传某个元素目前合并后的 canonical ranges。</p>

<p>例如：</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">insert</span><span class="o">(</span><span class="nt">Strong</span><span class="o">,</span> <span class="nt">2</span><span class="o">,</span> <span class="nt">4</span><span class="o">)</span>
<span class="nt">insert</span><span class="o">(</span><span class="nt">Strong</span><span class="o">,</span> <span class="nt">5</span><span class="o">,</span> <span class="nt">7</span><span class="o">)</span>
</code></pre></div></div>

<p>因为 <code class="language-plaintext highlighter-rouge">[2,4]</code> 和 <code class="language-plaintext highlighter-rouge">[5,7]</code> 在整数座标上相邻，所以结果是：</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[(</span><span class="err">2</span><span class="o">,</span> <span class="err">7</span><span class="o">)]</span>
</code></pre></div></div>

<p>RFC 明确要求回传的 intervals 必须排序、互不重叠、也不相邻。</p>

<h4 id="transitionsover"><code class="language-plaintext highlighter-rouge">transitions(over:)</code></h4>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">transitions</span><span class="err">(</span><span class="na">over</span><span class="p">:</span> <span class="n">ClosedRange</span><span class="o">&lt;</span><span class="n">Int</span><span class="o">&gt;</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">TransitionEvent</span><span class="p">]</span>
</code></pre></div></div>

<p>回传一段范围内的 open / close 边界事件。</p>

<p>例如：</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">insert</span><span class="o">(</span><span class="nt">Strong</span><span class="o">,</span> <span class="nt">2</span><span class="o">,</span> <span class="nt">5</span><span class="o">)</span>
<span class="nt">insert</span><span class="o">(</span><span class="nt">Italic</span><span class="o">,</span> <span class="nt">3</span><span class="o">,</span> <span class="nt">7</span><span class="o">)</span>
</code></pre></div></div>

<p>则 transitions 会是：</p>

<div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span>
  <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">open</span><span class="p">,</span>  <span class="n">Strong</span><span class="p">),</span>
  <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">open</span><span class="p">,</span>  <span class="n">Italic</span><span class="p">),</span>
  <span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="n">close</span><span class="p">,</span> <span class="n">Strong</span><span class="p">),</span>
  <span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="n">close</span><span class="p">,</span> <span class="n">Italic</span><span class="p">)</span>
<span class="p">]</span>
</code></pre></div></div>

<p>注意 close event 的位置是 <code class="language-plaintext highlighter-rouge">hi + 1</code> ，因为外部语意是闭区间 <code class="language-plaintext highlighter-rouge">[lo, hi]</code> ，但 sweep-line 内部用「第一个不再 active 的位置」当 close coordinate。RFC 明确说明 <code class="language-plaintext highlighter-rouge">transitions(over: lo..hi)</code> 会包含 <code class="language-plaintext highlighter-rouge">hi + 1</code> 的 close event，方便处理右边界。</p>

<h4 id="区间语意">区间语意</h4>

<h4 id="1-end-是-inclusive">1. <code class="language-plaintext highlighter-rouge">end</code> 是 inclusive</h4>

<p>这份 RFC 非常明确： <code class="language-plaintext highlighter-rouge">insert(e, start: a, end: b)</code> 表示闭区间 <code class="language-plaintext highlighter-rouge">[a, b]</code> ， <code class="language-plaintext highlighter-rouge">b</code> 本身也包含在 active range 里。</p>

<p>也就是：</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">insert</span><span class="o">(</span><span class="nt">Strong</span><span class="o">,</span> <span class="nt">2</span><span class="o">,</span> <span class="nt">5</span><span class="o">)</span>
</code></pre></div></div>

<p>代表：</p>

<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span> <span class="nx">都</span> <span class="nx">active</span>
</code></pre></div></div>

<p>不是 <code class="language-plaintext highlighter-rouge">[2, 5)</code> 。</p>

<p>RFC 选择 inclusive 的原因包括：</p>

<ol>
  <li>
    <p>符合 Medium markup / ZMediumToMarkdown 的历史资料模型</p>
  </li>
  <li>
    <p>比较符合「这个字元是否 active」的人类直觉</p>
  </li>
  <li>
    <p>整数相邻合并可以写成 <code class="language-plaintext highlighter-rouge">hi + 1 == lo</code></p>
  </li>
  <li>
    <p>单点区间 <code class="language-plaintext highlighter-rouge">[k, k]</code> 可以自然表示一个有效位置</p>
  </li>
</ol>

<h4 id="2-相邻区间要合并">2. 相邻区间要合并</h4>

<p>在整数座标上：</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="m">2</span><span class="p">,</span> <span class="m">4</span><span class="p">]</span> <span class="p">+</span> <span class="p">[</span><span class="m">5</span><span class="p">,</span> <span class="m">7</span><span class="p">]</span> <span class="p">=&gt;</span> <span class="p">[</span><span class="m">2</span><span class="p">,</span> <span class="m">7</span><span class="p">]</span>
</code></pre></div></div>

<p>因为 4 和 5 之间没有任何整数位置可以表示「不 active」。RFC 要求同一个元素的整数相邻区间必须合并。</p>

<p>但：</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="m">2</span><span class="p">,</span> <span class="m">4</span><span class="p">]</span> <span class="p">+</span> <span class="p">[</span><span class="m">6</span><span class="p">,</span> <span class="m">7</span><span class="p">]</span> <span class="p">=&gt;</span> <span class="p">[(</span><span class="m">2</span><span class="p">,</span> <span class="m">4</span><span class="p">),</span> <span class="p">(</span><span class="m">6</span><span class="p">,</span> <span class="m">7</span><span class="p">)]</span>
</code></pre></div></div>

<p>因为中间有 <code class="language-plaintext highlighter-rouge">5</code> 这个 gap。</p>

<h4 id="3-start--end-是合法-singleton-interval">3. <code class="language-plaintext highlighter-rouge">start == end</code> 是合法 singleton interval</h4>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">insert</span><span class="o">(</span><span class="nt">e</span><span class="o">,</span> <span class="nt">5</span><span class="o">,</span> <span class="nt">5</span><span class="o">)</span>
</code></pre></div></div>

<p>代表只有 index <code class="language-plaintext highlighter-rouge">5</code> active。RFC 要求这是合法且非空的区间。</p>

<h4 id="4-start--end-必须丢错">4. <code class="language-plaintext highlighter-rouge">start &gt; end</code> 必须丢错</h4>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">insert</span><span class="o">(</span><span class="nt">e</span><span class="o">,</span> <span class="nt">10</span><span class="o">,</span> <span class="nt">5</span><span class="o">)</span>
</code></pre></div></div>

<p>不能自动反转成 <code class="language-plaintext highlighter-rouge">[5,10]</code> ，也不能 silent normalize。RFC 要求必须丢出 <code class="language-plaintext highlighter-rouge">InvalidIntervalError</code> ，而且 container 状态不能改变。</p>

<h4 id="element-equality-语意">Element equality 语意</h4>

<p><code class="language-plaintext highlighter-rouge">Rangeable</code> 判断两个 element 是否同一个元素，是看语言原生的 value equality。</p>

<p>Ruby：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>eql? + <span class="nb">hash</span>
</code></pre></div></div>

<p>Swift：</p>

<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Hashable</span> <span class="o">/</span> <span class="nx">Equatable</span>
</code></pre></div></div>

<p>所以：</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">Link</span><span class="o">(</span><span class="s2">"a"</span><span class="o">)</span> <span class="err">和</span> <span class="nt">Link</span><span class="o">(</span><span class="s2">"a"</span><span class="o">)</span> <span class="err">會被視為同一個元素，區間會合併</span>
<span class="nt">Link</span><span class="o">(</span><span class="s2">"a"</span><span class="o">)</span> <span class="err">和</span> <span class="nt">Link</span><span class="o">(</span><span class="s2">"b"</span><span class="o">)</span> <span class="err">是不同元素，不會合併</span>
<span class="nt">Strong</span><span class="o">()</span> <span class="err">和</span> <span class="nt">Strong</span><span class="o">()</span> <span class="err">如果</span> <span class="nt">equality</span> <span class="err">相等，也會合併</span>
</code></pre></div></div>

<p>RFC 要求 equality 必须满足 reflexive、symmetric、transitive、hash consistency，而且元素插入后不应再被外部 mutation 破坏 hash/equality。</p>

<h4 id="排序规则">排序规则</h4>

<p>这是 RFC 很重要的部分。</p>

<h4 id="active-set-排序">Active set 排序</h4>

<p><code class="language-plaintext highlighter-rouge">r[i].objs</code> 的顺序不是依 hash、不是依字母、也不是依 range 长度，而是：</p>

<div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">元素第一次被</span> <span class="n">insert</span> <span class="err">的順序</span>
</code></pre></div></div>

<p>例如：</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">insert</span><span class="o">(</span><span class="nt">Strong</span><span class="o">,</span> <span class="nt">1</span><span class="o">,</span> <span class="nt">10</span><span class="o">)</span>
<span class="nt">insert</span><span class="o">(</span><span class="nt">Italic</span><span class="o">,</span> <span class="nt">1</span><span class="o">,</span> <span class="nt">10</span><span class="o">)</span>
<span class="nt">insert</span><span class="o">(</span><span class="nt">Code</span><span class="o">,</span> <span class="nt">1</span><span class="o">,</span> <span class="nt">10</span><span class="o">)</span>
</code></pre></div></div>

<p>则：</p>

<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">r</span><span class="p">[</span><span class="mi">5</span><span class="p">].</span><span class="nx">objs</span> <span class="o">==</span> <span class="p">[</span><span class="nx">Strong</span><span class="p">,</span> <span class="nx">Italic</span><span class="p">,</span> <span class="nx">Code</span><span class="p">]</span>
</code></pre></div></div>

<p>RFC 指出这样做是为了 deterministic、跨语言一致，而且符合 Markdown nesting：越早出现的 style 通常是外层。</p>

<h4 id="merge-不会改变-insertion-order">Merge 不会改变 insertion order</h4>

<p>例如：</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">insert</span><span class="o">(</span><span class="nt">Strong</span><span class="o">,</span> <span class="nt">1</span><span class="o">,</span> <span class="nt">5</span><span class="o">)</span>   <span class="o">//</span> <span class="nt">Strong</span> <span class="nt">ord</span> <span class="o">=</span> <span class="nt">1</span>
<span class="nt">insert</span><span class="o">(</span><span class="nt">Italic</span><span class="o">,</span> <span class="nt">3</span><span class="o">,</span> <span class="nt">7</span><span class="o">)</span>   <span class="o">//</span> <span class="nt">Italic</span> <span class="nt">ord</span> <span class="o">=</span> <span class="nt">2</span>
<span class="nt">insert</span><span class="o">(</span><span class="nt">Strong</span><span class="o">,</span> <span class="nt">4</span><span class="o">,</span> <span class="nt">8</span><span class="o">)</span>   <span class="o">//</span> <span class="nt">Strong</span> <span class="nt">range</span> <span class="err">合併成</span> <span class="o">[</span><span class="nt">1</span><span class="o">,</span><span class="nt">8</span><span class="o">]</span><span class="err">，但</span> <span class="nt">ord</span> <span class="err">還是</span> <span class="nt">1</span>
</code></pre></div></div>

<p>查询：</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">r</span><span class="o">[</span><span class="err">6</span><span class="o">]</span><span class="nc">.objs</span>
</code></pre></div></div>

<p>结果是：</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">Strong</span><span class="p">,</span> <span class="n">Italic</span><span class="p">]</span>
</code></pre></div></div>

<p>虽然 Strong 是第三步才延伸到 index 6，但它的 first-insert order 仍然比 Italic 早。RFC 用这个 case 钉死「元素第一次出现的顺序」才是排序基准。</p>

<h4 id="transitions-排序">Transitions 排序</h4>

<p>同一个 coordinate 上：</p>

<ol>
  <li>
    <p><code class="language-plaintext highlighter-rouge">.open</code> 比 <code class="language-plaintext highlighter-rouge">.close</code> 早</p>
  </li>
  <li>
    <p>多个 <code class="language-plaintext highlighter-rouge">.open</code> ：依 insertion order 升序</p>
  </li>
  <li>
    <p>多个 <code class="language-plaintext highlighter-rouge">.close</code> ：依 insertion order 降序，也就是 LIFO</p>
  </li>
</ol>

<p>这样可以符合 Markdown stack discipline：</p>

<div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">**</span> <span class="n">open</span>
<span class="n">_</span> <span class="n">open</span>
<span class="n">_</span> <span class="n">close</span>
<span class="o">**</span> <span class="n">close</span>
</code></pre></div></div>

<p>RFC 明确定义这套 tie-breaking，以避免 Ruby / Swift hash order 不一致造成跨语言输出不同。</p>

<h4 id="内部资料结构">内部资料结构</h4>

<p>RFC 选择的核心设计是：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Map&lt;Element, SortedList&lt;Interval&gt;&gt;
+ insertion_order
+ lazy boundary-event index
+ version counter
</code></pre></div></div>

<h4 id="1-per-element-sorted-disjoint-list">1. Per-element sorted disjoint list</h4>

<p>每个元素有自己的 interval list：</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">intervals</span><span class="p">:</span> <span class="kt">Map</span><span class="o">&lt;</span><span class="kt">Element</span><span class="p">,</span> <span class="kt">SortedList</span><span class="o">&lt;</span><span class="kt">Interval</span><span class="o">&gt;&gt;</span>
</code></pre></div></div>

<p>而且必须维持 canonical form：</p>

<ol>
  <li>
    <p>依 <code class="language-plaintext highlighter-rouge">lo</code> 递增排序</p>
  </li>
  <li>
    <p>彼此不重叠</p>
  </li>
  <li>
    <p>彼此不相邻</p>
  </li>
  <li>
    <p>每个 interval 都满足 <code class="language-plaintext highlighter-rouge">lo &lt;= hi</code></p>
  </li>
</ol>

<p>RFC 称这是 I1 invariant。</p>

<h4 id="2-lazy-boundary-event-index">2. Lazy boundary-event index</h4>

<p><code class="language-plaintext highlighter-rouge">Rangeable</code> 不会每次 insert 都重建查询 index，而是等第一次 query 时才 build。</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">version</span><span class="o">:</span> <span class="nf">Int</span>
<span class="nl">event_index</span><span class="o">:</span> <span class="nf">EventIndex?</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">event_index</code> 包含：</p>

<pre><code class="language-vbnet">events: SortedArray&lt;Event&gt;
segments: SortedArray&lt;Segment&gt;
version: Int
</code></pre>

<p>这个设计是为了符合「build-once-then-query-densely」的 workload：大量 insert 完后，再密集查询每个位置。RFC 明确说明 lazy index 适合这种模式，因为 build phase 不需要一直 rebuild index，query phase 只付一次 <code class="language-plaintext highlighter-rouge">O(M log M)</code> 成本。</p>

<h4 id="演算法重点">演算法重点</h4>

<h4 id="insert-的核心流程"><code class="language-plaintext highlighter-rouge">insert</code> 的核心流程</h4>

<p>RFC 的 pseudocode 大致是：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function </span>insert<span class="o">(</span>r, e, start, end<span class="o">)</span>:
  <span class="k">if </span>start <span class="o">&gt;</span> end:
    raise InvalidIntervalError

  e_frozen <span class="o">=</span> freeze_for_insert<span class="o">(</span>e<span class="o">)</span>

  <span class="k">if </span>e not <span class="k">in </span>intervals:
    intervals[e] <span class="o">=</span> <span class="o">[]</span>
    insertion_order.append<span class="o">(</span>e<span class="o">)</span>
    ord[e] <span class="o">=</span> insertion_order.length

  list <span class="o">=</span> intervals[e]
  lo <span class="o">=</span> start
  hi <span class="o">=</span> end

  找到第一個可能與 <span class="o">[</span>lo, hi] 重疊或相鄰的 interval

  <span class="k">while </span>interval 跟 <span class="o">[</span>lo, hi] 重疊或相鄰:
    lo <span class="o">=</span> min<span class="o">(</span>lo, interval.lo<span class="o">)</span>
    hi <span class="o">=</span> max<span class="o">(</span>hi, interval.hi<span class="o">)</span>
    移除舊 interval

  插入合併後的新 <span class="o">[</span>lo, hi]

  如果真的有改變:
    version +<span class="o">=</span> 1
    event_index <span class="o">=</span> nil
</code></pre></div></div>

<p>特别要注意 RFC 提醒不能用 <code class="language-plaintext highlighter-rouge">lo - 1</code> 来判断，因为 <code class="language-plaintext highlighter-rouge">lo == Int.min</code> 时会 underflow；应该用 <code class="language-plaintext highlighter-rouge">hi + 1 &gt;= lo</code> 或等价的 successor model。</p>

<h4 id="复杂度">复杂度</h4>

<p>RFC 选择的 reference structure 是：</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">per</span><span class="p">-</span><span class="n">element</span> <span class="n">sorted</span> <span class="n">disjoint</span> <span class="n">list</span> <span class="p">+</span> <span class="n">lazy</span> <span class="k">event</span> <span class="n">index</span>
</code></pre></div></div>

<p>复杂度大致如下：</p>

<p><img src="/assets/f7bec8f79c08/1*5HKeVhHLMRIWnuJJmmGTbQ.webp" alt="" loading="lazy" decoding="async" width="396" height="197" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzOTYiIGhlaWdodD0iMTk3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/f7bec8f79c08/1*5HKeVhHLMRIWnuJJmmGTbQ.png" /></p>

<p>其中：</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="py">m_e</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">某個 element 自己的 merged interval 數量</span>
<span class="py">k</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">本次 insert 吸收/合併掉的舊 intervals 數量</span>
<span class="py">M</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">所有 elements 的 merged intervals 總數</span>
<span class="py">r</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">查詢位置實際 active 的 elements 數量</span>
</code></pre></div></div>

<p>RFC 也指出，如果同一个位置真的有 <code class="language-plaintext highlighter-rouge">m</code> 个元素 active，那输出本身就需要 <code class="language-plaintext highlighter-rouge">Ω(m)</code> ，所以 <code class="language-plaintext highlighter-rouge">O(log M + m)</code> 已经是 output-sensitive 的合理界线。</p>

<h4 id="为什么不用-interval-tree--segment-tree--roaring-bitmap">为什么不用 Interval Tree / Segment Tree / Roaring Bitmap？</h4>

<p>RFC 有一整节比较替代方案，最后选择 <code class="language-plaintext highlighter-rouge">(a) Per-element sorted disjoint list + lazy event index</code> 。</p>

<p>重点如下：</p>

<p><img src="/assets/f7bec8f79c08/1*psrNFxHTKrwba92dA0rOLw.webp" alt="" loading="lazy" decoding="async" width="891" height="275" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4OTEiIGhlaWdodD0iMjc1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/f7bec8f79c08/1*psrNFxHTKrwba92dA0rOLw.png" /></p>

<p>RFC 总结选择主结构的三个原因：</p>

<ol>
  <li>
    <p>per-element merge 语意自然， <code class="language-plaintext highlighter-rouge">getRange</code> 可以直接回传 <code class="language-plaintext highlighter-rouge">R(e)</code></p>
  </li>
  <li>
    <p>deterministic、跨语言可重现</p>
  </li>
  <li>
    <p>lazy index 很适合 build-once-then-query workload</p>
  </li>
</ol>

<h4 id="v1-不包含的功能">v1 不包含的功能</h4>

<p>RFC 明确列出 v1 不做：</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">remove</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="k">start</span><span class="p">,</span> <span class="k">end</span><span class="p">)</span>
<span class="n">remove</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="n">clear</span>
<span class="k">union</span> <span class="o">/</span> <span class="k">intersect</span> <span class="o">/</span> <span class="n">difference</span>
<span class="n">persistent</span> <span class="k">immutable</span> <span class="n">snapshot</span>
<span class="n">floating</span><span class="o">-</span><span class="n">point</span> <span class="n">coordinates</span>
<span class="n">multi</span><span class="o">-</span><span class="n">dimensional</span> <span class="n">rectangle</span> <span class="n">stabbing</span>
<span class="n">r</span><span class="p">[</span><span class="n">lo</span><span class="p">...</span><span class="n">hi</span><span class="p">].</span><span class="n">objs</span> <span class="err">這種</span> <span class="k">range</span> <span class="n">slot</span> <span class="n">query</span>
</code></pre></div></div>

<p>删除、交集这块也请 AI 著手在 RFC V2 实现。</p>

<h3 id="请-ai-基于-rangeable-rfc-实现语言实作">请 AI 基于 <a href="https://github.com/ZhgChgLi/RangeableRFC" target="_blank">Rangeable RFC</a> 实现语言实作</h3>

<h4 id="流程-1">流程</h4>

<ol>
  <li>
    <p>一样是先走 <code class="language-plaintext highlighter-rouge">/plan</code> Plan Mode 请 AI 详细阅读 RFC 并规划实作</p>
  </li>
  <li>
    <p>一样拆分 developer / reviewer 一个做一个审核，直到没问题</p>
  </li>
  <li>
    <p>撰写 Readme 使用文件、Push 到 GitHub</p>
  </li>
</ol>

<blockquote>
  <p><em>最困难的 RFC 规格研究已经完成后面的实作只要 AI 遵照这个规格实现，几乎都不会有问题。</em></p>
</blockquote>

<h4 id="目前已实现的语言如下">目前已实现的语言如下</h4>

<ul>
  <li>
    <p>Ruby 3.2+ <a href="https://github.com/ZhgChgLi/RubyRangeable" target="_blank">github.com/ZhgChgLi/RubyRangeable</a></p>
  </li>
  <li>
    <p>Swift 5.7+ <a href="https://github.com/ZhgChgLi/SwiftRangeable" target="_blank">github.com/ZhgChgLi/SwiftRangeable</a></p>
  </li>
  <li>
    <p>Python 3.10+ <a href="https://github.com/ZhgChgLi/PythonRangeable" target="_blank">github.com/ZhgChgLi/PythonRangeable</a></p>
  </li>
  <li>
    <p>TypeScript / JS (Node 18+) <a href="https://github.com/ZhgChgLi/JSRangeable" target="_blank">github.com/ZhgChgLi/JSRangeable</a></p>
  </li>
  <li>
    <p>Kotlin / JVM 11+ <a href="https://github.com/ZhgChgLi/KotlinRangeable" target="_blank">github.com/ZhgChgLi/KotlinRangeable</a></p>
  </li>
  <li>
    <p>Go 1.22+ <a href="https://github.com/ZhgChgLi/GoRangeable" target="_blank">github.com/ZhgChgLi/GoRangeable</a></p>
  </li>
</ul>

<h3 id="实际应用-ai-设计开发的--rangeable-foundation">实际应用 AI 设计开发的 — Rangeable Foundation</h3>

<p>东西都准备好之后，回到最一开始的开源专案 ZMediumToMarkdown 的算法问题本身，请 AI 套用这个 Lib 回到、移除原本复杂的 walkthrough 做法优化架构＋ <strong>补上验证套用前后测试</strong> 。</p>

<h4 id="zmediumtomarkdown-360"><a href="https://github.com/ZhgChgLi/ZMediumToMarkdown/releases/tag/v3.6.0" target="_blank">ZMediumToMarkdown 3.6.0</a></h4>

<p><strong>Performance</strong></p>

<ul>
  <li>
    <p>Micro-benchmark: 5.5× faster on the markup render hot path.</p>
  </li>
  <li>
    <p>End-to-end on a real Medium article: 2.23× faster
(2073 µs → 930 µs per paragraph on average).</p>
  </li>
</ul>

<h4 id="avplayer-本地-cache-实作攻略"><a href="https://zhgchg.li/posts/zrealm-dev/avplayer-%E6%9C%AC%E5%9C%B0-cache-%E5%AF%A6%E4%BD%9C%E6%94%BB%E7%95%A5-%E4%BD%BF%E7%94%A8-avassetresourceloaderdelegate-%E7%AF%80%E7%9C%81-ios-%E9%9F%B3%E6%A8%82%E4%B8%B2%E6%B5%81%E6%B5%81%E9%87%8F-6ce488898003/#20260510-updated" target="_blank">AVPlayer 本地 Cache 实作攻略</a></h4>

<p>文章内容也多补充了套用 SwiftRangeable 的案例。</p>

<h3 id="赞叹-ai">赞叹 AI</h3>

<p>原本都只拿 AI 做一些应用问题，例如 <a href="/posts/zrealm-dev/jekyll-blog-自订主题设计-用-claude-design-claude-code-快速打造专属风格-6bf79c5b4dab/">重新设计网站</a> 、 <a href="/posts/zrealm-dev/别再从零开始-ai-写程式-让-ai-agent-直接帮你搞定-google-apps-script-串接与开发-35cc65327d28/">个人 Dashboard</a> 亦或是工作上的产品问题修正；首次尝试请他深入研究解决算法、底层资料设计的问题。</p>

<p>效果超乎我的想像，大略阅读了他写的 RFC，不管是格式还是内容都不比真实的人去研究写出来的东西还差(至少一定比我写的好)，中间有观察他在做什么，他会用 Web Search 去搜寻公开的相关论文或是技术文献然后整合评估实作合理性；拆分出 doer / reviewer 的效果也很显著，doer 会太著重在实作而 reviewer 能以更广更高的视角来纵观看 doer 做的东西有没有 side effect；最后 RFC 定下后再请 AI 基于这个文件实作，准确度几乎是 100%。</p>

<h4 id="ai-使用的反思">AI 使用的反思</h4>

<p>不过大家也不用怕被 AI 取代，主要还是解决问题的思维，这个 AI 就很弱了；例如如果直接叫他去优化 ZMediumToMarkdown 他可能只能专注在 Medium 的场景还有原本程式的写法； <strong>但是人知道可以抽成 Foundation，可以先研究 RFC，最后再实践，这样效果更好；当然我们也可以自己做，只是需要时间，AI 是帮我们加速这个过程，不是取代我们。</strong></p>]]></content>
  </entry><entry>
    <title type="html">IQUNIX MG75 Pro 三模铝合金机械键盘｜轻羽轴低矮轴设计，MacOS 完美支援</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-life/iqunix-mg75-pro-%E4%B8%89%E6%A8%A1%E9%93%9D%E5%90%88%E9%87%91%E6%9C%BA%E6%A2%B0%E9%94%AE%E7%9B%98-%E8%BD%BB%E7%BE%BD%E8%BD%B4%E4%BD%8E%E7%9F%AE%E8%BD%B4%E8%AE%BE%E8%AE%A1-macos-%E5%AE%8C%E7%BE%8E%E6%94%AF%E6%8F%B4-0d4a5fd2929b/" rel="alternate" type="text/html" title="IQUNIX MG75 Pro 三模铝合金机械键盘｜轻羽轴低矮轴设计，MacOS 完美支援" />
    <published>2026-05-09T00:33:11+08:00</published>
    <updated>2026-05-09T00:33:11+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-life/0d4a5fd2929b</id><summary type="html">Mac用户首选IQUNIX MG75 Pro，搭载轻羽轴与矮轴设计，结合铝合金外壳与三模连接，提供安静且有手感的打字体验，解决巧控键盘手感不足问题，轻松提升工作效率与舒适度。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Life." /><category term="iqunix" /><category term="淘寶" /><category term="生活" /><category term="開箱" /><category term="機械鍵盤" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/0d4a5fd2929b/1*UYsoPN7LJA8eLwCW3neySg.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-life/iqunix-mg75-pro-%E4%B8%89%E6%A8%A1%E9%93%9D%E5%90%88%E9%87%91%E6%9C%BA%E6%A2%B0%E9%94%AE%E7%9B%98-%E8%BD%BB%E7%BE%BD%E8%BD%B4%E4%BD%8E%E7%9F%AE%E8%BD%B4%E8%AE%BE%E8%AE%A1-macos-%E5%AE%8C%E7%BE%8E%E6%94%AF%E6%8F%B4-0d4a5fd2929b/"><![CDATA[<h3 id="iqunix-mg-657596-pro-矮轴轻羽轴三模铝合金外壳机械键盘夜游黑开箱">IQUNIX MG 65/75/96 Pro 矮轴轻羽轴三模铝合金外壳机械键盘夜游黑开箱</h3>

<p>MacOS 可用的铝合金质感与轻快手感的 IQUNIX MG75 Pro 开箱</p>

<p><img src="/assets/0d4a5fd2929b/1*UYsoPN7LJA8eLwCW3neySg.webp" alt="MG75 Pro 开箱体验" loading="lazy" decoding="async" width="3114" height="2340" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMTE0IiBoZWlnaHQ9IjIzNDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*UYsoPN7LJA8eLwCW3neySg.png" /></p>

<p><a href="https://iqunix.com/products/iqunix-magi75-96-aluminum-low-profile-mechanical-keyboard?variant=50355797393714" target="_blank">MG75 Pro 开箱体验</a></p>

<h4 id="前言">前言</h4>

<p>好久没写开箱文，也没什么特别的东西可以开箱；最近刚好用了两年的二手机械键盘寿终正寝(其实是泼到水)，是同事自己组装的高轴键盘(基底是 DUKHARO — VN66) 轴体应该是黄轴/白轴。</p>

<p><img src="/assets/0d4a5fd2929b/1*tBmCni-mJ0ZPat8Uf7dqfQ.webp" alt="旧的键盘" loading="lazy" decoding="async" width="1200" height="491" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQ5MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/0d4a5fd2929b/1*tBmCni-mJ0ZPat8Uf7dqfQ.png" /></p>

<p>旧的键盘</p>

<p>入坑机械键盘之前最喜欢用的是 Apple 巧控键盘，我比较喜欢低矮轴的键盘，又是苹果用户，那就飞这款莫属。</p>

<p><img src="/assets/0d4a5fd2929b/1*vMEz6OFmApz2ZXj2aeQq5A.webp" alt="Apple 巧控键盘" loading="lazy" decoding="async" width="2000" height="551" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDAwIiBoZWlnaHQ9IjU1MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/0d4a5fd2929b/1*vMEz6OFmApz2ZXj2aeQq5A.jpeg" /></p>

<p>Apple 巧控键盘</p>

<p>但是手感上就是纯巧克力键盘，干扁没有任何反馈手感。</p>

<h3 id="iqunix-mg657596-pro-矮轴轻羽轴三模铝合金外壳机械键盘">IQUNIX MG65/75/96 Pro 矮轴轻羽轴三模铝合金外壳机械键盘</h3>

<p><img src="/assets/0d4a5fd2929b/1*5tbfNVtQ2DxnxZNDApzf_A.webp" alt="&lt;https://iqunix.com/products/iqunix-magi75-96-aluminum-low-profile-mechanical-keyboard?variant=50355797590322&gt;" loading="lazy" decoding="async" width="2908" height="1042" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOTA4IiBoZWlnaHQ9IjEwNDIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*5tbfNVtQ2DxnxZNDApzf_A.png" /></p>

<p><a href="https://iqunix.com/products/iqunix-magi75-96-aluminum-low-profile-mechanical-keyboard?variant=50355797590322" target="_blank">https://iqunix.com/products/iqunix-magi75-96-aluminum-low-profile-mechanical-keyboard?variant=50355797590322</a></p>

<p>这块也算是被同事烧到的，就在我入手上一个键盘没多久办公室就有人买这款；亲自去按了几次，确认是我的梦中情「盘」矮轴符合我喜欢用巧克力键盘加上「轻羽轴」有手感但又不会太吵的特性，还有亮丽的外观跟多功能控制台，最重要的事是原厂就 MacOS 键位；现在终于有机会能入手了。</p>

<p><img src="/assets/0d4a5fd2929b/1*qKmRbmaj27xzB1Fdb4elhQ.webp" alt="图片取自 官方商品图" loading="lazy" decoding="async" width="1200" height="509" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjUwOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/0d4a5fd2929b/1*qKmRbmaj27xzB1Fdb4elhQ.png" /></p>

<p>图片取自 <a href="https://e.tb.cn/h.iBDV6UGnYYloGER?tk=m11t5opK0Zg" target="_blank">官方商品图</a></p>

<h4 id="轴体--订制款-轻羽轴-官方行销文案gold-red-switch-规格书"><strong>轴体 — 订制款</strong> 轻羽轴 (官方行销文案)、Gold Red Switch (规格书)</h4>

<ul>
  <li>
    <p>压力克数：40 ± 10 Ggf</p>
  </li>
  <li>
    <p>全行程 (全距离)：2.8 mm ± 0.25</p>
  </li>
  <li>
    <p>导通行程 (按键从最上方开始往下压，到「触发讯号」那一刻所需要的距离)：1.2 mm ± 0.30</p>
  </li>
  <li>
    <p>寿命：5 千万次</p>
  </li>
</ul>

<h4 id="键帽">键帽</h4>

<ul>
  <li>
    <p>高含量 PBT + 抗污涂层</p>
  </li>
  <li>
    <p>类肤质质感</p>
  </li>
</ul>

<h4 id="外壳">外壳</h4>

<ul>
  <li>
    <p>CNC 加工全铝合金</p>
  </li>
  <li>
    <p>高度 11 mm(低处) — 25.5 mm(高处)</p>
  </li>
  <li>
    <p>LE-Tray 结构、Poron 夹心棉、PET 垫底、IXPE 垫下轴、Poron 底棉、IXPE 底垫</p>
  </li>
</ul>

<h4 id="使用参数">使用参数</h4>

<ul>
  <li>
    <p>Type-C</p>
  </li>
  <li>
    <p>支援热插拔、VIA</p>
  </li>
  <li>
    <p>支援连接：有线、蓝芽 5.1、2.4 GHz 无线</p>
  </li>
  <li>
    <p>支援多彩 RGB 控制背光</p>
  </li>
  <li>
    <p>支援：Windows / macOS / iOS / Android
附可替换 Windows / macOS 键帽</p>
  </li>
</ul>

<h4 id="型号-mg65--mg75--mg96--mg65-pro--mg75-pro--mg96-pro">型号 MG65 / MG75 / MG96 / MG65 Pro / MG75 Pro / MG96 Pro</h4>

<p><img src="https://curly-lab-d1bd.zhgchgli-b1d.workers.dev/1*XHoih2u5-Azazt5Gkd1IKA.png" alt="" /></p>

<p>主要差别是 键盘配置(65/75/96) 跟 Pro 有右方多媒体控制板(+5 键)。</p>

<ul>
  <li>
    <p>MG65: 68键 电池 3,000mAh
900g / MG65 Pro 1030g</p>
  </li>
  <li>
    <p>MG75: 84键 电池 4,000mAh
947g / MG75 Pro 1110g</p>
  </li>
  <li>
    <p>MG96: 100键 电池 4,000mAh
1144g / MG96 Pro 1296g</p>
  </li>
</ul>

<p><strong>多媒体控制板功能：</strong></p>

<p><img src="/assets/0d4a5fd2929b/1*zIGfXexH_24_Pt1sTnVjBA.webp" alt="" loading="lazy" decoding="async" width="1172" height="1042" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTcyIiBoZWlnaHQ9IjEwNDIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*zIGfXexH_24_Pt1sTnVjBA.png" /></p>

<p>最下方是 2.4G USB 接收器收纳仓，无功能。</p>

<p><strong>外观：</strong></p>

<p><img src="/assets/0d4a5fd2929b/1*D69-323N4fUoRribRtXGnQ.webp" alt="" loading="lazy" decoding="async" width="2910" height="2110" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOTEwIiBoZWlnaHQ9IjIxMTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*D69-323N4fUoRribRtXGnQ.png" /></p>

<ul>
  <li>
    <p>雾苏白</p>
  </li>
  <li>
    <p>夜游黑</p>
  </li>
</ul>

<h4 id="价格方面">价格方面</h4>

<p>照淘宝 上面 <a href="https://e.tb.cn/h.iBDV6UGnYYloGER?tk=m11t5opK0Zg" target="_blank"><strong>(天猫 — IQUNIX 旗舰店)</strong></a> 2026/05 售价:</p>

<ul>
  <li>
    <p>MG65: 人民币 $699</p>
  </li>
  <li>
    <p>MG75: 人民币 $899</p>
  </li>
  <li>
    <p>MG96: 人民币 $899</p>
  </li>
  <li>
    <p>MG65 Pro: 人民币 $899</p>
  </li>
  <li>
    <p>MG75 Pro: 人民币 $999</p>
  </li>
  <li>
    <p>MG96 Pro: 人民币 $1,099</p>
  </li>
</ul>

<h4 id="选择">选择</h4>

<p>MG65 没有 F 系列按键所以不考虑，基础从 MG75 开始，MG96 感觉太大；Pro 功能可有可无但是因为价差不大所以就升级了， <strong>最终选择购买 — MG75 Pro。</strong></p>

<h4 id="购买渠道">购买渠道</h4>

<ul>
  <li>
    <p>台湾无代理或是代理商已无进货</p>
  </li>
  <li>
    <p>海外官网 <a href="https://iqunix.com/products/iqunix-magi75-96-aluminum-low-profile-mechanical-keyboard?variant=50355797590322" target="_blank">https://iqunix.com/</a> 但是价格(MG75Pro)加运费逼近 <code class="language-plaintext highlighter-rouge">NT$6,200</code></p>
  </li>
  <li>
    <p><strong>淘宝官方 <a href="https://e.tb.cn/h.iBDV6UGnYYloGER?tk=m11t5opK0Zg" target="_blank">IQUNIX 旗舰店</a></strong> MG75PRO 运费加包税总共支付 <code class="language-plaintext highlighter-rouge">NT$4,798</code></p>
  </li>
</ul>

<blockquote>
  <p><em>白色比黑色还热门，我看每周一上完架之后到周末就都售完了；我是买 <strong>黑色 MG75 PRO。</strong></em></p>
</blockquote>

<h4 id="淘宝官方-iqunix-旗舰店"><strong>淘宝官方 <a href="https://e.tb.cn/h.iBDV6UGnYYloGER?tk=m11t5opK0Zg" target="_blank">IQUNIX 旗舰店</a></strong></h4>

<p>不得不说现在买淘宝超方便，不需要自己研究集运也不用中国帐户、信用卡；可以直接用街口、Apple Pay、信用卡线上支付；然后官方集/直运寄到你家甚至可以超商取货。</p>

<ul>
  <li>
    <p>05/03 凌晨下单、早上出货</p>
  </li>
  <li>
    <p>05/05 船舶出港</p>
  </li>
  <li>
    <p>05/06 抵达台湾</p>
  </li>
  <li>
    <p>05/08 中午收到货</p>
  </li>
</ul>

<p>如果你没有从海外买东西回来的经验， <a href="https://www.rakuten.com.tw/magazine/life/2022/012802/#D" target="_blank">务必要完成 EZWay 实名验证，下载 EZWay App、完成注册、完成实名认证即可</a> ； <strong>大约在出货后几天会通知有一笔报关纪录，进入 App 按确认就可以了。</strong></p>

<h3 id="iqunix-mg75-pro-矮轴轻羽轴三模铝合金外壳机械键盘夜游黑开箱">IQUNIX MG75 Pro 矮轴轻羽轴三模铝合金外壳机械键盘夜游黑开箱</h3>

<p><img src="/assets/0d4a5fd2929b/1*8yLYKhBLcd0WbWRXtVteCw.webp" alt="" loading="lazy" decoding="async" width="1697" height="1193" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjk3IiBoZWlnaHQ9IjExOTMiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*8yLYKhBLcd0WbWRXtVteCw.png" /></p>

<p>包装非常简单，就是一个跟键盘一样大的纸盒子…其实有点怕会撞坏，但还好键盘收纳包是硬的。</p>

<p><img src="/assets/0d4a5fd2929b/1*PL9Fbr5_nRpgLEgKtrcVJA.webp" alt="" loading="lazy" decoding="async" width="1690" height="1195" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjkwIiBoZWlnaHQ9IjExOTUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*PL9Fbr5_nRpgLEgKtrcVJA.png" /></p>

<p>打开就是键盘收纳包，包装就只是直接放进纸箱子。</p>

<p><img src="/assets/0d4a5fd2929b/1*-hTJy3Cz8YSTFHX60HRzlg.webp" alt="" loading="lazy" decoding="async" width="569" height="178" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NjkiIGhlaWdodD0iMTc4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/0d4a5fd2929b/1*-hTJy3Cz8YSTFHX60HRzlg.png" /></p>

<p>看官方商品页说明好像是新包装，直接替换成键盘收纳包(等于多送你一个盒子)。</p>

<p><img src="/assets/0d4a5fd2929b/1*o4caqnDEgtJQBynfPEEKAg.webp" alt="" loading="lazy" decoding="async" width="1200" height="880" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg4MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/0d4a5fd2929b/1*o4caqnDEgtJQBynfPEEKAg.png" /></p>

<p>键盘包打开就是键盘本体、说明书、配件。</p>

<p><img src="/assets/0d4a5fd2929b/1*aRdH-fuap85bju8r5WHMdg.webp" alt="" loading="lazy" decoding="async" width="1602" height="1205" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjAyIiBoZWlnaHQ9IjEyMDUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*aRdH-fuap85bju8r5WHMdg.png" /></p>

<p>配件有：2.4Ghz 接收器、USB-A to USB-C 传输线、送的替换键帽、拔键器。</p>

<p><img src="/assets/0d4a5fd2929b/1*lqklyMPAqRFuNskhqcJwrg.webp" alt="" loading="lazy" decoding="async" width="1678" height="1241" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjc4IiBoZWlnaHQ9IjEyNDEiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*lqklyMPAqRFuNskhqcJwrg.png" /></p>

<p>原厂预设就是 macOS 键帽，就看自己想不想换上多送的 X 铝合金键帽增加质感；送的数据线是弹簧线可以伸比较长也好收纳，这点不错。</p>

<p><img src="/assets/0d4a5fd2929b/1*DZJLlUoscPXZsDWKq7sVpw.webp" alt="" loading="lazy" decoding="async" width="1594" height="621" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTk0IiBoZWlnaHQ9IjYyMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/0d4a5fd2929b/1*DZJLlUoscPXZsDWKq7sVpw.png" /></p>

<p>键盘背面，也很有金属质感；唯一美中不足是没有内建的支架可以调仰角角度。</p>

<p><img src="/assets/0d4a5fd2929b/1*IbjacAUuMmG36KG1yAA11w.webp" alt="" loading="lazy" decoding="async" width="1724" height="1038" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNzI0IiBoZWlnaHQ9IjEwMzgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*IbjacAUuMmG36KG1yAA11w.png" /></p>

<p>键高跟原本的键盘相比。</p>

<p><img src="/assets/0d4a5fd2929b/1*8Q3XPHzX7coQBMmshcxLlQ.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*8Q3XPHzX7coQBMmshcxLlQ.jpeg" /></p>

<p>直接先把 X 换上去了。</p>

<h4 id="本体细节">本体细节</h4>

<p><img src="/assets/0d4a5fd2929b/1*CsWUoUK0HSqcgPJ7rWFMBw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/0d4a5fd2929b/1*CsWUoUK0HSqcgPJ7rWFMBw.jpeg" /></p>

<p>买的时候没注意到，原来这块面板上还有一条光条会发光。</p>

<p><img src="/assets/0d4a5fd2929b/1*_-epZwLtuUlUBwUolthLgw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/0d4a5fd2929b/1*_-epZwLtuUlUBwUolthLgw.jpeg" /></p>

<p><img src="/assets/0d4a5fd2929b/1*eCMkEokNFYEDkdmPkqGpeg.webp" alt="" loading="lazy" decoding="async" width="2048" height="1536" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDQ4IiBoZWlnaHQ9IjE1MzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*eCMkEokNFYEDkdmPkqGpeg.jpeg" /></p>

<p><img src="/assets/0d4a5fd2929b/1*aJ3Q02uvkViRzL2eoQYXYQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/0d4a5fd2929b/1*aJ3Q02uvkViRzL2eoQYXYQ.jpeg" /></p>

<p><img src="/assets/0d4a5fd2929b/1*bYC27o6XOVINVrab6Nq7rQ.webp" alt="" loading="lazy" decoding="async" width="4048" height="3040" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MDQ4IiBoZWlnaHQ9IjMwNDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*bYC27o6XOVINVrab6Nq7rQ.png" /></p>

<p><img src="/assets/0d4a5fd2929b/1*nAz4ZUL677wsJsYBf7Zz-g.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/0d4a5fd2929b/1*nAz4ZUL677wsJsYBf7Zz-g.jpeg" /></p>

<p>按键本体是沈稳的黑色磨砂质感，键盘本身是磨砂铝合金非常有质感，拿起来稳重务实。</p>

<h4 id="说明书">说明书</h4>

<p><img src="/assets/0d4a5fd2929b/1*kuAtQ-dLWNNAjm37DuTWwA.webp" alt="" loading="lazy" decoding="async" width="4334" height="1642" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MzM0IiBoZWlnaHQ9IjE2NDIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*kuAtQ-dLWNNAjm37DuTWwA.png" /></p>

<p>基本上跟所有机械键盘差不多，反正就灯光调整跟连线方式设定。</p>

<h4 id="启动流程">启动流程</h4>

<ul>
  <li>
    <p>接线插到电脑上</p>
  </li>
  <li>
    <p>长按 <code class="language-plaintext highlighter-rouge">FN + ESC</code> 3 秒以上键盘开机 (Tab 底光会闪)</p>
  </li>
  <li>
    <p>切换成 macOS 键位配置： <code class="language-plaintext highlighter-rouge">FN + Tab</code> <strong>(macOS 务必设定，不然 CMD 会变要按 CTRL)</strong></p>
  </li>
  <li>
    <p>设定背光： <code class="language-plaintext highlighter-rouge">FN + [</code> / <code class="language-plaintext highlighter-rouge">FN + ]</code> / <code class="language-plaintext highlighter-rouge">FN + Shift</code> / <code class="language-plaintext highlighter-rouge">FN + Enter</code></p>
  </li>
</ul>

<p><img src="/assets/0d4a5fd2929b/1*2XHm8O4TUpCVmHiF0GrIrQ.webp" alt="" loading="lazy" decoding="async" width="2048" height="1536" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDQ4IiBoZWlnaHQ9IjE1MzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/0d4a5fd2929b/1*2XHm8O4TUpCVmHiF0GrIrQ.jpeg" /></p>

<h4 id="实际按键声音">实际按键声音</h4>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/Md2yzNBa1K4" title="IQUNIX MG 65/75/96 Pro 矮軸輕羽軸三模鋁合金外殼機械鍵盤夜遊黑開箱、按鍵聲音" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<blockquote>
  <p><em>请以对照大小为主，因为 iPhone 收音关系会放大实际音量。</em></p>
</blockquote>

<h4 id="使用手感">使用手感</h4>

<p>声音比原本的沉稳安静许多但又不失机械键盘的反馈手感，目前用起来挺舒服的；缺点可能是右边的按键太密集还不习惯很容易按错，例如想按删除按到 Home 键。</p>]]></content>
  </entry><entry>
    <title type="html">别再从零开始 AI 写程式：让 AI Agent 直接帮你搞定 Google Apps Script 串接与开发</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/%E5%88%AB%E5%86%8D%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B-ai-%E5%86%99%E7%A8%8B%E5%BC%8F-%E8%AE%A9-ai-agent-%E7%9B%B4%E6%8E%A5%E5%B8%AE%E4%BD%A0%E6%90%9E%E5%AE%9A-google-apps-script-%E4%B8%B2%E6%8E%A5%E4%B8%8E%E5%BC%80%E5%8F%91-35cc65327d28/" rel="alternate" type="text/html" title="别再从零开始 AI 写程式：让 AI Agent 直接帮你搞定 Google Apps Script 串接与开发" />
    <published>2026-05-03T21:06:17+08:00</published>
    <updated>2026-05-03T21:28:55+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/35cc65327d28</id><summary type="html">个人或团队想用 Google Apps Script 自动化流程却苦于串接复杂？透过 AI Agent 直接从零开发，3 小时内完成高准确度专案，实现个人桌面 Dashboard 串接天气、行事历与倒数日资料，提升开发效率与稳定性。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="claude-code" /><category term="google-apps-script" /><category term="dashboard" /><category term="ai" /><category term="claude" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/35cc65327d28/1*QFRr50u8zbS5WtVtvprG9w.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/%E5%88%AB%E5%86%8D%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B-ai-%E5%86%99%E7%A8%8B%E5%BC%8F-%E8%AE%A9-ai-agent-%E7%9B%B4%E6%8E%A5%E5%B8%AE%E4%BD%A0%E6%90%9E%E5%AE%9A-google-apps-script-%E4%B8%B2%E6%8E%A5%E4%B8%8E%E5%BC%80%E5%8F%91-35cc65327d28/"><![CDATA[<h3 id="别再从零开始-ai-写程式让-ai-agent-直接帮你搞定-google-apps-script-串接与开发">别再从零开始 AI 写程式：让 AI Agent 直接帮你搞定 Google Apps Script 串接与开发</h3>

<p>以 AI 变废为宝 —用 Claude Design &amp; Claude Code 打造属于你的个人桌面 Dashboard 为例。</p>

<p><img src="/assets/35cc65327d28/1*QFRr50u8zbS5WtVtvprG9w.webp" alt="" loading="lazy" decoding="async" width="1448" height="1086" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDQ4IiBoZWlnaHQ9IjEwODYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/35cc65327d28/1*QFRr50u8zbS5WtVtvprG9w.png" /></p>

<h4 id="完成品-demo">完成品 Demo</h4>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/Zu0rbnu_iy8" title="AI 變廢為寶 - 用 Claude Design &amp; Claude Code 打造屬於你的個人桌面 Dashboard" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<blockquote>
  <p><em>把尘封在抽屉许多年的 iPhone 8 Plus 摇身一变成个人专属的桌上 Dashboard Deck，内容完全客制化、制作完全免费。</em></p>
</blockquote>

<h3 id="前言">前言</h3>

<blockquote>
  <p><strong><em>TL;DR 如果你只在意怎么用 AI 打造属于你的个人桌面 Dashboard 请忽略此章节。</em></strong></p>
</blockquote>

<p>大约是从 2021 年开始用 Google Apps Script 开发小工具串接自动化优化工作流程；那个年代没有 AI、RPA 流程自动化也很少人在讨论；很单纯只是希望提升团队协作效率，或提高个人生活舒适度，所有脚本都是我一行一行手刻出来的(用现在来看就是古法写程式)， <strong>但最难的其实不是写程式本身，而是能不能串接？要怎么串接？思维要怎么跳脱框架？</strong></p>

<h4 id="之前做过的案例">之前做过的案例</h4>

<ol>
  <li>
    <p><strong>目标 —对外公开的 Email 窗口收到信时希望能转发到 Slack 工作 Channel。</strong>
<strong>技术上 Google Apps Script 没有当 Gmail 收到信件的事件</strong> ，因此我们换一条思路用排程功能每分钟(或更长)执行一次：检查未读信件 ➡️ 读取内容️️ ➡️ Strip HTML 转发到 Slack ➡️ 标记已读。
如果只想针对特定信件(寄件人、标题内容)那就在 Gmail 上设定 Label Filter、检查未读信件改成 检查未读信件+Label 就能达成。
ref: 「 <a href="/posts/zrealm-dev/google-apps-script-教学-自动转发-gmail-邮件到-slack-channel-客制化通知-d414bdbdb8c9/">运用 Google Apps Script 转发 Gmail 信件到 Slack</a> 」</p>
  </li>
  <li>
    <p><strong>目标 — 自动查询 GA 流量/Crash-free rate 发到 Slack 工作 Channel。</strong>
Google Apps Script 本身就有现成的 AnalyticsData / AdSense Library，只要引入并设定好参数就能直接使用，几乎是无痛整合。
如果 App 想查询闪退 Issue 细节、Top 10，只要再多做一步 <strong>Firebase to BigQuery</strong> 再从 Google Apps Script 引入 BigQuery Library 然后下 SQL 查询就能做到。
ref: 「 <a href="/posts/zrealm-dev/crashlytics与google-analytics自动查询app-crash-free-users-rate-google-apps-script整合实作-793cb8f89b72/">Crashlytics + Google Analytics 自动查询 App Crash-Free Users Rate</a> 」、「 <a href="/posts/zrealm-dev/crashlytics-big-query-串接教学-自动查询并转发-ios-app-闪退报告到-slack-e77b80cc6f89/">Crashlytics + Big Query 打造更即时便利的 Crash 追踪工具</a> 」</p>
  </li>
  <li>
    <p><strong>目标 — 自动汇整营运数据到 Google Sheet。</strong>
承上做法，当时多做个 Web App 让整个营运数据能在团队的电视墙上一目了然； <strong>那时候遇到的技术问题是部分数据是在内部</strong> ，外网无法穿透，所幸反过来改内网排程，每日发送数据到 Google Apps Script Web App，接收后处理填回 Google Sheet。
ref:「 <a href="/posts/zrealm-robotic-process-automation/google-apps-script-打造每日数据报表自动化-rpa-快速串接-google-analytics-与-google-sheet-f6713ba3fee3/">使用 Google Apps Script 实现每日数据报表 RPA 自动化</a> 」</p>
  </li>
  <li>
    <p><strong>目标 — 用现有资源建置一个简易的 App 打包平台</strong>
当时的背景是 App 打包服务迁移至 GitHub Actions，但是非工程团队也会有 App 打包需求，以往都是透过人工处理；需要一个公司团队内都可以用的服务来串接 GitHub Actions 来执行打包。
用 Google Apps Script Web App 当平台、锁住只有组织内帐号可使用，在平台表单填好打包资讯转手触发 GitHub Actions (GitHub API) 并发送打包 Slack 通知给对方。
App 打包好是上传到 Firebase App Distribution， <strong>可是 Google Apps Script 没有内建的 Library，不过 <a href="/posts/zrealm-robotic-process-automation/google-apps-script-快速串接-firebase-app-distribution-api-教学与进阶设定-71400d408dc8/">研究了一下可以直接用 googleapis 达成</a> ，最后也是无痛的串起来。</strong>
ref:「 <a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/">使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</a> 」</p>
  </li>
</ol>

<p>还有一些太小的案例就不列举出来了， <strong>总之想传达的是「办法总比困难多」实际写程式反而是最简单的，要如何突破重重障碍串接起来才是困难的</strong> 。</p>

<h4 id="技术限制">技术限制</h4>

<p>「办法总比困难多」的前提，是 <strong>技术上可行且合理</strong> ；换句话说「方向错了，努力也是徒劳」，我们可以不用实际写程式但一定要知道何时可以「选择」使用 Google Apps Script 开发小工具。</p>

<ul>
  <li>
    <p><strong>User-Agent 无法自订：</strong> 基于安全与防止滥用原因，Google Apps Script User-Agent 是无法自己指定的。(但其他 Header 栏位可以指定)
<strong>影响：</strong> 有些罕见的 API 服务需要带资料在 User-Agent、目标网站 / API 封锁 Google Apps Script User-Agent，这两种情况都是硬限制、无法使用。
<strong>Workaround：</strong> <a href="https://zhgchg.li/posts/88f0fb935120/" target="_blank">如果你硬要用的话可以透过 Cloudflare Worker 进行 Proxy 桥接。</a></p>
  </li>
  <li>
    <p><strong>最长执行 6 分钟：</strong> 每次执行最多 6 分钟，任务太大太多建议分段处理。
另外总额度也有上限例如 Trigger 一天最多执行 90 分钟。 <strong>(但这条似乎是软限制，我的脚本很多应该超过上限了却没有被阻挡)</strong></p>
  </li>
  <li>
    <p><strong>单次执行以同步阻塞为主</strong> ：你无法在单次 execution 内派发多个执行绪并行处理任务；若任务耗时或需要大量并行处理，建议拆成多次执行、排程触发。</p>
  </li>
  <li>
    <p><strong>冷启动：</strong> Faas 服务的通病，当任务太久没触发会进入睡眠、再次触发时需要等待较长的时间。
这问题加上任务需同步(阻塞)执行的限制，如果是部署成 Webhook 让其他服务来呼叫很容易会被判断成请求失败，可能会重复请求、重复收到、重复执行。
例如：Slack 硬要求 Webhook 服务端需在 3 秒内回应，以往经验很常踩到这个问题。</p>
  </li>
  <li>
    <p><strong>Web App API 会跳转址：</strong> 基于安全性，Content service 回传的内容会 redirect 到一次性 <code class="language-plaintext highlighter-rouge">script.googleusercontent.com</code> URL；HTTP client 需要支援 follow redirects。
有的 Webhook 服务不会自动 302 跳转就会失败(例如：Jira Webhook)。</p>
  </li>
  <li>
    <p><strong>Web App HTML</strong> ：网页顶部会有防滥用声明、无法达成真 RWD (页面实际是 iframe 在 google 框架内)、网址很丑无法自订、无法做到 PWA 满版页面。</p>
  </li>
</ul>

<p><img src="/assets/35cc65327d28/1*NI80VyLt-hHAKJskJLdTmg.webp" alt="" loading="lazy" decoding="async" width="693" height="196" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2OTMiIGhlaWdodD0iMTk2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/35cc65327d28/1*NI80VyLt-hHAKJskJLdTmg.png" /></p>

<ul>
  <li><strong>服务限制：</strong> 还有一些服务取用的限制，不过正常使用下不太会踩到上限，除非你是需要高频检查即时响应，那就很容易摸到限制。</li>
</ul>

<p><img src="/assets/35cc65327d28/1*bg8nLfiGaVJ7xqhIQewp1g.webp" alt="&lt;https://developers.google.com/apps-script/guides/services/quotas?hl=zh-tw&gt;" loading="lazy" decoding="async" width="1200" height="954" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk1NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/35cc65327d28/1*bg8nLfiGaVJ7xqhIQewp1g.png" /></p>

<p><a href="https://developers.google.com/apps-script/guides/services/quotas?hl=zh-tw" target="_blank">https://developers.google.com/apps-script/guides/services/quotas?hl=zh-tw</a></p>

<h4 id="优势与功能">优势与功能</h4>

<p>了解完限制再来看看有哪些优势、功能。</p>

<p>最大的优势是直接无痛串接 Google 本家相关服务，Web App 存取方式可以选择脚本拥有者本人身份、组织内人员、已登入 Google 的帐号、所有人， <strong>不需要自己做复杂的 OAuth 流程，一键设定一键完成一键开始执行</strong> ：</p>

<p><strong>内建整合服务 Built-in Services:</strong>
<strong>不需在 GAS 服务中引用就能使用。</strong></p>

<ul>
  <li>
    <p>DocumentApp → Google Docs</p>
  </li>
  <li>
    <p>SpreadsheetApp → Google Sheets</p>
  </li>
  <li>
    <p>SlidesApp → Google Slides</p>
  </li>
  <li>
    <p>FormApp → Google Forms</p>
  </li>
  <li>
    <p>GmailApp → Gmail</p>
  </li>
  <li>
    <p>CalendarApp → Google Calendar</p>
  </li>
  <li>
    <p>DriveApp → Google Drive</p>
  </li>
  <li>
    <p>SitesApp → Google Sites</p>
  </li>
  <li>
    <p>Maps → 地图 / 距离 / 路线</p>
  </li>
  <li>
    <p>Translate → 翻译</p>
  </li>
</ul>

<p><strong>进阶服务 Advanced Services:</strong>
<strong>需在 GAS 服务中引用才能使用。</strong></p>

<ul>
  <li>
    <p>Sheets API</p>
  </li>
  <li>
    <p>Drive API</p>
  </li>
  <li>
    <p>Calendar API</p>
  </li>
  <li>
    <p>Gmail API</p>
  </li>
  <li>
    <p>Analytics API / Analytics Data API</p>
  </li>
  <li>
    <p>BigQuery API</p>
  </li>
  <li>
    <p>Adsense API</p>
  </li>
  <li>
    <p>YouTube Data API</p>
  </li>
  <li>
    <p>Tasks API</p>
  </li>
  <li>
    <p>Googleapis (Other/GCP)</p>
  </li>
</ul>

<p><strong>工具 / 系统服务:</strong></p>

<ul>
  <li>
    <p>UrlFetchApp → 呼叫外部 API</p>
  </li>
  <li>
    <p>PropertiesService → Key-Value 储存</p>
  </li>
  <li>
    <p>CacheService → 快取</p>
  </li>
  <li>
    <p>LockService → 防并发控制</p>
  </li>
  <li>
    <p>Utilities → 日期 / Hash / Base64</p>
  </li>
  <li>
    <p>Logger → Log 输出</p>
  </li>
  <li>
    <p>HtmlService → 建立 Web UI、支援 Ajax 非同步更新内容</p>
  </li>
  <li>
    <p>ContentService → 建立 API endpoint</p>
  </li>
  <li>
    <p>Trigger → 排程自动执行</p>
  </li>
</ul>

<p>基本上开发上需要的东西该有的都有了，实务上就是把这些服务组合串接起来，就能达成流程自动化，例如：</p>

<ul>
  <li>
    <p>自动查询 GA 流量/Crash-free rate 发到 Slack 工作 Channel：
Analytics Data API 查资料、PropertiesService 储存 Slack Bot Token、UrlFetchApp 打 Slack Send Message API</p>
  </li>
  <li>
    <p>自动汇整营运数据到 Google Sheet、数据 Dashboard Web：
Trigger 排程执行 Function、LockService 确保只有我在执行、Analytics Data API 查资料、UrlFetchApp 取得外部服务资料、SpreadsheetApp 写入 Google Sheet、HtmlService 输出 Web App 介面、ContentService 输出 JSON 资料＋CacheService 资料缓存。</p>
  </li>
</ul>

<h4 id="与-cloud-function--lambda-之类的-faas-差异">与 Cloud Function / Lambda 之类的 FAAS 差异</h4>

<p>Google Apps Script 可以视为是环绕 Google 服务场景的 FAAS 脚本工具，限制较多但是 <strong>目前完全免费、无痛串接 Google 服务；</strong> 其他 FAAS 服务通常需要付费，但有部分免费额度、串接 Google 服务需要走正规 IAM or OAuth 流程比较复杂繁琐。</p>

<h4 id="不适合的场景">不适合的场景</h4>

<ul>
  <li>
    <p>本身非 Google 家族，例如想串接 Microsoft Office or OneNote…</p>
  </li>
  <li>
    <p>地端云端混合，这比较适合 n8n or AI Agent 来做</p>
  </li>
  <li>
    <p>复杂计算或是大量资料处理，每个执行阶段最多 6 分钟会跑不完</p>
  </li>
  <li>
    <p>大型网站爬虫、抢票程式，这也不用想了，Google Apps Script 很容易封锁或是被 Cloudflare 反爬虫阻挡</p>
  </li>
</ul>

<h4 id="适合的场景">适合的场景</h4>

<p>个人或是团队内工作流程串接，以我个人来说我有很多脚本在帮我管理日常例行公事，例如每日通知 <a href="https://zhgchg.li/" target="_blank">zhgchg.li</a> 网站流量概况、GitHub Repo Issues 甚至是更新持股 Google Sheet 上的现价；团队来说，App 发版流程可以结合 Google Calendar，检查行事历事件然后触发(呼叫 GitHub Actions)对应的 CI/CD 流程，然后发送讯息到团队 Slack Channel、转发 App 送审失败信件到 Slack。</p>

<blockquote>
  <p><em>以上是以人的视角重新回顾一次这几年开发 Google Apps Script 的心得感受， <strong>再来是最近开始使唤 AI Agent 从 0 直接帮我开发 GAS 的实作感想与实际案例 —个人桌面 Dashboard Deck</strong> 。</em></p>
</blockquote>

<h4 id="让-ai-agent-直接帮你搞定-google-apps-script-串接与开发">让 AI Agent 直接帮你搞定 Google Apps Script 串接与开发</h4>

<p>最近开始尝试从 0 就使用 AI 直接开发 Google Apps Script，结合上方的基础知识( <strong>即使没有，AI 掌握度也很高</strong> )； <strong>完成度与准确性几乎是 100%，</strong> 可以说「从零开始 AI 写程式」的时代也过去了。</p>

<h3 id="实战--ai-变废为宝--用-claude-design--claude-code-打造属于你的个人桌面-dashboard">实战 — AI 变废为宝 — 用 Claude Design &amp; Claude Code 打造属于你的个人桌面 Dashboard</h3>

<h4 id="问题">问题</h4>

<p>一直有一台汰换下来的 iPhone 8 Plus (iOS 16.7) 放在抽屉里毫无用处，想说可以把它当成桌面小萤幕 Dashboard 呈现我想看到的即时讯息。</p>

<h4 id="基础建设">基础建设</h4>

<p>要让 AI Agent 可以帮你开发 Google Apps Script，我们需要完成一些基本的基础建设。</p>

<blockquote>
  <p><em>就算不是要给 AI 开发，也强烈建议开发中大型脚本时务必要使用，Web Editor 有时候会当机或是不小心多开 Tab 旧的覆盖掉新的 Code，用 Clasp 可以更方便、安全的撰写管理程式源码。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>其他使用案例：</em></strong> <em>Google Apps Script Project 同时上传到 Git Repo 做版控 (排除 <code class="language-plaintext highlighter-rouge">.clasprc.json</code> 和 <code class="language-plaintext highlighter-rouge">.clasp.json</code> )、加上 CI 自动跑 Jest JS 单元测试、CD 用 Clasp Token 拉取最新程式码、可以用 .claspignore 排除没有要上传到 Google Apps Script Project 的档案。</em></p>
</blockquote>

<p>1.安装 <a href="https://codelabs.developers.google.com/codelabs/clasp?hl=zh-tw#1" target="_blank"><strong>clasp Google Apps Script CLI</strong> ( 官方 本地开发套件)</a></p>

<ul>
  <li>
    <p>Node.js &gt;= 20.0.0 ( <a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm" target="_blank">如果没有安装 nodejs 环境请先安装</a> )</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">npm i @google/clasp -g</code></p>
  </li>
</ul>

<ol>
  <li>
    <p>执行 <code class="language-plaintext highlighter-rouge">clasp login</code> 登入、产生授权 Token ( <a href="https://script.google.com/home" target="_blank">选择 Google Apps Script 对应的帐号</a> )</p>
  </li>
  <li>
    <p>将 clasprc (Clasp Token) 储存到 Keychain 让 AI Agent 能安全的调用</p>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>security add-generic-password <span class="se">\</span>
  <span class="nt">-U</span> <span class="se">\</span>
  <span class="nt">-s</span> <span class="s2">"com.google.clasp"</span> <span class="se">\</span>
  <span class="nt">-a</span> <span class="s2">"</span><span class="nv">$USER</span><span class="s2">"</span> <span class="se">\</span>
  <span class="nt">-w</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">cat</span> ~/.clasprc.json<span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>

<p>如果你想要复制出 Clasp Token 放到 CI/CD Secret 上执行任务可以用 <code class="language-plaintext highlighter-rouge">cat ~/.clasprc.json \\| base64 \\| pbcopy</code> (记得加上 base64 encode)，使用时再 <code class="language-plaintext highlighter-rouge">echo "$CLASPRC" \\| base64 — decode &gt; ~/.clasprc.json &amp;&amp; chmod 600 ~/.clasprc.json</code></p>

<ol>
  <li>建立专案目录</li>
</ol>

<p><img src="/assets/35cc65327d28/1*W5Y_173DcbwNeNZ8aeSGsA.webp" alt="" loading="lazy" decoding="async" width="219" height="36" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMTkiIGhlaWdodD0iMzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/35cc65327d28/1*W5Y_173DcbwNeNZ8aeSGsA.png" /></p>

<p>必须建立一个专案目录然后进入</p>

<ol>
  <li>在目录内建立 Google Apps Script Project (透过 clasp)</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>clasp create
</code></pre></div></div>

<blockquote>
  <p><em>会直接用目录名称当专案名称。</em></p>
</blockquote>

<p><img src="/assets/35cc65327d28/1*4OjgluUubwvz0cOrs3DZ9g.webp" alt="" loading="lazy" decoding="async" width="888" height="69" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4ODgiIGhlaWdodD0iNjkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/35cc65327d28/1*4OjgluUubwvz0cOrs3DZ9g.png" /></p>

<p>目前专案是空的，只有 <code class="language-plaintext highlighter-rouge">appsscript.json</code> 一个设定档。</p>

<h4 id="我的设计">我的设计</h4>

<p><a href="https://github.com/zhgchgli0718/GASDashboardExample" target="_blank"><img src="https://opengraph.githubassets.com/d4cf8b9a7c53130de6bf5b4b520b4a3bfc3b5fa520a7a6ff33f39bf82a88ffdf/zhgchgli0718/GASDashboardExample" alt="" /></a></p>

<blockquote>
  <p><em>如果你想节省 Token，可以直接 git clone 我的 GAS Web App 复用我的设计跟已开发好的 GAS 程式码。</em></p>
</blockquote>

<h4 id="使用-claude-design-or-design-agent-skill-设计-dashboard">使用 Claude Design or Design Agent Skill 设计 Dashboard</h4>

<p><strong>方式 1 — Claude Design</strong>
上一篇文章「 <a href="https://zhgchg.li/posts/zrealm-dev/jekyll-blog-%E8%87%AA%E8%A8%82%E4%B8%BB%E9%A1%8C%E8%A8%AD%E8%A8%88-%E7%94%A8-claude-design-claude-code-%E5%BF%AB%E9%80%9F%E6%89%93%E9%80%A0%E5%B0%88%E5%B1%AC%E9%A2%A8%E6%A0%BC-6bf79c5b4dab/#%E5%AF%A6%E7%8F%BE%E6%AD%A5%E9%A9%9F" target="_blank">Jekyll Blog 自订主题设计｜用 Claude Design + Claude Code 快速打造专属风格</a> 」中有介绍过，照相同的步骤调整到满意的设计然后汇出 Project 解压缩放到专案的 <code class="language-plaintext highlighter-rouge">./Design</code> 目录下。</p>

<p><strong>方式 2 — Design Agent Skill</strong>
使用第三方 <a href="https://github.com/alchaincyf/huashu-skills" target="_blank">设计 Skill</a> 完成设计，我的 Prompt 大致如下:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/huashu-design
設計一個可以在 iPhone 8 Plus 上橫放的網頁 Dashboard，把設計結果放到 ./Design 目錄下
- 之後會部署在 Google Apps Script Web App
- 上方有固定顯示日期星期還有翻頁時鐘
- 下方 tab 會定時切換，會顯示定時進度條
- 下方 tab 有:
-- 天氣狀況
-- 行事曆：當前行程 or 當日即將到來的行程、顯示剩餘事件
-- 倒數/計數日
</code></pre></div></div>

<blockquote>
  <p><em>我使用 Model: Opus 4.7 (1M context) / Effort: Medium</em></p>
</blockquote>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
⏺ 我先掌握了脈絡：iPhone 8 Plus 橫放 = 736×414 CSS px，內容資料結構（天氣 / 行事曆 / 倒數）已在 CLAUDE.md 定義清楚。
  樣式你還沒指定，我按「設計方向顧問」給你 3 個明顯不同流派 的方向，請選一個（或混搭，例如 "A 的字型 + C 的配色"），我再做完整 hi-fi。
<span class="p">  ---</span>
  🅐 方向一 · Massimo Vignelli 式瑞士網格（信息建筑派）
  ▎ Vignelli 替紐約地鐵設計的網格美學——Helvetica + 嚴格欄位 + 紅黑白三色。資訊本身就是裝飾，不靠插圖、icon、漸變。
<span class="p">  -</span> 字型：Neue Haas Grotesk / Inter Tight（display）+ IBM Plex Mono（時鐘/數字）
<span class="p">  -</span> 配色：純白底 #FAFAFA · 純黑墨 #0A0A0A · 單一朱紅 accent #E63946（用在進度條與當前 tab）
<span class="p">  -</span> 版面：12 欄 baseline grid，所有元素對齊；翻頁時鐘是黑底白字大字 + 細水平分隔線；tab 是無圓角的色塊
<span class="p">  -</span> 氣質關鍵字：理性 / 克制 / 印刷品 / 資訊密度 / 永恆
<span class="p">  -</span> 適合：你想要不會過時、像一張高品質報紙頭版的儀表板
<span class="p">  ---</span>
  🅑 方向二 · Dieter Rams × Braun 工業儀表（極簡產業派）
  ▎ Rams 為 Braun 設計的 ET66 計算機、Audio 系統的美學——淺米灰底 + 圓角硬體面板 + 單一橙色 accent +
  ▎ 物理按鍵質感。每個區塊像一個獨立的儀器面板。
<span class="p">  -</span> 字型：Söhne / Inter（標籤）+ JetBrains Mono（時鐘走 LCD 七段碼風）
<span class="p">  -</span> 配色：暖米灰 #E5E1DA · 深炭 #2B2B2B · Braun 橙 #E85D2C accent · 翻頁時鐘走 LCD 黃綠 #A8B547 仿舊液晶
<span class="p">  -</span> 版面：每個 card 有微弱的內陰影與 1px hairline 邊框，像實體儀表的凹陷感；tab 切換像按鍵下沉
<span class="p">  -</span> 氣質關鍵字：產業設計 / 觸感 / 1970s Braun / 沉穩 / 工程師審美
<span class="p">  -</span> 適合：你喜歡硬體感、想要長時間注視也舒服
<span class="p">  ---</span>
  🅒 方向三 · Teenage Engineering OP-1 / 終端機（運動詩學派）
  ▎ TE 的 OP-1 合成器面板與老 OLED 終端機美學——深炭灰底 + OLED 青綠光暈 + mono 字 + 細網格背景。翻頁時鐘做成大型 OLED
  ▎ 翻牌，進度條像音序器步進燈。
<span class="p">  -</span> 字型：JetBrains Mono / IBM Plex Mono（全場）+ Berkeley Mono（display 大字）
<span class="p">  -</span> 配色：底 #0E0F0D · 主文字 #E8E5DA 米白 · OLED 青 #9DEF8F accent · 警示橙 #FFB454
<span class="p">  -</span> 版面：背景有極淡 8px dot grid；翻頁時鐘大字佔 1/3 寬，帶微弱掃描線；tab 進度條走 LED 步進；天氣用 ASCII 風小圖
<span class="p">  -</span> 氣質關鍵字：OLED / cyberdeck / 模擬合成器 / hacker chic / 駭客文化
<span class="p">  -</span> 適合：你想要它在書桌上像一台「設備」而不是一張「網頁」
<span class="p">  ---</span>
  請告訴我選哪個（或哪幾個元素混搭），我接著做完整 hi-fi 進 ./Design/。 也可以說「都不對，再來幾個」我換流派重推。
</code></pre></div></div>

<p>可以选择喜欢的风格或是跟 AI 说自己想要的风格，例如 <code class="language-plaintext highlighter-rouge">纸感风格，米白宣纸 + 朱印章美学</code> 。</p>

<p>等待 AI 完成设计… <strong>AI 可能会在完成后用 Playwright 截图验证，如果想省 Token、自己验证结果可以加在 Prompt 跟他说。</strong></p>

<p><strong>在目录里直接点击 .html 档案查看设计结果：</strong></p>

<p><img src="/assets/35cc65327d28/1*dTXDvk5dttT_RrCTNaSR5w.webp" alt="" loading="lazy" decoding="async" width="1200" height="681" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY4MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/35cc65327d28/1*dTXDvk5dttT_RrCTNaSR5w.png" /></p>

<blockquote>
  <p><em>调整到满意后再进下一步开发。</em></p>
</blockquote>

<p><strong>建立 <a href="https://docs.google.com/spreadsheets/d/1R98OcfLMB3Dx9MSUsH849ZxLv0Hveh8Py_YxtJ1JljE/edit?usp=sharing" target="_blank">倒数日资料来源 Google Sheet</a> ：</strong></p>

<p><img src="/assets/35cc65327d28/1*Rb4yLjOhg9XwgICKCM7aww.webp" alt="" loading="lazy" decoding="async" width="1056" height="465" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDU2IiBoZWlnaHQ9IjQ2NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/35cc65327d28/1*Rb4yLjOhg9XwgICKCM7aww.png" /></p>

<p>最后顺手建立一个倒数日资料来源 Google Sheet，以后要加资料只要增加到这个 Sheet。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>title,date,repeat
生日,1994-07-18,yes
日本行,2026-12-12,
</code></pre></div></div>

<blockquote>
  <p><em>repeat=yes: 每年循环的事件</em></p>
</blockquote>

<blockquote>
  <p><strong><em>记下 Sheet Id: 上图网址红底部分 / Gid: 0(第一张 Sheet)。</em></strong></p>
</blockquote>

<p><strong>注册交通部中央气象署 API Key:</strong></p>

<ul>
  <li>
    <p>注册登入: <a href="https://opendata.cwa.gov.tw/userLogin" target="_blank">https://opendata.cwa.gov.tw/userLogin</a></p>
  </li>
  <li>
    <p>取得授权码</p>
  </li>
</ul>

<h4 id="使用-claude-code-开发实现-dashboard">使用 Claude Code 开发实现 Dashboard</h4>

<p>先 Init Claude Code Memory Markdown:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/init
</code></pre></div></div>

<p>执行 Plan 规划开发工作:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/plan
實現 ./Design 的 Dashboard 網頁功能與設計，部署到 Google Apps Script Web App。
- 天氣使用交通部中央氣象署 API https://opendata.cwa.gov.tw/api/v1/rest/datastore/F-C0032-00
- 顯示 臺北市 天氣，有什麼欄位就顯示什麼
- 在開發階段你可以自己產一個 Token 然後部署 Web App 自主觸發必要方法與測試驗證，開發完畢務必移除這個開口
- Web App 部署成所有人都可存取，但是透過自訂的 Token 保護，初次使用使用者可輸入 Token 或是從網址帶入
- 行事曆默認讀取：primary
- 倒數日從我給你的 Google Sheet 裡讀取，title,date,repeat，如果 repeat 是 yes 代表是年循環倒數，多顯示已經過了 x 年 y 月 (無條件捨去)
- API Key, Google Sheet ID/GID... 統一都放在 PropertiesService 設定
- 直接幫我使用 clasp push &amp; deploy，clasprc login token 在 keychain security add-generic-password \ -U \ -s "com.google.clasp" \ -a "$USER"
- 如果需要我手動處理的地方請用繁體中文告訴我每個步驟
- oauthScopes": [ "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/script.scriptapp" ]
- 特別確認 google.script.run 串接取用格式是否確
- The live GAS Web App HTML is rendered inside an iframe wrapper.
- ./Design 等等不用上傳到 Google Apps Script 的檔案加入到 .claspignore
</code></pre></div></div>

<ul>
  <li>
    <p>Web App 有四种存取权限：所有人、只有自己、只有已登入的人、已登入&amp;组织内的帐号</p>
  </li>
  <li>
    <p>上面范例的设计是简单做：所有人都可以存取但需要输入正确的乱数 Token 才能看到资料、天气可以改成自己所在的地区，也能多个地区。</p>
  </li>
  <li>
    <p>行事历默认只处理主行事历，如果你有其他行事历可以从行事历 设定与共用 -&gt; 整合日历 -&gt; 日历 ID 取得</p>
  </li>
  <li>
    <p><strong>这边加了一段懒人开发，直接请 AI 部署测试用 Web App 入口让他边开发边测试边修正，都好了再叫我</strong></p>
  </li>
</ul>

<blockquote>
  <p><em>Plan 完如果有问题再回答 AI，没有就可以开始实作了！</em></p>
</blockquote>

<h4 id="泡咖啡等-ai-开发">泡咖啡等 AI 开发…</h4>

<p><img src="/assets/35cc65327d28/1*TEYsNQzxxveclbMvaeAwAw.webp" alt="" loading="lazy" decoding="async" width="1246" height="1318" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjQ2IiBoZWlnaHQ9IjEzMTgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/35cc65327d28/1*TEYsNQzxxveclbMvaeAwAw.png" /></p>

<p><strong>AI Agent Question:</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">Action</span> <span class="n">needed</span> <span class="n">from</span> <span class="nf">you</span> <span class="p">(</span><span class="n">one</span><span class="o">-</span><span class="n">time</span><span class="p">):</span>

  <span class="mf">1.</span> <span class="n">Open</span> <span class="n">the</span> <span class="n">editor</span><span class="p">:</span> <span class="n">https</span><span class="p">:</span><span class="c1">//script.google.com/d/1KEWgIql-gqTNI_Tv_w2-5t7VE_R0eBtjAtd3iqLqabYLOnzJZ8Ga8N4s/edit</span>
  <span class="mf">2.</span> <span class="n">Top</span><span class="o">-</span><span class="n">right</span> <span class="s">"部署 / Deploy"</span> <span class="err">→</span> <span class="s">"管理部署作業 / Manage deployments"</span>
  <span class="mf">3.</span> <span class="n">Delete</span> <span class="n">both</span> <span class="n">existing</span> <span class="nf">deployments</span> <span class="p">(</span><span class="n">the</span> <span class="n">bare</span> <span class="o">@</span><span class="n">HEAD</span> <span class="n">and</span> <span class="n">dev</span> <span class="n">v1</span> <span class="err">—</span> <span class="n">the</span> <span class="n">pencil</span><span class="o">-</span><span class="n">icon</span> <span class="n">edit</span> <span class="n">doesn</span><span class="nv">'t</span> <span class="k">let</span> <span class="n">you</span> <span class="n">change</span> <span class="n">access</span> <span class="k">type</span><span class="p">)</span>
  <span class="mf">4.</span> <span class="n">Then</span> <span class="s">"新增部署 / New deployment"</span> <span class="err">→</span> <span class="n">類型</span><span class="p">:</span> <span class="n">網路應用程式</span> <span class="err">→</span> <span class="n">執行身分</span><span class="p">:</span> <span class="n">我</span><span class="err">（</span><span class="n">your</span> <span class="n">account</span><span class="err">）→</span> <span class="n">誰可以存取</span><span class="p">:</span> <span class="n">任何人</span> <span class="o">/</span> <span class="n">Anyone</span> <span class="err">→</span> <span class="n">部署</span>
  <span class="mf">5.</span> <span class="n">Grant</span> <span class="n">OAuth</span> <span class="n">on</span> <span class="n">the</span> <span class="n">consent</span> <span class="nf">screen</span> <span class="p">(</span><span class="n">calendar</span><span class="py">.readonly</span><span class="p">,</span> <span class="n">spreadsheets</span><span class="py">.readonly</span><span class="p">,</span> <span class="n">external_request</span><span class="p">)</span>
  <span class="mf">6.</span> <span class="nb">Copy</span> <span class="n">the</span> <span class="n">new</span> <span class="n">web</span> <span class="n">app</span> <span class="nf">URL</span> <span class="p">(</span><span class="n">looks</span> <span class="n">like</span> <span class="n">https</span><span class="p">:</span><span class="c1">//script.google.com/macros/s/AKfycb.../exec) and paste it here</span>

  <span class="n">Also</span> <span class="n">paste</span><span class="p">:</span>
  <span class="o">-</span> <span class="n">CWA</span> <span class="n">API</span> <span class="nf">Key</span> <span class="p">(</span><span class="n">交通部中央氣象署</span> <span class="n">Open</span> <span class="n">Data</span> <span class="n">Authorization</span><span class="p">)</span>
  <span class="o">-</span> <span class="n">倒數日</span> <span class="n">Sheet</span> <span class="nf">ID</span> <span class="p">(</span><span class="n">the</span> <span class="n">long</span> <span class="n">part</span> <span class="k">in</span> <span class="n">the</span> <span class="n">Sheet</span> <span class="n">URL</span> <span class="n">between</span> <span class="o">/</span><span class="n">d</span><span class="o">/</span> <span class="n">and</span> <span class="o">/</span><span class="n">edit</span><span class="p">)</span>
  <span class="o">-</span> <span class="n">Sheet</span> <span class="nf">GID</span> <span class="p">(</span><span class="n">the</span> <span class="n">number</span> <span class="n">after</span> <span class="n">gid</span><span class="o">=</span> <span class="k">in</span> <span class="n">the</span> <span class="n">URL</span> <span class="err">—</span> <span class="n">defaults</span> <span class="n">to</span> <span class="mi">0</span> <span class="k">for</span> <span class="n">the</span> <span class="n">first</span> <span class="n">tab</span><span class="p">)</span>

  <span class="n">Once</span> <span class="n">I</span> <span class="n">have</span> <span class="n">the</span> <span class="n">URL</span> <span class="o">+</span> <span class="n">secrets</span><span class="p">,</span> <span class="n">I</span><span class="nv">'ll</span> <span class="n">seed</span> <span class="n">Properties</span> <span class="n">via</span> <span class="n">the</span> <span class="n">dev</span> <span class="n">endpoint</span><span class="p">,</span> <span class="n">mint</span> <span class="n">the</span> <span class="n">access</span> <span class="n">token</span><span class="p">,</span> <span class="n">verify</span> <span class="n">each</span> <span class="n">handler</span><span class="p">,</span> <span class="n">and</span> <span class="n">wire</span> <span class="n">you</span> <span class="k">in</span><span class="err">.</span>
</code></pre></div></div>

<p>(1. ) 第一次执行还是需要我们授权，AI Agent 之后才能自己跑，前往 Script Editor 网址：</p>

<p><img src="/assets/35cc65327d28/1*qif-nDDBfttn-y6kR2I2VA.webp" alt="" loading="lazy" decoding="async" width="863" height="404" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjMiIGhlaWdodD0iNDA0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/35cc65327d28/1*qif-nDDBfttn-y6kR2I2VA.png" /></p>

<p>随便选择一个有函式的档案，选择一个函式点侦错：</p>

<p><img src="/assets/35cc65327d28/1*BgTkreP26mNx7nu9gkhedA.webp" alt="" loading="lazy" decoding="async" width="1200" height="654" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY1NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/35cc65327d28/1*BgTkreP26mNx7nu9gkhedA.png" /></p>

<ul>
  <li>只有第一次执行或是有新增权限时会需要授权</li>
</ul>

<blockquote>
  <p><em>如果 AI 一直说有权限问题，但是实际执行又没跳授权视窗可以先去专案设定勾选「在编辑器中显示「appsscript.json」资讯清单档案」然后回到编辑器编辑 <code class="language-plaintext highlighter-rouge">appsscript.json</code> 改变一下 oauthScopes 的内容执行一次再改回来执行应该就会跳出授权流程了。</em></p>
</blockquote>

<p><strong>只有 1. 需要自己处理其他可以叫 AI 自己做:</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">1. OK，你直接幫我部署</span>
  <span class="s">CWA API Key</span><span class="err">:</span> <span class="s">CWA-XXXX-XXXX-XXXX-XXXX-XXXX</span>
  <span class="s">倒數日 Sheet ID</span><span class="na">: XXXX / GID</span><span class="pi">:</span> <span class="m">0</span>
</code></pre></div></div>

<p><img src="/assets/35cc65327d28/1*E1UAPVqKXjYtmAsJRRABdw.webp" alt="" loading="lazy" decoding="async" width="1266" height="577" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjY2IiBoZWlnaHQ9IjU3NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/35cc65327d28/1*E1UAPVqKXjYtmAsJRRABdw.png" /></p>

<p><strong>协助 AI 设定 Google Apps Script. .</strong></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">⏺</span> <span class="n">Scope</span> <span class="ow">is</span> <span class="n">updated</span> <span class="ow">and</span> <span class="n">pushed</span> <span class="n">but</span> <span class="n">the</span> <span class="n">deployer</span><span class="sh">'</span><span class="s">s OAuth grant needs to be re-authorized for the new scope. The web app runs under your account — newly added
  scopes require you to re-grant.

  Please do this once:

  1. Open the editor: https://script.google.com/d/1KEWgIql-gqTNI_Tv_w2-5t7VE_R0eBtjAtd3iqLqabYLOnzJZ8Ga8N4s/edit
  2. From the function dropdown at the top, pick setupConfig (or any function)
  3. Click 執行 / Run — Google will pop a </span><span class="sh">"</span><span class="s">需要授權 / Authorization required</span><span class="sh">"</span><span class="s"> dialog
  4. Allow → grants the upgraded auth/spreadsheets scope
  5. Tell me when done and I</span><span class="sh">'</span><span class="n">ll</span> <span class="n">re</span><span class="o">-</span><span class="n">test</span> <span class="n">the</span> <span class="n">countdown</span> <span class="n">handler</span>
</code></pre></div></div>

<p>虽然我们都跟 AI 说好了但他还是有可能卡在一些地方需要人工帮忙，例如以上讯息； <strong>我们也很简单就是照他步骤点击执行一次函式再跟他说 OK 就好，就当帮个忙。(如果没出现他说的方法就重整一下网页)</strong></p>

<p><img src="/assets/35cc65327d28/1*oLIgKwY7YYbDZszAEMiSKQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="896" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg5NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/35cc65327d28/1*oLIgKwY7YYbDZszAEMiSKQ.png" /></p>

<h4 id="ai-开发完成验收">AI 开发完成，验收！</h4>

<p><img src="/assets/35cc65327d28/1*_lM4Az2SosWIYlp26KG8zQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="257" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjI1NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/35cc65327d28/1*_lM4Az2SosWIYlp26KG8zQ.png" /></p>

<p>如果发现问题，可以再请 AI 修正。</p>

<h3 id="用-ai-打造属于你的个人桌面-dashboard--成果">用 AI 打造属于你的个人桌面 Dashboard — 成果</h3>

<h4 id="桌面版">桌面版</h4>

<p><img src="/assets/35cc65327d28/1*a70ymWexht6E2RLr7v0PWQ.webp" alt="" loading="lazy" decoding="async" width="1952" height="1165" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOTUyIiBoZWlnaHQ9IjExNjUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/35cc65327d28/1*a70ymWexht6E2RLr7v0PWQ.png" /></p>

<h4 id="iphone-手机版">iPhone 手机版</h4>

<p><img src="/assets/35cc65327d28/1*o6rsj5YDo5x47eo4JpvbkQ.webp" alt="" loading="lazy" decoding="async" width="2208" height="1242" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMjA4IiBoZWlnaHQ9IjEyNDIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/35cc65327d28/1*o6rsj5YDo5x47eo4JpvbkQ.png" /></p>

<blockquote>
  <p><em>GAS Web App 无法做到满版 PWA 隐藏网址列，如果想做到 100% 体验请参考进阶内容。</em></p>
</blockquote>

<h4 id="最终程式码">最终程式码</h4>

<p><a href="https://github.com/zhgchgli0718/GASDashboardExample" target="_blank"><img src="https://opengraph.githubassets.com/d4cf8b9a7c53130de6bf5b4b520b4a3bfc3b5fa520a7a6ff33f39bf82a88ffdf/zhgchgli0718/GASDashboardExample" alt="" /></a></p>

<h4 id="后续任务">后续任务</h4>

<ul>
  <li>
    <p>[required] 跟 AI 说：开发完毕请移除所有开发阶段的介面／端点</p>
  </li>
  <li>
    <p>[optional] Google Apps Script Project -&gt; 专案设定 -&gt; 指令码属性 -&gt; <code class="language-plaintext highlighter-rouge">ACCESS_TOKEN</code> -&gt; 重新产生一个乱数字串，网址上的 <code class="language-plaintext highlighter-rouge">?token=</code> 也换成这个字串
macOS 可以用这个指令产生乱数字串: <code class="language-plaintext highlighter-rouge">openssl rand -hex 32</code></p>
  </li>
  <li>
    <p>[optional] <a href="https://opendata.cwa.gov.tw/userLogin" target="_blank">重新产生交通部中央气象署API Key 授权码</a> 并填入 Google Apps Script Project -&gt; 专案设定 -&gt; 指令码属性 -&gt; <code class="language-plaintext highlighter-rouge">CWA_API_KEY</code></p>
  </li>
</ul>

<blockquote>
  <p><strong><em>⚠️根据 Claude Code 警告：</em></strong> <em>所有暴露在对话内容的 Token 都有机会泄漏，需当成已泄漏，但是为了验证开发方便所以先直接输入，验证完没问题后需要重新产生填入。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>如果你熟悉 GAS 也可以在一开始就自己先设好 指令码属性 然后跟 AI 说直接使用。</em></strong></p>
</blockquote>

<h4 id="延伸">延伸</h4>

<p>如果这篇文章有激起你的创意，不妨想想还能串接显示什么，例如我多串接了 Yahoo Finance 取得我关注的股票即时股价、串接 AnalyticsData / AdSense 取得网站的流量与广告状况。</p>

<h4 id="进阶">进阶</h4>

<p>因为 GAS Web App 无法达成真 RWD、满版 PWA (隐藏网址列)，所以我自己是把 GAS Web App 当 API 服务只回传 JSON 资料，然后另外用 GitHub Pages 实现前端功能，部署成正式网页；这样就能达到完整使用的体验。</p>

<p><img src="/assets/35cc65327d28/1*Cx-dFPrSRjj8g2tL5Z_kJw.webp" alt="" loading="lazy" decoding="async" width="1160" height="695" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTYwIiBoZWlnaHQ9IjY5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/35cc65327d28/1*Cx-dFPrSRjj8g2tL5Z_kJw.png" /></p>

<p><img src="/assets/35cc65327d28/1*vtT3UhsGwmx15v4vNYS4vw.webp" alt="iOS 满版 PWA 网页设定 -&gt; Safari 打开网址 -&gt; 分享 -&gt; 加入主画面" loading="lazy" decoding="async" width="1200" height="675" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY3NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/35cc65327d28/1*vtT3UhsGwmx15v4vNYS4vw.jpeg" /></p>

<p>iOS 满版 PWA 网页设定 -&gt; Safari 打开网址 -&gt; 分享 -&gt; 加入主画面</p>

<p><strong>这条路会比较复杂一点，可以在 /plan 阶段跟 AI 说:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- GAS Web App 只做後端服務，輸出 JSON 給前端使用
- 前端使用 GitHub Pages 進行設計呈現和部署，幫我完成所有程式開發和部署任務開發
- 前端與後端之間用自訂亂數字串 Token 保護
</code></pre></div></div>

<h3 id="总结">总结</h3>

<p>以上就是这次使用 AI Agent 直接进行 Google Apps Script 的开发体验介绍，最近也有在用 AI 重整之前开发过的中大型 GAS 专案，效果都不错， <strong>还能请他在本地端加上函式单元测试(用 Jest、MOCK Google APIs) 提升稳定性</strong> (跑在 CI/CD 端、结合 clasp pull &amp; backup GAS Project)；AI 对 GAS 的掌握度与产出正确性都接近 100%。</p>

<h4 id="如果是-2021-年">如果是 2021 年…</h4>

<p>如果是那个没有 AI 的年代，手搓从 0 包含设计、切版、程式逻辑开发到上线，我预估大约需要 30 小时左右；如今用 AI 3 小时内就能搞定。</p>

<blockquote>
  <p>基本上我以后应该不会再从头开发 GAS，也不会从零开始 AI 写程式，而是从零开始叫 AI 做好产品给我 (程式? IDGAF)。</p>
</blockquote>

<h4 id="案例2--个人持股清单管理">案例(2) — 个人持股清单管理</h4>

<p><img src="/assets/35cc65327d28/1*ouM-S6-JDJ8ddoUDVh8TVg.webp" alt="" loading="lazy" decoding="async" width="1147" height="1295" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTQ3IiBoZWlnaHQ9IjEyOTUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/35cc65327d28/1*ouM-S6-JDJ8ddoUDVh8TVg.png" /></p>

<p>最近尝试的另一个 AI 直接搞定 Google Apps Script 的案例，请他把我的 Google Sheet 持股表格转成可视化 Web App，结合 Yahoo Finance 取得最新股价做成表格显示给我看，下方也可以快速地输入买入卖出纪录，会再串接写入回 Google Sheet。</p>

<h4 id="延伸阅读">延伸阅读</h4>

<blockquote>
  <p><em>TL;DR 这些都是之前手搓的 GAS 服务、工具</em></p>
</blockquote>

<ul>
  <li>
    <p><a href="https://medium.com/zrealm-robotic-process-automation/%E4%BD%BF%E7%94%A8-google-apps-script-%E5%AF%A6%E7%8F%BE-google-%E6%9C%8D%E5%8B%99-rpa-%E8%87%AA%E5%8B%95%E5%8C%96-f6713ba3fee3?source=collection_home---6------3-----------------------" target="_blank"><strong>使用 Google Apps Script 实现每日数据报表 RPA 自动化</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-robotic-process-automation/google-apps-script-快速串接-firebase-app-distribution-api-教学与进阶设定-71400d408dc8/"><strong>Google Apps Script x Google APIs 快速串接整合方式</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/"><strong>使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-robotic-process-automation/ga4-自动数据通知机器人-3-步骤用-google-apps-script-串接-telegram-bot-1e85b8df2348/">简单 3 步骤 — 打造免费 GA4 自动数据通知机器人</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/google-apps-script-教学-自动转发-gmail-邮件到-slack-channel-客制化通知-d414bdbdb8c9/">运用 Google Apps Script 转发 Gmail 信件到 Slack</a></p>
  </li>
  <li>
    <p><a href="https://medium.com/zrealm-robotic-process-automation/slack-%E6%89%93%E9%80%A0%E5%85%A8%E8%87%AA%E5%8B%95-wfh-%E5%93%A1%E5%B7%A5%E5%81%A5%E5%BA%B7%E7%8B%80%E6%B3%81%E5%9B%9E%E5%A0%B1%E7%B3%BB%E7%B5%B1-d61062833c1a?source=collection_home---6------9-----------------------" target="_blank">Slack 打造全自动 WFH 员工健康状况回报系统</a></p>
  </li>
  <li>
    <p><a href="https://medium.com/zrealm-robotic-process-automation/crashlytics-big-query-%E6%89%93%E9%80%A0%E6%9B%B4%E5%8D%B3%E6%99%82%E4%BE%BF%E5%88%A9%E7%9A%84-crash-%E8%BF%BD%E8%B9%A4%E5%B7%A5%E5%85%B7-e77b80cc6f89?source=collection_home---6------7-----------------------" target="_blank">Crashlytics + Big Query 打造更即时便利的 Crash 追踪工具</a></p>
  </li>
  <li>
    <p><a href="https://medium.com/zrealm-robotic-process-automation/crashlytics-google-analytics-%E8%87%AA%E5%8B%95%E6%9F%A5%E8%A9%A2-app-crash-free-users-rate-793cb8f89b72?source=collection_home---6------6-----------------------" target="_blank">Crashlytics + Google Analytics 自动查询 App Crash-Free Users Rate</a></p>
  </li>
  <li>
    <p><a href="https://medium.com/zrealm-robotic-process-automation/%E4%BD%BF%E7%94%A8-google-apps-script-%E4%B8%89%E6%AD%A5%E9%A9%9F%E5%85%8D%E8%B2%BB%E5%BB%BA%E7%AB%8B-github-repo-star-notifier-382218e15697?source=collection_home---6------5-----------------------" target="_blank">使用 Google Apps Script 三步骤免费建立 GitHub Repo Star Notifier</a></p>
  </li>
  <li>
    <p><a href="https://medium.com/zrealm-robotic-process-automation/10-%E5%88%86%E9%90%98%E5%BF%AB%E9%80%9F%E7%A7%BB%E8%BD%89-line-notify-%E5%88%B0-telegram-bot-%E9%80%9A%E7%9F%A5-6922e90ba90c?source=collection_home---6------0-----------------------" target="_blank">10 分钟快速移转 Line Notify 到 Telegram Bot 通知</a></p>
  </li>
</ul>]]></content>
  </entry><entry>
    <title type="html">Jekyll Blog 自订主题设计｜用 Claude Design + Claude Code 快速打造专属风格</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/jekyll-blog-%E8%87%AA%E8%AE%A2%E4%B8%BB%E9%A2%98%E8%AE%BE%E8%AE%A1-%E7%94%A8-claude-design-claude-code-%E5%BF%AB%E9%80%9F%E6%89%93%E9%80%A0%E4%B8%93%E5%B1%9E%E9%A3%8E%E6%A0%BC-6bf79c5b4dab/" rel="alternate" type="text/html" title="Jekyll Blog 自订主题设计｜用 Claude Design + Claude Code 快速打造专属风格" />
    <published>2026-04-27T23:00:32+08:00</published>
    <updated>2026-05-06T22:40:53+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/6bf79c5b4dab</id><summary type="html">程式设计师用 Claude Design 与 Claude Code 于一个周末完成 Jekyll Blog 主题重设，解决找不到理想主题的痛点，成功打造专属风格且支援 RWD 与 SEO，部署于免费可靠的 GitHub Pages，提升网站专业度与使用体验。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="claude-code" /><category term="github-pages" /><category term="jekyll" /><category term="ai" /><category term="blog" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/6bf79c5b4dab/1*cQbgChJysDv6MjvNic7Hlw.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/jekyll-blog-%E8%87%AA%E8%AE%A2%E4%B8%BB%E9%A2%98%E8%AE%BE%E8%AE%A1-%E7%94%A8-claude-design-claude-code-%E5%BF%AB%E9%80%9F%E6%89%93%E9%80%A0%E4%B8%93%E5%B1%9E%E9%A3%8E%E6%A0%BC-6bf79c5b4dab/"><![CDATA[<h3 id="一个周末午后--claude-design--claude-code--打造属于你自己风格的-blog">一个周末午后 + Claude Design + Claude Code = 打造属于你自己风格的 Blog</h3>

<p>使用 Claude Design + Claude Code 打造你专属的 Jekyll Theme Blog 主题</p>

<h4 id="httpszhgchgli-20"><a href="https://zhgchg.li/" target="_blank">https://zhgchg.li/</a> 2.0!</h4>

<p><img src="/assets/6bf79c5b4dab/1*cQbgChJysDv6MjvNic7Hlw.webp" alt="&lt;https://zhgchg.li/&gt;" loading="lazy" decoding="async" width="1200" height="1057" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwNTciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/6bf79c5b4dab/1*cQbgChJysDv6MjvNic7Hlw.png" /></p>

<p><a href="https://zhgchg.li/" target="_blank">https://zhgchg.li/</a></p>

<blockquote>
  <p><em>花了一个周末午后，用 Claude Design 设计喜欢的 Blog 样式与功能，再透过 Claude Code 实作并套用回 Jekyll Blog，把用了 5 年的 Chirpy Theme 介面完美替换成我心目中理想的个人 Blog 样式。</em></p>
</blockquote>

<h4 id="技术">技术</h4>

<ul>
  <li>
    <p><strong>Blog 架构:</strong> Jekyll 静态网站</p>
  </li>
  <li>
    <p><strong>文章原始档:</strong> Markdown 档案</p>
  </li>
  <li>
    <p><strong>伺服器/网页寄存:</strong> GitHub Pages (免费可靠)</p>
  </li>
  <li>
    <p><strong>Engineering:</strong> Claude Code Max ($100 USD，5 小时额度 <strong>还没用完就做好了</strong> )</p>
  </li>
  <li>
    <p><strong>Design:</strong> Claude Design (Blog 页面不多，2 小时额度内就够用)</p>
  </li>
</ul>

<h4 id="花费">花费</h4>

<ul>
  <li>
    <p>Claude Code Max $100 USD</p>
  </li>
  <li>
    <p>伺服器/网页寄存: $0 USD</p>
  </li>
  <li>
    <p>Jekyll Theme: $0 USD</p>
  </li>
  <li>
    <p>时间: 一个周末的下午</p>
  </li>
</ul>

<h3 id="实现步骤">实现步骤</h3>

<h4 id="1-在本地建立一个干净的-jekyll-blog">1. 在本地建立一个干净的 Jekyll Blog</h4>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jekyll new blog
</code></pre></div></div>

<h4 id="2-搜集-theme-页面案例并上传到-claude-design">2. 搜集 Theme 页面案例并上传到 Claude Design</h4>

<h4 id="20260506-upadte-21-design-agent-skill-使用第三方-设计-skill-完成设计">[2026/05/06 Upadte] <a href="https://zhgchg.li/posts/zrealm-dev/%E5%88%A5%E5%86%8D%E5%BE%9E%E9%9B%B6%E9%96%8B%E5%A7%8B-ai-%E5%AF%AB%E7%A8%8B%E5%BC%8F-%E8%AE%93-ai-agent-%E7%9B%B4%E6%8E%A5%E5%B9%AB%E4%BD%A0%E6%90%9E%E5%AE%9A-google-apps-script-%E4%B8%B2%E6%8E%A5%E8%88%87%E9%96%8B%E7%99%BC-35cc65327d28/#%E4%BD%BF%E7%94%A8-claude-design-or-design-agent-skill-%E8%A8%AD%E8%A8%88-dashboard" target="_blank">2–1 Design Agent Skill 使用第三方 设计 Skill 完成设计</a></h4>

<p>细节可参考此篇文章「 <a href="https://zhgchg.li/posts/zrealm-dev/%E5%88%A5%E5%86%8D%E5%BE%9E%E9%9B%B6%E9%96%8B%E5%A7%8B-ai-%E5%AF%AB%E7%A8%8B%E5%BC%8F-%E8%AE%93-ai-agent-%E7%9B%B4%E6%8E%A5%E5%B9%AB%E4%BD%A0%E6%90%9E%E5%AE%9A-google-apps-script-%E4%B8%B2%E6%8E%A5%E8%88%87%E9%96%8B%E7%99%BC-35cc65327d28/#%E4%BD%BF%E7%94%A8-claude-design-or-design-agent-skill-%E8%A8%AD%E8%A8%88-dashboard" target="_blank">别再从零开始 AI 写程式：让 AI Agent 直接帮你搞定 Google Apps Script 串接与开发</a> 」</p>

<h4 id="22-claude-design">2–2 Claude Design</h4>

<p>我直接到目前的 Blog，在各页面按右键「Save as」例如 Home、Post、Page、PostList、Archives、Tags…</p>

<p><img src="/assets/6bf79c5b4dab/1*EWBgWOobhy5kFeNPq9-uqQ.webp" alt="" loading="lazy" decoding="async" width="482" height="359" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0ODIiIGhlaWdodD0iMzU5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6bf79c5b4dab/1*EWBgWOobhy5kFeNPq9-uqQ.png" /></p>

<p><strong>建一个 Theme 目录，把所有页面跟附加档案都放进去:</strong></p>

<p><img src="/assets/6bf79c5b4dab/1*eo3d-J4ehZpBIZfx4bV4Wg.webp" alt="" loading="lazy" decoding="async" width="253" height="231" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNTMiIGhlaWdodD0iMjMxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6bf79c5b4dab/1*eo3d-J4ehZpBIZfx4bV4Wg.png" /></p>

<p><strong>到 <a href="https://claude.ai/design" target="_blank">Claude Design</a> 建立专案:</strong></p>

<p><img src="/assets/6bf79c5b4dab/1*AYCu31HSzfOHST8nberNWA.webp" alt="&lt;https://claude.ai/design&gt;" loading="lazy" decoding="async" width="377" height="441" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNzciIGhlaWdodD0iNDQxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6bf79c5b4dab/1*AYCu31HSzfOHST8nberNWA.png" /></p>

<p><a href="https://claude.ai/design" target="_blank">https://claude.ai/design</a></p>

<p><strong>将 Theme 页面案例上传到 Claude Design，选择「Attach codebase」:</strong></p>

<p><img src="/assets/6bf79c5b4dab/1*1A08G_oNaieGA_8t17xPow.webp" alt="" loading="lazy" decoding="async" width="323" height="340" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMjMiIGhlaWdodD0iMzQwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6bf79c5b4dab/1*1A08G_oNaieGA_8t17xPow.png" /></p>

<p><strong>选择刚刚整理好的 Theme 目录:</strong></p>

<p><img src="/assets/6bf79c5b4dab/1*KbXyuIRuWnisFYbtnIUhzg.webp" alt="" loading="lazy" decoding="async" width="998" height="560" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5OTgiIGhlaWdodD0iNTYwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6bf79c5b4dab/1*KbXyuIRuWnisFYbtnIUhzg.png" /></p>

<p><strong>选择完成后，输入 Prompt 请 Claude Design 帮你设计页面:</strong></p>

<p><img src="/assets/6bf79c5b4dab/1*bvO5_7XHaQSRdjbIcj_QsA.webp" alt="" loading="lazy" decoding="async" width="391" height="153" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzOTEiIGhlaWdodD0iMTUzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6bf79c5b4dab/1*bvO5_7XHaQSRdjbIcj_QsA.png" /></p>

<blockquote>
  <p><em>重新设计我的 Blog，用繁体中文跟我交流。</em></p>
</blockquote>

<h4 id="3-使用-claude-design-重新设计">3. 使用 Claude Design 重新设计</h4>

<p>送出对话后，Claude Design 会问你关于你想要的设计问题:</p>

<p><img src="/assets/6bf79c5b4dab/1*EvWpwlNUXDcLI5MHUz9Jug.webp" alt="" loading="lazy" decoding="async" width="646" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NDYiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6bf79c5b4dab/1*EvWpwlNUXDcLI5MHUz9Jug.png" /></p>

<ul>
  <li>
    <p>想看几个视觉方向的变体？ AI 会产出多个方案供你选择</p>
  </li>
  <li>
    <p>希望可即时调整哪些 Tweaks？右下角 Debug 小工具需要哪些切换功能</p>
  </li>
  <li>
    <p>其他就照喜好自己填写啰。</p>
  </li>
</ul>

<h4 id="4-claude-design-cooking">4. Claude Design Cooking…</h4>

<p><img src="/assets/6bf79c5b4dab/1*pBQcJF9Bim581CsPHGdlxQ.webp" alt="" loading="lazy" decoding="async" width="1022" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDIyIiBoZWlnaHQ9IjEyMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/6bf79c5b4dab/1*pBQcJF9Bim581CsPHGdlxQ.png" /></p>

<p>大约需要 3–5 分钟，AI 会建立完整的 Design System（.css），并用 React.js／HTML 展示结果。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>已完成 Blog 的重新設計，放在 Blog Redesign.html。

設計系統

字體：Noto Serif TC（宋體）+ Inter + JetBrains Mono
色調：暖紙張米白 + 赤陶主色（oklch warm 系）
三條分類軸線：科技 / 旅行 / 分享，全部使用真實的中文範例內容
兩個方向，共 7 個畫板（雙擊可全螢幕預覽）

方向 A · 雜誌風（Magazine）

首頁 — 報頭刊名 + 主打報導 + 三欄次要文章 + 編號式條列 + Newsletter
文章頁 — 完整單篇含目錄、首字下沉、引言、程式碼區塊、留言、相關文章
分類頁 — 2×2 大圖式索引
標籤頁 — 視覺化條狀統計 + 標籤雲
歸檔頁 — 年份 + 月份的時光軸
關於頁 — 個人介紹 + Now 區塊 + 訂閱
方向 B · 現代刊物（Substack 風） 7. 首頁 — 大圖 Hero + 卡片式網格 + 側欄訂閱牆

Tweaks 面板（右下角開啟）可即時切換：

標題字體（Noto Serif / 思源宋體）
寬版面 / 標準版面
主色與紙張色（含 4 組預設配色：赤陶、深藍、墨綠、酒紅）
</code></pre></div></div>

<h4 id="5-claude-design-结果调整">5. Claude Design 结果调整</h4>

<p><img src="/assets/6bf79c5b4dab/1*fRHChM-U_a_dbtde2NcO3w.webp" alt="" loading="lazy" decoding="async" width="1200" height="769" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc2OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6bf79c5b4dab/1*fRHChM-U_a_dbtde2NcO3w.png" /></p>

<ul>
  <li>
    <p>可以点击右下角的 Tweak，快速调整参数并查看结果</p>
  </li>
  <li>
    <p>可以点击页面右上角放大查看完整网页；若有互动功能，也能直接操作 Mockup</p>
  </li>
  <li>
    <p>如果点击无效、无法滚动、页面显示不完整或内容被裁切，都可以请 AI 调整</p>
  </li>
</ul>

<p>可以继续跟 AI 对话请他加上你要的功能、调整现有功能，例如我希望文章末可以加入 buy me a coffee donate 连结、留言， <strong>我就可以再跟他说:</strong></p>

<p><img src="/assets/6bf79c5b4dab/1*5IdYAz7JCerimasdQQl8lA.webp" alt="" loading="lazy" decoding="async" width="389" height="684" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzODkiIGhlaWdodD0iNjg0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6bf79c5b4dab/1*5IdYAz7JCerimasdQQl8lA.png" /></p>

<p><strong>结果:</strong></p>

<p><img src="/assets/6bf79c5b4dab/1*UdAS4J2B494L3RYk_Dpgcg.webp" alt="" loading="lazy" decoding="async" width="846" height="1184" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NDYiIGhlaWdodD0iMTE4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6bf79c5b4dab/1*UdAS4J2B494L3RYk_Dpgcg.png" /></p>

<blockquote>
  <p>持续跟 AI 对话把功能跟页面设计成自己想要。</p>
</blockquote>

<h4 id="6-claude-design-完成">6. Claude Design 完成</h4>

<p>设计到满意后，点右上角「Share」→「Download project as .zip」，将原始设计档下载回来:</p>

<p><img src="/assets/6bf79c5b4dab/1*HD6TIUrAQXeduhkUoRdC7g.webp" alt="" loading="lazy" decoding="async" width="477" height="450" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NzciIGhlaWdodD0iNDUwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6bf79c5b4dab/1*HD6TIUrAQXeduhkUoRdC7g.png" /></p>

<p>下载并解压缩后，把资料夹放到 Jekyll Blog 目录中:</p>

<p><img src="/assets/6bf79c5b4dab/1*ZUZcFtumkmeo9UuTACQakw.webp" alt="" loading="lazy" decoding="async" width="326" height="476" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMjYiIGhlaWdodD0iNDc2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6bf79c5b4dab/1*ZUZcFtumkmeo9UuTACQakw.png" /></p>

<h4 id="7-请-claude-code-实现-claude-design-设计稿">7. 请 Claude Code 实现 Claude Design 设计稿</h4>

<p><img src="/assets/6bf79c5b4dab/1*npQOf0QkzG6qDJKwT1-f9A.webp" alt="" loading="lazy" decoding="async" width="1078" height="725" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDc4IiBoZWlnaHQ9IjcyNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6bf79c5b4dab/1*npQOf0QkzG6qDJKwT1-f9A.png" /></p>

<p>记得先在 Jekyll Blog 目录下执行一次 <code class="language-plaintext highlighter-rouge">/init</code> ，让 AI 知道这是 Jekyll Blog 架构。</p>

<p><img src="/assets/6bf79c5b4dab/1*sEtu11Zbw5ZkP5n69uyVmA.webp" alt="" loading="lazy" decoding="async" width="668" height="217" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NjgiIGhlaWdodD0iMjE3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6bf79c5b4dab/1*sEtu11Zbw5ZkP5n69uyVmA.png" /></p>

<blockquote>
  <p><em>使用 ./MyBlogTheme 的主题设计套用到我的 blog</em></p>
</blockquote>

<h4 id="8-claude-code-baking">8. Claude Code baking…</h4>

<p><img src="/assets/6bf79c5b4dab/1*_iSl56RBPuHX9OqAjR4q-g.webp" alt="" loading="lazy" decoding="async" width="1192" height="1174" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTkyIiBoZWlnaHQ9IjExNzQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/6bf79c5b4dab/1*_iSl56RBPuHX9OqAjR4q-g.png" /></p>

<p><img src="/assets/6bf79c5b4dab/1*D8RjjpPikNWEqe2G55PkhA.webp" alt="" loading="lazy" decoding="async" width="1192" height="1174" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTkyIiBoZWlnaHQ9IjExNzQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/6bf79c5b4dab/1*D8RjjpPikNWEqe2G55PkhA.png" /></p>

<ul>
  <li>首次建置大约花费 20K Tokens (Opus 4.7 / effort: medium)</li>
</ul>

<h4 id="成果">成果：</h4>

<p>执行 <code class="language-plaintext highlighter-rouge">bundle exec jekyll serve</code> 打开 http://127.0.0.1:4000/ 查看结果:</p>

<p><img src="/assets/6bf79c5b4dab/1*nvsTfFy1S2siBrAlHcbguQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="638" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjYzOCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6bf79c5b4dab/1*nvsTfFy1S2siBrAlHcbguQ.png" /></p>

<blockquote>
  <p>接著持续请 AI 优化与修正问题，但基本完成度已经很高了！</p>
</blockquote>

<h3 id="实现小-tips">实现小 Tips</h3>

<ul>
  <li>
    <p>可以跟 AI 说： <code class="language-plaintext highlighter-rouge">你的 Blog 会部署到 GitHub Pages</code> 或其他平台，因为每个平台可能机能不一样，例如 GitHub Pages 只允许部分的 <a href="https://github.com/github/pages-gem/blob/master/lib/github-pages/plugins.rb#L21-L42" target="_blank">Jekyll Plugins</a> ，不在允许清单中的套件，上线后也无法使用。</p>
  </li>
  <li>
    <p>可以跟 AI 说： <code class="language-plaintext highlighter-rouge">优先使用 Jekyll 原生、Jekyll Plugin、免费开源的专案实现功能。</code></p>
  </li>
  <li>
    <p>可以跟 AI 说： <code class="language-plaintext highlighter-rouge">网站设计务必要重视 SEO 结构与 RWD 操作体验。</code></p>
  </li>
  <li>
    <p>可以跟 AI 说： <code class="language-plaintext highlighter-rouge">设计新的 Theme 替代掉现有的</code> 。</p>
  </li>
  <li>
    <p>部署到 GitHub Pages 的 CI/CD YAML 也可以请 AI 写，步骤他也会教你。</p>
  </li>
  <li>
    <p><strong>如果想调整新的页面设计，建议回到 Claude Design 修改设计稿，调整完再重新下载并放回目录；不建议直接请 Claude Code 做视觉设计，它不太擅长美感。</strong></p>
  </li>
</ul>

<h4 id="我用到的套件或功能"><strong>我用到的套件或功能</strong></h4>

<p><strong>Jekyll 套件:</strong></p>

<ul>
  <li>
    <p>jekyll 4.3 + kramdown (GFM) + kramdown-parser-gfm</p>
  </li>
  <li>
    <p>rouge — code highlight</p>
  </li>
  <li>
    <p>jekyll-feed — Atom feed (/feed.xml)</p>
  </li>
  <li>
    <p>jekyll-sitemap — /sitemap.xml</p>
  </li>
  <li>
    <p>jekyll-paginate-v2 — 文章分页功能</p>
  </li>
  <li>
    <p>jekyll-archives — 归档页面</p>
  </li>
  <li>
    <p>jekyll-seo-tag — SEO Meta Tag / OG / Twitter Card meta</p>
  </li>
  <li>
    <p>jekyll-redirect-from — 短网址 redirect</p>
  </li>
</ul>

<p><strong>CSS / 前端资源:</strong></p>

<ul>
  <li>
    <p>GLightbox v3（CDN, MIT） — 图片点击放大 lightbox</p>
  </li>
  <li>
    <p>SCSS：assets/css/main.scss</p>
  </li>
  <li>
    <p><a href="https://fontawesome.com/" target="_blank">Font Awesome</a> icon svg</p>
  </li>
</ul>

<p><strong>JavaScript 功能:</strong></p>

<ul>
  <li>
    <p>抽屉选单（topbar menu / overlay / ESC 关闭）</p>
  </li>
  <li>
    <p>LQIP hydrator &amp; Lazy Load — 文章图片 Placeholder &amp; 延迟载入</p>
  </li>
  <li>
    <p>Reading progress bar</p>
  </li>
  <li>
    <p>Client-side TOC</p>
  </li>
  <li>
    <p>Search：/search.json build-time + 纯 JS substring filter（无 lunr）</p>
  </li>
</ul>

<p><strong>第三方服务:</strong></p>

<ul>
  <li>giscus — 留言（GitHub Discussions）</li>
</ul>

<h3 id="背景">背景</h3>

<p>2018 年起在 Medium 撰写文章纪录程式与生活，后来自己开发了一个小工具 <a href="https://github.com/ZhgChgLi/ZMediumToMarkdown" target="_blank">ZMediumToMarkdown</a> 可以把 Medium 文章下载转换成 Markdown 档案备份，并顺带用 Jekyll + Chirpy theme 建立了独立的 Blog 网站，部署在免费的 GitHub Pages 之上。</p>

<p><a href="https://github.com/jekyll/jekyll" target="_blank"><img src="https://repository-images.githubusercontent.com/65252/f2b7c780-70b6-11e9-85d2-f4bda8708a2d" alt="" /></a></p>

<p>Jekyll 是一套很方便的静态网站产生工具，可以把 Markdown 和模板转换成 HTML，再将 HTML 档案放到托管服务上，内容就能上线。</p>

<ul>
  <li>
    <p>我也用 Jekyll 做了一个自己的 Linktree: <a href="https://link.zhgchg.li" target="_blank">https://link.zhgchg.li</a></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">jekyll new blog</code> 就能快速建立一个预设的 Blog 专案</p>
  </li>
</ul>

<p><strong>Jekyll 预设的 Blog 专案样式非常阳春:</strong></p>

<p><img src="/assets/6bf79c5b4dab/1*SB1pZSaMsMvUG8AiUla62w.webp" alt="" loading="lazy" decoding="async" width="792" height="937" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3OTIiIGhlaWdodD0iOTM3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6bf79c5b4dab/1*SB1pZSaMsMvUG8AiUla62w.png" /></p>

<p>但是要找到满意的 Jekyll Blog Theme 不太容易，有的是首页漂亮、有的是文章内容页体验好、有的是列表页不错，就算是付费主题也很难找到完全满意的；也有可能装了都设定好了才发现少了什么功能或是页面，又只能舍弃再找，很痛苦。</p>

<p><a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank"><img src="https://repository-images.githubusercontent.com/165360641/257ebaa6-61dd-40a4-b075-d21b546026d6" alt="" /></a></p>

<p><strong>来来回回找了好几轮，最终找到一个布局不差、支援 RWD、Blog 功能完善的主题 — <a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank">Theme Chirpy</a> :</strong></p>

<p><img src="/assets/6bf79c5b4dab/1*Ayc3pF9qbahE5U2BnzixaQ.webp" alt="Live Demo" loading="lazy" decoding="async" width="1576" height="1143" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTc2IiBoZWlnaHQ9IjExNDMiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/6bf79c5b4dab/1*Ayc3pF9qbahE5U2BnzixaQ.png" /></p>

<p><a href="https://chirpy.cotes.page/posts/text-and-typography/" target="_blank">Live Demo</a></p>

<p>一用就是 5 年，当中也有看得很腻想要换的时候；但每次鬼打墙找了一轮后，最后还是回来用 <a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank"><strong>Theme Chirpy</strong></a> ，如同前述找不到比它更好看又实用的主题了。</p>

<blockquote>
  <p>直到 Claude Design + Claude Code 出现，我才一鼓作气请 AI 帮我设计想要的 Blog 风格，并实作功能页。</p>
</blockquote>]]></content>
  </entry><entry>
    <title type="html">北海道札幌6日游攻略｜定山溪温泉泡汤＋富良野美瑛点灯一日游全记录</title>
    <link href="https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E5%8C%97%E6%B5%B7%E9%81%93%E6%9C%AD%E5%B9%8C6%E6%97%A5%E6%B8%B8%E6%94%BB%E7%95%A5-%E5%AE%9A%E5%B1%B1%E6%BA%AA%E6%B8%A9%E6%B3%89%E6%B3%A1%E6%B1%A4-%E5%AF%8C%E8%89%AF%E9%87%8E%E7%BE%8E%E7%91%9B%E7%82%B9%E7%81%AF%E4%B8%80%E6%97%A5%E6%B8%B8%E5%85%A8%E8%AE%B0%E5%BD%95-055527a739dd/" rel="alternate" type="text/html" title="北海道札幌6日游攻略｜定山溪温泉泡汤＋富良野美瑛点灯一日游全记录" />
    <published>2026-04-19T23:51:51+08:00</published>
    <updated>2026-04-20T23:33:43+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/055527a739dd</id><summary type="html">规划北海道札幌6日游，详细分享定山溪温泉交通预约技巧、札幌市区美食与景点、小樽水族馆体验，及KKday富良野精灵台与美瑛青池点灯行程，助你轻松掌握交通、住宿与行程安排，打造无忧冬季北海道旅游。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="Z 度旅行遊記" /><category term="japan" /><category term="生活" /><category term="travel" /><category term="travel-writing" /><category term="hokkaido" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/055527a739dd/1*4N6zFGkzcM6QsIulPOwslQ.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E5%8C%97%E6%B5%B7%E9%81%93%E6%9C%AD%E5%B9%8C6%E6%97%A5%E6%B8%B8%E6%94%BB%E7%95%A5-%E5%AE%9A%E5%B1%B1%E6%BA%AA%E6%B8%A9%E6%B3%89%E6%B3%A1%E6%B1%A4-%E5%AF%8C%E8%89%AF%E9%87%8E%E7%BE%8E%E7%91%9B%E7%82%B9%E7%81%AF%E4%B8%80%E6%97%A5%E6%B8%B8%E5%85%A8%E8%AE%B0%E5%BD%95-055527a739dd/"><![CDATA[<h3 id="游记-2026-北海道札幌-6-日游--札幌市区定山溪温泉北海道点灯富良野精灵台--美瑛青池一日游">[游记] 2026 北海道札幌 6 日游 — 札幌市区、定山溪温泉、北海道点灯(富良野精灵台 &amp; 美瑛青池)一日游</h3>

<p>北海道札幌市区散策、定山溪泡汤、富良野精灵台与美瑛青池点灯行程全记录</p>

<p><img src="/assets/055527a739dd/1*4N6zFGkzcM6QsIulPOwslQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="760" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc2MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*4N6zFGkzcM6QsIulPOwslQ.png" /></p>

<p>新工作做了快半年加上手上专案刚结束，也从没去过下雪的日本，于是就在 3 月中来场日本北海道之旅。</p>

<h3 id="出发前准备">出发前准备</h3>

<h4 id="计划">计划</h4>

<ul>
  <li>
    <p>第一天：到札幌后直接去定山溪温泉住一晚</p>
  </li>
  <li>
    <p>第二天：回札幌市区逛景点</p>
  </li>
  <li>
    <p>第三天：小樽、小樽水族馆</p>
  </li>
  <li>
    <p>第四天： <a href="https://www.kkday.com/zh-tw/product/157133-hokkaido-sapporo-biei-blue-pond-illumination-tour-japan?cid=19365" target="_blank"><strong>KKday 北海道点灯之旅 ｜富良野精灵台＆美瑛青池＆白须瀑布一日游｜札幌出发</strong></a></p>
  </li>
  <li>
    <p>第五天：逛街购物、北海道神宫</p>
  </li>
  <li>
    <p>第六天：前往机场返程</p>
  </li>
</ul>

<h4 id="行">行</h4>

<h4 id="机票--中华航空"><strong>机票 — 中华航空</strong></h4>

<ul>
  <li>
    <p>🛫 03/15 去程 CI130 : TPE 桃园国际机场 T2 <strong>08:35</strong> (实际延误 3 分钟) -&gt; CTS 北海道新千岁机场 <strong>13:15</strong> (实际延误 7 分钟)</p>
  </li>
  <li>
    <p>🛬 03/20 回程 CI131 : CTS 北海道新千岁机场 <strong>14:20</strong> (实际延误 8 分钟) <strong>-&gt;</strong> TPE 桃园国际机场 <strong>18:15</strong> (实际提早 3 分钟)</p>
  </li>
</ul>

<blockquote>
  <p><em>价格：NT $24,356/人</em></p>
</blockquote>

<blockquote>
  <p>*因为雪季还没过还是贵，周五回因为六日更贵…</p>
</blockquote>

<h4 id="札幌车站---定山溪-往返巴士车票"><strong>札幌车站 &lt;-&gt; 定山溪 往返巴士车票</strong></h4>

<p><img src="/assets/055527a739dd/1*WwGk0L6ccnJi3FweO4qr_g.webp" alt="" loading="lazy" decoding="async" width="1130" height="1600" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTMwIiBoZWlnaHQ9IjE2MDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*WwGk0L6ccnJi3FweO4qr_g.jpeg" /></p>

<p><img src="/assets/055527a739dd/1*i7zUMAOkPm7RwhcYbs3xVA.webp" alt="https://jozankei.jp/tw/news/newaccess/" loading="lazy" decoding="async" width="1536" height="1086" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjEwODYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*i7zUMAOkPm7RwhcYbs3xVA.jpeg" /></p>

<p>https://jozankei.jp/tw/news/newaccess/</p>

<p>新千岁机场到札幌站的 JR 我看班次很多加上飞机落地时间抓不太准就没先买票；前往定山溪温泉只能搭乘巴士，根据 <a href="https://jozankei.jp/tw/news/newaccess/" target="_blank">2025/12 最新交通资讯</a> ，有 3 种路线可以选择：</p>

<ol>
  <li>
    <p><strong>[需预约] [约 60 分钟] 札幌车站 → 搭乘 Kappa Liner 巴士 → 定山溪温泉。</strong>
<strong>点此查看时刻表</strong></p>
  </li>
  <li>
    <p>[不用预约] [约 70 分钟] 札幌车站 → 真驹内站 → 巴士 → 定山溪温泉。</p>
  </li>
  <li>
    <p>[不用预约] [约 120 分钟] 新千岁机场 → <a href="https://www.hokto.co.jp/makomanai-chitose/" target="_blank">机场巴士（北斗交通）</a> → 真驹内站→ 定山溪温泉。</p>
  </li>
</ol>

<p><strong>路线(1) — <a href="https://www.jotetsu.co.jp/bus/kappa_liner/index.html" target="_blank">かっぱライナー号 / 卡帕​内​衣号 / Kappa Liner</a> 是最顺最方便的</strong> ，查了一下班次飞机落地后入关再搭 JR 到札幌站走出来，下午 4:00 发车(秋冬限定班次)的时间上绰绰有余，就先在网路上预约了(外国人也可以！)。</p>

<p><strong>去程 札幌站 -&gt; 定山溪：</strong></p>

<p><img src="/assets/055527a739dd/1*cAKpufRPO7_kJuG-f3l74w.webp" alt="&lt;https://www.jotetsu.co.jp/bus/kappa_liner/index.html&gt;" loading="lazy" decoding="async" width="868" height="619" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjgiIGhlaWdodD0iNjE5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*cAKpufRPO7_kJuG-f3l74w.png" /></p>

<p><a href="https://www.jotetsu.co.jp/bus/kappa_liner/index.html" target="_blank">https://www.jotetsu.co.jp/bus/kappa_liner/index.html</a></p>

<ul>
  <li>要注意 <strong>红色字的班次只有秋冬季有行驶</strong> 、札幌站 16:00/17:00 发车的班次只开到定山溪车库前。</li>
</ul>

<p><strong>回程 定山溪 -&gt; 札幌站：</strong></p>

<p><img src="/assets/055527a739dd/1*qVXeuuYsNv__vp_ye6jnvw.webp" alt="&lt;https://www.jotetsu.co.jp/bus/kappa_liner/index.html&gt;" loading="lazy" decoding="async" width="923" height="535" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjMiIGhlaWdodD0iNTM1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*qVXeuuYsNv__vp_ye6jnvw.png" /></p>

<p><a href="https://www.jotetsu.co.jp/bus/kappa_liner/index.html" target="_blank">https://www.jotetsu.co.jp/bus/kappa_liner/index.html</a></p>

<ul>
  <li>回程想说 11:00 Checkout 后在温泉街走一走再回去，所以订 13:15 发车 (白丝瀑布 13:31 上车)的班次</li>
</ul>

<p><strong>预约方式：</strong></p>

<p>1.到 <a href="https://jotetsu.quicktrip.jp/buy" target="_blank">官方预约网站</a> 注册会员</p>

<p><img src="/assets/055527a739dd/1*CzG4MgskigUp8NXhe3xExw.webp" alt="" loading="lazy" decoding="async" width="767" height="484" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjciIGhlaWdodD0iNDg0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*CzG4MgskigUp8NXhe3xExw.png" /></p>

<ul>
  <li>
    <p>Email / 台湾手机号码 OK。</p>
  </li>
  <li>
    <p>务必记得帐号密码，因为是电子车票直接线上启用给司机确认。</p>
  </li>
</ul>

<p>2.选择购买 <a href="https://jotetsu.quicktrip.jp/buy/reservation?salesTicketId=1943" target="_blank">かっぱライナー号 / 卡帕​内​衣号 / Kappa Liner</a> 来回 or 单程</p>

<p><img src="/assets/055527a739dd/1*HjF2Kh18Rm6CxchhV8rP7g.webp" alt="" loading="lazy" decoding="async" width="721" height="187" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MjEiIGhlaWdodD0iMTg3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*HjF2Kh18Rm6CxchhV8rP7g.png" /></p>

<p>3.选择人数</p>

<p><img src="/assets/055527a739dd/1*BuuwoHzpfc4R2XeDb-0Luw.webp" alt="" loading="lazy" decoding="async" width="745" height="279" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NDUiIGhlaWdodD0iMjc5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*BuuwoHzpfc4R2XeDb-0Luw.png" /></p>

<p>4.选择 去程 的日期与班次(班次时间以札幌出发表示)</p>

<p><img src="/assets/055527a739dd/1*6JVbtozEiw37fj0EqFDADw.webp" alt="" loading="lazy" decoding="async" width="773" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NzMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*6JVbtozEiw37fj0EqFDADw.png" /></p>

<p>5.选择去程上下车位置</p>

<p><img src="/assets/055527a739dd/1*apTSepE2RXgoJmbK_IoFjA.webp" alt="" loading="lazy" decoding="async" width="762" height="486" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjIiIGhlaWdodD0iNDg2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*apTSepE2RXgoJmbK_IoFjA.png" /></p>

<p>上下车站点可参考下方图表：</p>

<p><img src="/assets/055527a739dd/1*NyUAFnQb4KqMSoXiRiT6iw.webp" alt="&lt;https://www.jotetsu.co.jp/bus/kappa_liner/index.html&gt;" loading="lazy" decoding="async" width="1200" height="736" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjczNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*NyUAFnQb4KqMSoXiRiT6iw.png" /></p>

<p><a href="https://www.jotetsu.co.jp/bus/kappa_liner/index.html" target="_blank">https://www.jotetsu.co.jp/bus/kappa_liner/index.html</a></p>

<p>我们的饭店离 <strong>(2) <a href="https://jozankei.jp/tw/spot/1449/" target="_blank">白丝瀑布/白糸の滝/Shiraitonotaki</a></strong> 比较近所以预约在这站下车。</p>

<blockquote>
  <p><em>后来才发现也可以继续坐绕一圈坐到 <strong>(7) Jozankei onsen higashi 2 chome / 定山渓温泉东2丁目</strong> 站下车，就是饭店门口。</em></p>
</blockquote>

<p>5.选择回程日期与班次(班次时间以出发站点表示)、上下车位置</p>

<p>6.线上刷卡完成付款</p>

<blockquote>
  <p><em>价格： ¥2,920 日圆/大人。</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*5flfur4c5dHTJsugsXkN0A.webp" alt="" loading="lazy" decoding="async" width="569" height="1013" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NjkiIGhlaWdodD0iMTAxMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*5flfur4c5dHTJsugsXkN0A.png" /></p>

<p>预约订位成功会收到 Email 通知， <strong>不需要再去兑换直接在 <a href="https://jotetsu.quicktrip.jp/bought" target="_blank">车票网站线上启用</a> 给司机看即可</strong> 。</p>

<h4 id="esim">eSIM</h4>

<p>同样在 KKday 购买 5G 吃到饱 eSIM，这次在北海道使用只有在美瑛深山一度收不到讯号之外其他时候都没问题；这次特别选支援 ChatGPT 的方案，方便查资料。</p>

<ul>
  <li>
    <p>KKday 购买： <a href="https://www.kkday.com/zh-tw/product/137689-japan-unlimited-data-esim-card?cid=19365" target="_blank">日本 eSIM｜Docomo / KDDI / SoftBank / Rakuten｜ <strong>支援ChatGPT 及 Gemini</strong></a></p>
  </li>
  <li>
    <p><strong>eSIM 要在有网路环境下启用，最好是在机场上飞机前就先在台湾启用</strong></p>
  </li>
</ul>

<blockquote>
  <p><em>价格：NT $343/6 日，无限流量（须遵守公平原则）</em></p>
</blockquote>

<h4 id="visit-japan">Visit Japan</h4>

<p><a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E4%BA%AC%E9%98%AA%E7%A5%9E%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E4%BA%AC%E9%83%BD%E5%A4%A7%E9%98%AA%E7%A5%9E%E6%88%B68%E6%97%A5%E9%81%8A%E5%85%A8%E7%B4%80%E9%8C%84%E8%88%87%E5%AF%A6%E7%94%A8%E4%BA%A4%E9%80%9A%E4%BD%8F%E5%AE%BF%E6%8C%87%E5%8D%97-76d66c2e34af/#20241125-%E6%9B%B4%E6%96%B0%E5%85%A5%E5%A2%83%E5%AF%A9%E6%9F%A5%E8%88%87%E6%B5%B7%E9%97%9C%E7%94%B3%E5%A0%B1qr-code-%E5%B7%B2%E5%90%88%E4%BD%B5%E6%88%90%E5%90%8C%E4%B8%80%E5%80%8B%E5%85%A5%E5%A2%83%E5%AE%A1%E6%9F%A5%E5%8F%8A%E6%B5%B7%E5%85%B3%E7%94%B3%E6%8A%A5%E7%9A%84qr%E7%A0%81%E6%B2%92%E6%9C%89%E8%97%8D%E7%A2%BC%E9%BB%83%E7%A2%BC%E5%8D%80%E5%88%A5%E4%BB%A5%E4%B8%8B%E5%85%A7%E5%AE%B9%E5%8F%AA%E7%95%B6%E7%B4%80%E9%8C%84%E5%8F%AF%E4%BB%A5%E5%BF%BD%E7%95%A5" target="_blank">请参考之前的文章，事前完成登录就好，现在入境审查与海关审查都用同一个 QRCode。</a></p>

<h3 id="住">住</h3>

<h4 id="031516-1-晚--jozankei-yurakusoan-ゆらく草庵-日式温泉饭店"><strong>03/15–16 (1 晚) — <a href="https://maps.app.goo.gl/mi1LRdo79NghFL3n7" target="_blank">Jozankei Yurakusoan ゆらく草庵 日式温泉饭店</a></strong></h4>

<p><img src="/assets/055527a739dd/1*NeSAUcKO7d4QbVw6OGaF6A.webp" alt="*3 Chome-228–1 Jozankeionsenhigashi, Minami Ward, Sapporo, Hokkaido 061–2301日本*" loading="lazy" decoding="async" width="512" height="362" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTIiIGhlaWdodD0iMzYyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*NeSAUcKO7d4QbVw6OGaF6A.png" /></p>

<p><a href="https://maps.app.goo.gl/H3xB8zhQ7vNSeqtaA" target="_blank"><em>3 Chome-228–1 Jozankeionsenhigashi, Minami Ward, Sapporo, Hokkaido 061–2301日本</em></a></p>

<p>位置在定山溪温泉街的入口。</p>

<blockquote>
  <p><em>价格： ¥ 52,150 日圆 — 1晚双人房/含丰盛日式早餐/有私人汤屋/禁烟 (Hollywood Twin Room with Tatami — Non-Smoking)</em></p>
</blockquote>

<h4 id="031620-4-晚--keio-prelia-hotel-sapporo--京王プレリアホテル札幌--札幌京王普雷利亚饭店"><strong>03/16–20 (4 晚) —</strong> <a href="https://maps.app.goo.gl/agffZjxdVngA5p5B9" target="_blank">Keio Prelia Hotel Sapporo / 京王プレリアホテル札幌 / 札幌京王普雷利亚饭店</a></h4>

<p><img src="/assets/055527a739dd/1*3oY7bhsG8XdTjJQprMIvhQ.webp" alt="4 Chome-11–1 Kita 8 Jonishi, Kita Ward, Sapporo, Hokkaido 060–0808日本" loading="lazy" decoding="async" width="1144" height="832" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTQ0IiBoZWlnaHQ9IjgzMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*3oY7bhsG8XdTjJQprMIvhQ.png" /></p>

<p><a href="https://maps.app.goo.gl/yko9ThsVPsdDj4WP6" target="_blank">4 Chome-11–1 Kita 8 Jonishi, Kita Ward, Sapporo, Hokkaido 060–0808日本</a></p>

<p>位置在札幌车站后站步行约 5 分钟。</p>

<blockquote>
  <p><em>价格： ¥58,389 日圆 — 4晚舒适加大双人床房/禁烟。</em></p>
</blockquote>

<h3 id="乐">乐</h3>

<h4 id="kkday-一日游北海道点灯之旅-富良野精灵台美瑛青池白须瀑布一日游札幌出发"><a href="https://www.kkday.com/zh-tw/product/157133-hokkaido-sapporo-biei-blue-pond-illumination-tour-japan?cid=19365" target="_blank">KKday 一日游：北海道点灯之旅 ｜富良野精灵台＆美瑛青池＆白须瀑布一日游｜札幌出发</a></h4>

<p><img src="/assets/055527a739dd/1*5vq3ePeRaN3GcAHfFINuvA.webp" alt="北海道点灯之旅 ｜富良野精灵台＆美瑛青池＆白须瀑布一日游｜札幌出发" loading="lazy" decoding="async" width="1175" height="1075" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTc1IiBoZWlnaHQ9IjEwNzUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*5vq3ePeRaN3GcAHfFINuvA.png" /></p>

<p><a href="https://www.kkday.com/zh-tw/product/157133-hokkaido-sapporo-biei-blue-pond-illumination-tour-japan?cid=19365" target="_blank">北海道点灯之旅 ｜富良野精灵台＆美瑛青池＆白须瀑布一日游｜札幌出发</a></p>

<ul>
  <li><strong>[悠闲11:50出发 B方案]</strong> 2026/3月&amp;4月 \| 白天富良野精灵台＆圣诞树＆白须瀑布＆夜晚青池点灯（无四季彩之丘）</li>
</ul>

<blockquote>
  <p><em>价格：NT $1,807 台币/人。</em></p>
</blockquote>

<h4 id="kkday---官方销售北海道小樽水族馆门票-即买即用购票后-30-天内都可使用"><a href="https://www.kkday.com/zh-tw/product/139823-otaru-aquarium-admission-ticket-hokkaido?cid=19365" target="_blank">KKday — 【 官方销售】北海道小樽水族馆门票 (即买即用/购票后 30 天内都可使用)</a></h4>

<p><img src="/assets/055527a739dd/1*LV2OUgLymbyCMmfLjgsfpg.webp" alt="【官方销售】北海道小樽水族馆门票 (即买即用/购票后 30 天内都可使用)" loading="lazy" decoding="async" width="1158" height="939" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTU4IiBoZWlnaHQ9IjkzOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*LV2OUgLymbyCMmfLjgsfpg.png" /></p>

<p><a href="https://www.kkday.com/zh-tw/product/139823-otaru-aquarium-admission-ticket-hokkaido?cid=19365" target="_blank">【官方销售】北海道小樽水族馆门票 (即买即用/购票后 30 天内都可使用)</a></p>

<ul>
  <li>特色是户外港口圈养、有很多展演跟冬季会有企鹅走路巡回</li>
</ul>

<blockquote>
  <p><em>准备！出发！</em></p>
</blockquote>

<blockquote>
  <p><a href="https://calec.china-airlines.com/eCheckin/eCheckin_home.aspx" target="_blank"><em>可在出发前三天完成选位与网路报到，加速流程。</em></a></p>
</blockquote>

<h3 id="day-1-0315-日--抵达-北海道札幌定山溪温泉饭店">Day 1 (03/15 日) — 抵达 北海道札幌、定山溪温泉饭店</h3>

<h4 id="0500-机场接送-出发"><a href="https://www.kkday.com/zh-tw/trans/airport_transfer?cid=19365" target="_blank">05:00 机场接送</a> 出发</h4>

<h4 id="0535-机场接送-抵达-tpe-桃园国际机场-t2-第二航厦"><a href="https://www.kkday.com/zh-tw/trans/airport_transfer?cid=19365" target="_blank">05:35 机场接送</a> 抵达 TPE 桃园国际机场 T2 第二航厦</h4>

<p><img src="/assets/055527a739dd/1*6_vxPCIXLx06F53yP4zS3g.webp" alt="" loading="lazy" decoding="async" width="1066" height="512" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDY2IiBoZWlnaHQ9IjUxMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*6_vxPCIXLx06F53yP4zS3g.png" /></p>

<p>分配到边边角角，06:10 才开柜。</p>

<p><img src="/assets/055527a739dd/1*2LMJVQ9PSoJkWNLER6nBfA.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*2LMJVQ9PSoJkWNLER6nBfA.jpeg" /></p>

<p>趁空档先 <a href="https://www.kkday.com/zh-tw/product/137689-japan-unlimited-data-esim-card?cid=19365" target="_blank">启用日本 eSIM</a> 。</p>

<h4 id="0640-完成-报到行李托运出境安检">06:40 完成 报到＋行李托运＋出境安检</h4>

<p>报到托运可能是因为提早来所以没花多久时间，出境人蛮多的但也消化的很快，大约 06:40 就已经出境了。</p>

<p><img src="/assets/055527a739dd/1*oOO3XXdFpobNN_KqNEtOyw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*oOO3XXdFpobNN_KqNEtOyw.jpeg" /></p>

<p>悠闲吃个早餐 Zzzzz。</p>

<h4 id="0730-候机逛逛--d6-登机门">07:30 候机逛逛 — D6 登机门</h4>

<p><img src="/assets/055527a739dd/1*G4-ZNKS-LpmIN5tRNEHe6g.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*G4-ZNKS-LpmIN5tRNEHe6g.jpeg" /></p>

<p>离登机还有一点时间先去 <a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E6%9D%B1%E4%BA%AC%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E5%B7%9D%E8%B6%8A%E5%B0%8F%E6%B1%9F%E6%88%B6%E4%B8%80%E6%97%A5%E9%81%8A%E8%88%87%E7%86%B1%E6%B5%B7%E6%B5%B7%E4%B8%8A%E8%8A%B1%E7%81%AB%E5%A4%A7%E6%9C%83%E5%85%A8%E7%B4%80%E9%8C%84-958599363857/#%E4%BA%8C%E8%88%AA%E5%87%BA%E5%A2%83%E5%85%8D%E7%A8%85%E5%BA%97-le-labo" target="_blank">D1 坐个免费按摩椅(代币可以跟附近商家索取)</a> 。</p>

<h4 id="0750-准备登机">07:50 准备登机</h4>

<p><img src="/assets/055527a739dd/1*TqzxK3cXR-j2tfGBVLspow.webp" alt="" loading="lazy" decoding="async" width="2048" height="1536" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDQ4IiBoZWlnaHQ9IjE1MzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*TqzxK3cXR-j2tfGBVLspow.jpeg" /></p>

<h4 id="0838-飞机起飞-tpe---cts">08:38 飞机起飞 TPE -&gt; CTS</h4>

<p><img src="/assets/055527a739dd/1*kGuZuIVYW2fYPb3clzIfXg.webp" alt="" loading="lazy" decoding="async" width="788" height="512" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3ODgiIGhlaWdodD0iNTEyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*kGuZuIVYW2fYPb3clzIfXg.png" /></p>

<p>搭到的是华航比较新的飞机 Airbus A330–300，空间蛮大的，电视机上娱乐设备也很齐全。</p>

<p><img src="/assets/055527a739dd/1*jTKu8WMuRVfU9IZTxQvfpg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*jTKu8WMuRVfU9IZTxQvfpg.jpeg" /></p>

<p>吃的就…普普吧。</p>

<blockquote>
  <p><em>飞行时间约：3 小时 50 分钟，还会再给小点心。</em></p>
</blockquote>

<h4 id="1322-飞机降落-tpe---cts">13:22 飞机降落 TPE -&gt; CTS</h4>

<p><img src="/assets/055527a739dd/1*TAHPtMwcNQIVPH7AohEhOg.webp" alt="" loading="lazy" decoding="async" width="786" height="512" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3ODYiIGhlaWdodD0iNTEyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*TAHPtMwcNQIVPH7AohEhOg.png" /></p>

<h4 id="1410-完成入境行李提领">14:10 完成入境＋行李提领</h4>

<p>入境蛮快的但是等了很久的行李，不知道是不是人太多(所有机位都卖完)。</p>

<p><img src="/assets/055527a739dd/1*b35AwJ_fwCxrOJqJGcwOTg.webp" alt="" loading="lazy" decoding="async" width="2112" height="878" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMTEyIiBoZWlnaHQ9Ijg3OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*b35AwJ_fwCxrOJqJGcwOTg.png" /></p>

<p>出机场一路跟著「国内线、JR 线」指标一路走。</p>

<p><img src="/assets/055527a739dd/1*UFM6K_85XwH7g19kKd6vRA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*UFM6K_85XwH7g19kKd6vRA.jpeg" /></p>

<p>到另一栋大厅后下去 B1F 就是 JR 站了。(手扶梯的话还要再绕一下)</p>

<p><img src="/assets/055527a739dd/1*yTccLA73k_OJ6E5OKFMWQw.webp" alt="时刻表" loading="lazy" decoding="async" width="931" height="862" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzEiIGhlaWdodD0iODYyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*yTccLA73k_OJ6E5OKFMWQw.png" /></p>

<p><a href="https://jrhokkaidonorikae.com/vtime/vtime.php?s=9650&amp;d=20260419" target="_blank">时刻表</a></p>

<h4 id="1429-搭乘-区间快速-从-新千岁机场站-前往-札幌站">14:29 搭乘 区间快速 从 新千岁机场站 前往 札幌站</h4>

<p><img src="/assets/055527a739dd/1*J47APGl3TjqzWKm7XQQJrA.webp" alt="&lt;https://www.jrhokkaido.co.jp/global/chinese/travel/airport.html&gt;" loading="lazy" decoding="async" width="1101" height="564" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTAxIiBoZWlnaHQ9IjU2NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*J47APGl3TjqzWKm7XQQJrA.png" /></p>

<p><a href="https://www.jrhokkaido.co.jp/global/chinese/travel/airport.html" target="_blank">https://www.jrhokkaido.co.jp/global/chinese/travel/airport.html</a></p>

<ul>
  <li>
    <p><a href="https://www.jrhokkaido.co.jp/global/chinese/travel/airport.html" target="_blank">札幌 &lt;-&gt; 新千岁机场所需时间约 33 - 41 分钟； <strong>可使用 Kitaca、Suica、PASMO等IC卡、不需要在自动售票机排队</strong> 、1天行驶163班次，非常密集。</a></p>
  </li>
  <li>
    <p><a href="https://www.jrhokkaido.co.jp/global/chinese/travel/airport.html" target="_blank">5 节自由席、 1 节指定席</a></p>
  </li>
</ul>

<p><img src="/assets/055527a739dd/1*6UaZZp6c43PLTj9EhJT36w.webp" alt="" loading="lazy" decoding="async" width="965" height="781" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjUiIGhlaWdodD0iNzgxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*6UaZZp6c43PLTj9EhJT36w.png" /></p>

<blockquote>
  <p><strong><em>可以用西瓜卡直接进站，</em></strong> <em>不过想说把钱找开所以还是去投币买了车票。</em></p>
</blockquote>

<h4 id="1506-抵达-札幌站">15:06 抵达 札幌站</h4>

<p><img src="/assets/055527a739dd/1*UgPpbSYwAcb02Kb74ML8lw.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*UgPpbSYwAcb02Kb74ML8lw.jpeg" /></p>

<ul>
  <li>上个厕所、买个吃的就继续走去 27 巴士站</li>
</ul>

<h4 id="1515-前往-札幌駅-27番のりば-kappa-line-上车处">15:15 前往 <a href="https://maps.app.goo.gl/MScVjZQHnW84qn626" target="_blank">札幌駅 27番のりば (Kappa Line 上车处)</a></h4>

<p><img src="/assets/055527a739dd/1*8ARDa4cvMa0NvmAMXENJkQ.webp" alt="" loading="lazy" decoding="async" width="1390" height="1076" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzkwIiBoZWlnaHQ9IjEwNzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*8ARDa4cvMa0NvmAMXENJkQ.png" /></p>

<h4 id="1525-抵达-札幌駅-27番のりば-kappa-line-上车处-候车">15:25 抵达 <a href="https://maps.app.goo.gl/MScVjZQHnW84qn626" target="_blank">札幌駅 27番のりば (Kappa Line 上车处)</a> 候车</h4>

<p><img src="/assets/055527a739dd/1*XQcnNbnu6N_IBLvKtW_5Fg.webp" alt="" loading="lazy" decoding="async" width="4696" height="2060" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0Njk2IiBoZWlnaHQ9IjIwNjAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*XQcnNbnu6N_IBLvKtW_5Fg.png" /></p>

<blockquote>
  <p><em>札幌站前站走出来左转下一个路口右转就看到了，后面有一栋红色大楼。</em></p>
</blockquote>

<ul>
  <li>日本的服务就是安心，这里也会有工作人员确认你是要去定山溪的并且有预约的。</li>
</ul>

<h4 id="1600-发车前往定山溪温泉">16:00 发车前往定山溪温泉</h4>

<p><img src="/assets/055527a739dd/1*mX62B7-0IYGOOkiCFard2g.webp" alt="" loading="lazy" decoding="async" width="2504" height="2036" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNTA0IiBoZWlnaHQ9IjIwMzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*mX62B7-0IYGOOkiCFard2g.png" /></p>

<ul>
  <li>
    <p><a href="https://jotetsu.quicktrip.jp/bought" target="_blank">手机登入预约购票网站点启用给工作人员看就可以直接上车。</a></p>
  </li>
  <li>
    <p>因为是观光巴士所以直接把行李箱交给工作人员放车厢就可以。</p>
  </li>
</ul>

<p><img src="/assets/055527a739dd/1*zDFW68P2S_0QYBuo7WJN8g.webp" alt="" loading="lazy" decoding="async" width="3762" height="2490" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNzYyIiBoZWlnaHQ9IjI0OTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*zDFW68P2S_0QYBuo7WJN8g.png" /></p>

<ul>
  <li>车程时间约 50 分钟，3 月中市区已经没什么雪了，郊外还有些许积雪</li>
</ul>

<h4 id="1650-抵达定山溪温泉-2白丝瀑布白糸の滝-站下车">16:50 抵达定山溪温泉 (2)白丝瀑布/白糸の滝 站下车</h4>

<p><img src="/assets/055527a739dd/1*U1I_hwru8pgom6R3qG_9jA.webp" alt="" loading="lazy" decoding="async" width="3444" height="2282" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNDQ0IiBoZWlnaHQ9IjIyODIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*U1I_hwru8pgom6R3qG_9jA.png" /></p>

<ul>
  <li>
    <p>Kappa Line 巴士涂装就是定山溪温泉吉祥物 — 河童</p>
  </li>
  <li>
    <p><strong>下车时候再给司机看一下电子车票然后告知要拿行李</strong></p>
  </li>
  <li>
    <p>下车往前走过个马路就到今天要下榻的温泉饭店了！</p>
  </li>
</ul>

<h4 id="1700-抵达-jozankei-yurakusoan-ゆらく草庵-日式温泉饭店">17:00 抵达 <a href="https://maps.app.goo.gl/mi1LRdo79NghFL3n7" target="_blank">Jozankei Yurakusoan ゆらく草庵 日式温泉饭店</a></h4>

<p><img src="/assets/055527a739dd/1*jXijzCdM080XooCnRKifIQ.webp" alt="" loading="lazy" decoding="async" width="3368" height="2238" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMzY4IiBoZWlnaHQ9IjIyMzgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*jXijzCdM080XooCnRKifIQ.png" /></p>

<p>非常传统日式，整个饭店都是木造建筑，入厅就是榻榻米要换鞋子放鞋柜。</p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/aQBG5TI_Zzg" title="Jozankei Yurakusoan ゆらく草庵 日式溫泉飯店" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<ul>
  <li>房間很大有獨立的廁所、私人衛浴/湯屋、客廳跟床；厲害的是雖然是傳統木造榻榻米但是整體維護的非常好， <strong>沒有任何髒髒舊舊或是霉味的感覺</strong> 。</li>
  <li>也有公共的私人湯屋可以使用 (有好幾間，沒人就可以進去)</li>
</ul>

<h4 id="1800-出门觅食">18:00 出门觅食</h4>

<p>饭店有一泊二食，我们订一泊一食(早餐)；出去找找吃的。</p>

<h4 id="1810-北の国定山渓万世阁ホテルミリオーネ3阶">18:10 <a href="https://maps.app.goo.gl/x1Wu1bSFXkk8PDbm7" target="_blank">北の国｜定山渓万世阁・ホテルミリオーネ3阶</a></h4>

<p>温泉街几乎都是泊+食，所以外面的餐厅不多；最后走去另一家饭店 <a href="https://maps.app.goo.gl/x1Wu1bSFXkk8PDbm7" target="_blank">万世阁</a> 的 3 楼居酒屋吃晚餐。</p>

<p><img src="/assets/055527a739dd/1*iCfHKvgNp00NMpSeW_MnXw.webp" alt="" loading="lazy" decoding="async" width="4000" height="1412" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MDAwIiBoZWlnaHQ9IjE0MTIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*iCfHKvgNp00NMpSeW_MnXw.png" /></p>

<ul>
  <li>
    <p>第一杯: 正 — Sapporo 生啤酒</p>
  </li>
  <li>
    <p>吃了猪排饭 跟 名物炸鲫鱼 (蛮好吃的)</p>
  </li>
</ul>

<h4 id="1930-回饭店泡汤休息">19:30 回饭店泡汤休息</h4>

<p><img src="/assets/055527a739dd/1*IqDyTM7yqweHmbUSLNZSRQ.webp" alt="" loading="lazy" decoding="async" width="2976" height="1428" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOTc2IiBoZWlnaHQ9IjE0MjgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*IqDyTM7yqweHmbUSLNZSRQ.png" /></p>

<ul>
  <li>幸好路上超商蛮多家的，去全家顺路买了宵夜晚上吃。</li>
</ul>

<blockquote>
  <p><em>虽然没下雪了，但是晚上太阳下山后还是很冷，奔波一天，早早回饭店泡汤休息。</em></p>
</blockquote>

<h3 id="day-2-0316-一--定山溪温泉街札幌市区景点">Day 2 (03/16 一) — 定山溪温泉街、札幌市区景点</h3>

<h4 id="0900-吃早餐">09:00 吃早餐</h4>

<p><img src="/assets/055527a739dd/1*ypWZE7fthJG5vBU8uC_F2A.webp" alt="" loading="lazy" decoding="async" width="1200" height="452" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQ1MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*ypWZE7fthJG5vBU8uC_F2A.png" /></p>

<p>刚好分配到靠窗的位子，窗外景色非常幽美。</p>

<p><img src="/assets/055527a739dd/1*zIdJFU-HuUUqDTW20dTX2Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="574" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjU3NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*zIdJFU-HuUUqDTW20dTX2Q.png" /></p>

<blockquote>
  <p><em>早餐很丰盛：主要有饭/野菜饭、味增汤、(1) 中间蒸猪肉＋野菜、(2)冷鲑鱼 — 可用中间酒精灯铝箔加热、(3)玉子烧。</em></p>
</blockquote>

<h4 id="1100-checkout-寄放行李定山溪温泉街附近走走">11:00 Checkout 寄放行李、定山溪温泉街附近走走</h4>

<p><img src="/assets/055527a739dd/1*RIvrEU6Nizz0EnOj-extDw.webp" alt="" loading="lazy" decoding="async" width="1456" height="1151" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDU2IiBoZWlnaHQ9IjExNTEiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*RIvrEU6Nizz0EnOj-extDw.png" /></p>

<blockquote>
  <p><em>离回程预约的巴士 13:31 上车还有一段时间，就把整个定山溪温泉走了一圈。</em></p>
</blockquote>

<h4 id="1110-定山溪神社">11:10 定山溪神社</h4>

<p><img src="/assets/055527a739dd/1*otr7MA3QH-m__iTJI6AxWg.webp" alt="" loading="lazy" decoding="async" width="960" height="1280" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjAiIGhlaWdodD0iMTI4MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*otr7MA3QH-m__iTJI6AxWg.jpeg" /></p>

<p><img src="/assets/055527a739dd/1*gOkeBho1WpoY-Bowj3e5qA.webp" alt="" loading="lazy" decoding="async" width="902" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDIiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*gOkeBho1WpoY-Bowj3e5qA.png" /></p>

<p>整个神社都被大雪冰封了。</p>

<h4 id="1130-河童家族的祈愿手汤"><a href="https://maps.app.goo.gl/q9rNER1WAPXw9DPH7" target="_blank">11:30 河童家族的祈愿手汤</a></h4>

<p><img src="/assets/055527a739dd/1*dBB1541WoB5lOVGSfaG44g.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*dBB1541WoB5lOVGSfaG44g.jpeg" /></p>

<p>简单洗个手。</p>

<p>旁边斜坡往下走就是温泉公园。</p>

<h4 id="1140-定山源泉公园"><a href="https://maps.app.goo.gl/j7K1pCCkWTsPX2uKA" target="_blank">11:40 定山源泉公园</a></h4>

<p><img src="/assets/055527a739dd/1*e4RVh1Mg-cxup8svIuUpPw.webp" alt="" loading="lazy" decoding="async" width="1200" height="792" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc5MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*e4RVh1Mg-cxup8svIuUpPw.png" /></p>

<p>公园有公共泡脚的浴池跟可以煮水煮蛋的涌口。</p>

<p><img src="/assets/055527a739dd/1*FVNqZAQ-8GVQsEcLza7uMg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*FVNqZAQ-8GVQsEcLza7uMg.jpeg" /></p>

<blockquote>
  <p><em>如果想要体验煮温泉蛋可以走过桥到对面的 <a href="https://maps.app.goo.gl/JQ8MedX36trBSw7EA" target="_blank">㈱定山渓物产馆 中央店</a> 买温泉蛋来煮然后带回店里吃。</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*JXKfDrv0HzbuwK7HENsOcA.webp" alt="" loading="lazy" decoding="async" width="3004" height="1996" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMDA0IiBoZWlnaHQ9IjE5OTYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*JXKfDrv0HzbuwK7HENsOcA.png" /></p>

<h4 id="1200-路过-ふる川果日-jglacée"><a href="https://maps.app.goo.gl/iUFZh6uSjqmqffw88" target="_blank">12:00 路过 ふる川果日 J.glacée</a></h4>

<p><img src="/assets/055527a739dd/1*Ap1oNMTiOhNzn6JBFs6mcg.webp" alt="" loading="lazy" decoding="async" width="1200" height="798" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*Ap1oNMTiOhNzn6JBFs6mcg.png" /></p>

<p>继续往上走路过一家面包店，有刚出炉的苹果可颂，买了一个来尝鲜，味道不错。</p>

<h4 id="1215-经过-岩户观音堂"><a href="https://maps.app.goo.gl/6Ymw95Ptk4BNpX1z6" target="_blank">12:15 经过 岩户观音堂</a></h4>

<p><img src="/assets/055527a739dd/1*QxUH_qMGIGBPCNJNG16zBw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*QxUH_qMGIGBPCNJNG16zBw.jpeg" /></p>

<p>经过这里之后往前再往下走就会回到起点饭店了。</p>

<p><img src="/assets/055527a739dd/1*BhscZ015lnl7cK7NxMlAPA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*BhscZ015lnl7cK7NxMlAPA.jpeg" /></p>

<p><img src="/assets/055527a739dd/1*qYBqoqgOiP2n19HP1pwXEg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*qYBqoqgOiP2n19HP1pwXEg.jpeg" /></p>

<p>可以想像之前的雪有多大，溪上的吊桥也都被雪冰封了！</p>

<h4 id="1230-走回到饭店">12:30 走回到饭店</h4>

<p>还有点时间就继续去附近的白丝瀑布看看。</p>

<p><img src="/assets/055527a739dd/1*wOsNH9LlgSPzBv2LHxB3aA.webp" alt="" loading="lazy" decoding="async" width="3312" height="2210" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMzEyIiBoZWlnaHQ9IjIyMTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*wOsNH9LlgSPzBv2LHxB3aA.png" /></p>

<p>要拐个弯走下坡；结果悲报，也是被雪冰封了没有开放。</p>

<h4 id="1310-回到饭店拿行李">13:10 回到饭店拿行李</h4>

<h4 id="1315-到-2-白丝瀑布-候车-来的时候的对面">13:15 到 <a href="https://maps.app.goo.gl/XE4wcHVAofeew1DQ8" target="_blank">(2) 白丝瀑布 候车 (来的时候的对面)</a></h4>

<p><img src="/assets/055527a739dd/1*6fAEfLztaLDeyirDO8CTmg.webp" alt="" loading="lazy" decoding="async" width="1200" height="797" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc5NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*6fAEfLztaLDeyirDO8CTmg.png" /></p>

<p><img src="/assets/055527a739dd/1*m8v0h-nb67YzZWgkldbdBQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*m8v0h-nb67YzZWgkldbdBQ.jpeg" /></p>

<p>我们的车是 13:15 从起始站发车，预计是 13:31 才会到白丝瀑布站，等待时间很无聊，踩踩雪。</p>

<h4 id="1340-上车回札幌站">13:40 上车回札幌站</h4>

<ul>
  <li>上下车一样出示一次电子车票给司机看</li>
</ul>

<h4 id="1450-回到札幌入住-keio-prelia-hotel-sapporo--京王プレリアホテル札幌--札幌京王普雷利亚饭店">14:50 回到札幌，入住 <a href="https://maps.app.goo.gl/JP8qZhQiLpvaFaVq9" target="_blank">Keio Prelia Hotel Sapporo : 京王プレリアホテル札幌 : 札幌京王普雷利亚饭店</a></h4>

<p><img src="/assets/055527a739dd/1*ShHQszkicgDZYCPb-3VaHw.webp" alt="" loading="lazy" decoding="async" width="2912" height="1936" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOTEyIiBoZWlnaHQ9IjE5MzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*ShHQszkicgDZYCPb-3VaHw.png" /></p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/6ENDDDNTK8g" title="Keio Prelia Hotel Sapporo : 京王プレリアホテル札幌 : 札幌京王普雷利亞飯店" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<ul>
  <li>飯店很新、設備齊全，房間算大。</li>
  <li>地點在後站比較不熱鬧，要走一小段、札幌站也沒藥妝店； <strong>相較之下大通站周邊比較熱鬧。</strong></li>
</ul>

<blockquote>
  <p><em>15:20 左右整装重新出发，没有吃午餐呢，计划早点去大通公园附近吃晚餐。</em></p>
</blockquote>

<h4 id="1530-yodobashi">15:30 <a href="https://maps.app.goo.gl/AGEuLosKQh1iSNE4A" target="_blank">Yodobashi</a></h4>

<p><img src="/assets/055527a739dd/1*6RC-qsV-DaGBnN-Yd4OSnw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*6RC-qsV-DaGBnN-Yd4OSnw.jpeg" /></p>

<p>饭店走到 JR/地铁站的路上就有一家 Yodobashi (后面有 <a href="https://maps.app.goo.gl/3xn9SZskRd8Yzr2t9" target="_blank">麦当劳</a> )，去看了看扭蛋。</p>

<h4 id="1610-抵达-薄野-すすきの駅">16:10 抵达 薄野 すすきの駅</h4>

<p><img src="/assets/055527a739dd/1*jdoeeUN6g1laKeVunxxbaQ.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*jdoeeUN6g1laKeVunxxbaQ.jpeg" /></p>

<p>搭车到薄野站准备去吃札幌有名的「羊肉」烤肉。</p>

<h4 id="1615-成吉思汗-达摩-本店-开吃">16:15 <a href="https://maps.app.goo.gl/3TvfU2SAzF8beSFm6" target="_blank">成吉思汗 达摩 本店</a> 开吃</h4>

<p><img src="/assets/055527a739dd/1*VKpLNNn6ryHdjU0c80J2Cw.webp" alt="" loading="lazy" decoding="async" width="3452" height="2302" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNDUyIiBoZWlnaHQ9IjIzMDIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*VKpLNNn6ryHdjU0c80J2Cw.png" /></p>

<ul>
  <li>
    <p>点了两份招牌跟一份一般的肉还有白饭、生啤(大杯…有点太大杯)。</p>
  </li>
  <li>
    <p>肉非常好吃，完全没有羊骚味，肉质很嫩。</p>
  </li>
  <li>
    <p>这样狂吃一人大约才 $700 台币。</p>
  </li>
</ul>

<blockquote>
  <p><em>店内不大，附近还有分店，吃饱接近 17:00 外面已经很多人在排队了。</em></p>
</blockquote>

<h4 id="1700-薄野站十字路口"><a href="https://maps.app.goo.gl/kN9qw85rbk16KAWh6" target="_blank">17:00 薄野站十字路口</a></h4>

<p><img src="/assets/055527a739dd/1*0_Uo2gxSY01IJ7PS2jgWCg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*0_Uo2gxSY01IJ7PS2jgWCg.jpeg" /></p>

<p>吃饱慢慢走回大通站，想去 <a href="https://maps.app.goo.gl/HdrBr15BZhTY9xoy5" target="_blank">札幌电视塔</a> ，路过札幌最有名的十字路口。</p>

<h4 id="1715-经过-狸小路顺便逛逛扭蛋唐吉诃德">17:15 经过 <a href="https://maps.app.goo.gl/t9UREfvkAkyNrCim6" target="_blank">狸小路顺便逛逛扭蛋、唐吉诃德</a></h4>

<p><img src="/assets/055527a739dd/1*Z0HU0h6iFvmVKFFxlFcrTA.webp" alt="" loading="lazy" decoding="async" width="2048" height="911" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDQ4IiBoZWlnaHQ9IjkxMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*Z0HU0h6iFvmVKFFxlFcrTA.png" /></p>

<p>这里有一家 MEGA 整栋的 <a href="https://maps.app.goo.gl/t9UREfvkAkyNrCim6" target="_blank">唐吉诃德</a> 。</p>

<h4 id="1741-札幌电视塔">17:41 <a href="https://maps.app.goo.gl/HdrBr15BZhTY9xoy5" target="_blank">札幌电视塔</a></h4>

<p><img src="/assets/055527a739dd/1*uW87zB98sSmv7KTGQBwWRw.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*uW87zB98sSmv7KTGQBwWRw.jpeg" /></p>

<h4 id="1830-札幌电视塔-夜景">18:30 <a href="https://maps.app.goo.gl/HdrBr15BZhTY9xoy5" target="_blank">札幌电视塔</a> 夜景</h4>

<p><img src="/assets/055527a739dd/1*66Xgue8l-kfCCv_N8iGa3Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="798" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*66Xgue8l-kfCCv_N8iGa3Q.png" /></p>

<p>在札幌塔待到大约 18:30 看完夜景就下来了。</p>

<p><img src="/assets/055527a739dd/1*XgVlX-8dfSDPQzb3ajJzug.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*XgVlX-8dfSDPQzb3ajJzug.jpeg" /></p>

<p>可以顺便盖印章搜集明信片。</p>

<p><img src="/assets/055527a739dd/1*D5X9adov6oTZWgf4qOMZUQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*D5X9adov6oTZWgf4qOMZUQ.jpeg" /></p>

<h4 id="1840-parco-札幌-逛街"><a href="https://maps.app.goo.gl/pexoh92RLGVdG9N36" target="_blank">18:40 PARCO 札幌</a> 逛街</h4>

<p><img src="/assets/055527a739dd/1*f44BK8MmMCPBRjyRgD9N4g.webp" alt="" loading="lazy" decoding="async" width="1200" height="529" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjUyOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*f44BK8MmMCPBRjyRgD9N4g.png" /></p>

<p>电视塔出来下一个路口就是 Parco 札幌店，来逛逛街。</p>

<h4 id="2030-买超商宵夜回饭店休息">20:30 买超商宵夜回饭店休息</h4>

<p><img src="/assets/055527a739dd/1*x52OxjlfB-Udv1DWwxrSVA.webp" alt="" loading="lazy" decoding="async" width="4334" height="1622" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MzM0IiBoZWlnaHQ9IjE2MjIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*x52OxjlfB-Udv1DWwxrSVA.png" /></p>

<p>晚餐很早就吃，所以宵夜要多吃一点；买了超商泡面＋串烧＋炸鸡还有草莓水果酒(好喝)跟 <a href="https://the-sapporo-bar.susukino-brewing.com/" target="_blank"><strong>北海道 The Sapporo Bar 物语联名的威士忌巧克力冰淇淋</strong></a> (真的有酒味，蛮好吃的)。</p>

<h3 id="day-3-0317-二--小樽小樽水族馆">Day 3 (03/17 二) — 小樽、小樽水族馆</h3>

<h4 id="0930-出门">09:30 出门</h4>

<p><img src="/assets/055527a739dd/1*NCc4ExDsn14kx-uIpTxBWw.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*NCc4ExDsn14kx-uIpTxBWw.jpeg" /></p>

<p>买个麦当劳早餐在车上吃。</p>

<h4 id="1000-札幌站上车前往小樽站">10:00 札幌站上车前往小樽站</h4>

<p><img src="/assets/055527a739dd/1*sVzzX65_gTfTTnwA5kG-XA.webp" alt="" loading="lazy" decoding="async" width="379" height="153" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNzkiIGhlaWdodD0iMTUzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*sVzzX65_gTfTTnwA5kG-XA.png" /></p>

<blockquote>
  <p><strong><em>结果是区间车，人很多只能站著，</em></strong> <em>根本没办法在车上吃。</em></p>
</blockquote>

<h4 id="1042-抵达小樽站">10:42 抵达小樽站</h4>

<p><img src="/assets/055527a739dd/1*pH7YPEhWohZ5L9mVmdhX7A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*pH7YPEhWohZ5L9mVmdhX7A.jpeg" /></p>

<p>看这人潮就知道很多人来小樽了。</p>

<h4 id="1045-小樽站">10:45 小樽站</h4>

<p><img src="/assets/055527a739dd/1*0oQhRkSceYFsf3jHZwV9Bg.webp" alt="" loading="lazy" decoding="async" width="1074" height="810" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDc0IiBoZWlnaHQ9IjgxMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*0oQhRkSceYFsf3jHZwV9Bg.png" /></p>

<p>小樽站正面出来过马路右边就是巴士站，直接在 3月台 等候前往 <strong>１０小樽水族馆线：</strong></p>

<p><img src="/assets/055527a739dd/1*1iMFSEhrHNtnxkYzh8O30Q.webp" alt="图片来源：Google Map - K T (torute)" loading="lazy" decoding="async" width="935" height="907" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzUiIGhlaWdodD0iOTA3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*1iMFSEhrHNtnxkYzh8O30Q.png" /></p>

<p><a href="https://maps.app.goo.gl/p7mnP8KpppyUdtwu7" target="_blank">图片来源：Google Map</a> - <a href="https://maps.google.com/maps/contrib/117333353874320617109" target="_blank">K T (torute)</a></p>

<p><img src="/assets/055527a739dd/1*irY-RRWlc8mKIiM6s6bdXw.webp" alt="" loading="lazy" decoding="async" width="734" height="826" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MzQiIGhlaWdodD0iODI2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*irY-RRWlc8mKIiM6s6bdXw.png" /></p>

<ul>
  <li>
    <p><strong>１０小樽水族馆线</strong> ：几乎是直达，只需约 20 分钟就能抵达小樽水族馆。</p>
  </li>
  <li>
    <p><strong>１１祝津线</strong> ：不是直达、也是会到但是要约 30 分钟。</p>
  </li>
</ul>

<h4 id="1110-抵达小樽水族馆">11:10 抵达小樽水族馆</h4>

<p><img src="/assets/055527a739dd/1*f3ZL6ho5OMt3wYHfVRT-TQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="452" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQ1MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*f3ZL6ho5OMt3wYHfVRT-TQ.png" /></p>

<p>直接在柜台出示线上买的 <a href="https://www.kkday.com/zh-tw/product/139823-otaru-aquarium-admission-ticket-hokkaido?cid=19365" target="_blank">【官方销售】北海道小樽水族馆门票 (即买即用/购票后 30 天内都可使用)</a> QR Code，就能直接进场。</p>

<h4 id="小樽水族馆自制地图">小樽水族馆自制地图</h4>

<p><img src="/assets/055527a739dd/1*H0BTCoeqStQ7n4POyH6ymw.webp" alt="" loading="lazy" decoding="async" width="1200" height="913" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkxMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*H0BTCoeqStQ7n4POyH6ymw.png" /></p>

<ul>
  <li>
    <p>冬天摩天轮封闭中，摩天轮不在水族馆园区内要另外买票</p>
  </li>
  <li>
    <p>小樽水族馆虽然不大但是物种丰富、照顾的也不错；展演也很多整体体验不错。</p>
  </li>
  <li>
    <p>红色是企鹅散步路线</p>
  </li>
</ul>

<p><img src="/assets/055527a739dd/1*VpRX9psi2InntONIV365jA.webp" alt="时间会因为季节而有所不同请 参考官网资讯 。" loading="lazy" decoding="async" width="3116" height="1400" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMTE2IiBoZWlnaHQ9IjE0MDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*VpRX9psi2InntONIV365jA.png" /></p>

<p>时间会因为季节而有所不同请 <a href="https://uu-beihaidao.tw/corporate/otaru-aq.shtml" target="_blank">参考官网资讯</a> 。</p>

<h4 id="进场后右转出来往下走去--海兽公园">进场后右转出来往下走去 — 海兽公园</h4>

<p><img src="/assets/055527a739dd/1*HjDF6BvQMKbWcx1HpFS4yA.webp" alt="" loading="lazy" decoding="async" width="1200" height="913" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkxMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*HjDF6BvQMKbWcx1HpFS4yA.png" /></p>

<p><img src="/assets/055527a739dd/1*frqiW_5h5tX81n9DqKUXlw.webp" alt="" loading="lazy" decoding="async" width="1200" height="685" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY4NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*frqiW_5h5tX81n9DqKUXlw.png" /></p>

<p>这边只有上坡有手扶梯，下坡蛮抖的。</p>

<p><strong>所有户外的展演活动都在这边：</strong></p>

<ul>
  <li>
    <p>海豹活动：来的时候 11:20 正在表演</p>
  </li>
  <li>
    <p>北海狮活动 (超大海狮)：11:40</p>
  </li>
  <li>
    <p>企鹅野餐：12:00</p>
  </li>
  <li>
    <p>企鹅活动：没看到</p>
  </li>
  <li>
    <p>海象的觅食解说：没看到</p>
  </li>
</ul>

<p><img src="/assets/055527a739dd/1*DB-wHVOUcIjP73sMVSXeCA.webp" alt="" loading="lazy" decoding="async" width="1200" height="1006" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwMDYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*DB-wHVOUcIjP73sMVSXeCA.png" /></p>

<h4 id="1140-北海狮表演">11:40 北海狮表演</h4>

<p><img src="/assets/055527a739dd/1*0cK0DaJLgqU8v2aqloSntg.webp" alt="" loading="lazy" decoding="async" width="1200" height="531" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjUzMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*0cK0DaJLgqU8v2aqloSntg.png" /></p>

<p>来的时间早站在第一排，北海狮真的好巨大！</p>

<h4 id="海豹">海豹</h4>

<p><img src="/assets/055527a739dd/1*VlGMYBS8lHbzv--Fnoccxg.webp" alt="" loading="lazy" decoding="async" width="4086" height="1964" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MDg2IiBoZWlnaHQ9IjE5NjQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*VlGMYBS8lHbzv--Fnoccxg.png" /></p>

<p>看完表演隔壁是海豹池，每一只都很惬意。</p>

<blockquote>
  <p><em>海豹海狮可以买鱼投喂互动， <strong>有限量、有的池子不能喂要自己看标示。</strong></em></p>
</blockquote>

<h4 id="1200-企鹅散步">12:00 企鹅散步</h4>

<p><img src="/assets/055527a739dd/1*OI0aGYtaim4YBadFYp91nQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="602" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjYwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*OI0aGYtaim4YBadFYp91nQ.png" /></p>

<blockquote>
  <p><em>完整路线如上图红色线，最后会去企鹅池泡泡水。</em></p>
</blockquote>

<p>看完海豹之后就来企鹅散步路线等，地板有一条白线，站在线外等企鹅经过；我站在转角这(如上图人的位置)。</p>

<p><img src="/assets/055527a739dd/1*FxieyG5_jW2rSbBjlz4jPg.webp" alt="" loading="lazy" decoding="async" width="1200" height="1103" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjExMDMiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*FxieyG5_jW2rSbBjlz4jPg.png" /></p>

<p>是小企鹅，有点像南崁企鹅。</p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/iGPgTEcVJWc" title="小樽水族館 企鵝散步 (海獸公園) / おたる水族館 ペンギンの海まで遠足（海獣公園） / Otaru Aquarium Penguin Picnic (Marine mammal park)" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p><strong>最终会走到企鹅池泡泡水：</strong></p>

<p><img src="/assets/055527a739dd/1*AC942rnUoH5eUTxG8hpdfQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*AC942rnUoH5eUTxG8hpdfQ.jpeg" /></p>

<h4 id="也去看其他在室内的动物们海豹海象">也去看其他在室内的动物们：(海豹、海象)</h4>

<p><img src="/assets/055527a739dd/1*L4Ow3BnB1I2VaSfm-HraCw.webp" alt="" loading="lazy" decoding="async" width="2654" height="1756" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNjU0IiBoZWlnaHQ9IjE3NTYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*L4Ow3BnB1I2VaSfm-HraCw.png" /></p>

<p>看完后往海豚馆方向移动：</p>

<p><img src="/assets/055527a739dd/1*YJq8kpXFK_b7gwOu7fw9tQ.webp" alt="" loading="lazy" decoding="async" width="2808" height="1638" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyODA4IiBoZWlnaHQ9IjE2MzgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*YJq8kpXFK_b7gwOu7fw9tQ.png" /></p>

<p>海豚馆外也有一个小的企鹅池：</p>

<p><img src="/assets/055527a739dd/1*eSjHmjQ2Xb6J1mQjH93i1Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*eSjHmjQ2Xb6J1mQjH93i1Q.jpeg" /></p>

<h4 id="1240-南海狮海豚表演">12:40 南海狮＋海豚表演</h4>

<p><img src="/assets/055527a739dd/1*zApgCBreekd_oHyGNhuGmA.webp" alt="" loading="lazy" decoding="async" width="1200" height="798" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*zApgCBreekd_oHyGNhuGmA.png" /></p>

<p>看完回到本馆参观市内的海洋生物：</p>

<p><img src="/assets/055527a739dd/1*7JOgPNrhoEEWZ9fvaDk7dw.webp" alt="" loading="lazy" decoding="async" width="2048" height="1536" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDQ4IiBoZWlnaHQ9IjE1MzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*7JOgPNrhoEEWZ9fvaDk7dw.jpeg" /></p>

<p>物种也蛮丰富的。</p>

<p><strong>日本最高龄的小爪水獭：</strong></p>

<p><img src="/assets/055527a739dd/1*2TlrnSrYe31PT_qlk9RrMQ.webp" alt="" loading="lazy" decoding="async" width="4310" height="2072" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MzEwIiBoZWlnaHQ9IjIwNzIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*2TlrnSrYe31PT_qlk9RrMQ.png" /></p>

<blockquote>
  <p><em>这只水獭年事已高，动作踉跄缓慢，大家就不要再去打扰他享受晚年了。</em></p>
</blockquote>

<p>逛完纪念品店后，我们就回到来时的巴士站等车。</p>

<h4 id="1400-搭乘公车回小樽站">14:00 搭乘公车回小樽站</h4>

<h4 id="1420-回到小樽站">14:20 回到小樽站</h4>

<p>走站前大道往小樽运河方向走。</p>

<p><img src="/assets/055527a739dd/1*eCDjh5Dp6zq7Lra8dZyQzg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*eCDjh5Dp6zq7Lra8dZyQzg.jpeg" /></p>

<p>接近路底就能看到 LeTAO 运河店：</p>

<p><img src="/assets/055527a739dd/1*j9S4vpv8COBT_jiAu_95wA.webp" alt="" loading="lazy" decoding="async" width="3360" height="1916" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMzYwIiBoZWlnaHQ9IjE5MTYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*j9S4vpv8COBT_jiAu_95wA.png" /></p>

<p><img src="/assets/055527a739dd/1*sPnweRj4fwtR97NXNLchTw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*sPnweRj4fwtR97NXNLchTw.jpeg" /></p>

<p>这边除了有卖伴手礼也有卖冰淇淋甜点还有熟食咖啡厅 <a href="https://maps.app.goo.gl/K9PY2rFURawPitX38" target="_blank">ルタオ小樽运河店 三番库カフェ</a> 。</p>

<p><img src="/assets/055527a739dd/1*u-odR1T48phugsDA844MHQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="902" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*u-odR1T48phugsDA844MHQ.png" /></p>

<blockquote>
  <p><em>饼干蛮好吃的，另外一盒铁盒是草莓干巧克力，有点太甜。</em></p>
</blockquote>

<h4 id="1440-ルタオ小樽运河店-三番库カフェ-吃午餐"><a href="https://maps.app.goo.gl/K9PY2rFURawPitX38" target="_blank">14:40 ルタオ小樽运河店 三番库カフェ</a> 吃午餐</h4>

<p><img src="/assets/055527a739dd/1*Pm2hpXp23qw2J1hKJ0oixg.webp" alt="" loading="lazy" decoding="async" width="3998" height="1502" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzOTk4IiBoZWlnaHQ9IjE1MDIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*Pm2hpXp23qw2J1hKJ0oixg.png" /></p>

<p>随便点了个义大利面熟食果腹，还有甜点套餐(蛋糕好吃)。</p>

<h4 id="1600-小樽运河漫步">16:00 小樽运河漫步</h4>

<p><img src="/assets/055527a739dd/1*64MslNJEByUEGfoSK0YTGA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*64MslNJEByUEGfoSK0YTGA.jpeg" /></p>

<p><img src="/assets/055527a739dd/1*6XxJGWGJCVSZGo-sualLdg.webp" alt="" loading="lazy" decoding="async" width="612" height="711" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MTIiIGhlaWdodD0iNzExIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*6XxJGWGJCVSZGo-sualLdg.png" /></p>

<p>吃饱继续前进到小樽运河漫步，一路走往 <a href="https://maps.app.goo.gl/fX5yyT2tVRV8Lo98A" target="_blank">小樽蒸汽钟</a> 。</p>

<p><img src="/assets/055527a739dd/1*xCKpu7uLjK8VgfkbRuCSAQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*xCKpu7uLjK8VgfkbRuCSAQ.jpeg" /></p>

<p>往 <a href="https://maps.app.goo.gl/fX5yyT2tVRV8Lo98A" target="_blank">小樽蒸汽钟</a> 的商店家有非常多小店、伴手礼店、琉璃制品店可以逛。</p>

<p><img src="/assets/055527a739dd/1*kzVBtUi0gLMICty86NrsSA.webp" alt="" loading="lazy" decoding="async" width="3988" height="1746" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzOTg4IiBoZWlnaHQ9IjE3NDYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*kzVBtUi0gLMICty86NrsSA.png" /></p>

<p>在这边买了很多饼干伴手礼，尤其是北海道才买得到的 — 六花亭。</p>

<p><img src="/assets/055527a739dd/1*skVsoy14UQ1TzJ26bBOShA.webp" alt="" loading="lazy" decoding="async" width="2920" height="1400" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOTIwIiBoZWlnaHQ9IjE0MDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*skVsoy14UQ1TzJ26bBOShA.png" /></p>

<blockquote>
  <p><em>六花亭必买的 — 莱姆酒饼干(保存期限短、冰过比较好吃)、酒心糖(是真的酒)</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*6TcrcwJUKKGXrSHL1_vJSg.webp" alt="" loading="lazy" decoding="async" width="2724" height="1818" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzI0IiBoZWlnaHQ9IjE4MTgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*6TcrcwJUKKGXrSHL1_vJSg.png" /></p>

<p>路上有一家 <a href="https://maps.app.goo.gl/eq7F2zZ5P6RuUJ1H6" target="_blank">北一硝子 Outlet</a> 有卖北海道地酒而且可以免费试喝。</p>

<p><img src="/assets/055527a739dd/1*9KidHCaTaB9XSzch8ul8vA.webp" alt="" loading="lazy" decoding="async" width="1200" height="902" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*9KidHCaTaB9XSzch8ul8vA.png" /></p>

<blockquote>
  <p><em>买了一瓶哈密瓜酒回去喝。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>有哈密瓜果肉的浓稠感，哈密瓜味也很重，套冰块、气泡水喝比较好喝。</em></strong></p>
</blockquote>

<h4 id="1710-走到路底-小樽蒸汽钟">17:10 走到路底 <a href="https://maps.app.goo.gl/fX5yyT2tVRV8Lo98A" target="_blank">小樽蒸汽钟</a></h4>

<p><img src="/assets/055527a739dd/1*F2amQ8v_lM3yYvDnzXta3A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*F2amQ8v_lM3yYvDnzXta3A.jpeg" /></p>

<p>时间接近傍晚了，开始往回走。</p>

<p><img src="/assets/055527a739dd/1*4FRDy264prK1bVwCm2BpRw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*4FRDy264prK1bVwCm2BpRw.jpeg" /></p>

<h4 id="1810-回到小樽站">18:10 回到小樽站</h4>

<p><img src="/assets/055527a739dd/1*WI719YuzTLNf4fTMVWBOOg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*WI719YuzTLNf4fTMVWBOOg.jpeg" /></p>

<p><img src="/assets/055527a739dd/1*hcCX6rn7zFpfD38KbgP-Jw.webp" alt="" loading="lazy" decoding="async" width="2048" height="1536" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDQ4IiBoZWlnaHQ9IjE1MzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*hcCX6rn7zFpfD38KbgP-Jw.jpeg" /></p>

<p>没搭到 18:00 快速机场回札幌的，随便搭了一班回去(比较慢)。</p>

<h4 id="1900-回到-札幌站">19:00 回到 札幌站</h4>

<h4 id="1930-savoy-sapporo-station-kitaguchi-北海道汤咖喱">19:30 <a href="https://maps.app.goo.gl/1tAe4EyEFP2r5wC98" target="_blank">Savoy Sapporo Station Kitaguchi</a> 北海道汤咖喱</h4>

<p><img src="/assets/055527a739dd/1*uWJwZJH4ZnZq92cIDGUabg.webp" alt="" loading="lazy" decoding="async" width="2612" height="1482" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNjEyIiBoZWlnaHQ9IjE0ODIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*uWJwZJH4ZnZq92cIDGUabg.png" /></p>

<p>饭店附近有一家评价蛮高＋可以外带(太累)的汤咖喱，买回饭店吃。</p>

<blockquote>
  <p><em>食材都很新鲜，咖喱味不会抢过食材的锋头，清爽好吃。</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*8MK6Ra5FKK9jKxpKwWrIvg.webp" alt="" loading="lazy" decoding="async" width="2356" height="1118" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMzU2IiBoZWlnaHQ9IjExMTgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*8MK6Ra5FKK9jKxpKwWrIvg.png" /></p>

<p>宵夜是超商热狗＋哈密瓜酒(也不错)＋养乐多 1000 减糖版，补充乳酸菌(其实每天都有喝，只是懒得拍了)。</p>

<h3 id="day-4-0318-三--kkday-北海道点灯之旅-富良野精灵台美瑛青池白须瀑布一日游札幌出发">Day 4 (03/18 三) — <a href="https://www.kkday.com/zh-tw/product/157133-hokkaido-sapporo-biei-blue-pond-illumination-tour-japan?cid=19365" target="_blank"><strong>KKday 北海道点灯之旅 ｜富良野精灵台＆美瑛青池＆白须瀑布一日游｜札幌出发</strong></a></h3>

<blockquote>
  <p><em>我们选的是 <strong>悠闲11:50 出发 B方案</strong> ，但是晚上就会到很晚，预计 21:40 才会回到札幌大通站。</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*r4yUA95KAdrxtt6SBKWZfA.webp" alt="" loading="lazy" decoding="async" width="872" height="783" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzIiIGhlaWdodD0iNzgzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*r4yUA95KAdrxtt6SBKWZfA.png" /></p>

<p>集合地点： <a href="https://maps.app.goo.gl/dgPQLs75bVNTbVPR9" target="_blank">大通地铁站 31 号出口</a> ，前一天有收到行前通知信可以加导游/车导的联络方式。</p>

<ul>
  <li>
    <p><strong>11:50 是发车时间，务必在 11:40 抵达</strong></p>
  </li>
  <li>
    <p><strong>11:50 是发车时间，务必在 11:40 抵达</strong></p>
  </li>
  <li>
    <p><strong>11:50 是发车时间，务必在 11:40 抵达</strong></p>
  </li>
</ul>

<h4 id="1000-出门前往大通站">10:00 出门前往大通站</h4>

<h4 id="1030-先去附近的-客美多咖啡-大通西二丁目店-吃早餐">10:30 先去附近的 <a href="https://maps.app.goo.gl/3m7TRSjJWUJAWDfi9" target="_blank">客美多咖啡 大通西二丁目店</a> 吃早餐</h4>

<p><img src="/assets/055527a739dd/1*HpkfNpNAwG8fjJ-Cm9BsUg.webp" alt="" loading="lazy" decoding="async" width="1200" height="451" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQ1MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*HpkfNpNAwG8fjJ-Cm9BsUg.png" /></p>

<ul>
  <li>点饮料送餐包＋单点炸虾汉堡</li>
</ul>

<blockquote>
  <p><em>因为路程遥远想说多储备一些体力。</em></p>
</blockquote>

<h4 id="1130-左右抵达-大通地铁站-31-号出口-公园这等车">11:30 左右抵达 <a href="https://maps.app.goo.gl/dgPQLs75bVNTbVPR9" target="_blank">大通地铁站 31 号出口</a> 公园这等车</h4>

<p><img src="/assets/055527a739dd/1*v4Yooh8ijGwkJw00MO1gMg.webp" alt="" loading="lazy" decoding="async" width="1200" height="452" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQ1MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*v4Yooh8ijGwkJw00MO1gMg.png" /></p>

<p><img src="/assets/055527a739dd/1*mc74gZLhUIfqbW49JYgUXw.webp" alt="" loading="lazy" decoding="async" width="960" height="1280" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjAiIGhlaWdodD0iMTI4MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*mc74gZLhUIfqbW49JYgUXw.jpeg" /></p>

<blockquote>
  <p><em>一日游几乎都在这个公园四周集合，要跟导游确认一下是不是自己的团，不然会上错车。</em></p>
</blockquote>

<h4 id="1140-车导出现上车">11:40 车导出现，上车</h4>

<p><img src="/assets/055527a739dd/1*AFAqnskVajf2pY0py1Bn7w.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*AFAqnskVajf2pY0py1Bn7w.jpeg" /></p>

<p>上次去「 <a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E4%B9%9D%E5%B7%9E%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E9%87%9C%E5%B1%B1%E6%96%B0%E5%B1%B1%E8%8C%B6%E8%8A%B1%E8%99%9F%E9%83%B5%E8%BC%AA%E5%85%A5%E5%A2%83%E6%97%A5%E6%9C%AC%E5%8D%9A%E5%A4%9A-%E6%B7%B1%E5%85%A5%E7%94%B1%E5%B8%83%E9%99%A2-%E5%A4%A7%E5%88%86-%E7%A6%8F%E5%B2%A1%E7%AD%89%E5%9C%B0-cb65fd5ab770/#day-9-kkday-%E9%AB%98%E5%8D%83%E7%A9%97%E4%B8%80%E6%97%A5%E9%81%8A%E9%AB%98%E5%8D%83%E7%A9%97%E7%A5%9E%E7%A4%BE%E9%AB%98%E5%8D%83%E7%A9%97%E5%B3%BD%E8%B0%B7%E5%A4%A9%E5%B2%A9%E6%88%B8%E7%A5%9E%E7%A4%BE%E5%A4%A9%E5%AE%89%E6%B2%B3%E5%8E%9F" target="_blank">KKDAY 高千穗一日游，高千穗神社、高千穗峡谷、天岩戸神社、天安河原</a> 」是大团游览车司机＋导游；这次第一次遇到 6 人小团，就只有车导；不过好处是人少移动比较快速。</p>

<p><img src="/assets/055527a739dd/1*GGf6O-gDlFpehOsdYEx-vw.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*GGf6O-gDlFpehOsdYEx-vw.jpeg" /></p>

<p>先高速公路＋进入深山的山路，真的蛮远的。</p>

<blockquote>
  <p><strong><em>到第一个景点车程约：1 小时 50 分钟。</em></strong></p>
</blockquote>

<h4 id="1330-富良野森林精灵露台-白天"><a href="https://www.google.com/maps/search/?api=1&amp;query=43.3232668%2C142.3563319&amp;query_place_id=ChIJPbaM-V5Sc18RLOjzIysMtac" target="_blank">13:30 富良野森林精灵露台-白天</a></h4>

<p><img src="/assets/055527a739dd/1*2ur7G9_kzOM1MD8eauR0fg.webp" alt="" loading="lazy" decoding="async" width="1200" height="686" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY4NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*2ur7G9_kzOM1MD8eauR0fg.png" /></p>

<p>这里有游客中心可以上厕所，后面就是富良野滑雪场。</p>

<p><img src="/assets/055527a739dd/1*7M8YnUnPp4Srks7MyeFIHw.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*7M8YnUnPp4Srks7MyeFIHw.jpeg" /></p>

<p><img src="/assets/055527a739dd/1*aJdiFhYD9bY2-DjAjpJxog.webp" alt="" loading="lazy" decoding="async" width="3052" height="2036" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMDUyIiBoZWlnaHQ9IjIwMzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*aJdiFhYD9bY2-DjAjpJxog.png" /></p>

<p><img src="/assets/055527a739dd/1*vBRe8LKhvuxUAPJ1YMuVPw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*vBRe8LKhvuxUAPJ1YMuVPw.jpeg" /></p>

<blockquote>
  <p><em>富良野森林精灵露台就是在森林中的木栈道，有很多小木屋卖手作商品，整体不大，走一圈不到 10 分钟；冬天白天可以看雪景，晚上有夜景点灯。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>店家门口、店内都禁止摄影。</em></strong></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*Bh5lCi-uhSPsvKmRHxITag.webp" alt="买了一个木头月对手做纪念品" loading="lazy" decoding="async" width="903" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*Bh5lCi-uhSPsvKmRHxITag.png" /></p>

<p>买了一个木头月对手做纪念品</p>

<blockquote>
  <p><em>因为我们比较早到，所以在此停留 50 分钟。</em></p>
</blockquote>

<h4 id="1420-出发前往-ハーブガーデン富良野-herb-garden-furano">14:20 出发前往 <a href="https://maps.app.goo.gl/kYdVBB1XYsgGo45x7" target="_blank">ハーブガーデン富良野 (HERB GARDEN FURANO)</a></h4>

<blockquote>
  <p><strong><em>车程约：30 分钟。</em></strong></p>
</blockquote>

<blockquote>
  <p><em>休息站(购物站) 行程， <strong>无强迫推销，里面的冰淇淋好吃！</strong></em></p>
</blockquote>

<blockquote>
  <p><em>停留约 30 分钟。</em></p>
</blockquote>

<h4 id="1540-抵达-美瑛车站">15:40 抵达 <a href="https://www.google.com/maps/search/?api=1&amp;query=43.5911991%2C142.4633615&amp;query_place_id=ChIJVzdU8tzFDF8RTXvFSGX1S8Y" target="_blank">美瑛车站</a></h4>

<p><img src="/assets/055527a739dd/1*fEsxWXDi675dMyBw-cZnag.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*fEsxWXDi675dMyBw-cZnag.jpeg" /></p>

<p><img src="/assets/055527a739dd/1*kquYhK10b7_hz5ASDgp5gQ.webp" alt="" loading="lazy" decoding="async" width="2914" height="1936" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOTE0IiBoZWlnaHQ9IjE5MzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*kquYhK10b7_hz5ASDgp5gQ.png" /></p>

<blockquote>
  <p><a href="https://www.google.com/maps/search/?api=1&amp;query=43.5911991%2C142.4633615&amp;query_place_id=ChIJVzdU8tzFDF8RTXvFSGX1S8Y" target="*blank"><em>美瑛车站</em></a> _很小附近很荒凉，主要是拍拍照上个厕所跟 <strong>去附近买些东西当晚餐带在路上吃</strong> 。*</p>
</blockquote>

<blockquote>
  <p><em>附近有一家 7–11 跟面包店可以选择。</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*e2sqcvDP_rl7hJpTK8FlWQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*e2sqcvDP_rl7hJpTK8FlWQ.jpeg" /></p>

<p>买了一个面包跟超商熟食当路上的晚餐。</p>

<blockquote>
  <p><em>停留约 50 分钟。</em></p>
</blockquote>

<h4 id="1630-出发前往-美瑛圣诞树">16:30 出发前往 <a href="https://maps.app.goo.gl/5MbFa5QCD46tfjH67" target="_blank">美瑛圣诞树</a></h4>

<blockquote>
  <p><em>车程约 10 分钟，路边景点。</em></p>
</blockquote>

<h4 id="1640-抵达-美瑛圣诞树">16:40 抵达 <a href="https://maps.app.goo.gl/5MbFa5QCD46tfjH67" target="_blank">美瑛圣诞树</a></h4>

<p><img src="/assets/055527a739dd/1*VNDn9fdGddz9VJpvUunO_g.webp" alt="" loading="lazy" decoding="async" width="3198" height="2130" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMTk4IiBoZWlnaHQ9IjIxMzAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*VNDn9fdGddz9VJpvUunO_g.png" /></p>

<p><img src="/assets/055527a739dd/1*bmTIWwQmcsnzZoqe0ciDlg.webp" alt="" loading="lazy" decoding="async" width="1477" height="1108" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDc3IiBoZWlnaHQ9IjExMDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*bmTIWwQmcsnzZoqe0ciDlg.jpeg" /></p>

<p>四季来看都有不同风景，今天是夕阳若隐若现的雪景。</p>

<blockquote>
  <p><em>停留约 20 分钟。</em></p>
</blockquote>

<h4 id="1700-出发前往-白须瀑布">17:00 出发前往 <a href="https://www.google.com/maps/search/?api=1&amp;query=43.474803813168%2C142.63934225235&amp;query_place_id=none" target="_blank">白须瀑布</a></h4>

<blockquote>
  <p><em>车程约 30 分钟，桥景点。</em></p>
</blockquote>

<h4 id="1730-抵达-白须瀑布">17:30 抵达 <a href="https://www.google.com/maps/search/?api=1&amp;query=43.474803813168%2C142.63934225235&amp;query_place_id=none" target="_blank">白须瀑布</a></h4>

<p><img src="/assets/055527a739dd/1*dDpDKI44Mek6JN6zFChEhA.webp" alt="" loading="lazy" decoding="async" width="1200" height="683" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY4MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*dDpDKI44Mek6JN6zFChEhA.png" /></p>

<p>从这座人行铁桥往下看就是结冰的白须瀑布。</p>

<p><img src="/assets/055527a739dd/1*tiviDULpwjoqXcl4kcncfw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*tiviDULpwjoqXcl4kcncfw.jpeg" /></p>

<blockquote>
  <p><em>停留约 20 分钟。</em></p>
</blockquote>

<blockquote>
  <p><em>时间接近傍晚，天气寒冷； <strong>桥面有结冰走路要小心</strong> 。</em></p>
</blockquote>

<h4 id="1750-出发前往-白金青池">17:50 出发前往 <a href="https://www.google.com/maps/search/?api=1&amp;query=43.493606086454%2C142.61433241373&amp;query_place_id=none" target="_blank">白金青池</a></h4>

<blockquote>
  <p><em>车程约 5 分钟。</em></p>
</blockquote>

<h4 id="1755-抵达最后一个景点-白金青池">17:55 抵达最后一个景点 <a href="https://www.google.com/maps/search/?api=1&amp;query=43.493606086454%2C142.61433241373&amp;query_place_id=none" target="_blank">白金青池</a></h4>

<p><img src="/assets/055527a739dd/1*E9VIGAECznfFqG9QKyRqBA.webp" alt="" loading="lazy" decoding="async" width="1193" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTkzIiBoZWlnaHQ9IjEyMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*E9VIGAECznfFqG9QKyRqBA.png" /></p>

<blockquote>
  <p><em>停留约 30 分钟，有游客中心厕所。</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*l61TfdQcTz-adTlROZsmnA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*l61TfdQcTz-adTlROZsmnA.jpeg" /></p>

<p>停车场往上走就能看到青池。</p>

<p><img src="/assets/055527a739dd/1*1g4Qki4CDbE4WWOoNig2Rg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*1g4Qki4CDbE4WWOoNig2Rg.jpeg" /></p>

<p><img src="/assets/055527a739dd/1*68bEAmSijcpqQbGn8z58lA.webp" alt="" loading="lazy" decoding="async" width="2048" height="1536" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDQ4IiBoZWlnaHQ9IjE1MzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*68bEAmSijcpqQbGn8z58lA.jpeg" /></p>

<p><img src="/assets/055527a739dd/1*b92j-p7ghCGyP3peml3M3A.webp" alt="" loading="lazy" decoding="async" width="2048" height="1536" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDQ4IiBoZWlnaHQ9IjE1MzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*b92j-p7ghCGyP3peml3M3A.jpeg" /></p>

<blockquote>
  <p><em>是一个静谧景点，死寂冰冻的潭面透过光影的变换展现出一丝生机。</em></p>
</blockquote>

<h4 id="1830-回程-大通地铁站-31-号出口">18:30 回程 <a href="https://maps.app.goo.gl/dgPQLs75bVNTbVPR9" target="_blank">大通地铁站 31 号出口</a></h4>

<p><img src="/assets/055527a739dd/1*VwEV_rxTwap-JzHlqs4kMw.webp" alt="" loading="lazy" decoding="async" width="2048" height="1536" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDQ4IiBoZWlnaHQ9IjE1MzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*VwEV_rxTwap-JzHlqs4kMw.jpeg" /></p>

<blockquote>
  <p><em>车程：约 2 小时 30 分钟，中间大约 20:00 左右有经过休息站让大家去上厕所。</em></p>
</blockquote>

<h4 id="2055-抵达-大通地铁站-31-号出口">20:55 抵达 <a href="https://maps.app.goo.gl/dgPQLs75bVNTbVPR9" target="_blank">大通地铁站 31 号出口</a></h4>

<p>整体来说跟之前「 <a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E4%B9%9D%E5%B7%9E%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E9%87%9C%E5%B1%B1%E6%96%B0%E5%B1%B1%E8%8C%B6%E8%8A%B1%E8%99%9F%E9%83%B5%E8%BC%AA%E5%85%A5%E5%A2%83%E6%97%A5%E6%9C%AC%E5%8D%9A%E5%A4%9A-%E6%B7%B1%E5%85%A5%E7%94%B1%E5%B8%83%E9%99%A2-%E5%A4%A7%E5%88%86-%E7%A6%8F%E5%B2%A1%E7%AD%89%E5%9C%B0-cb65fd5ab770/#day-9-kkday-%E9%AB%98%E5%8D%83%E7%A9%97%E4%B8%80%E6%97%A5%E9%81%8A%E9%AB%98%E5%8D%83%E7%A9%97%E7%A5%9E%E7%A4%BE%E9%AB%98%E5%8D%83%E7%A9%97%E5%B3%BD%E8%B0%B7%E5%A4%A9%E5%B2%A9%E6%88%B8%E7%A5%9E%E7%A4%BE%E5%A4%A9%E5%AE%89%E6%B2%B3%E5%8E%9F" target="_blank">KKDAY 高千穗一日游，高千穗神社、高千穗峡谷、天岩戸神社、天安河原</a> 」心得差不多，就是坐车走马看花；自己要去这些景点非常麻烦，路程一半是高速一半是山路无人区(感觉就会有很多熊)；这次遇到小团体行动加上司机狂飙所以比预期时间早回到市区。</p>

<h4 id="2130-回到札幌站">21:30 回到札幌站</h4>

<p>大通站附近走一走后就回札幌站了，大部分吃的也都关门了。</p>

<h4 id="札幌-つなぐ-横町"><a href="https://maps.app.goo.gl/kWrKsjCDcQXqZ7MW6" target="_blank"><strong>札幌 つなぐ 横町</strong></a></h4>

<p>查了一下车站附近还有一个夜市还有营业就走去看看，随便都好，吃个什么。</p>

<p><img src="/assets/055527a739dd/1*PthAxfmCvDvVAb1A96Xxcw.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*PthAxfmCvDvVAb1A96Xxcw.jpeg" /></p>

<p><img src="/assets/055527a739dd/1*chm5p8whKi2G8nLTCbNu1Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="681" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY4MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*chm5p8whKi2G8nLTCbNu1Q.png" /></p>

<p>随便选了一家有烤串的 (主要是烤鳗鱼)，先吃一点。</p>

<blockquote>
  <p><em>这家也只营业到 3 月，本来是想吃手羽先的，结果选错家。</em></p>
</blockquote>

<h4 id="2230-回饭店">22:30 回饭店</h4>

<p><img src="/assets/055527a739dd/1*iVNNjGw0DokpzTnl6XKUyg.webp" alt="" loading="lazy" decoding="async" width="1200" height="683" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY4MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*iVNNjGw0DokpzTnl6XKUyg.png" /></p>

<p>吃完还有点饿，去附近超商买点宵夜回去吃。</p>

<blockquote>
  <p>S <em>eicomart 有卖一些 Lawsone/711/全家没有的东西。</em></p>
</blockquote>

<h3 id="day-5-0319-四-逛街采购北海道神宫">Day 5 (03/19 四) —逛街采购、北海道神宫</h3>

<h4 id="1000-出门吃早餐-麦当劳">10:00 出门吃早餐 <a href="https://maps.app.goo.gl/3xn9SZskRd8Yzr2t9" target="_blank">麦当劳</a></h4>

<p><img src="/assets/055527a739dd/1*38MT4SC9vjfjZBJua2NE1A.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*38MT4SC9vjfjZBJua2NE1A.jpeg" /></p>

<p><img src="/assets/055527a739dd/1*kODLJ4LXRV_ZXVa20qwZNg.webp" alt="" loading="lazy" decoding="async" width="1200" height="799" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc5OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*kODLJ4LXRV_ZXVa20qwZNg.png" /></p>

<ul>
  <li>
    <p>McGriddles 厚松饼堡(台湾没卖) — 培根起司蛋，有蜂蜜甜甜咸咸的</p>
  </li>
  <li>
    <p>草莓起司派(台湾后来也开卖) — 草莓果酱＋起司</p>
  </li>
</ul>

<h4 id="1000-大通-狸小路继续逛扭蛋-唐吉诃德-采购">10:00 大通 狸小路继续逛扭蛋 <a href="https://maps.app.goo.gl/t9UREfvkAkyNrCim6" target="_blank">、唐吉诃德</a> 采购</h4>

<p><img src="/assets/055527a739dd/1*7TSlQ_cHD2h9sBSh_w1XVQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="684" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*7TSlQ_cHD2h9sBSh_w1XVQ.png" /></p>

<p><img src="/assets/055527a739dd/1*B9w_5kkFC02FeDDpl49I_Q.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*B9w_5kkFC02FeDDpl49I_Q.jpeg" /></p>

<blockquote>
  <p><em>札幌站没什么好逛，这里比较多东西可以逛。</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*ATM-ffFeXSn1OU2MsF1VYw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*ATM-ffFeXSn1OU2MsF1VYw.jpeg" /></p>

<p>扭了一个火灾报警器跟一些有趣的扭蛋。</p>

<h4 id="1330-回札幌站饭店放东西百货公司继续逛吃">13:30 回札幌站饭店放东西、百货公司继续逛吃</h4>

<p><img src="/assets/055527a739dd/1*WlIAL89mRGqmZUHBO6zqTg.webp" alt="午餐随意吃了百货公司的散寿司＋荞麦面" loading="lazy" decoding="async" width="4117" height="3093" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MTE3IiBoZWlnaHQ9IjMwOTMiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*WlIAL89mRGqmZUHBO6zqTg.png" /></p>

<p>午餐随意吃了百货公司的散寿司＋荞麦面</p>

<h4 id="le-labo-ル-ラボ-札幌大丸店"><a href="https://maps.app.goo.gl/fdeQ5DFzfkGPGgaQ8" target="_blank">LE LABO ル ラボ 札幌大丸店</a></h4>

<p>顺便瞄一眼 Le Labo 2026 / 札幌 买的价格：</p>

<p><img src="/assets/055527a739dd/1*Q039ga_Vw3MQgF0g0BRqwA.webp" alt="" loading="lazy" decoding="async" width="1086" height="1013" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDg2IiBoZWlnaHQ9IjEwMTMiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*Q039ga_Vw3MQgF0g0BRqwA.png" /></p>

<ul>
  <li>50ml ¥31,350 跟 <a href="/posts/z-度旅行遊記/东京自由行攻略-川越小江户一日游与热海海上花火大会全纪录-958599363857/">2025 东京价格一样</a></li>
</ul>

<blockquote>
  <p><em>逛逛买买大约 15:00 左右出发去 <a href="https://maps.app.goo.gl/sZDHVC7X3ctkwQzX9" target="_blank">北海道神宫</a> 。</em></p>
</blockquote>

<blockquote>
  <p><em>札幌出发先坐南北线到大通站转东西线 <a href="https://maps.app.goo.gl/rhiPPKBaugwZBxid6" target="_blank">圆山公园站</a> ，车埕约 30 分钟。</em></p>
</blockquote>

<h4 id="1540-抵达-圆山公园站">15:40 抵达 <a href="https://maps.app.goo.gl/rhiPPKBaugwZBxid6" target="_blank">圆山公园站</a></h4>

<p><img src="/assets/055527a739dd/1*UVfaLNsp7YdujXBEEzQHCQ.webp" alt="" loading="lazy" decoding="async" width="895" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4OTUiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*UVfaLNsp7YdujXBEEzQHCQ.png" /></p>

<blockquote>
  <p><em>如果早点去可以先坐去附近 <a href="https://maps.app.goo.gl/jZe1NSebYoACZfEj8" target="_blank"><strong>有名的北海道海产回转寿司 Toriton</strong></a></em> 。</p>
</blockquote>

<blockquote>
  <p><em>圆山公园站 3 号出口出来直接朝面公园的方向往里面走就是北海道神宫了。</em></p>
</blockquote>

<blockquote>
  <p><em>路程约：850公尺 / 15 分钟</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*S002OiQvL92tuOKH1IdGkg.webp" alt="" loading="lazy" decoding="async" width="3366" height="2246" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMzY2IiBoZWlnaHQ9IjIyNDYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*S002OiQvL92tuOKH1IdGkg.png" /></p>

<p>过个马路到底就是公园入口了：</p>

<p><img src="/assets/055527a739dd/1*D8BbsmFeID8pc06a0JjeTw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*D8BbsmFeID8pc06a0JjeTw.jpeg" /></p>

<blockquote>
  <p><em>当你跟朋友约在圆山时…</em></p>
</blockquote>

<blockquote>
  <p><em>我：圆山公园 💁</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*xqB_Gf70oekdjB_7kAlyUw.webp" alt="" loading="lazy" decoding="async" width="3426" height="2284" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNDI2IiBoZWlnaHQ9IjIyODQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*xqB_Gf70oekdjB_7kAlyUw.png" /></p>

<p>先穿过圆山公园(这里还有很多积雪)，就能看到神宫鸟居入口了：</p>

<p><img src="/assets/055527a739dd/1*cBmTSlECefOGTo6xrR-uLA.webp" alt="" loading="lazy" decoding="async" width="3092" height="4117" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMDkyIiBoZWlnaHQ9IjQxMTciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*cBmTSlECefOGTo6xrR-uLA.png" /></p>

<h4 id="1550-神宫茶屋"><a href="https://maps.app.goo.gl/A4X2vpZic2F3onHD9" target="_blank">15:50 神宫茶屋</a></h4>

<p><img src="/assets/055527a739dd/1*cDFq2pN_R-mdNkjb9J6M2Q.webp" alt="" loading="lazy" decoding="async" width="1128" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTI4IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*cDFq2pN_R-mdNkjb9J6M2Q.png" /></p>

<p>继续走路上会经过神宫茶屋，先去吃个北海道牛奶冰淇淋。</p>

<p><img src="/assets/055527a739dd/1*ak0-XC8XNs7U80Jv7w0SHw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*ak0-XC8XNs7U80Jv7w0SHw.jpeg" /></p>

<p>很浓郁好吃。</p>

<blockquote>
  <p><strong><em>神宫内不能吃东西，在茶屋这吃完再走。</em></strong></p>
</blockquote>

<h4 id="1615-北海道神宫"><a href="https://maps.app.goo.gl/sZDHVC7X3ctkwQzX9" target="_blank">16:15 北海道神宫</a></h4>

<p><img src="/assets/055527a739dd/1*geeJcHKwKdulE3ZAKdrdXw.webp" alt="" loading="lazy" decoding="async" width="1698" height="1236" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjk4IiBoZWlnaHQ9IjEyMzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*geeJcHKwKdulE3ZAKdrdXw.png" /></p>

<blockquote>
  <p><em>参拜： <strong>投五円(意结缘) -&gt; 鞠躬两次 -&gt; 拍手两次 -&gt; 许愿 -&gt; 结束鞠躬一次</strong></em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*vIk2569WTqkQU_EOFagzkA.webp" alt="" loading="lazy" decoding="async" width="2826" height="1484" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyODI2IiBoZWlnaHQ9IjE0ODQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*vIk2569WTqkQU_EOFagzkA.png" /></p>

<p><img src="/assets/055527a739dd/1*Mvgp7m0K3DkGJTemBXAIEw.webp" alt="" loading="lazy" decoding="async" width="1200" height="902" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*Mvgp7m0K3DkGJTemBXAIEw.png" /></p>

<p>买了两个御守，比较特别的是交通御守，可以挂在车内跟有一个贴纸可以贴在机车、脚踏车、安全帽上。</p>

<h4 id="1630-离开北海道神宫">16:30 离开北海道神宫</h4>

<p><img src="/assets/055527a739dd/1*uf7nqGUX9f_Sx-RWSieeSQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="799" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc5OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*uf7nqGUX9f_Sx-RWSieeSQ.png" /></p>

<p>从神宫跟公园慢慢走回地铁站准备回札幌站附近吃晚餐了。</p>

<h3 id="1720-经过札幌北海道厅红砖厅舍">17:20 <a href="https://maps.app.goo.gl/TPopSdeEizc4L3pt9" target="_blank">经过札幌北海道厅红砖厅舍</a></h3>

<p><img src="/assets/055527a739dd/1*HepNYeLKdeZnUDG-5z9OjA.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*HepNYeLKdeZnUDG-5z9OjA.jpeg" /></p>

<p>只是路过，主要是去隔壁的札幌三井吃烧肉：</p>

<p><img src="/assets/055527a739dd/1*0q_FfJh3NGkGSK2Qy3R0Yg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*0q_FfJh3NGkGSK2Qy3R0Yg.jpeg" /></p>

<h3 id="1730-yakiniku-bar-tamura-烧肉"><a href="https://maps.app.goo.gl/G8HjR4dNjvcoLA246" target="_blank">17:30 Yakiniku Bar Tamura</a> 烧肉</h3>

<p><img src="/assets/055527a739dd/1*VNc3gye9wK6y56eHPc2deA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*VNc3gye9wK6y56eHPc2deA.jpeg" /></p>

<p>来试试北海道和牛。</p>

<p><img src="/assets/055527a739dd/1*AYwFzwBblluHK6-hmf_Cfw.webp" alt="" loading="lazy" decoding="async" width="3458" height="1640" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNDU4IiBoZWlnaHQ9IjE2NDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*AYwFzwBblluHK6-hmf_Cfw.png" /></p>

<blockquote>
  <p><em>点了北海道牛套餐＋生菜＋啤酒＋饮料＋冷面，总共约 NT$3,100；和牛油脂丰富入口即化，牛排也很好吃，最惊艳的是牛舌，很 Q 很好吃。</em></p>
</blockquote>

<h4 id="1900-札幌东急百货"><a href="https://maps.app.goo.gl/rR4a14JofuNjSBXT8" target="_blank">19:00 札幌东急百货</a></h4>

<p><img src="/assets/055527a739dd/1*M1Jvj4MqsexEZInEN2CYiw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*M1Jvj4MqsexEZInEN2CYiw.jpeg" /></p>

<p>吃饱走来最后一逛，东急百货。</p>

<p><img src="/assets/055527a739dd/1*ruyLfADnDmXwM1iObk1rig.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*ruyLfADnDmXwM1iObk1rig.jpeg" /></p>

<p>这边楼上也有玩具、扭蛋。</p>

<h4 id="2000-回到札幌站">20:00 回到札幌站</h4>

<p><img src="/assets/055527a739dd/1*Qm2l3HH2jAG788N4lvMRDA.webp" alt="" loading="lazy" decoding="async" width="3095" height="4120" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMDk1IiBoZWlnaHQ9IjQxMjAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*Qm2l3HH2jAG788N4lvMRDA.png" /></p>

<p>百货公司快关门了，最后再逛逛。</p>

<h4 id="札幌车站--サンドイッチ工房-sandria"><a href="https://www.s-sandwich.com/" target="_blank">札幌车站 — サンドイッチ工房 Sandria</a></h4>

<p><img src="/assets/055527a739dd/1*6d-W6JOQaseQid4b7YrKow.webp" alt="" loading="lazy" decoding="async" width="1200" height="686" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY4NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*6d-W6JOQaseQid4b7YrKow.png" /></p>

<p>回饭店的路上买了每天经过 JR 车站都很多人都在排的三明治贩卖机。</p>

<blockquote>
  <p><em>一人限购两个，我买了一个猪排当宵夜、马铃薯蛋沙拉当明天早餐。</em></p>
</blockquote>

<h4 id="2230-札幌最后一晚的宵夜">22:30 札幌最后一晚的宵夜</h4>

<p><img src="/assets/055527a739dd/1*RUURJltr-9QnEkSuGXEsUA.webp" alt="" loading="lazy" decoding="async" width="3552" height="2020" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTUyIiBoZWlnaHQ9IjIwMjAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*RUURJltr-9QnEkSuGXEsUA.png" /></p>

<blockquote>
  <p>配了第 <em>一天有喝的草莓酒跟北海道牛奶冰淇淋。</em></p>
</blockquote>

<h3 id="day-6-0320-五--新千岁机场回程">Day 6 (03/20 五) — 新千岁机场、回程</h3>

<h4 id="1000-起床房间吃早餐">10:00 起床房间吃早餐</h4>

<p><img src="/assets/055527a739dd/1*O6AlKj2q5BGnpifN8xfb1Q.webp" alt="" loading="lazy" decoding="async" width="2048" height="1536" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDQ4IiBoZWlnaHQ9IjE1MzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*O6AlKj2q5BGnpifN8xfb1Q.jpeg" /></p>

<p>吃完收一收 Checkout 后就直奔机场了。</p>

<h4 id="1105-札幌站等车">11:05 札幌站等车</h4>

<p><img src="/assets/055527a739dd/1*NZDX273R7I57ua8K7dgQZg.webp" alt="" loading="lazy" decoding="async" width="1200" height="728" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjcyOCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*NZDX273R7I57ua8K7dgQZg.png" /></p>

<h4 id="1119-札幌站搭车前往新千岁机场">11:19 札幌站搭车前往新千岁机场</h4>

<blockquote>
  <p><em>快速机场 68快速新千岁机场、38 分钟</em></p>
</blockquote>

<h4 id="1200-抵达新千岁机场">12:00 抵达新千岁机场</h4>

<p><img src="/assets/055527a739dd/1*GY04A3vbPbQHK3yCnjUSyw.webp" alt="" loading="lazy" decoding="async" width="958" height="1115" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTgiIGhlaWdodD0iMTExNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*GY04A3vbPbQHK3yCnjUSyw.png" /></p>

<h4 id="jr-新千岁空港国内线大厅">JR 新千岁空港、国内线大厅</h4>

<p><img src="/assets/055527a739dd/1*gh59koOOU8_OF3ONpsXV-g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*gh59koOOU8_OF3ONpsXV-g.jpeg" /></p>

<blockquote>
  <p><em>地铁往上走到 1 楼这边大厅有很多吃的跟伴手礼，如果买不够这里还有的逛。</em></p>
</blockquote>

<h4 id="要回去了一路从来时的方向往回走">要回去了…一路从来时的方向往回走</h4>

<p><img src="/assets/055527a739dd/1*6W0gH8pkfaj0OJyXMEdLbQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*6W0gH8pkfaj0OJyXMEdLbQ.jpeg" /></p>

<h4 id="1217-抵达国际线大厅">12:17 抵达国际线大厅</h4>

<p><img src="/assets/055527a739dd/1*7WibQith1SFr80NzDbpVpw.webp" alt="" loading="lazy" decoding="async" width="1704" height="1179" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNzA0IiBoZWlnaHQ9IjExNzkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*7WibQith1SFr80NzDbpVpw.png" /></p>

<p>分配到最边边的报到柜台，还有走 165 公尺才会到：</p>

<p><img src="/assets/055527a739dd/1*s5JrKPKZCS7aalLWzJzQAQ.webp" alt="" loading="lazy" decoding="async" width="961" height="772" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjEiIGhlaWdodD0iNzcyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/055527a739dd/1*s5JrKPKZCS7aalLWzJzQAQ.png" /></p>

<p>北海道鸟银喉长尾山雀：</p>

<p><img src="/assets/055527a739dd/1*vfgtjZcmirVzk2On2jCiaA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*vfgtjZcmirVzk2On2jCiaA.jpeg" /></p>

<h4 id="1222-抵达报到柜台">12:22 抵达报到柜台</h4>

<blockquote>
  <p><em>现场人很多，网路报到少一点，因此务必在回程 <a href="https://calec.china-airlines.com/eCheckin/eCheckin_home.aspx" target="_blank">前三天完成选位与网路报到，节省排队时间。</a></em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*Kf8mo1c0_Q_dCgUF3cYV-g.webp" alt="" loading="lazy" decoding="async" width="1200" height="835" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgzNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*Kf8mo1c0_Q_dCgUF3cYV-g.png" /></p>

<p>这边后面还有一家唐吉诃德可以在托运前最后采购：</p>

<p><img src="/assets/055527a739dd/1*Nh4v3mOEt0UkPi9ERBJ8yw.webp" alt="" loading="lazy" decoding="async" width="1705" height="1183" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNzA1IiBoZWlnaHQ9IjExODMiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*Nh4v3mOEt0UkPi9ERBJ8yw.png" /></p>

<h4 id="1303-完成报到行李托运">13:03 完成报到＋行李托运</h4>

<h4 id="1317-完成安检出境审查">13:17 完成安检、出境审查</h4>

<blockquote>
  <p><em>日本机场安检比较严格，如果穿靴子都要脱下来过 X 光。</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*KEoEKjL5F66qscCtVKyLcw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*KEoEKjL5F66qscCtVKyLcw.jpeg" /></p>

<h4 id="1320-候机逛逛">13:20 候机逛逛</h4>

<p><img src="/assets/055527a739dd/1*jYqkVX8z5aFrCMr9LD7vlQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="384" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjM4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*jYqkVX8z5aFrCMr9LD7vlQ.png" /></p>

<p><img src="/assets/055527a739dd/1*vwC7ieofFNIOVl2L_0YjKA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*vwC7ieofFNIOVl2L_0YjKA.jpeg" /></p>

<blockquote>
  <p><em>有一条美食街可以吃东西，我只买了面包、炸鸡、哈密瓜冰淇淋加减吃一点。</em></p>
</blockquote>

<p><img src="/assets/055527a739dd/1*_83IZv2r6TiRQW-isqq3iw.webp" alt="" loading="lazy" decoding="async" width="1200" height="833" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgzMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*_83IZv2r6TiRQW-isqq3iw.png" /></p>

<p>一楼有整排伴手礼店还可以买，几乎什么都有；但是精品店比较少。</p>

<p><img src="/assets/055527a739dd/1*5UHmAXCqA7_aR5EeHTvWzg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*5UHmAXCqA7_aR5EeHTvWzg.jpeg" /></p>

<p>二楼也有一些伴手礼。</p>

<h4 id="1430-完成登机">14:30 完成登机</h4>

<p><img src="/assets/055527a739dd/1*ggFHkcOkMXJO-u8Opfn1lw.webp" alt="" loading="lazy" decoding="async" width="1200" height="802" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*ggFHkcOkMXJO-u8Opfn1lw.png" /></p>

<p>跟来时候一样是新的空客飞机，位置大、娱乐设施新。</p>

<h4 id="1500-起飞再会--札幌">15:00 起飞，再会 — 札幌</h4>

<p><img src="/assets/055527a739dd/1*NsbLIJ-RuRa4YOkVICnPGA.webp" alt="" loading="lazy" decoding="async" width="1536" height="2048" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTM2IiBoZWlnaHQ9IjIwNDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*NsbLIJ-RuRa4YOkVICnPGA.jpeg" /></p>

<p>飞机餐一样普普：</p>

<p><img src="/assets/055527a739dd/1*a20WxDinpEcoDIUd6Bi3xw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*a20WxDinpEcoDIUd6Bi3xw.jpeg" /></p>

<h4 id="1815-落地台湾桃园国际机场">18:15 落地台湾桃园国际机场</h4>

<h4 id="1915-入境提领行李回家休息">19:15 入境＋提领行李，回家休息</h4>

<p>这次行李等了超久…</p>

<h3 id="感谢阅读">感谢阅读</h3>

<p>感谢您看到这里，一起体验北海道的各种风景，下个地方再见！</p>

<h3 id="机上免费-wifi">机上免费 WiFi</h3>

<p><img src="/assets/055527a739dd/1*lK1NDVwT4V1iu0XiZhUtsw.webp" alt="" loading="lazy" decoding="async" width="1978" height="2120" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOTc4IiBoZWlnaHQ9IjIxMjAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/055527a739dd/1*lK1NDVwT4V1iu0XiZhUtsw.png" /></p>

<p>这航次华航提供全程的讯息 WiFi 功能，可以跟朋友传讯息聊天。</p>

<blockquote>
  <p><strong><em>如果你手机有装 AdGuard DNS 或是类似的 DNS 广告阻挡服务，需要先去设定 -&gt; 一般 -&gt; VPN与装置管理 -&gt; 限制和代理伺服器 -&gt; DNS -&gt; 改回自动。</em></strong></p>
</blockquote>

<blockquote>
  <p><em>不然会无法连上机上 WiFi。</em></p>
</blockquote>

<h3 id="战利品">战利品</h3>

<p><img src="/assets/055527a739dd/1*zSYwjAvHNp4zYYXixRVExA.webp" alt="" loading="lazy" decoding="async" width="1200" height="901" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*zSYwjAvHNp4zYYXixRVExA.png" /></p>

<ul>
  <li>札幌农学校(牛奶饼干)、烤玉米饼干(膨化) 也不错</li>
</ul>

<h4 id="玩具">玩具</h4>

<p><img src="/assets/055527a739dd/1*Q4kKEs40fKLCm6dfF0LG7Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="901" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/055527a739dd/1*Q4kKEs40fKLCm6dfF0LG7Q.png" /></p>

<ul>
  <li>
    <p>扭了平交道、招牌灯、车钥匙、火灾报警器、唐吉诃德公仔、日本队球衣</p>
  </li>
  <li>
    <p>富良野精灵台买的木制手作乐手</p>
  </li>
</ul>]]></content>
  </entry><entry>
    <title type="html">iOS Certificates、Identifiers与Profiles详解｜Fastlane Match统一管理凭证与CI/CD整合实战</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/ios-certificates-identifiers%E4%B8%8Eprofiles%E8%AF%A6%E8%A7%A3-fastlane-match%E7%BB%9F%E4%B8%80%E7%AE%A1%E7%90%86%E5%87%AD%E8%AF%81%E4%B8%8Eci-cd%E6%95%B4%E5%90%88%E5%AE%9E%E6%88%98-823ac523ccc8/" rel="alternate" type="text/html" title="iOS Certificates、Identifiers与Profiles详解｜Fastlane Match统一管理凭证与CI/CD整合实战" />
    <published>2026-01-04T01:03:46+08:00</published>
    <updated>2026-01-05T08:55:47+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/823ac523ccc8</id><summary type="html">针对iOS开发者与团队，解决凭证混乱与管理困难问题，透过Fastlane Match统一管理Certificates、Profiles并安全同步至Git私有库，搭配GitHub Actions实现CI/CD自动化，提升开发效率与凭证安全性。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="ios-app-development" /><category term="fastlane" /><category term="keychain" /><category term="github-actions" /><category term="macos" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/823ac523ccc8/1*-OS8G9xu0CFpnlAQRgnGAg.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/ios-certificates-identifiers%E4%B8%8Eprofiles%E8%AF%A6%E8%A7%A3-fastlane-match%E7%BB%9F%E4%B8%80%E7%AE%A1%E7%90%86%E5%87%AD%E8%AF%81%E4%B8%8Eci-cd%E6%95%B4%E5%90%88%E5%AE%9E%E6%88%98-823ac523ccc8/"><![CDATA[<h3 id="ios-certificates-identifiers--profiles-是什么及-fastlane-match-统一-管理-凭证与-cicd-的一些笔记">iOS Certificates, Identifiers &amp; Profiles 是什么及 <strong>Fastlane Match 统一</strong> 管理 <strong>凭证与 CI/CD 的一些笔记</strong></h3>

<p>介绍 Certificates, Identifiers &amp; Profiles 之间的关系与使用 Fastlane Match 统一管理签发凭证并整合进 CI/CD 工作流程的纪录。</p>

<p><img src="/assets/823ac523ccc8/1*-OS8G9xu0CFpnlAQRgnGAg.webp" alt="Photo by marcos mayer" loading="lazy" decoding="async" width="5184" height="3456" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTg0IiBoZWlnaHQ9IjM0NTYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/823ac523ccc8/1*-OS8G9xu0CFpnlAQRgnGAg.jpeg" /></p>

<p>Photo by <a href="https://unsplash.com/@mmayyer?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank">marcos mayer</a></p>

<h4 id="前言">前言</h4>

<p>2025 年中时写过一系列从 0 到 1 使用 GitHub Actions 建置 App CI/CD 完整流程的文章：</p>

<ul>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-是什么-打造高效稳定开发团队的关键流程与工具选择-c008a9e8ceca/">CI/CD 实战指南（一）：CI/CD 是什么？如何透过 CI/CD 打造稳定高效的开发团队？工具选择？</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-self-hosted-runner-详解与实战案例-ci-cd-自动化工作流程建置-404bd5c70040/">CI/CD 实战指南（二）：GitHub Actions 与 self-hosted Runner 使用与建置大全</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/">CI/CD 实战指南（三）：使用 GitHub Actions 实作 App 专案的 CI 与 CD 工作流程</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/">CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</a></p>
  </li>
</ul>

<p>最近到新环境又重新跑了一次，每次都有学习到新的东西，这次聚焦在 iOS Codesigning：Certificates / Profiles / Devices 的关系，与我如何用 Fastlane Match 把凭证管理与 CI/CD 串起来。</p>

<h3 id="certificates-identifiers--profiles-devices-是什么"><a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Certificates, Identifiers &amp; Profiles, Devices 是什么？</a></h3>

<p>在 Apple 生态系中，App 开发是基于凭证与描述档控管的，跟 Android 只要有 .apk 就能安装使用不同；Apple 有严格的凭证对应管制，不符合规则就不能安装、使用。</p>

<h4 id="主要项目组成及功能"><strong>主要项目组成及功能：</strong></h4>

<p><img src="/assets/823ac523ccc8/1*PyM0l-jXXcVBKubOwCiTsw.webp" alt="" loading="lazy" decoding="async" width="1572" height="575" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTcyIiBoZWlnaHQ9IjU3NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/823ac523ccc8/1*PyM0l-jXXcVBKubOwCiTsw.png" /></p>

<h4 id="certificates-签署-app-的身分-signing-identity"><strong>Certificates:</strong> 签署 App 的身分 (Signing Identity)</h4>

<ul>
  <li>
    <p><strong>Development</strong> — 开发阶段跑在实体机上使用(只跑模拟器不用凭证)，所属是人或 API Key (有数量限制)。</p>
  </li>
  <li>
    <p><strong>Distribution</strong> — 打包上 AppStore, TestFlight 或是 Ad Hoc 内测(限定已注册装置)使用，有数量限制，所属是 Team。</p>
  </li>
  <li>
    <p><strong>Enterprise</strong> — 企业内部 App 使用。</p>
  </li>
</ul>

<blockquote>
  <p><strong><em>格式</em></strong> <em>：需要有 <code class="language-plaintext highlighter-rouge">Private Key (私钥)</code> 加 <code class="language-plaintext highlighter-rouge">Certificate .cer (公钥凭证)</code> 才能使用，或是在原创建电脑上的 Keychain 汇出成 <code class="language-plaintext highlighter-rouge">.p12</code> 档案就会同时包含。</em></p>
</blockquote>

<p><img src="/assets/823ac523ccc8/1*oP_p2kJ1Prqku4D8LIZ7yg.webp" alt="" loading="lazy" decoding="async" width="371" height="115" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNzEiIGhlaWdodD0iMTE1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/823ac523ccc8/1*oP_p2kJ1Prqku4D8LIZ7yg.png" /></p>

<h4 id="identifiers-哪一个-appextension-bundle-id"><strong>Identifiers: 哪一个 App/Extension (Bundle ID)</strong></h4>

<p>App 的 Bundle ID 注册跟需要启用的 Capabilities(例如启用 Push Notifications, App Groups…)、App Services。</p>

<p>Extension 也会有自己的 Identifier。</p>

<h4 id="devices-已注册装置-iphoneipad--"><strong>Devices: 已注册装置 (iPhone/iPad. . )</strong></h4>

<p>Development 跑在实体机上跟 Distribution Ad Hoc 内测只有注册的装置才能使用。</p>

<blockquote>
  <p><strong><em>上限：100 个；包含取消，要等到每年付费周期才会重新刷新释出额度。</em></strong></p>
</blockquote>

<h4 id="provisioning-profile-以下简称-profile-描述档"><strong>Provisioning Profile (以下简称 Profile): 描述档</strong></h4>

<p>组合 Certificates+Identifiers+Devices 关系。</p>

<ul>
  <li>
    <p><strong>Development</strong> — 开发阶段使用的描述档，如果要跑实体机测试就必须使用，描述档包含 Certificates+Identifiers+Devices 之间的关系。</p>
  </li>
  <li>
    <p><strong>Ad Hoc</strong> —打包给内部测试使用(e.g. Deploy to Firebase App Distribution)的描述档，描述档包含 Certificates+Identifiers+Devices 之间的关系。</p>
  </li>
  <li>
    <p><strong>App Store</strong> — 打包上传到 App Store / TestFlight 使用的描述档，描述档包含 Certificates+Identifiers 之间的关系。</p>
  </li>
</ul>

<blockquote>
  <p><em>格式： <code class="language-plaintext highlighter-rouge">.mobileprovision</code></em></p>
</blockquote>

<blockquote>
  <p><strong><em>要注意：Profile 只是描述档，描述关系，不会包含凭证本体。</em></strong></p>
</blockquote>

<h4 id="小结">小结</h4>

<p>综合以上，如果要在一台干净的机器、不登入 Xcode Apple Account 的情况下要能 Build 实体机 (Development Certificate) 或是执行 Archive 打包 (Distribution Certificate)， <strong>必须要有两个档案</strong> ：</p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">.mobileprovision</code> Provisioning Profile 描述档: 描述Certificates+Identifiers+Devices 关系。</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">.p12</code> Certificate: 凭证的实体 (从原创建 Certificate 的电脑汇出)。</p>
  </li>
</ul>

<p><strong>另外 macOS ≥ 15 后的 Keychain 移动到：</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>open /System/Library/CoreServices/Applications/Keychain<span class="se">\ </span>Access.app
</code></pre></div></div>

<p><em>找了超久. .</em></p>

<h4 id="常见错误">常见错误</h4>

<p><strong>⚠️⚠️⚠️ 确定凭证、Profile 都正确但怎么样都报错:</strong></p>

<blockquote>
  <p><em>多半是你还残存有之前的凭证、多张凭证，Xcode 会错乱。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>这问题很常会遇到！</em></strong></p>
</blockquote>

<ol>
  <li>
    <p>关闭 Xcode</p>
  </li>
  <li>
    <p>打开 macOS keychain: <code class="language-plaintext highlighter-rouge">open /System/Library/CoreServices/Applications/Keychain\ Access.app</code></p>
  </li>
  <li>
    <p>login keychain -&gt; All items -&gt; 搜寻 <code class="language-plaintext highlighter-rouge">apple development</code> -&gt; 删除所有 Certificates 凭证</p>
  </li>
  <li>
    <p>Finder -&gt; Go -&gt; Go to -&gt; <code class="language-plaintext highlighter-rouge">~/Library/MobileDevice/Provisioning\ Profiles</code> -&gt; 删除所有 Profiles 描述档</p>
  </li>
  <li>
    <p>重新拉取凭证</p>
  </li>
  <li>
    <p>重开 Xcode 应该就正常了</p>
  </li>
</ol>

<p><strong>No signing certificate “iOS Distribution” found / No signing certificate “iOS Development” found.:</strong></p>

<pre><code class="language-vbnet">No "iOS Distribution" signing certificate matching team ID "" with a private key was found.
No "iOS Development" signing certificate matching team ID "" with a private key was found.
</code></pre>

<p><strong>原因:</strong></p>

<ul>
  <li>
    <p>缺少 iOS Distribution/iOS Development Certificate 凭证</p>
  </li>
  <li>
    <p>有 iOS Distribution/iOS Development Certificate 凭证 <strong>但是 没有对应的 Private Key 私钥</strong></p>
  </li>
</ul>

<p><strong>解决办法:</strong></p>

<ul>
  <li>
    <p>删除 Keychain 里的所有旧 Certificates 凭证、Profiles 描述档</p>
  </li>
  <li>
    <p>在当初创建 Certificate 的电脑 Keychain 上找到该凭证，汇出成 <code class="language-plaintext highlighter-rouge">.p12</code> 格式，在有问题电脑上安装。</p>
  </li>
  <li>
    <p>到 <a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Certificates, Identifiers &amp; Profiles</a> Revoke 旧的 Certificate，重新产生
(放心，不影响线上版 App；只影响开发与打包阶段)</p>
  </li>
</ul>

<p><strong>Provisioning profile “” doesn’t include signing certificate “Apple Development: XXX”. / Provisioning profile “” doesn’t include signing certificate “Apple Distribution: XXX”.:</strong></p>

<p><strong>原因:</strong></p>

<ul>
  <li>目前选择的 Provisioning profile 描述档跟当前的 Certificate 没有对应关系</li>
</ul>

<p><strong>解决办法:</strong></p>

<ul>
  <li>
    <p>删除 Keychain 里的所有旧 Certificates 凭证、Profiles 描述档</p>
  </li>
  <li>
    <p>到 <a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Certificates, Identifiers &amp; Profiles</a> Profiles 确认描述档有勾选对应凭证或重产 Profile 使用</p>
  </li>
</ul>

<p><strong>No profile for team ‘’ matching ‘’ found: Xcode couldn’t find any provisioning profiles matching ‘’.:</strong></p>

<p><strong>原因:</strong></p>

<ul>
  <li>找不到指定的 Provisioning profile 描述档</li>
</ul>

<p><strong>解决办法:</strong></p>

<ul>
  <li>
    <p>删除 Keychain 里的所有旧 Certificates 凭证、Profiles 描述档</p>
  </li>
  <li>
    <p>到 <a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Certificates, Identifiers &amp; Profiles</a> Profiles 下载对应的 Profile 使用</p>
  </li>
</ul>

<p><strong>Provisioning profile “” has app ID “”, which does not match the bundle ID “”. / Provisioning profile doesn’t match the bundle identifier:</strong></p>

<p><strong>原因:</strong></p>

<ul>
  <li>Provisioning profile 不包含目前的 Bundle Identifier</li>
</ul>

<p><strong>解决办法:</strong></p>

<ul>
  <li>
    <p>删除 Keychain 里的所有旧 Certificates 凭证、Profiles 描述档</p>
  </li>
  <li>
    <p>到 <a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Certificates, Identifiers &amp; Profiles</a> Identifiers 确认 Bundle Identifier 已注册</p>
  </li>
  <li>
    <p>到 <a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Certificates, Identifiers &amp; Profiles</a> Profiles 下载对应的 Profile 使用</p>
  </li>
</ul>

<p><strong>Provisioning profile “” doesn’t include the currently selected device “” (identifier ) .:</strong></p>

<p><strong>原因:</strong></p>

<ul>
  <li>Provisioning profile 不包含选择的实体机 Device Identifier</li>
</ul>

<p><strong>解决办法:</strong></p>

<ul>
  <li>
    <p>到 <a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Certificates, Identifiers &amp; Profiles</a> Devices 确认实体机的 Identifier 已注册</p>
  </li>
  <li>
    <p>到 <a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Certificates, Identifiers &amp; Profiles</a> Profiles 对应的 Profile 该 实体机 有勾选启用。</p>
  </li>
  <li>
    <p>重新下载 Profile 使用</p>
  </li>
</ul>

<p><strong>Could not create another Development/Distribution certificate, reached the maximum number of available Development/Distribution certificates. :</strong></p>

<p><strong>原因:</strong></p>

<p>代表建立的 Development/Distribution Certificate 已达上限数量。</p>

<p><strong>解决办法:</strong></p>

<ul>
  <li>到 <a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Certificates, Identifiers &amp; Profiles</a> 删除不使用的凭证。</li>
</ul>

<p><strong>Xcode 凭证正确且可以正常打包但是用 CLI (Fastlane) 执行打包命令会出现签名错误:</strong></p>

<p><strong>原因:</strong></p>

<p>这边还有踩到另一个雷，就是我手贱把专案放在 iCloud 同步目录下，不知道为何Fastlane 会一直出现凭证问题 (疑似 keychain 存取有问题)。</p>

<p><strong>解决办法:</strong></p>

<p>移出 iCloud 同步目录即可。</p>

<h3 id="日常使用的问题场景">日常使用的问题场景</h3>

<h4 id="development-certificate">Development Certificate</h4>

<p><img src="/assets/823ac523ccc8/1*uNICvLN0a9gdGAzi4EZ24g.webp" alt="" loading="lazy" decoding="async" width="1693" height="1029" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjkzIiBoZWlnaHQ9IjEwMjkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/823ac523ccc8/1*uNICvLN0a9gdGAzi4EZ24g.png" /></p>

<ul>
  <li>
    <p>在导入 Match 统一管理凭证之前，每位开发者都会建立自己的 <code class="language-plaintext highlighter-rouge">Development Certificate</code> 和 <code class="language-plaintext highlighter-rouge">Development Profile</code> ；假设组织内有 1,000+ 位开发者，在 <a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Certificates, Identifiers &amp; Profiles, Devices</a> 后台会非常的混乱可怕。</p>
  </li>
  <li>
    <p>如果有外包团队，只负责开发工作，还是需要把他加入到 Apple Developer Program 后台，让他产自己的开发凭证跟 Profile。</p>
  </li>
</ul>

<h4 id="distribution-certificate">Distribution Certificate</h4>

<p><img src="/assets/823ac523ccc8/1*1JKlvoO8d89dlcpz2mJvjg.webp" alt="" loading="lazy" decoding="async" width="1373" height="1264" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzczIiBoZWlnaHQ9IjEyNjQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/823ac523ccc8/1*1JKlvoO8d89dlcpz2mJvjg.png" /></p>

<ul>
  <li>
    <p>Distribution Certificate 是 by Team 建立，因此每个开发者计划的 Team 只能建立有限数量的发行凭证。</p>
  </li>
  <li>
    <p>常见做法是由一位工程师建立产生 Distribution Certificate 再汇出 .p12 档案给其他需要上架的开发者或是放到 CI/CD 机器上使用。</p>
  </li>
  <li>
    <p>团队大、App 数量多时要寄来寄去的会很麻烦，而且 <strong>每年都要更新一次</strong></p>
  </li>
  <li>
    <p><strong>打包 Ad Hoc 时，当有新装置注册；所有人、CI/CD 都需要重新下载 Profile 才能让新装置生效。</strong></p>
  </li>
</ul>

<h3 id="fastlane-match"><a href="https://docs.fastlane.tools/actions/match/" target="_blank">Fastlane Match</a></h3>

<p>基于以上问题我们希望能有一个平台帮我们代为管理所有跟凭证有关的事物，所有开发者跟 CI/CD 服务都是统一对这个平台拉取、更新资料，这个平台的储存必须安全，这就是 — <a href="https://docs.fastlane.tools/actions/match/" target="_blank">Fastlane Match</a> 。</p>

<blockquote>
  <p><em>Easily sync your certificates and profiles across your team</em></p>
</blockquote>

<blockquote>
  <p><em>A new approach to iOS and macOS code signing: Share one code signing identity across your development team to simplify your codesigning setup and prevent code signing issues.</em></p>
</blockquote>

<blockquote>
  <p><em>match is the implementation of the <a href="https://codesigning.guide/" target="_blank">codesigning.guide concept</a> . match creates all required certificates &amp; provisioning profiles and stores them in a separate git repository, Google Cloud, or Amazon S3. Every team member with access to the selected storage can use those credentials for code signing. match also automatically repairs broken and expired credentials. It’s the easiest way to share signing credentials across teams</em></p>
</blockquote>

<p><img src="/assets/823ac523ccc8/1*UEL7Abx3PFrYbAc2yVlq8A.webp" alt="" loading="lazy" decoding="async" width="1200" height="495" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQ5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/823ac523ccc8/1*UEL7Abx3PFrYbAc2yVlq8A.png" /></p>

<p><strong>Fastlane Match：</strong></p>

<ul>
  <li>
    <p>跟 App Store Connect 做交互 (透过 App Store Connect API or Apple Developer Login Session)，产生或是更新凭证</p>
  </li>
  <li>
    <p>把凭证结果 ( <code class="language-plaintext highlighter-rouge">.mobileprovision</code> Profiles, <code class="language-plaintext highlighter-rouge">.p12</code> Certificate, <code class="language-plaintext highlighter-rouge">.cer</code> Certificate) 三个档案加密上传到 Git Repo (也可以用其他 Storage)
<code class="language-plaintext highlighter-rouge">.cer</code> Certificate 也会独立存，因为这样才能知道凭证是否有效</p>
  </li>
  <li>
    <p>如果要细分权限可以分两个 Repos，一个管理 Development 凭证、一个管理 Distribution 凭证。</p>
  </li>
</ul>

<p><a href="https://docs.fastlane.tools/actions/match/" target="_blank"><strong>Folder structure:</strong></a></p>

<ul>
  <li>
    <p>The <code class="language-plaintext highlighter-rouge">certs</code> folder contains all certificates with their private keys</p>
  </li>
  <li>
    <p>The <code class="language-plaintext highlighter-rouge">profiles</code> folder contains all provisioning profiles</p>
  </li>
</ul>

<p><img src="/assets/823ac523ccc8/1*mStp0t3Ty3xGTKvbiBGtqw.webp" alt="&lt;https://docs.fastlane.tools/actions/match/&gt;" loading="lazy" decoding="async" width="683" height="508" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2ODMiIGhlaWdodD0iNTA4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/823ac523ccc8/1*mStp0t3Ty3xGTKvbiBGtqw.png" /></p>

<p><a href="https://docs.fastlane.tools/actions/match/" target="_blank">https://docs.fastlane.tools/actions/match/</a></p>

<p>加密算法： <a href="https://github.com/fastlane/fastlane/blob/master/match/lib/match/encryption/encryption.rb" target="_blank">AES-256-GCM</a></p>

<p><strong>开发者、CI/CD 服务：</strong></p>

<ul>
  <li>
    <p>统一使用 Fastlane match 指令操作凭证。</p>
  </li>
  <li>
    <p>Fastlane Match 会优先拉回 Git Repo 的凭证档案、解密回来使用，如果发现过期或是无法使用，有权限(Create/Write)的情况下会自动重新产生并 Push 回去 Repo；若只有 Read 权限则报错。</p>
  </li>
</ul>

<p><strong>Create/Write：</strong></p>

<ul>
  <li>
    <p>只有负责管理凭证的人可以产生/更新、Push 上传凭证</p>
  </li>
  <li>
    <p><strong>重要的 Distribution Certificate 最好放在独立 Repo 且只有 CI/CD 服务或管理者可以使用</strong></p>
  </li>
</ul>

<p><strong>Read:</strong></p>

<ul>
  <li>
    <p>其他开发者、CI/CD 服务都 <strong>只有读取</strong> Pull 凭证权限</p>
  </li>
  <li>
    <p>CI/CD 服务会在每次执行任务前拉取最新凭证</p>
  </li>
  <li>
    <p>所有人共用同一张 Development &amp; Distribution Certificate</p>
  </li>
  <li>
    <p>人员异动后会失去 Match Repo 权限，可以 Revoke 旧的凭证重新产生，其他人在重新 Pull 就好(如果有整合到 make project script 那更无痛)</p>
  </li>
</ul>

<h3 id="fastlane-match-设定与使用">Fastlane Match 设定与使用</h3>

<p>我们以 Git Storage 为例，所有凭证。</p>

<p><strong>1.建立一个空的储存凭证的 Git Private Match Repo</strong>
虽然所有 Certificates, Profiles 都会加密储存，但还是要设定好该 Repo 的存取权限。</p>

<p>2.确认本地有设定好 Git SSH 存取权限，可以使用 <code class="language-plaintext highlighter-rouge">git clone git@github.com:xxx/certificates.git</code></p>

<blockquote>
  <p><em>这边建议 <strong>统一都使用 SSH Git Clone Repo</strong> ，因为 CI/CD 也会使用相同的方式。</em></p>
</blockquote>

<blockquote>
  <p><em>如果执行 fastlane match 一直卡在 <code class="language-plaintext highlighter-rouge">If cloning the repo takes too long, you can use the </code>clone_branch_directly<code class="language-plaintext highlighter-rouge"> option in match.</code> 多半就是遇到 SSH 权限问题。</em></p>
</blockquote>

<ol>
  <li>在专案目录执行 <code class="language-plaintext highlighter-rouge">bundle exec fastlane match init</code> 完成设定</li>
</ol>

<div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="mi">21</span><span class="p">:</span><span class="mi">54</span><span class="p">:</span><span class="mi">32</span><span class="p">]:</span> <span class="n">fastlane</span> <span class="n">match</span> <span class="n">supports</span> <span class="n">multiple</span> <span class="n">storage</span> <span class="n">modes</span><span class="p">,</span> <span class="n">please</span> <span class="nb">select</span> <span class="n">the</span> <span class="n">one</span> <span class="n">you</span> <span class="n">want</span> <span class="n">to</span> <span class="n">use</span><span class="p">:</span>
<span class="mi">1</span><span class="p">.</span> <span class="n">git</span>
<span class="mi">2</span><span class="p">.</span> <span class="n">google_cloud</span>
<span class="mi">3</span><span class="p">.</span> <span class="n">s3</span>
<span class="mi">4</span><span class="p">.</span> <span class="n">gitlab_secure_files</span>
<span class="o">#</span> <span class="err">输入</span> <span class="mi">1</span> <span class="err">用</span> <span class="n">git</span>
<span class="err">?</span>   <span class="mi">1</span>

<span class="p">[</span><span class="mi">22</span><span class="p">:</span><span class="mi">04</span><span class="p">:</span><span class="mi">40</span><span class="p">]:</span> <span class="n">Please</span> <span class="n">create</span> <span class="n">a</span> <span class="n">new</span><span class="p">,</span> <span class="n">private</span> <span class="n">git</span> <span class="n">repository</span> <span class="n">to</span> <span class="n">store</span> <span class="n">the</span> <span class="n">certificates</span> <span class="ow">and</span> <span class="n">profiles</span> <span class="n">there</span>
<span class="p">[</span><span class="mi">22</span><span class="p">:</span><span class="mi">04</span><span class="p">:</span><span class="mi">40</span><span class="p">]:</span> <span class="n">URL</span> <span class="n">of</span> <span class="n">the</span> <span class="n">Git</span> <span class="n">Repo</span><span class="p">:</span> <span class="n">git</span><span class="err">@</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="p">:</span><span class="n">xxx</span><span class="o">/</span><span class="n">certificates</span><span class="p">.</span><span class="n">git</span>
<span class="o">#</span> <span class="err">输入你建立的</span> <span class="n">Git</span> <span class="n">Private</span> <span class="n">Match</span> <span class="n">Repo</span> <span class="n">SSH</span> <span class="n">URL</span>

<span class="p">[</span><span class="mi">22</span><span class="p">:</span><span class="mi">04</span><span class="p">:</span><span class="mi">47</span><span class="p">]:</span> <span class="n">Successfully</span> <span class="n">created</span> <span class="s1">'./fastlane/Matchfile'</span><span class="p">.</span> <span class="n">You</span> <span class="n">can</span> <span class="n">open</span> <span class="n">the</span> <span class="n">file</span> <span class="n">using</span> <span class="n">a</span> <span class="n">code</span> <span class="n">editor</span><span class="p">.</span>
<span class="p">[</span><span class="mi">22</span><span class="p">:</span><span class="mi">04</span><span class="p">:</span><span class="mi">47</span><span class="p">]:</span> <span class="n">You</span> <span class="n">can</span> <span class="n">now</span> <span class="n">run</span> <span class="err">`</span><span class="n">fastlane</span> <span class="n">match</span> <span class="n">development</span><span class="err">`</span><span class="p">,</span> <span class="err">`</span><span class="n">fastlane</span> <span class="n">match</span> <span class="n">adhoc</span><span class="err">`</span><span class="p">,</span> <span class="err">`</span><span class="n">fastlane</span> <span class="n">match</span> <span class="n">enterprise</span><span class="err">`</span> <span class="ow">and</span> <span class="err">`</span><span class="n">fastlane</span> <span class="n">match</span> <span class="n">appstore</span><span class="err">`</span>
<span class="p">[</span><span class="mi">22</span><span class="p">:</span><span class="mi">04</span><span class="p">:</span><span class="mi">47</span><span class="p">]:</span> <span class="n">On</span> <span class="n">the</span> <span class="n">first</span> <span class="n">run</span> <span class="k">for</span> <span class="n">each</span> <span class="n">environment</span> <span class="n">it</span> <span class="n">will</span> <span class="n">create</span> <span class="n">the</span> <span class="n">provisioning</span> <span class="n">profiles</span> <span class="ow">and</span>
<span class="p">[</span><span class="mi">22</span><span class="p">:</span><span class="mi">04</span><span class="p">:</span><span class="mi">47</span><span class="p">]:</span> <span class="n">certificates</span> <span class="k">for</span> <span class="n">you</span><span class="p">.</span> <span class="n">From</span> <span class="k">then</span> <span class="n">on</span><span class="p">,</span> <span class="n">it</span> <span class="n">will</span> <span class="n">automatically</span> <span class="n">import</span> <span class="n">the</span> <span class="n">existing</span> <span class="n">profiles</span><span class="p">.</span>
<span class="p">[</span><span class="mi">22</span><span class="p">:</span><span class="mi">04</span><span class="p">:</span><span class="mi">47</span><span class="p">]:</span> <span class="n">For</span> <span class="n">more</span> <span class="n">information</span> <span class="n">visit</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">docs</span><span class="p">.</span><span class="n">fastlane</span><span class="p">.</span><span class="n">tools</span><span class="o">/</span><span class="n">actions</span><span class="o">/</span><span class="n">match</span><span class="o">/</span>
</code></pre></div></div>

<p>4.完成后会产生一个 <strong><code class="language-plaintext highlighter-rouge">fastlane/Matchfile</code> :</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 你的 Git Private Match Repo SSH URL</span>
git_url<span class="o">(</span><span class="s2">"git@github.com:xxxx/certificates.git"</span><span class="o">)</span>

storage_mode<span class="o">(</span><span class="s2">"git"</span><span class="o">)</span>

<span class="nb">type</span><span class="o">(</span><span class="s2">"development"</span><span class="o">)</span> <span class="c"># The default type, can be: appstore, adhoc, enterprise or development</span>

<span class="c"># app_identifier(["tools.fastlane.app", "tools.fastlane.app2"])</span>
<span class="c"># username("user@fastlane.tools") # Your Apple Developer Portal username</span>

<span class="c"># For all available options run `fastlane match --help`</span>
<span class="c"># Remove the # in the beginning of the line to enable the other options</span>

<span class="c"># The docs are available on https://docs.fastlane.tools/actions/match</span>
</code></pre></div></div>

<p><strong>5. 产生 <a href="https://developer.apple.com/documentation/appstoreconnectapi/creating-api-keys-for-app-store-connect-api" target="_blank">App Store Connect API .p8 Key</a></strong> ， <strong>统一使用 API Key 产生凭证:</strong></p>

<p><img src="/assets/823ac523ccc8/1*RFhS_XtZ3TfIJBAeoE-laA.webp" alt="" loading="lazy" decoding="async" width="1181" height="349" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTgxIiBoZWlnaHQ9IjM0OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/823ac523ccc8/1*RFhS_XtZ3TfIJBAeoE-laA.png" /></p>

<blockquote>
  <p><em>⚠️️️️ <a href="https://developer.apple.com/documentation/appstoreconnectapi/creating-api-keys-for-app-store-connect-api" target="_blank"><strong>App Store Connect API .p8 Key</strong></a> <strong>的权限很大</strong> ，除了可以管理凭证、也可以管理 App 的上架、送审，还有后台使用者跟评论、财务数据报表。</em></p>
</blockquote>

<blockquote>
  <p><em>要不要进到团队的 .git 让大家都能存取，可依照团队情境自行决定。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>比较高风控的方式是只有负责管理的人跟加密储存在 CI/CD 上使用(文后会介绍)。</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>这边为了 Demo 方便直接放进 fastlane 目录下存取。</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>另外本篇的 Fastlane Script 为了方便展示，不考虑重复程式码与程式结构。</em></strong></p>
</blockquote>

<h4 id="凭证管理">凭证管理</h4>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>platform :ios <span class="k">do
  </span>lane :match_development <span class="k">do</span> <span class="se">\\</span>|options<span class="se">\\</span>|
    <span class="c"># 换成你的 App Identifier ID</span>
    app_identifier <span class="o">=</span> <span class="s2">"li.zhgchg.myApp"</span>

    <span class="nb">type</span> <span class="o">=</span> options.fetch<span class="o">(</span>:type, <span class="s2">"development"</span><span class="o">)</span>
    isRead <span class="o">=</span> options.fetch<span class="o">(</span>:isRead, <span class="nb">true</span><span class="o">)</span>
    <span class="k">if </span>isRead 
      <span class="nb">readonly</span> <span class="o">=</span> <span class="nb">true
      </span>force <span class="o">=</span> <span class="nb">false
    </span><span class="k">else
      </span><span class="nb">readonly</span> <span class="o">=</span> <span class="nb">false
      </span>force <span class="o">=</span> <span class="nb">true</span>

      <span class="c"># 需要 App Store Connect API Key 才有权限去 Apple 后台管理凭证</span>
      <span class="c"># 假设 App Store Connect API .p8 Key 在 ./fastlane/ 目录内</span>
      app_store_connect_api_key<span class="o">(</span>
        key_id: <span class="s2">"XXXXXX"</span>,
        issuer_id: <span class="s2">"XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX"</span>,
        key_filepath: <span class="s2">"./fastlane/AuthKey_XXXXXX.p8"</span>,
      <span class="o">)</span>
    end

    <span class="c"># 拉取 app_identifier 的 Development 凭证</span>
    match<span class="o">(</span>
      <span class="nb">type</span>: <span class="nb">type</span>,
      app_identifier: app_identifier, 
      <span class="nb">readonly</span>: <span class="nb">readonly</span>, <span class="c"># 能否从有需要时，更新、上传 cert / profile</span>
      force: force <span class="c"># 要不要无条件重建 provisioning profile</span>
    <span class="o">)</span>
  end
end
</code></pre></div></div>

<p><strong>建立 Development Certificate &amp; Profile 并上传到 Match Repo:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle exec fastlane match_development type:development isRead:false
</code></pre></div></div>

<ul>
  <li>没有错误就代表 Development Certificate &amp; Profile 产生、安装成功并同步 Push 上传到 Match Repo 成功。</li>
</ul>

<p><strong>首次建立会需要你设定 <code class="language-plaintext highlighter-rouge">Passphrase</code> ：</strong></p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="ss">23:29:12</span><span class="p">]:</span> <span class="sx">Enter</span> the passphrase that should be used to encrypt/decrypt your certificates
<span class="p">[</span><span class="ss">23:29:12</span><span class="p">]:</span> <span class="sx">This</span> passphrase is specific per repository and will be stored in your local keychain
<span class="p">[</span><span class="ss">23:29:12</span><span class="p">]:</span> <span class="sx">Make</span> sure to remember the password, as you'll need it when you run match on a different machine
<span class="p">[</span><span class="ss">23:29:12</span><span class="p">]:</span> <span class="sx">Passphrase</span> for Match storage:
</code></pre></div></div>

<ul>
  <li>
    <p>这个值就是用来加密你的所有 Match Repo 上的档案的会需要用到的参考 (passphrase + random salt)</p>
  </li>
  <li>
    <p>建议产生一个 <a href="https://www.random.org/strings/?num=1&amp;len=32&amp;digits=on&amp;upperalpha=on&amp;loweralpha=on&amp;unique=on&amp;format=html&amp;rnd=new" target="_blank">随机字串</a> 设定并记录下来</p>
  </li>
  <li>
    <p>日后更新或是其他人拉取 Match Repo 凭证都需要输入这个 字串 解密回原始档案。</p>
  </li>
</ul>

<p><strong>团队其他成员统一从 Match Repo Pull 拉取 Development Certificate &amp; Profile:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle <span class="nb">exec </span>fastlane match_development <span class="nb">type</span>:development
</code></pre></div></div>

<p><strong>首次使用会询问你的登入密码 (login keychain)，因为要把凭证安装到 keychain 中，输入两次确认即可:</strong></p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="ss">16:52:59</span><span class="p">]:</span> <span class="sx">Installing</span> certificate...
<span class="p">[</span><span class="ss">16:53:00</span><span class="p">]:</span> <span class="sx">There</span> are no local code signing identities found.
You can run security find-identity -v -p codesigning to get this output.
This Stack Overflow thread has more information: https://stackoverflow.com/q/35390072/774.
(Check in Keychain Access for an expired WWDR certificate: https://stackoverflow.com/a/35409835/774 has more info.)
<span class="p">[</span><span class="ss">16:53:00</span><span class="p">]:</span> <span class="sx">Enter</span> the password for /Users/zhgchgli/Library/Keychains/login.keychain-db
<span class="p">[</span><span class="ss">16:53:00</span><span class="p">]:</span> <span class="sx">This</span> passphrase will be stored in your local keychain with the name fastlane_keychain_login and used in future runs
<span class="p">[</span><span class="ss">16:53:00</span><span class="p">]:</span> <span class="sx">This</span> prompt can be avoided by specifying the 'keychain_password' option or 'MATCH_KEYCHAIN_PASSWORD' environment variable
<span class="p">[</span><span class="ss">16:53:00</span><span class="p">]:</span> <span class="sx">Password</span> for login keychain: <span class="ge">********</span>
<span class="p">[</span><span class="ss">16:53:24</span><span class="p">]:</span> <span class="sx">Type</span> password for login keychain again: <span class="ge">********</span>
</code></pre></div></div>

<p><strong>如果 Match Development 拉完凭证，但 Xcode 一直显示有错误或无效:</strong></p>

<p>可参考前文提到的常见错误，多半是有旧的脏凭证，清除所有凭证再重新拉取，应该就可以了。</p>

<p>—</p>

<p><strong>建立 AdHoc Distribution Certificate &amp; Profile 并上传到 Match Repo:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle <span class="nb">exec </span>fastlane match_development <span class="nb">type</span>:adhoc isRead:false
</code></pre></div></div>

<p><strong>建立 AppStore Distribution Certificate &amp; Profile 并上传到 Match Repo:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle <span class="nb">exec </span>fastlane match_development <span class="nb">type</span>:appstore isRead:false
</code></pre></div></div>

<p><strong>CI/CD 服务统一从 Match Repo Pull 拉取 Distribution Certificate &amp; Profile ( <code class="language-plaintext highlighter-rouge">isRead:true</code> )，然后再执行打包发布任务。</strong></p>

<h4 id="注册新装置">注册新装置</h4>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">platform</span> <span class="o">:</span><span class="n">ios</span> <span class="k">do</span>  
  <span class="n">desc</span> <span class="s2">"Register a new device and refresh profiles"</span>
  <span class="n">lane</span> <span class="o">:</span><span class="n">registerDevice</span> <span class="k">do</span> <span class="err">\\</span><span class="o">|</span><span class="n">options</span><span class="err">\\</span><span class="o">|</span>
    <span class="c1"># 换成你的 App Identifier ID</span>
    <span class="n">app_identifier</span> <span class="o">=</span> <span class="s2">"li.zhgchg.myApp"</span>

    <span class="c1"># 需要 App Store Connect API Key 才有权限去 Apple 后台管理凭证</span>
    <span class="c1"># 假设 App Store Connect API .p8 Key 在 ./fastlane/ 目录内</span>
    <span class="nf">app_store_connect_api_key</span><span class="p">(</span>
      <span class="n">key_id</span><span class="o">:</span> <span class="s2">"XXXXXX"</span><span class="p">,</span>
      <span class="n">issuer_id</span><span class="o">:</span> <span class="s2">"XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX"</span><span class="p">,</span>
      <span class="n">key_filepath</span><span class="o">:</span> <span class="s2">"./fastlane/AuthKey_XXXXXX.p8"</span><span class="p">,</span>
    <span class="p">)</span>
    <span class="c1"># Input: UDID and device name</span>
    <span class="n">udid</span> <span class="o">=</span> <span class="n">options</span><span class="p">[</span><span class="o">:</span><span class="n">udid</span><span class="p">]</span> <span class="err">\\</span><span class="o">|</span><span class="err">\\</span><span class="o">|</span> <span class="no">UI</span><span class="mf">.</span><span class="nf">input</span><span class="p">(</span><span class="s2">"Enter device UDID:"</span><span class="p">)</span>
    <span class="n">device_name</span> <span class="o">=</span> <span class="n">options</span><span class="p">[</span><span class="o">:</span><span class="n">name</span><span class="p">]</span> <span class="err">\\</span><span class="o">|</span><span class="err">\\</span><span class="o">|</span> <span class="no">UI</span><span class="mf">.</span><span class="nf">input</span><span class="p">(</span><span class="s2">"Enter device name:"</span><span class="p">)</span>
    <span class="no">UI</span><span class="mf">.</span><span class="nf">message</span><span class="p">(</span><span class="s2">"📱 Registering device #</span><span class="si">{</span><span class="nv">device_name</span><span class="si">}</span><span class="s2"> (#</span><span class="si">{</span><span class="nv">udid</span><span class="si">}</span><span class="s2">)"</span><span class="p">)</span>
    <span class="nf">register_device</span><span class="p">(</span>
      <span class="n">name</span><span class="o">:</span> <span class="n">device_name</span><span class="p">,</span>
      <span class="n">udid</span><span class="o">:</span> <span class="n">udid</span><span class="p">,</span>
      <span class="n">platform</span><span class="o">:</span> <span class="s1">'ios'</span>
    <span class="p">)</span>

    <span class="c1"># 更新 app_identifier 的 Development 凭证</span>
    <span class="k">match</span><span class="p">(</span>
      <span class="n">type</span><span class="o">:</span> <span class="s2">"development"</span><span class="p">,</span>
      <span class="n">app_identifier</span><span class="o">:</span> <span class="n">app_identifier</span><span class="p">,</span> 
      <span class="k">readonly</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span> <span class="c1"># 如果有需要，更新、上传 cert / profile</span>
      <span class="n">force_for_new_devices</span><span class="o">:</span> <span class="kc">true</span> <span class="c1"># 如果为新装置则重建 provisioning profile</span>
    <span class="p">)</span>

    <span class="c1"># 更新 app_identifier 的 AdHoc 凭证</span>
    <span class="k">match</span><span class="p">(</span>
      <span class="n">type</span><span class="o">:</span> <span class="s2">"adhoc"</span><span class="p">,</span>
      <span class="n">app_identifier</span><span class="o">:</span> <span class="n">app_identifier</span><span class="p">,</span> 
      <span class="k">readonly</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span> <span class="c1"># 如果有需要，更新、上传 cert / profile</span>
      <span class="n">force_for_new_devices</span><span class="o">:</span> <span class="kc">true</span> <span class="c1"># 如果为新装置则重建 provisioning profile</span>
    <span class="p">)</span>
  <span class="n">end</span>
<span class="n">end</span>
</code></pre></div></div>

<p>注册完之后其他开发者或 CI/CD 服务再从 Match Repo 拉 Profile (Development or AdHoc) 就会包含新的装置了。</p>

<h3 id="fastlane-match-x-cicd-工作流程整合">Fastlane Match x CI/CD 工作流程整合</h3>

<p>大致介绍完 Fastlane Match 怎么产生 Push / 拉取 Pull 凭证后，再来要讲怎么整合进 CI/CD 流程。</p>

<h4 id="问题1--怎么-clone-private-match-repo">问题1 — 怎么 Clone Private Match Repo</h4>

<p>第一个最常见的问题就是在 CI/CD 上怎么 Clone Private Match Repo 专案，在本机开发上因为我们统一都使用 ssh git clone 并且是用我们自己帐号的 ssh key 所以不会遇到问题；但是 CI/CD 上没有这个 key，当然也可以用个人的 key 但是很不保险。</p>

<p><strong>GitHub — Repo Deploy Key:</strong></p>

<p>1.我们先在本地产生 private/public key: <code class="language-plaintext highlighter-rouge">ssh-keygen -t rsa -b 4096 -f ./id_rsa</code> ( <strong>不要输入 <code class="language-plaintext highlighter-rouge">passphrase</code></strong> )</p>

<p>2.到 <strong>Match Private Repo</strong> -&gt; Settings -&gt; Security -&gt; Deploy keys -&gt; Add deploy key:</p>

<p><img src="/assets/823ac523ccc8/1*nzo-oPRi7DDxPvtJIWBspw.webp" alt="" loading="lazy" decoding="async" width="1149" height="774" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTQ5IiBoZWlnaHQ9Ijc3NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/823ac523ccc8/1*nzo-oPRi7DDxPvtJIWBspw.png" /></p>

<ol>
  <li>用文字编辑器打开「 <code class="language-plaintext highlighter-rouge">id_rsa.pub</code> 」复制内容贴上到 Key -&gt;「Add key」</li>
</ol>

<p><img src="/assets/823ac523ccc8/1*mbwtijzM-2iAzfgFiT32rw.webp" alt="" loading="lazy" decoding="async" width="1200" height="626" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjYyNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/823ac523ccc8/1*mbwtijzM-2iAzfgFiT32rw.png" /></p>

<ol>
  <li>回到主要 Repo -&gt; Settings -&gt; Security -&gt; Secrets and variables</li>
</ol>

<p><img src="/assets/823ac523ccc8/1*jvY8Yg6tI85LNKHgIaHVVQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="869" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/823ac523ccc8/1*jvY8Yg6tI85LNKHgIaHVVQ.png" /></p>

<ol>
  <li>新增 SSH Private Key Content 到 Secret:</li>
</ol>

<p><img src="/assets/823ac523ccc8/1*8WiPfOz21rJWD6yiMwP3aw.webp" alt="" loading="lazy" decoding="async" width="1607" height="923" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjA3IiBoZWlnaHQ9IjkyMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/823ac523ccc8/1*8WiPfOz21rJWD6yiMwP3aw.png" /></p>

<ul>
  <li>Name: <code class="language-plaintext highlighter-rouge">MATCH_REPO_DEPLOY_PRIVATE_KEY</code></li>
</ul>

<ol>
  <li>回到主要 Repo 的 GitHub Actions 设定 SSH Key:</li>
</ol>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">CI - Deploy</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span> <span class="pi">[</span> <span class="nv">main</span> <span class="pi">]</span>
  <span class="na">pull_request</span><span class="pi">:</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">build</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout current repo (Repo A)</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Setup SSH for Deploy Key</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">mkdir -p ~/.ssh</span>
          <span class="s">echo "${{ secrets.MATCH_REPO_DEPLOY_PRIVATE_KEY }}" &gt; ~/.ssh/id_ed25519</span>
          <span class="s">chmod 600 ~/.ssh/id_ed25519</span>
          <span class="s">ssh-keyscan github.com &gt;&gt; ~/.ssh/known_hosts</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Test Clone</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">git clone git@github.com:xxxx/match-certificates.git</span>
<span class="c1"># Success!</span>
<span class="c1"># .. do deploy job...</span>
</code></pre></div></div>

<ol>
  <li>设定成功!</li>
</ol>

<h4 id="问题2-app-store-connect-api-p8-key-安全存放使用">问题2— App Store Connect API .p8 Key 安全存放使用</h4>

<p>因为 GitHub Actions 不能存档案，所以只能先存成字串，然后写入档案。</p>

<ol>
  <li>
    <p>同问题 1 步骤，在主要 Repo 新增一个 <code class="language-plaintext highlighter-rouge">APP_STORE_CONNECT_API_KEY_CONTENT</code> Secret</p>
  </li>
  <li>
    <p>用文字编辑器打开 <code class="language-plaintext highlighter-rouge">AuthKey_XXXXXX.p8</code> 复制并贴上内容</p>
  </li>
  <li>
    <p><strong>主要 Repo 的 GitHub Actions 加上一个步骤读出内容写入档案:</strong></p>
  </li>
</ol>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">CI - Deploy</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span> <span class="pi">[</span> <span class="nv">main</span> <span class="pi">]</span>
  <span class="na">pull_request</span><span class="pi">:</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">build</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout current repo (Repo A)</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Setup SSH for Deploy Key</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">mkdir -p ~/.ssh</span>
          <span class="s">echo "${{ secrets.MATCH_REPO_DEPLOY_PRIVATE_KEY }}" &gt; ~/.ssh/id_ed25519</span>
          <span class="s">chmod 600 ~/.ssh/id_ed25519</span>
          <span class="s">ssh-keyscan github.com &gt;&gt; ~/.ssh/known_hosts</span>  
      
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Write Secret Key to File</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">APP_STORE_CONNECT_API_KEY_CONTENT</span><span class="pi">:</span> <span class="s">${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s"># ensure fastlane directory exists</span>
          <span class="s">mkdir -p ./fastlane</span>
      
          <span class="s"># create file path</span>
          <span class="s">APP_STORE_CONNECT_API_KEY_PATH=./fastlane/AuthKey_XXXXXX.p8</span>
      
          <span class="s"># write content to file (keep newline)</span>
          <span class="s">echo "$APP_STORE_CONNECT_API_KEY_CONTENT" &gt; "$APP_STORE_CONNECT_API_KEY_PATH"</span>
      
          <span class="s"># (optional) restrict permissions</span>
          <span class="s">chmod 600 "$APP_STORE_CONNECT_API_KEY_PATH"</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy to Firebase</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">MATCH_PASSWORD</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">secrets.MATCH_PASSWORD</span><span class="nv"> </span><span class="s">}}"</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">bundle exec fastlane deploy_to_firebase</span>
</code></pre></div></div>

<h4 id="问题3--设定-private-match-repo-的-passphrase防止-match-时跳-prompt-中断">问题3 — 设定 Private Match Repo 的 Passphrase，防止 Match 时跳 Prompt 中断</h4>

<ol>
  <li>
    <p>同问题 1 步骤，在主要 Repo 新增 <code class="language-plaintext highlighter-rouge">MATCH_PASSWORD</code> 到 Secret</p>
  </li>
  <li>
    <p>内容输入你设定的 Fastlane Match Repo <code class="language-plaintext highlighter-rouge">Passphrase</code></p>
  </li>
  <li>
    <p><strong>主要 Repo 的 GitHub Actions 加上</strong> <code class="language-plaintext highlighter-rouge">env: secret.MATCH_PASSWORD</code> <strong>:</strong></p>
  </li>
</ol>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">CI - Deploy</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span> <span class="pi">[</span> <span class="nv">main</span> <span class="pi">]</span>
  <span class="na">pull_request</span><span class="pi">:</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">build</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout current repo (Repo A)</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Setup SSH for Deploy Key</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">mkdir -p ~/.ssh</span>
          <span class="s">echo "${{ secrets.MATCH_REPO_DEPLOY_PRIVATE_KEY }}" &gt; ~/.ssh/id_ed25519</span>
          <span class="s">chmod 600 ~/.ssh/id_ed25519</span>
          <span class="s">ssh-keyscan github.com &gt;&gt; ~/.ssh/known_hosts</span>  
      
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Write Secret Key to File</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">APP_STORE_CONNECT_API_KEY_CONTENT</span><span class="pi">:</span> <span class="s">${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s"># ensure fastlane directory exists</span>
          <span class="s">mkdir -p ./fastlane</span>
      
          <span class="s"># create file path</span>
          <span class="s">APP_STORE_CONNECT_API_KEY_PATH=./fastlane/AuthKey_XXXXXX.p8</span>
      
          <span class="s"># write content to file (keep newline)</span>
          <span class="s">echo "$APP_STORE_CONNECT_API_KEY_CONTENT" &gt; "$APP_STORE_CONNECT_API_KEY_PATH"</span>
      
          <span class="s"># (optional) restrict permissions</span>
          <span class="s">chmod 600 "$APP_STORE_CONNECT_API_KEY_PATH"</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy to Firebase</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">MATCH_PASSWORD</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">secrets.MATCH_PASSWORD</span><span class="nv"> </span><span class="s">}}"</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">bundle exec fastlane deploy_to_firebase</span>
</code></pre></div></div>

<h4 id="问题4--self-hosted-runner-上的-keychain-处理">问题4 — Self-hosted Runner 上的 Keychain 处理</h4>

<p>跟云端机器每次都是干净全新的不同，如果是用 Self-hosted Runner 我们可以在 Fastlane 指定 <code class="language-plaintext highlighter-rouge">derived_data_path</code> 、 <code class="language-plaintext highlighter-rouge">output_directory</code> 、 <code class="language-plaintext highlighter-rouge">buildlog_path</code> 、 <code class="language-plaintext highlighter-rouge">reinstall_app</code> 让每次执行的环境都是干净的；但是 Certificates, Profiles 是安装到系统的 Keychain 应用中，该如何处理？</p>

<p>其实 Fastlane 也帮我们考虑到了，可以在 Match 之前先建立一个干净的 Keychain:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">CI - Deploy</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span> <span class="pi">[</span> <span class="nv">main</span> <span class="pi">]</span>
  <span class="na">pull_request</span><span class="pi">:</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">build</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout current repo (Repo A)</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Setup SSH for Deploy Key</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">mkdir -p ~/.ssh</span>
          <span class="s">echo "${{ secrets.MATCH_REPO_DEPLOY_PRIVATE_KEY }}" &gt; ~/.ssh/id_ed25519</span>
          <span class="s">chmod 600 ~/.ssh/id_ed25519</span>
          <span class="s">ssh-keyscan github.com &gt;&gt; ~/.ssh/known_hosts</span>  
      
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Write Secret Key to File</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">APP_STORE_CONNECT_API_KEY_CONTENT</span><span class="pi">:</span> <span class="s">${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s"># ensure fastlane directory exists</span>
          <span class="s">mkdir -p ./fastlane</span>
      
          <span class="s"># create file path</span>
          <span class="s">APP_STORE_CONNECT_API_KEY_PATH=./fastlane/AuthKey_XXXXXX.p8</span>
      
          <span class="s"># write content to file (keep newline)</span>
          <span class="s">echo "$APP_STORE_CONNECT_API_KEY_CONTENT" &gt; "$APP_STORE_CONNECT_API_KEY_PATH"</span>
      
          <span class="s"># (optional) restrict permissions</span>
          <span class="s">chmod 600 "$APP_STORE_CONNECT_API_KEY_PATH"</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Create fastlane keychain</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">KEYCHAIN_NAME</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">runner.name</span><span class="nv"> </span><span class="s">}}"</span>
          <span class="na">MATCH_PASSWORD</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">secrets.MATCH_PASSWORD</span><span class="nv"> </span><span class="s">}}"</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">bundle exec fastlane run create_keychain \</span>
            <span class="s">name:"$KEYCHAIN_NAME" \</span>
            <span class="s">password:"$MATCH_PASSWORD" \</span>
            <span class="s">unlock:true \</span>
            <span class="s">timeout:0 \</span>
            <span class="s">lock_when_sleeps:false</span>
      
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy to Firebase</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">MATCH_PASSWORD</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">secrets.MATCH_PASSWORD</span><span class="nv"> </span><span class="s">}}"</span>
          <span class="na">KEYCHAIN_NAME</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">runner.name</span><span class="nv"> </span><span class="s">}}"</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">bundle exec fastlane deploy_to_firebase</span>

      <span class="c1"># 🔥 不管前面成功或失败，一定会执行</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Delete fastlane keychain</span>
        <span class="na">if</span><span class="pi">:</span> <span class="s">always()</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">KEYCHAIN_NAME</span><span class="pi">:</span> <span class="s">${{ runner.name }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">bundle exec fastlane run delete_keychain \</span>
            <span class="s">name:"$KEYCHAIN_NAME"</span>
</code></pre></div></div>

<ul>
  <li>
    <p>每个 Runner 同时只会执行一个，因此我们用 Runner Name 当成 Keychain Name，每个 Runner 都会有自己的 Keychain</p>
  </li>
  <li>
    <p>执行完毕，不管成功或失败都会删除</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">keychain_password</code> 我就没特别另外设定了，统一用 <code class="language-plaintext highlighter-rouge">MATCH_PASSWORD</code></p>
  </li>
</ul>

<p><code class="language-plaintext highlighter-rouge">Fastlane/Fastfile</code> 里的 match 方法多加上 keychain parameters:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#...</span>
    <span class="n">match</span><span class="p">(</span>
      <span class="ss">type: </span><span class="s2">"adhoc"</span><span class="p">,</span>
      <span class="ss">app_identifier: </span><span class="n">app_identifier</span><span class="p">,</span> 
      <span class="ss">readonly: </span><span class="kp">false</span><span class="p">,</span> <span class="c1"># 如果有需要，更新、上传 cert / profile</span>
      <span class="ss">force_for_new_devices: </span><span class="kp">true</span><span class="p">,</span> <span class="c1"># 如果为新装置则重建 provisioning profile</span>
      <span class="ss">keychain_name: </span><span class="no">ENV</span><span class="p">[</span><span class="s1">'KEYCHAIN_NAME'</span><span class="p">],</span> <span class="c1"># default value: nil</span>
      <span class="ss">keychain_password: </span><span class="no">ENV</span><span class="p">[</span><span class="s1">'MATCH_PASSWORD'</span><span class="p">]</span> <span class="c1"># default value: nil</span>
    <span class="p">)</span>
<span class="c1">#...</span>
</code></pre></div></div>

<p>这样 Match 在拉取凭证的时候就会改存到指定的 Keychain，而非共用的 login keychain。</p>

<h3 id="结语">结语</h3>

<p>Fastlane 的文章范围太大了，这边就只记录使用 Fastlane Match 的过程；其他关于 Fastlane 跑测试、打包发布…等等 Lane 有机会再写一篇新的补充；其他 Match 相关的问题，有想到什么案例会再来补充！也欢迎留言提问！</p>

<h3 id="延伸阅读">延伸阅读</h3>

<ul>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-是什么-打造高效稳定开发团队的关键流程与工具选择-c008a9e8ceca/">CI/CD 实战指南（一）：CI/CD 是什么？如何透过 CI/CD 打造稳定高效的开发团队？工具选择？</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-self-hosted-runner-详解与实战案例-ci-cd-自动化工作流程建置-404bd5c70040/">CI/CD 实战指南（二）：GitHub Actions 与 self-hosted Runner 使用与建置大全</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/">CI/CD 实战指南（三）：使用 GitHub Actions 实作 App 专案的 CI 与 CD 工作流程</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/">CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</a></p>
  </li>
</ul>

<p><strong>敬请移步阅览。🤞🏻</strong></p>]]></content>
  </entry><entry>
    <title type="html">Medium API 爬取资料与突破 Cloudflare 防护｜完整 GraphQL 操作教学</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/medium-api-%E7%88%AC%E5%8F%96%E8%B5%84%E6%96%99%E4%B8%8E%E7%AA%81%E7%A0%B4-cloudflare-%E9%98%B2%E6%8A%A4-%E5%AE%8C%E6%95%B4-graphql-%E6%93%8D%E4%BD%9C%E6%95%99%E5%AD%A6-88f0fb935120/" rel="alternate" type="text/html" title="Medium API 爬取资料与突破 Cloudflare 防护｜完整 GraphQL 操作教学" />
    <published>2025-12-31T12:36:53+08:00</published>
    <updated>2026-01-02T22:43:48+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/88f0fb935120</id><summary type="html">针对 Medium 使用者担心文章无备份、Cloudflare 阻挡爬虫的痛点，详解如何透过 Medium API 与 GraphQL 取得追踪人数、文章列表及内容，并示范用 Cloudflare Worker 成功绕过防护，实现自动备份与资料同步。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="cloudflare" /><category term="medium" /><category term="api" /><category term="graphql" /><category term="medium-api" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/88f0fb935120/1*Lh9a_XR4zvvsaP3y58x9Aw.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/medium-api-%E7%88%AC%E5%8F%96%E8%B5%84%E6%96%99%E4%B8%8E%E7%AA%81%E7%A0%B4-cloudflare-%E9%98%B2%E6%8A%A4-%E5%AE%8C%E6%95%B4-graphql-%E6%93%8D%E4%BD%9C%E6%95%99%E5%AD%A6-88f0fb935120/"><![CDATA[<h3 id="medium-api-资料爬虫与-cloudflare-攻防的心路历程">Medium API 资料爬虫与 Cloudflare 攻防的心路历程</h3>

<p>使用 Medium Graphql Private API 爬取资料、备份文章及 Cloudflare 验证阻挡突破方式。</p>

<h4 id="背景">背景</h4>

<p>自 2018 年开始经营 Medium 撰写文章，大约在 2022 年时累积的文章数量已超过 50+ 篇，接近 6+ 万字加上约 3 GB 的文章图片 (直至 2025 已破 120+ 篇/10+万字/6 GB+图片)； <strong>没有备份! 没有备份! 没有备份!</strong> ，因为我一直以来都直接用 Medium 写文章(编辑器真的好用)， <strong>写完就直接储存发布，本地没有任何备份。</strong></p>

<p>那时候有一股不安感油然而生，如果哪一天 Medium 倒了我的文章不就不见了？(而且那几年 Medium 状况一直都很不好，没有赚钱) 或是我的帐号突然被停权心血不就都付之一炬了？</p>

<p>于是在那年开始研究如何爬取 Medium 资料、尤其是文章内容跟如何下载备份。</p>

<h4 id="medium-html-">Medium HTML ❌</h4>

<p>结构非常复杂、易改变、爬取缓慢，直接起浏览器爬内容是下下策。</p>

<h4 id="medium-official-api-">Medium Official API ❌</h4>

<p><a href="https://github.com/Medium/medium-api-docs" target="_blank"><img src="https://opengraph.githubassets.com/2b799fabbf4dcd1318819317b5292720f760def3b23591643c23fa6410abe4b0/Medium/medium-api-docs" alt="" /></a></p>

<blockquote>
  <p><strong><em>Warning The Medium API is no longer supported. We do not recommend using it.</em></strong></p>
</blockquote>

<p>Medium 曾经提供过官方的 API 接口，但是应该在推出没多久就停用了；推测应该是跟产品目标不同，Medium 是私域流量应该要尽量把内容留在站内，而不是开 API 让外部有机会串接拿到资料。</p>

<h4 id="medium-unofficial-api-">Medium Unofficial API 🤔</h4>

<p><a href="https://mediumapi.com/" target="_blank"><img src="https://mediumapi.com/imgs/mediumapi-website-image.jpg" alt="" /></a></p>

<p>也因为官方不提供 API，有民间大神自行开发对外的 API 接口让有需求的使用者串接；但其中原理我推测也是打 Medium Private API，只是过了它那一层的封装桥接，帮你把请求转换成 Private API 取得原始资料。</p>

<blockquote>
  <p><strong><em>收费也不便宜，约每 2,500次请求 $USD 5 美元</em></strong> <em>；这个服务做蛮久的，但既然最终都是打 Medium Private API，那我自己嗅探自己打就好了。</em></p>
</blockquote>

<h3 id="medium-private-api-">Medium Private API ✅</h3>

<p>何谓 Private API? 就是这个 API 接口 <strong>并非给外部使用、没有文件、可能随时停用、可能有法律风险</strong> ；等于 <strong>直接去看他网站 / App 的行为找到呼叫的对应 API</strong> ，自己写程式重用这个 API 捞资料到自己的服务上。</p>

<h4 id="httpsmediumcom_graphql"><a href="https://medium.com/_/graphql" target="_blank">https://medium.com/_/graphql</a></h4>

<p>经过网路请求嗅探，我们可以发现所有的 Medium API 都是使用 <a href="https://medium.com/_/graphql" target="_blank">https://medium.com/_/graphql</a> 这个接口，只要我们能在自己的程式上呼叫并取得相同的资料，这条路就能达成。</p>

<h4 id="medium-private-api--嗅探-medium-graphql-取得追踪人数为例">Medium Private API — 嗅探 Medium Graphql (取得追踪人数为例)</h4>

<p>我的第一个应用是想爬取我的追踪人数显示在我的入口网站。</p>

<p><a href="https://link.zhgchg.li/" target="_blank"><strong>link.zhgchg.li</strong></a> <strong>:</strong></p>

<p><img src="/assets/88f0fb935120/1*Lh9a_XR4zvvsaP3y58x9Aw.webp" alt="" loading="lazy" decoding="async" width="963" height="526" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjMiIGhlaWdodD0iNTI2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/88f0fb935120/1*Lh9a_XR4zvvsaP3y58x9Aw.png" /></p>

<p>因此我必须爬取 Medium 上我的帐号的追踪人数。</p>

<ul>
  <li>
    <p>我们先打开浏览器的「开发者模式」(Chrome -&gt; 右键 -&gt; 检查) 切换到「Network」页签，勾选「Preserve log」、搜寻匡输入「 <code class="language-plaintext highlighter-rouge">graphql</code> 」</p>
  </li>
  <li>
    <p>进入 Medium 帐号追踪者页面:「 <code class="language-plaintext highlighter-rouge">https://medium.com/@YOUR_USER_NAME/followers</code> 」
只能用这个格式的 Follower 网址嗅探， <code class="language-plaintext highlighter-rouge">https://YOUR_USER_NAME.medium.com/followers</code> 这种格式的没有呼叫取得 Followers API。</p>
  </li>
</ul>

<p><img src="/assets/88f0fb935120/1*jmGbo-BQK9amNmoRneJRPw.webp" alt="" loading="lazy" decoding="async" width="1200" height="848" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/88f0fb935120/1*jmGbo-BQK9amNmoRneJRPw.png" /></p>

<ul>
  <li>
    <p>一个一个查看左方「graphql」请求，在「Response」资料中搜寻「 <code class="language-plaintext highlighter-rouge">followerCount</code> 」关键字，找到有这个关键字且 <code class="language-plaintext highlighter-rouge">username</code> 同网页的使用者名称 &amp; 追踪数字跟网页显示相同，找到这个目标请求。</p>
  </li>
  <li>
    <p>找到目标的 API 后，切换到 Payload -&gt; View Source -&gt; 复制以下全部内容</p>
  </li>
</ul>

<p><img src="/assets/88f0fb935120/1*CGyScjCEe9Cf_3VIJrUJzQ.webp" alt="" loading="lazy" decoding="async" width="1437" height="633" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDM3IiBoZWlnaHQ9IjYzMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/88f0fb935120/1*CGyScjCEe9Cf_3VIJrUJzQ.png" /></p>

<p>现在我们已经有取得 Medium 追踪者的 API &amp; Payload 了，用 <a href="https://www.postman.com/" target="_blank">Postman</a> 测试看看！</p>

<h4 id="medium-取得追踪人数-endpoint--request--response">Medium 取得追踪人数 Endpoint — Request &amp; Response</h4>

<p><strong>Endpoint:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>POST https://medium.com/_/graphql
</code></pre></div></div>

<p>Authorization: No authorization required (不用带 Token or set cookies)</p>

<p><strong>Payload:</strong></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
        </span><span class="nl">"operationName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"UserFollowers"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"variables"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
            </span><span class="nl">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"zhgchgli"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"query"</span><span class="p">:</span><span class="w"> </span><span class="s2">"query UserFollowers($username: ID, $id: ID, $paging: PagingOptions) {</span><span class="se">\n</span><span class="s2">  userResult(username: $username, id: $id) {</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    ... on User {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      followersUserConnection(paging: $paging) {</span><span class="se">\n</span><span class="s2">        pagingInfo {</span><span class="se">\n</span><span class="s2">          next {</span><span class="se">\n</span><span class="s2">            from</span><span class="se">\n</span><span class="s2">            limit</span><span class="se">\n</span><span class="s2">            __typename</span><span class="se">\n</span><span class="s2">          }</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        users {</span><span class="se">\n</span><span class="s2">          ...FollowList_publisher</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      ...UserCanonicalizer_user</span><span class="se">\n</span><span class="s2">      ...FollowersHeader_publisher</span><span class="se">\n</span><span class="s2">      ...NoFollows_publisher</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment collectionUrl_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  domain</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CollectionAvatar_collection on Collection {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  avatar {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...collectionUrl_collection</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignInOptions_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignUpOptions_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiModal_collection on Collection {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...SignInOptions_collection</span><span class="se">\n</span><span class="s2">  ...SignUpOptions_collection</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublicationFollowButton_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...SusiModal_collection</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublicationFollowRow_collection on Collection {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  description</span><span class="se">\n</span><span class="s2">  ...CollectionAvatar_collection</span><span class="se">\n</span><span class="s2">  ...PublicationFollowButton_collection</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment userUrl_user on User {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  customDomainState {</span><span class="se">\n</span><span class="s2">    live {</span><span class="se">\n</span><span class="s2">      domain</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  hasSubdomain</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserAvatar_user on User {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  membership {</span><span class="se">\n</span><span class="s2">    tier</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  ...userUrl_user</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment isUserVerifiedBookAuthor_user on User {</span><span class="se">\n</span><span class="s2">  verifications {</span><span class="se">\n</span><span class="s2">    isBookAuthor</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignInOptions_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignUpOptions_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiModal_user on User {</span><span class="se">\n</span><span class="s2">  ...SignInOptions_user</span><span class="se">\n</span><span class="s2">  ...SignUpOptions_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useNewsletterV3Subscription_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  user {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    username</span><span class="se">\n</span><span class="s2">    newsletterV3 {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useNewsletterV3Subscription_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    ...useNewsletterV3Subscription_newsletterV3</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useAuthorFollowSubscribeButton_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...useNewsletterV3Subscription_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useAuthorFollowSubscribeButton_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...useNewsletterV3Subscription_newsletterV3</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment AuthorFollowSubscribeButton_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  ...SusiModal_user</span><span class="se">\n</span><span class="s2">  ...useAuthorFollowSubscribeButton_user</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...useAuthorFollowSubscribeButton_newsletterV3</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserFollowRow_user on User {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  bio</span><span class="se">\n</span><span class="s2">  ...UserAvatar_user</span><span class="se">\n</span><span class="s2">  ...isUserVerifiedBookAuthor_user</span><span class="se">\n</span><span class="s2">  ...AuthorFollowSubscribeButton_user</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment FollowsHeader_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    ...collectionUrl_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...userUrl_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment FollowList_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    ...PublicationFollowRow_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...UserFollowRow_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserCanonicalizer_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  hasSubdomain</span><span class="se">\n</span><span class="s2">  customDomainState {</span><span class="se">\n</span><span class="s2">    live {</span><span class="se">\n</span><span class="s2">      domain</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment FollowersHeader_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  ...FollowsHeader_publisher</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    subscriberCount</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    socialStats {</span><span class="se">\n</span><span class="s2">      followerCount</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment NoFollows_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n</span><span class="s2">"</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">username</code> : 换成你要查询的使用者名称。</p>

<p><a href="https://www.postman.com/" target="_blank"><strong>Postman</strong></a> <strong>:</strong></p>

<p><img src="/assets/88f0fb935120/1*MuntmkeqjFqqD_ma_td3VA.webp" alt="" loading="lazy" decoding="async" width="1552" height="1325" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTUyIiBoZWlnaHQ9IjEzMjUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/88f0fb935120/1*MuntmkeqjFqqD_ma_td3VA.png" /></p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">POST https://medium.com/_/graphql</code></p>
  </li>
  <li>
    <p>Body -&gt; raw -&gt; JSON</p>
  </li>
</ul>

<p><strong>Response:</strong></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
        </span><span class="nl">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nl">"userResult"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nl">"__typename"</span><span class="p">:</span><span class="w"> </span><span class="s2">"User"</span><span class="p">,</span><span class="w">
                </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"8854784154b8"</span><span class="p">,</span><span class="w">
                </span><span class="nl">"followersUserConnection"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"pagingInfo"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                        </span><span class="nl">"next"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                            </span><span class="nl">"from"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1140babdfef7"</span><span class="p">,</span><span class="w">
                            </span><span class="nl">"limit"</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span><span class="w">
                            </span><span class="nl">"__typename"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PageParams"</span><span class="w">
                        </span><span class="p">},</span><span class="w">
                        </span><span class="nl">"__typename"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Paging"</span><span class="w">
                    </span><span class="p">},</span><span class="w">
                    </span><span class="nl">"users"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
                        </span><span class="err">///..</span><span class="w"> </span><span class="err">略</span><span class="w">
                    </span><span class="p">],</span><span class="w">
                    </span><span class="nl">"__typename"</span><span class="p">:</span><span class="w"> </span><span class="s2">"UserConnection"</span><span class="w">
                </span><span class="p">},</span><span class="w">
                </span><span class="nl">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"zhgchgli"</span><span class="p">,</span><span class="w">
                </span><span class="nl">"hasSubdomain"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
                </span><span class="nl">"customDomainState"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"live"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                        </span><span class="nl">"domain"</span><span class="p">:</span><span class="w"> </span><span class="s2">"zhgchgli.medium.com"</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"__typename"</span><span class="p">:</span><span class="w"> </span><span class="s2">"CustomDomain"</span><span class="w">
                    </span><span class="p">},</span><span class="w">
                    </span><span class="nl">"__typename"</span><span class="p">:</span><span class="w"> </span><span class="s2">"CustomDomainState"</span><span class="w">
                </span><span class="p">},</span><span class="w">
                </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ZhgChgLi"</span><span class="p">,</span><span class="w">
                </span><span class="nl">"socialStats"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"followerCount"</span><span class="p">:</span><span class="w"> </span><span class="mi">1050</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"__typename"</span><span class="p">:</span><span class="w"> </span><span class="s2">"SocialStats"</span><span class="w">
                </span><span class="p">}</span><span class="w">
            </span><span class="p">}</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<p>关键资讯： <code class="language-plaintext highlighter-rouge">response[0]["data"]["userResult"]["socialStats"]["followerCount"]</code> 就是目标追踪人数了！</p>

<p><strong>Ruby Demo Code:</strong></p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">load_medium_followers</span><span class="p">(</span><span class="n">username</span><span class="p">)</span>
    <span class="k">begin</span>
        <span class="n">url</span> <span class="o">=</span> <span class="s2">"https://medium.com/_/graphql"</span>
        <span class="n">uri</span> <span class="o">=</span> <span class="no">URI</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>

        <span class="n">payload</span> <span class="o">=</span> <span class="p">[</span>
            <span class="p">{</span>
            <span class="s2">"operationName"</span><span class="p">:</span> <span class="s2">"UserFollowers"</span><span class="p">,</span>
            <span class="s2">"variables"</span><span class="p">:</span> <span class="p">{</span>
                <span class="s2">"id"</span><span class="p">:</span> <span class="kp">nil</span><span class="p">,</span>
                <span class="s2">"username"</span><span class="p">:</span> <span class="n">username</span><span class="p">,</span>
                <span class="s2">"paging"</span><span class="p">:</span> <span class="kp">nil</span>
            <span class="p">},</span>
            <span class="s2">"query"</span><span class="p">:</span> <span class="s2">"query UserFollowers($username: ID, $id: ID, $paging: PagingOptions) {</span><span class="se">\n</span><span class="s2">  userResult(username: $username, id: $id) {</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    ... on User {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      followersUserConnection(paging: $paging) {</span><span class="se">\n</span><span class="s2">        pagingInfo {</span><span class="se">\n</span><span class="s2">          next {</span><span class="se">\n</span><span class="s2">            from</span><span class="se">\n</span><span class="s2">            limit</span><span class="se">\n</span><span class="s2">            __typename</span><span class="se">\n</span><span class="s2">          }</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        users {</span><span class="se">\n</span><span class="s2">          ...FollowList_publisher</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      ...UserCanonicalizer_user</span><span class="se">\n</span><span class="s2">      ...FollowersHeader_publisher</span><span class="se">\n</span><span class="s2">      ...NoFollows_publisher</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment collectionUrl_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  domain</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CollectionAvatar_collection on Collection {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  avatar {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...collectionUrl_collection</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignInOptions_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignUpOptions_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiModal_collection on Collection {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...SignInOptions_collection</span><span class="se">\n</span><span class="s2">  ...SignUpOptions_collection</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublicationFollowButton_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...SusiModal_collection</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublicationFollowRow_collection on Collection {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  description</span><span class="se">\n</span><span class="s2">  ...CollectionAvatar_collection</span><span class="se">\n</span><span class="s2">  ...PublicationFollowButton_collection</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment userUrl_user on User {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  customDomainState {</span><span class="se">\n</span><span class="s2">    live {</span><span class="se">\n</span><span class="s2">      domain</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  hasSubdomain</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserAvatar_user on User {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  membership {</span><span class="se">\n</span><span class="s2">    tier</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  ...userUrl_user</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment isUserVerifiedBookAuthor_user on User {</span><span class="se">\n</span><span class="s2">  verifications {</span><span class="se">\n</span><span class="s2">    isBookAuthor</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignInOptions_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignUpOptions_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiModal_user on User {</span><span class="se">\n</span><span class="s2">  ...SignInOptions_user</span><span class="se">\n</span><span class="s2">  ...SignUpOptions_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useNewsletterV3Subscription_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  user {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    username</span><span class="se">\n</span><span class="s2">    newsletterV3 {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useNewsletterV3Subscription_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    ...useNewsletterV3Subscription_newsletterV3</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useAuthorFollowSubscribeButton_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...useNewsletterV3Subscription_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useAuthorFollowSubscribeButton_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...useNewsletterV3Subscription_newsletterV3</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment AuthorFollowSubscribeButton_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  ...SusiModal_user</span><span class="se">\n</span><span class="s2">  ...useAuthorFollowSubscribeButton_user</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...useAuthorFollowSubscribeButton_newsletterV3</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserFollowRow_user on User {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  bio</span><span class="se">\n</span><span class="s2">  ...UserAvatar_user</span><span class="se">\n</span><span class="s2">  ...isUserVerifiedBookAuthor_user</span><span class="se">\n</span><span class="s2">  ...AuthorFollowSubscribeButton_user</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment FollowsHeader_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    ...collectionUrl_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...userUrl_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment FollowList_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    ...PublicationFollowRow_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...UserFollowRow_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserCanonicalizer_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  hasSubdomain</span><span class="se">\n</span><span class="s2">  customDomainState {</span><span class="se">\n</span><span class="s2">    live {</span><span class="se">\n</span><span class="s2">      domain</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment FollowersHeader_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  ...FollowsHeader_publisher</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    subscriberCount</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    socialStats {</span><span class="se">\n</span><span class="s2">      followerCount</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment NoFollows_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n</span><span class="s2">"</span>
            <span class="p">}</span>
        <span class="p">];</span>

        <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s2">"User-Agent"</span> <span class="o">=&gt;</span> <span class="s2">"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"</span><span class="p">,</span>
            <span class="s2">"Content-Type"</span> <span class="o">=&gt;</span> <span class="s2">"application/json"</span>
        <span class="p">}</span>

        <span class="n">https</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">uri</span><span class="p">.</span><span class="nf">host</span><span class="p">,</span> <span class="n">uri</span><span class="p">.</span><span class="nf">port</span><span class="p">)</span>
        <span class="n">https</span><span class="p">.</span><span class="nf">read_timeout</span> <span class="o">=</span> <span class="mi">30</span>
        <span class="n">https</span><span class="p">.</span><span class="nf">open_timeout</span> <span class="o">=</span> <span class="mi">10</span>
        <span class="n">https</span><span class="p">.</span><span class="nf">use_ssl</span> <span class="o">=</span> <span class="kp">true</span>

        <span class="c1"># --- TLS / Certificate verification setup ---</span>
        <span class="c1"># Some OpenSSL builds/configs enable CRL checking, which can fail with:</span>
        <span class="c1"># "certificate verify failed (unable to get certificate CRL)".</span>
        <span class="c1"># Net::HTTP/OpenSSL does not automatically fetch CRLs, so we use a default</span>
        <span class="c1"># cert store and clear CRL-related flags to avoid hard failures while still</span>
        <span class="c1"># verifying the peer certificate.</span>
        <span class="n">https</span><span class="p">.</span><span class="nf">verify_mode</span> <span class="o">=</span> <span class="no">OpenSSL</span><span class="o">::</span><span class="no">SSL</span><span class="o">::</span><span class="no">VERIFY_PEER</span>

        <span class="n">store</span> <span class="o">=</span> <span class="no">OpenSSL</span><span class="o">::</span><span class="no">X509</span><span class="o">::</span><span class="no">Store</span><span class="p">.</span><span class="nf">new</span>
        <span class="n">store</span><span class="p">.</span><span class="nf">set_default_paths</span>
        <span class="c1"># Ensure no CRL-check flags are enabled by default</span>
        <span class="n">store</span><span class="p">.</span><span class="nf">flags</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="n">https</span><span class="p">.</span><span class="nf">cert_store</span> <span class="o">=</span> <span class="n">store</span>

        <span class="c1"># Allow overriding CA bundle paths via environment variables if needed.</span>
        <span class="k">if</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'SSL_CERT_FILE'</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="no">ENV</span><span class="p">[</span><span class="s1">'SSL_CERT_FILE'</span><span class="p">].</span><span class="nf">empty?</span>
        <span class="n">https</span><span class="p">.</span><span class="nf">ca_file</span> <span class="o">=</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'SSL_CERT_FILE'</span><span class="p">]</span>
        <span class="k">end</span>
        <span class="k">if</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'SSL_CERT_DIR'</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="no">ENV</span><span class="p">[</span><span class="s1">'SSL_CERT_DIR'</span><span class="p">].</span><span class="nf">empty?</span>
        <span class="n">https</span><span class="p">.</span><span class="nf">ca_path</span> <span class="o">=</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'SSL_CERT_DIR'</span><span class="p">]</span>
        <span class="k">end</span>

        <span class="c1"># (Optional) timeouts to avoid hanging on network issues</span>
        <span class="n">https</span><span class="p">.</span><span class="nf">open_timeout</span> <span class="o">=</span> <span class="mi">10</span>
        <span class="n">https</span><span class="p">.</span><span class="nf">read_timeout</span> <span class="o">=</span> <span class="mi">30</span>
        <span class="c1"># --- end TLS setup ---</span>


        <span class="n">req</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">::</span><span class="no">Post</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">uri</span><span class="p">.</span><span class="nf">request_uri</span><span class="p">,</span> <span class="n">headers</span><span class="p">)</span>
        <span class="n">req</span><span class="p">.</span><span class="nf">body</span> <span class="o">=</span> <span class="no">JSON</span><span class="p">.</span><span class="nf">dump</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>

        <span class="n">res</span> <span class="o">=</span> <span class="n">https</span><span class="p">.</span><span class="nf">request</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>

        <span class="n">json</span> <span class="o">=</span> <span class="no">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="nf">body</span><span class="p">)</span>
        <span class="n">count</span> <span class="o">=</span> <span class="n">json</span><span class="o">&amp;</span><span class="p">.</span><span class="nf">dig</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="s2">"data"</span><span class="p">,</span> <span class="s2">"userResult"</span><span class="p">,</span> <span class="s2">"socialStats"</span><span class="p">,</span> <span class="s2">"followerCount"</span><span class="p">)</span>
        <span class="n">count</span> <span class="p">?</span> <span class="n">count</span><span class="p">.</span><span class="nf">to_i</span> <span class="p">:</span> <span class="mi">0</span>
        <span class="k">return</span> <span class="s2">"1K+"</span> <span class="k">unless</span> <span class="n">count</span><span class="p">.</span><span class="nf">to_i</span> <span class="o">&gt;</span> <span class="mi">0</span>
        <span class="k">return</span> <span class="s2">"</span><span class="si">#{</span><span class="n">count</span><span class="p">.</span><span class="nf">to_s</span><span class="p">.</span><span class="nf">reverse</span><span class="p">.</span><span class="nf">gsub</span><span class="p">(</span><span class="sr">/(\d{3})(?=\d)/</span><span class="p">,</span> <span class="s1">'\\1,'</span><span class="p">).</span><span class="nf">reverse</span><span class="si">}</span><span class="s2">+"</span>
    <span class="k">rescue</span> <span class="o">=&gt;</span> <span class="n">e</span>
        <span class="s2">"1K+"</span>
    <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<h4 id="medium-private-api--取得帐号的所有文章">Medium Private API — 取得帐号的所有文章</h4>

<p>用相同的方式我们也可以取得目标帐号的文章列表。</p>

<p>Graphql Query Body:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="w">
      </span><span class="p">{</span><span class="w">
        </span><span class="nl">"operationName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"UserProfileQuery"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"variables"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"homepagePostsFrom"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
          </span><span class="nl">"includeDistributedResponses"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
          </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"8854784154b8"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"homepagePostsLimit"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"query"</span><span class="p">:</span><span class="w"> </span><span class="s2">"query UserProfileQuery($id: ID, $username: ID, $homepagePostsLimit: PaginationLimit, $homepagePostsFrom: String = null, $includeDistributedResponses: Boolean = true) {</span><span class="se">\n</span><span class="s2">  userResult(id: $id, username: $username) {</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    ... on User {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      name</span><span class="se">\n</span><span class="s2">      viewerIsUser</span><span class="se">\n</span><span class="s2">      viewerEdge {</span><span class="se">\n</span><span class="s2">        id</span><span class="se">\n</span><span class="s2">        isFollowing</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      homePostsPublished: homepagePostsConnection(paging: {limit: 1}) {</span><span class="se">\n</span><span class="s2">        posts {</span><span class="se">\n</span><span class="s2">          id</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      ...UserCanonicalizer_user</span><span class="se">\n</span><span class="s2">      ...UserProfileScreen_user</span><span class="se">\n</span><span class="s2">      ...EntityDrivenSubscriptionLandingPageScreen_writer</span><span class="se">\n</span><span class="s2">      ...useShouldShowEntityDrivenSubscription_creator</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserCanonicalizer_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  hasSubdomain</span><span class="se">\n</span><span class="s2">  customDomainState {</span><span class="se">\n</span><span class="s2">    live {</span><span class="se">\n</span><span class="s2">      domain</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserProfileScreen_user on User {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  viewerIsUser</span><span class="se">\n</span><span class="s2">  ...PublisherHeader_publisher</span><span class="se">\n</span><span class="s2">  ...PublisherHomePosts_publisher</span><span class="se">\n</span><span class="s2">  ...UserSubdomainFlow_user</span><span class="se">\n</span><span class="s2">  ...UserProfileMetadata_user</span><span class="se">\n</span><span class="s2">  ...SuspendedBannerLoader_user</span><span class="se">\n</span><span class="s2">  ...ExpandablePost_user</span><span class="se">\n</span><span class="s2">  ...useAnalytics_user</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHeader_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...PublisherHeaderBackground_publisher</span><span class="se">\n</span><span class="s2">  ...PublisherHeaderNameplate_publisher</span><span class="se">\n</span><span class="s2">  ...PublisherHeaderActions_publisher</span><span class="se">\n</span><span class="s2">  ...PublisherHeaderNav_publisher</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHeaderBackground_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  customStyleSheet {</span><span class="se">\n</span><span class="s2">    ...PublisherHeaderBackground_customStyleSheet</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    colorPalette {</span><span class="se">\n</span><span class="s2">      tintBackgroundSpectrum {</span><span class="se">\n</span><span class="s2">        backgroundColor</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    isAuroraVisible</span><span class="se">\n</span><span class="s2">    legacyHeaderBackgroundImage {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      originalWidth</span><span class="se">\n</span><span class="s2">      focusPercentX</span><span class="se">\n</span><span class="s2">      focusPercentY</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    ...collectionTintBackgroundTheme_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...publisherUrl_publisher</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHeaderBackground_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  global {</span><span class="se">\n</span><span class="s2">    colorPalette {</span><span class="se">\n</span><span class="s2">      background {</span><span class="se">\n</span><span class="s2">        rgb</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  header {</span><span class="se">\n</span><span class="s2">    headerScale</span><span class="se">\n</span><span class="s2">    backgroundImageDisplayMode</span><span class="se">\n</span><span class="s2">    backgroundImageVerticalAlignment</span><span class="se">\n</span><span class="s2">    backgroundColorDisplayMode</span><span class="se">\n</span><span class="s2">    backgroundColor {</span><span class="se">\n</span><span class="s2">      alpha</span><span class="se">\n</span><span class="s2">      rgb</span><span class="se">\n</span><span class="s2">      ...getHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">      ...getOpaqueHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    secondaryBackgroundColor {</span><span class="se">\n</span><span class="s2">      ...getHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    postBackgroundColor {</span><span class="se">\n</span><span class="s2">      ...getHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    backgroundImage {</span><span class="se">\n</span><span class="s2">      ...MetaHeaderBackground_imageMetadata</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getHexFromColorValue_colorValue on ColorValue {</span><span class="se">\n</span><span class="s2">  rgb</span><span class="se">\n</span><span class="s2">  alpha</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getOpaqueHexFromColorValue_colorValue on ColorValue {</span><span class="se">\n</span><span class="s2">  rgb</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderBackground_imageMetadata on ImageMetadata {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  originalWidth</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment collectionTintBackgroundTheme_collection on Collection {</span><span class="se">\n</span><span class="s2">  colorPalette {</span><span class="se">\n</span><span class="s2">    ...collectionTintBackgroundTheme_colorPalette</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  customStyleSheet {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...collectionTintBackgroundTheme_customStyleSheet</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment collectionTintBackgroundTheme_colorPalette on ColorPalette {</span><span class="se">\n</span><span class="s2">  ...customTintBackgroundTheme_colorPalette</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment customTintBackgroundTheme_colorPalette on ColorPalette {</span><span class="se">\n</span><span class="s2">  tintBackgroundSpectrum {</span><span class="se">\n</span><span class="s2">    ...ThemeUtil_colorSpectrum</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ThemeUtil_colorSpectrum on ColorSpectrum {</span><span class="se">\n</span><span class="s2">  backgroundColor</span><span class="se">\n</span><span class="s2">  ...ThemeUtilInterpolateHelpers_colorSpectrum</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ThemeUtilInterpolateHelpers_colorSpectrum on ColorSpectrum {</span><span class="se">\n</span><span class="s2">  colorPoints {</span><span class="se">\n</span><span class="s2">    ...ThemeUtil_colorPoint</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ThemeUtil_colorPoint on ColorPoint {</span><span class="se">\n</span><span class="s2">  color</span><span class="se">\n</span><span class="s2">  point</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment collectionTintBackgroundTheme_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...customTintBackgroundTheme_customStyleSheet</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment customTintBackgroundTheme_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  global {</span><span class="se">\n</span><span class="s2">    colorPalette {</span><span class="se">\n</span><span class="s2">      primary {</span><span class="se">\n</span><span class="s2">        colorPalette {</span><span class="se">\n</span><span class="s2">          ...customTintBackgroundTheme_colorPalette</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment publisherUrl_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    ...collectionUrl_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...userUrl_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment collectionUrl_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  domain</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment userUrl_user on User {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  customDomainState {</span><span class="se">\n</span><span class="s2">    live {</span><span class="se">\n</span><span class="s2">      domain</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  hasSubdomain</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHeaderNameplate_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  ...PublisherAvatar_publisher</span><span class="se">\n</span><span class="s2">  ...PublisherHeaderLogo_publisher</span><span class="se">\n</span><span class="s2">  ...PublisherFollowerCount_publisher</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherAvatar_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...CollectionAvatar_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...UserAvatar_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CollectionAvatar_collection on Collection {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  avatar {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...collectionUrl_collection</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserAvatar_user on User {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  mediumMemberAt</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  ...userUrl_user</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHeaderLogo_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  customStyleSheet {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    header {</span><span class="se">\n</span><span class="s2">      logoImage {</span><span class="se">\n</span><span class="s2">        id</span><span class="se">\n</span><span class="s2">        originalHeight</span><span class="se">\n</span><span class="s2">        originalWidth</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      appNameColor {</span><span class="se">\n</span><span class="s2">        ...getHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      appNameTreatment</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    isAuroraVisible</span><span class="se">\n</span><span class="s2">    logo {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      originalHeight</span><span class="se">\n</span><span class="s2">      originalWidth</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...CustomHeaderTooltip_publisher</span><span class="se">\n</span><span class="s2">  ...publisherUrl_publisher</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CustomHeaderTooltip_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  customStyleSheet {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    header {</span><span class="se">\n</span><span class="s2">      appNameTreatment</span><span class="se">\n</span><span class="s2">      nameTreatment</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    isAuroraVisible</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherFollowerCount_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    subscriberCount</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    socialStats {</span><span class="se">\n</span><span class="s2">      followerCount</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    username</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHeaderActions_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ...MetaHeaderPubMenu_publisher</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    ...CollectionFollowButton_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...FollowAndSubscribeButtons_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderPubMenu_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    ...MetaHeaderPubMenu_publisher_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...MetaHeaderPubMenu_publisher_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderPubMenu_publisher_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  domain</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...MutePopoverOptions_collection</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MutePopoverOptions_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderPubMenu_publisher_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  ...MutePopoverOptions_creator</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MutePopoverOptions_creator on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CollectionFollowButton_collection on Collection {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  ...collectionUrl_collection</span><span class="se">\n</span><span class="s2">  ...SusiClickable_collection</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiClickable_collection on Collection {</span><span class="se">\n</span><span class="s2">  ...SusiContainer_collection</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiContainer_collection on Collection {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...SignInOptions_collection</span><span class="se">\n</span><span class="s2">  ...SignUpOptions_collection</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignInOptions_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignUpOptions_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment FollowAndSubscribeButtons_user on User {</span><span class="se">\n</span><span class="s2">  ...UserFollowButton_user</span><span class="se">\n</span><span class="s2">  ...UserSubscribeButton_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserFollowButton_user on User {</span><span class="se">\n</span><span class="s2">  ...UserFollowButtonSignedIn_user</span><span class="se">\n</span><span class="s2">  ...UserFollowButtonSignedOut_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserFollowButtonSignedIn_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserFollowButtonSignedOut_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...SusiClickable_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiClickable_user on User {</span><span class="se">\n</span><span class="s2">  ...SusiContainer_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiContainer_user on User {</span><span class="se">\n</span><span class="s2">  ...SignInOptions_user</span><span class="se">\n</span><span class="s2">  ...SignUpOptions_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignInOptions_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignUpOptions_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserSubscribeButton_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  isPartnerProgramEnrolled</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  viewerEdge {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    isFollowing</span><span class="se">\n</span><span class="s2">    isUser</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  viewerIsUser</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...useNewsletterV3Subscription_newsletterV3</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...useNewsletterV3Subscription_user</span><span class="se">\n</span><span class="s2">  ...MembershipUpsellModal_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useNewsletterV3Subscription_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  user {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    username</span><span class="se">\n</span><span class="s2">    newsletterV3 {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useNewsletterV3Subscription_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    ...useNewsletterV3Subscription_newsletterV3</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MembershipUpsellModal_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  postSubscribeMembershipUpsellShownAt</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHeaderNav_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  customStyleSheet {</span><span class="se">\n</span><span class="s2">    navigation {</span><span class="se">\n</span><span class="s2">      navItems {</span><span class="se">\n</span><span class="s2">        name</span><span class="se">\n</span><span class="s2">        ...PublisherHeaderNavLink_headerNavigationItem</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...PublisherHeaderNavLink_publisher</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    domain</span><span class="se">\n</span><span class="s2">    isAuroraVisible</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    navItems {</span><span class="se">\n</span><span class="s2">      tagSlug</span><span class="se">\n</span><span class="s2">      title</span><span class="se">\n</span><span class="s2">      url</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    customDomainState {</span><span class="se">\n</span><span class="s2">      live {</span><span class="se">\n</span><span class="s2">        domain</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    hasSubdomain</span><span class="se">\n</span><span class="s2">    username</span><span class="se">\n</span><span class="s2">    about</span><span class="se">\n</span><span class="s2">    homePostsPublished: homepagePostsConnection(paging: {limit: 1}) {</span><span class="se">\n</span><span class="s2">      posts {</span><span class="se">\n</span><span class="s2">        id</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHeaderNavLink_headerNavigationItem on HeaderNavigationItem {</span><span class="se">\n</span><span class="s2">  href</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  tags {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    normalizedTagSlug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHeaderNavLink_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHomePosts_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  homepagePostsConnection(</span><span class="se">\n</span><span class="s2">    paging: {limit: $homepagePostsLimit, from: $homepagePostsFrom}</span><span class="se">\n</span><span class="s2">    includeDistributedResponses: $includeDistributedResponses</span><span class="se">\n</span><span class="s2">  ) {</span><span class="se">\n</span><span class="s2">    posts {</span><span class="se">\n</span><span class="s2">      ...PublisherHomePosts_post</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    pagingInfo {</span><span class="se">\n</span><span class="s2">      next {</span><span class="se">\n</span><span class="s2">        from</span><span class="se">\n</span><span class="s2">        limit</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...CardByline_publisher</span><span class="se">\n</span><span class="s2">  ...NewsletterV3Promo_publisher</span><span class="se">\n</span><span class="s2">  ...PublisherHomePosts_user</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHomePosts_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    ...collectionUrl_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...ExpandablePost_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ExpandablePost_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  creator {</span><span class="se">\n</span><span class="s2">    ...ExpandablePost_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    ...CardByline_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...InteractivePostBody_postPreview</span><span class="se">\n</span><span class="s2">  firstPublishedAt</span><span class="se">\n</span><span class="s2">  isLocked</span><span class="se">\n</span><span class="s2">  isSeries</span><span class="se">\n</span><span class="s2">  isShortform</span><span class="se">\n</span><span class="s2">  latestPublishedAt</span><span class="se">\n</span><span class="s2">  inResponseToCatalogResult {</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  mediumUrl</span><span class="se">\n</span><span class="s2">  postResponses {</span><span class="se">\n</span><span class="s2">    count</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  previewImage {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    focusPercentX</span><span class="se">\n</span><span class="s2">    focusPercentY</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  readingTime</span><span class="se">\n</span><span class="s2">  sequence {</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  title</span><span class="se">\n</span><span class="s2">  uniqueSlug</span><span class="se">\n</span><span class="s2">  visibility</span><span class="se">\n</span><span class="s2">  ...CardByline_post</span><span class="se">\n</span><span class="s2">  ...ExpandablePostFooter_post</span><span class="se">\n</span><span class="s2">  ...InResponseToEntityPreview_post</span><span class="se">\n</span><span class="s2">  ...PostScrollTracker_post</span><span class="se">\n</span><span class="s2">  ...ReadMore_post</span><span class="se">\n</span><span class="s2">  ...HighDensityPreview_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ExpandablePost_user on User {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  ...CardByline_user</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CardByline_user on User {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  mediumMemberAt</span><span class="se">\n</span><span class="s2">  socialStats {</span><span class="se">\n</span><span class="s2">    followerCount</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...userUrl_user</span><span class="se">\n</span><span class="s2">  ...UserMentionTooltip_user</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserMentionTooltip_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  bio</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  mediumMemberAt</span><span class="se">\n</span><span class="s2">  ...UserAvatar_user</span><span class="se">\n</span><span class="s2">  ...UserFollowButton_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CardByline_collection on Collection {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...collectionUrl_collection</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment InteractivePostBody_postPreview on Post {</span><span class="se">\n</span><span class="s2">  extendedPreviewContent(</span><span class="se">\n</span><span class="s2">    truncationConfig: {previewParagraphsWordCountThreshold: 400, minimumWordLengthForTruncation: 150, truncateAtEndOfSentence: true, showFullImageCaptions: true, shortformPreviewParagraphsWordCountThreshold: 30, shortformMinimumWordLengthForTruncation: 30}</span><span class="se">\n</span><span class="s2">  ) {</span><span class="se">\n</span><span class="s2">    bodyModel {</span><span class="se">\n</span><span class="s2">      ...PostBody_bodyModel</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    isFullContent</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostBody_bodyModel on RichText {</span><span class="se">\n</span><span class="s2">  sections {</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    startIndex</span><span class="se">\n</span><span class="s2">    textLayout</span><span class="se">\n</span><span class="s2">    imageLayout</span><span class="se">\n</span><span class="s2">    backgroundImage {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      originalHeight</span><span class="se">\n</span><span class="s2">      originalWidth</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    videoLayout</span><span class="se">\n</span><span class="s2">    backgroundVideo {</span><span class="se">\n</span><span class="s2">      videoId</span><span class="se">\n</span><span class="s2">      originalHeight</span><span class="se">\n</span><span class="s2">      originalWidth</span><span class="se">\n</span><span class="s2">      previewImageId</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...PostBodySection_paragraph</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...normalizedBodyModel_richText</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostBodySection_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...PostBodyParagraph_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostBodyParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  ...ImageParagraph_paragraph</span><span class="se">\n</span><span class="s2">  ...TextParagraph_paragraph</span><span class="se">\n</span><span class="s2">  ...IframeParagraph_paragraph</span><span class="se">\n</span><span class="s2">  ...MixtapeParagraph_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ImageParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  href</span><span class="se">\n</span><span class="s2">  layout</span><span class="se">\n</span><span class="s2">  metadata {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    originalHeight</span><span class="se">\n</span><span class="s2">    originalWidth</span><span class="se">\n</span><span class="s2">    focusPercentX</span><span class="se">\n</span><span class="s2">    focusPercentY</span><span class="se">\n</span><span class="s2">    alt</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...Markups_paragraph</span><span class="se">\n</span><span class="s2">  ...ParagraphRefsMapContext_paragraph</span><span class="se">\n</span><span class="s2">  ...PostAnnotationsMarker_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment Markups_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  text</span><span class="se">\n</span><span class="s2">  hasDropCap</span><span class="se">\n</span><span class="s2">  dropCapImage {</span><span class="se">\n</span><span class="s2">    ...MarkupNode_data_dropCapImage</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  markups {</span><span class="se">\n</span><span class="s2">    type</span><span class="se">\n</span><span class="s2">    start</span><span class="se">\n</span><span class="s2">    end</span><span class="se">\n</span><span class="s2">    href</span><span class="se">\n</span><span class="s2">    anchorType</span><span class="se">\n</span><span class="s2">    userId</span><span class="se">\n</span><span class="s2">    linkMetadata {</span><span class="se">\n</span><span class="s2">      httpStatus</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MarkupNode_data_dropCapImage on ImageMetadata {</span><span class="se">\n</span><span class="s2">  ...DropCap_image</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment DropCap_image on ImageMetadata {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  originalHeight</span><span class="se">\n</span><span class="s2">  originalWidth</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ParagraphRefsMapContext_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  text</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostAnnotationsMarker_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  ...PostViewNoteCard_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostViewNoteCard_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment TextParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  hasDropCap</span><span class="se">\n</span><span class="s2">  ...Markups_paragraph</span><span class="se">\n</span><span class="s2">  ...ParagraphRefsMapContext_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment IframeParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  iframe {</span><span class="se">\n</span><span class="s2">    mediaResource {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      iframeSrc</span><span class="se">\n</span><span class="s2">      iframeHeight</span><span class="se">\n</span><span class="s2">      iframeWidth</span><span class="se">\n</span><span class="s2">      title</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  layout</span><span class="se">\n</span><span class="s2">  ...getEmbedlyCardUrlParams_paragraph</span><span class="se">\n</span><span class="s2">  ...Markups_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getEmbedlyCardUrlParams_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  iframe {</span><span class="se">\n</span><span class="s2">    mediaResource {</span><span class="se">\n</span><span class="s2">      iframeSrc</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MixtapeParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  mixtapeMetadata {</span><span class="se">\n</span><span class="s2">    href</span><span class="se">\n</span><span class="s2">    mediaResource {</span><span class="se">\n</span><span class="s2">      mediumCatalog {</span><span class="se">\n</span><span class="s2">        id</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...GenericMixtapeParagraph_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment GenericMixtapeParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  text</span><span class="se">\n</span><span class="s2">  mixtapeMetadata {</span><span class="se">\n</span><span class="s2">    href</span><span class="se">\n</span><span class="s2">    thumbnailImageId</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  markups {</span><span class="se">\n</span><span class="s2">    start</span><span class="se">\n</span><span class="s2">    end</span><span class="se">\n</span><span class="s2">    type</span><span class="se">\n</span><span class="s2">    href</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment normalizedBodyModel_richText on RichText {</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    markups {</span><span class="se">\n</span><span class="s2">      type</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    ...getParagraphHighlights_paragraph</span><span class="se">\n</span><span class="s2">    ...getParagraphPrivateNotes_paragraph</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  sections {</span><span class="se">\n</span><span class="s2">    startIndex</span><span class="se">\n</span><span class="s2">    ...getSectionEndIndex_section</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...getParagraphStyles_richText</span><span class="se">\n</span><span class="s2">  ...getParagraphSpaces_richText</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getParagraphHighlights_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getParagraphPrivateNotes_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getSectionEndIndex_section on Section {</span><span class="se">\n</span><span class="s2">  startIndex</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getParagraphStyles_richText on RichText {</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    text</span><span class="se">\n</span><span class="s2">    type</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  sections {</span><span class="se">\n</span><span class="s2">    ...getSectionEndIndex_section</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getParagraphSpaces_richText on RichText {</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    layout</span><span class="se">\n</span><span class="s2">    metadata {</span><span class="se">\n</span><span class="s2">      originalHeight</span><span class="se">\n</span><span class="s2">      originalWidth</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    type</span><span class="se">\n</span><span class="s2">    ...paragraphExtendsImageGrid_paragraph</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...getSeriesParagraphTopSpacings_richText</span><span class="se">\n</span><span class="s2">  ...getPostParagraphTopSpacings_richText</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment paragraphExtendsImageGrid_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  layout</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getSeriesParagraphTopSpacings_richText on RichText {</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  sections {</span><span class="se">\n</span><span class="s2">    startIndex</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getPostParagraphTopSpacings_richText on RichText {</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    layout</span><span class="se">\n</span><span class="s2">    text</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  sections {</span><span class="se">\n</span><span class="s2">    startIndex</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CardByline_post on Post {</span><span class="se">\n</span><span class="s2">  ...DraftStatus_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment DraftStatus_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  pendingCollection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    creator {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    ...BoldCollectionName_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  statusForCollection</span><span class="se">\n</span><span class="s2">  creator {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  isPublished</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment BoldCollectionName_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ExpandablePostFooter_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  allowResponses</span><span class="se">\n</span><span class="s2">  postResponses {</span><span class="se">\n</span><span class="s2">    count</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  isLimitedState</span><span class="se">\n</span><span class="s2">  ...ExpandablePostCardOverflowButton_post</span><span class="se">\n</span><span class="s2">  ...BookmarkButton_post</span><span class="se">\n</span><span class="s2">  ...PostFooterSocialPopover_post</span><span class="se">\n</span><span class="s2">  ...MultiVote_post</span><span class="se">\n</span><span class="s2">  ...OverflowMenuButtonWithNegativeSignal_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ExpandablePostCardOverflowButton_post on Post {</span><span class="se">\n</span><span class="s2">  creator {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...ExpandablePostCardEditorWriterButton_post</span><span class="se">\n</span><span class="s2">  ...ExpandablePostCardReaderButton_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ExpandablePostCardEditorWriterButton_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  allowResponses</span><span class="se">\n</span><span class="s2">  clapCount</span><span class="se">\n</span><span class="s2">  visibility</span><span class="se">\n</span><span class="s2">  mediumUrl</span><span class="se">\n</span><span class="s2">  responseDistribution</span><span class="se">\n</span><span class="s2">  ...useIsPinnedInContext_post</span><span class="se">\n</span><span class="s2">  ...CopyFriendLinkMenuItem_post</span><span class="se">\n</span><span class="s2">  ...NewsletterV3EmailToSubscribersMenuItem_post</span><span class="se">\n</span><span class="s2">  ...OverflowMenuItemUndoClaps_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useIsPinnedInContext_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  pendingCollection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  pinnedAt</span><span class="se">\n</span><span class="s2">  pinnedByCreatorAt</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CopyFriendLinkMenuItem_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment NewsletterV3EmailToSubscribersMenuItem_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  creator {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    newsletterV3 {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      subscribersCount</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  isNewsletter</span><span class="se">\n</span><span class="s2">  isAuthorNewsletter</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment OverflowMenuItemUndoClaps_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  clapCount</span><span class="se">\n</span><span class="s2">  ...ClapMutation_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ClapMutation_post on Post {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  clapCount</span><span class="se">\n</span><span class="s2">  ...MultiVoteCount_post</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MultiVoteCount_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...PostVotersNetwork_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostVotersNetwork_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  voterCount</span><span class="se">\n</span><span class="s2">  recommenders {</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ExpandablePostCardReaderButton_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  creator {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  clapCount</span><span class="se">\n</span><span class="s2">  ...ClapMutation_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment BookmarkButton_post on Post {</span><span class="se">\n</span><span class="s2">  visibility</span><span class="se">\n</span><span class="s2">  ...SusiClickable_post</span><span class="se">\n</span><span class="s2">  ...AddToCatalogBookmarkButton_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiClickable_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  mediumUrl</span><span class="se">\n</span><span class="s2">  ...SusiContainer_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiContainer_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment AddToCatalogBookmarkButton_post on Post {</span><span class="se">\n</span><span class="s2">  ...AddToCatalogBase_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment AddToCatalogBase_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostFooterSocialPopover_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  mediumUrl</span><span class="se">\n</span><span class="s2">  title</span><span class="se">\n</span><span class="s2">  ...SharePostButton_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SharePostButton_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MultiVote_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  clapCount</span><span class="se">\n</span><span class="s2">  creator {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...SusiClickable_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  isPublished</span><span class="se">\n</span><span class="s2">  ...SusiClickable_post</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  isLimitedState</span><span class="se">\n</span><span class="s2">  ...MultiVoteCount_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment OverflowMenuButtonWithNegativeSignal_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...OverflowMenuWithNegativeSignal_post</span><span class="se">\n</span><span class="s2">  ...CreatorActionOverflowPopover_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment OverflowMenuWithNegativeSignal_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  creator {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...OverflowMenuItemUndoClaps_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CreatorActionOverflowPopover_post on Post {</span><span class="se">\n</span><span class="s2">  allowResponses</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  statusForCollection</span><span class="se">\n</span><span class="s2">  isLocked</span><span class="se">\n</span><span class="s2">  isPublished</span><span class="se">\n</span><span class="s2">  clapCount</span><span class="se">\n</span><span class="s2">  mediumUrl</span><span class="se">\n</span><span class="s2">  pinnedAt</span><span class="se">\n</span><span class="s2">  pinnedByCreatorAt</span><span class="se">\n</span><span class="s2">  curationEligibleAt</span><span class="se">\n</span><span class="s2">  mediumUrl</span><span class="se">\n</span><span class="s2">  responseDistribution</span><span class="se">\n</span><span class="s2">  visibility</span><span class="se">\n</span><span class="s2">  inResponseToPostResult {</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  inResponseToCatalogResult {</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  pendingCollection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    creator {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    avatar {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    domain</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  creator {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...MutePopoverOptions_creator</span><span class="se">\n</span><span class="s2">    ...auroraHooks_publisher</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    creator {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    avatar {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    domain</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    ...MutePopoverOptions_collection</span><span class="se">\n</span><span class="s2">    ...auroraHooks_publisher</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...useIsPinnedInContext_post</span><span class="se">\n</span><span class="s2">  ...NewsletterV3EmailToSubscribersMenuItem_post</span><span class="se">\n</span><span class="s2">  ...OverflowMenuItemUndoClaps_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment auroraHooks_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    isAuroraEligible</span><span class="se">\n</span><span class="s2">    isAuroraVisible</span><span class="se">\n</span><span class="s2">    viewerEdge {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      isEditor</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    isAuroraVisible</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment InResponseToEntityPreview_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  inResponseToEntityType</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostScrollTracker_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  sequence {</span><span class="se">\n</span><span class="s2">    sequenceId</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ReadMore_post on Post {</span><span class="se">\n</span><span class="s2">  mediumUrl</span><span class="se">\n</span><span class="s2">  readingTime</span><span class="se">\n</span><span class="s2">  ...usePostUrl_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment usePostUrl_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  creator {</span><span class="se">\n</span><span class="s2">    ...userUrl_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    domain</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  isSeries</span><span class="se">\n</span><span class="s2">  mediumUrl</span><span class="se">\n</span><span class="s2">  sequence {</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  uniqueSlug</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment HighDensityPreview_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  title</span><span class="se">\n</span><span class="s2">  previewImage {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    focusPercentX</span><span class="se">\n</span><span class="s2">    focusPercentY</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  extendedPreviewContent(</span><span class="se">\n</span><span class="s2">    truncationConfig: {previewParagraphsWordCountThreshold: 400, minimumWordLengthForTruncation: 150, truncateAtEndOfSentence: true, showFullImageCaptions: true, shortformPreviewParagraphsWordCountThreshold: 30, shortformMinimumWordLengthForTruncation: 30}</span><span class="se">\n</span><span class="s2">  ) {</span><span class="se">\n</span><span class="s2">    subtitle</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...HighDensityFooter_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment HighDensityFooter_post on Post {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  readingTime</span><span class="se">\n</span><span class="s2">  tags {</span><span class="se">\n</span><span class="s2">    ...TopicPill_tag</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...BookmarkButton_post</span><span class="se">\n</span><span class="s2">  ...ExpandablePostCardOverflowButton_post</span><span class="se">\n</span><span class="s2">  ...OverflowMenuButtonWithNegativeSignal_post</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment TopicPill_tag on Tag {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  displayTitle</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CardByline_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...CardByline_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...CardByline_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment NewsletterV3Promo_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...NewsletterV3Promo_publisher_User</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    ...NewsletterV3Promo_publisher_Collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment NewsletterV3Promo_publisher_User on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  viewerIsUser</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...NewsletterV3Promo_newsletterV3</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment NewsletterV3Promo_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  description</span><span class="se">\n</span><span class="s2">  promoHeadline</span><span class="se">\n</span><span class="s2">  promoBody</span><span class="se">\n</span><span class="s2">  ...NewsletterV3AmpButton_newsletterV3</span><span class="se">\n</span><span class="s2">  ...NewsletterV3SubscribeButton_newsletterV3</span><span class="se">\n</span><span class="s2">  ...NewsletterV3SubscribeByEmail_newsletterV3</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment NewsletterV3AmpButton_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    ...collectionDefaultBackgroundTheme_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment collectionDefaultBackgroundTheme_collection on Collection {</span><span class="se">\n</span><span class="s2">  colorPalette {</span><span class="se">\n</span><span class="s2">    ...collectionDefaultBackgroundTheme_colorPalette</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  customStyleSheet {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...collectionDefaultBackgroundTheme_customStyleSheet</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment collectionDefaultBackgroundTheme_colorPalette on ColorPalette {</span><span class="se">\n</span><span class="s2">  ...customDefaultBackgroundTheme_colorPalette</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment customDefaultBackgroundTheme_colorPalette on ColorPalette {</span><span class="se">\n</span><span class="s2">  highlightSpectrum {</span><span class="se">\n</span><span class="s2">    ...ThemeUtil_colorSpectrum</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  defaultBackgroundSpectrum {</span><span class="se">\n</span><span class="s2">    ...ThemeUtil_colorSpectrum</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  tintBackgroundSpectrum {</span><span class="se">\n</span><span class="s2">    ...ThemeUtil_colorSpectrum</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment collectionDefaultBackgroundTheme_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...customDefaultBackgroundTheme_customStyleSheet</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment customDefaultBackgroundTheme_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  global {</span><span class="se">\n</span><span class="s2">    colorPalette {</span><span class="se">\n</span><span class="s2">      primary {</span><span class="se">\n</span><span class="s2">        colorPalette {</span><span class="se">\n</span><span class="s2">          ...customDefaultBackgroundTheme_colorPalette</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      background {</span><span class="se">\n</span><span class="s2">        colorPalette {</span><span class="se">\n</span><span class="s2">          ...customDefaultBackgroundTheme_colorPalette</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment NewsletterV3SubscribeButton_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  user {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    username</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    ...SusiClickable_collection</span><span class="se">\n</span><span class="s2">    ...collectionDefaultBackgroundTheme_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...SusiClickable_newsletterV3</span><span class="se">\n</span><span class="s2">  ...useNewsletterV3Subscription_newsletterV3</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiClickable_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  ...SusiContainer_newsletterV3</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SusiContainer_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  ...SignInOptions_newsletterV3</span><span class="se">\n</span><span class="s2">  ...SignUpOptions_newsletterV3</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignInOptions_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SignUpOptions_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment NewsletterV3SubscribeByEmail_newsletterV3 on NewsletterV3 {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  user {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    username</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  collection {</span><span class="se">\n</span><span class="s2">    ...collectionDefaultBackgroundTheme_collection</span><span class="se">\n</span><span class="s2">    ...collectionUrl_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment NewsletterV3Promo_publisher_Collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  domain</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...NewsletterV3Promo_newsletterV3</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherHomePosts_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...useShowAuthorNewsletterV3Promo_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useShowAuthorNewsletterV3Promo_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    showPromo</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserSubdomainFlow_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  hasCompletedProfile</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  bio</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  ...UserCompleteProfileDialog_user</span><span class="se">\n</span><span class="s2">  ...UserSubdomainOnboardingDialog_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserCompleteProfileDialog_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  bio</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  hasCompletedProfile</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserSubdomainOnboardingDialog_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  customDomainState {</span><span class="se">\n</span><span class="s2">    pending {</span><span class="se">\n</span><span class="s2">      status</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    live {</span><span class="se">\n</span><span class="s2">      status</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserProfileMetadata_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  bio</span><span class="se">\n</span><span class="s2">  socialStats {</span><span class="se">\n</span><span class="s2">    followerCount</span><span class="se">\n</span><span class="s2">    followingCount</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...userUrl_user</span><span class="se">\n</span><span class="s2">  ...UserProfileMetadataHelmet_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserProfileMetadataHelmet_user on User {</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  twitterScreenName</span><span class="se">\n</span><span class="s2">  navItems {</span><span class="se">\n</span><span class="s2">    title</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SuspendedBannerLoader_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  isSuspended</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useAnalytics_user on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment EntityDrivenSubscriptionLandingPageScreen_writer on User {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  imageId</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  username</span><span class="se">\n</span><span class="s2">  isPartnerProgramEnrolled</span><span class="se">\n</span><span class="s2">  customStyleSheet {</span><span class="se">\n</span><span class="s2">    ...CustomThemeProvider_customStyleSheet</span><span class="se">\n</span><span class="s2">    ...CustomBackgroundWrapper_customStyleSheet</span><span class="se">\n</span><span class="s2">    ...MetaHeader_customStyleSheet</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...MetaHeader_publisher</span><span class="se">\n</span><span class="s2">  ...userUrl_user</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CustomThemeProvider_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...customDefaultBackgroundTheme_customStyleSheet</span><span class="se">\n</span><span class="s2">  ...customStyleSheetFontTheme_customStyleSheet</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment customStyleSheetFontTheme_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  global {</span><span class="se">\n</span><span class="s2">    fonts {</span><span class="se">\n</span><span class="s2">      font1 {</span><span class="se">\n</span><span class="s2">        name</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      font2 {</span><span class="se">\n</span><span class="s2">        name</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      font3 {</span><span class="se">\n</span><span class="s2">        name</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CustomBackgroundWrapper_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  global {</span><span class="se">\n</span><span class="s2">    colorPalette {</span><span class="se">\n</span><span class="s2">      background {</span><span class="se">\n</span><span class="s2">        ...getHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeader_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  header {</span><span class="se">\n</span><span class="s2">    headerScale</span><span class="se">\n</span><span class="s2">    horizontalAlignment</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...MetaHeaderBackground_customStyleSheet</span><span class="se">\n</span><span class="s2">  ...MetaHeaderEngagement_customStyleSheet</span><span class="se">\n</span><span class="s2">  ...MetaHeaderLogo_customStyleSheet</span><span class="se">\n</span><span class="s2">  ...MetaHeaderNavVertical_customStyleSheet</span><span class="se">\n</span><span class="s2">  ...MetaHeaderTagline_customStyleSheet</span><span class="se">\n</span><span class="s2">  ...MetaHeaderThemeProvider_customStyleSheet</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderBackground_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  header {</span><span class="se">\n</span><span class="s2">    headerScale</span><span class="se">\n</span><span class="s2">    backgroundImageDisplayMode</span><span class="se">\n</span><span class="s2">    backgroundImageVerticalAlignment</span><span class="se">\n</span><span class="s2">    backgroundColorDisplayMode</span><span class="se">\n</span><span class="s2">    backgroundColor {</span><span class="se">\n</span><span class="s2">      ...getHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">      ...getOpaqueHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    secondaryBackgroundColor {</span><span class="se">\n</span><span class="s2">      ...getHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    postBackgroundColor {</span><span class="se">\n</span><span class="s2">      ...getHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    backgroundImage {</span><span class="se">\n</span><span class="s2">      ...MetaHeaderBackground_imageMetadata</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderEngagement_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  ...MetaHeaderNav_customStyleSheet</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderNav_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  navigation {</span><span class="se">\n</span><span class="s2">    navItems {</span><span class="se">\n</span><span class="s2">      ...MetaHeaderNav_headerNavigationItem</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderNav_headerNavigationItem on HeaderNavigationItem {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  tagSlugs</span><span class="se">\n</span><span class="s2">  ...MetaHeaderNavLink_headerNavigationItem</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderNavLink_headerNavigationItem on HeaderNavigationItem {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...getNavItemHref_headerNavigationItem</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getNavItemHref_headerNavigationItem on HeaderNavigationItem {</span><span class="se">\n</span><span class="s2">  href</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  tags {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    normalizedTagSlug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderLogo_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  header {</span><span class="se">\n</span><span class="s2">    nameColor {</span><span class="se">\n</span><span class="s2">      ...getHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    nameTreatment</span><span class="se">\n</span><span class="s2">    postNameTreatment</span><span class="se">\n</span><span class="s2">    logoImage {</span><span class="se">\n</span><span class="s2">      ...MetaHeaderLogo_imageMetadata</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    logoScale</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderLogo_imageMetadata on ImageMetadata {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  originalWidth</span><span class="se">\n</span><span class="s2">  originalHeight</span><span class="se">\n</span><span class="s2">  ...PublisherLogo_image</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherLogo_image on ImageMetadata {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  originalHeight</span><span class="se">\n</span><span class="s2">  originalWidth</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderNavVertical_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  navigation {</span><span class="se">\n</span><span class="s2">    navItems {</span><span class="se">\n</span><span class="s2">      ...MetaHeaderNavLink_headerNavigationItem</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...MetaHeaderNav_customStyleSheet</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderTagline_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  header {</span><span class="se">\n</span><span class="s2">    taglineColor {</span><span class="se">\n</span><span class="s2">      ...getHexFromColorValue_colorValue</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    taglineTreatment</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderThemeProvider_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...useMetaHeaderTheme_customStyleSheet</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useMetaHeaderTheme_customStyleSheet on CustomStyleSheet {</span><span class="se">\n</span><span class="s2">  ...customDefaultBackgroundTheme_customStyleSheet</span><span class="se">\n</span><span class="s2">  global {</span><span class="se">\n</span><span class="s2">    colorPalette {</span><span class="se">\n</span><span class="s2">      primary {</span><span class="se">\n</span><span class="s2">        colorPalette {</span><span class="se">\n</span><span class="s2">          tintBackgroundSpectrum {</span><span class="se">\n</span><span class="s2">            ...ThemeUtil_colorSpectrum</span><span class="se">\n</span><span class="s2">            __typename</span><span class="se">\n</span><span class="s2">          }</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  header {</span><span class="se">\n</span><span class="s2">    backgroundColor {</span><span class="se">\n</span><span class="s2">      colorPalette {</span><span class="se">\n</span><span class="s2">        tintBackgroundSpectrum {</span><span class="se">\n</span><span class="s2">          ...ThemeUtil_colorSpectrum</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    postBackgroundColor {</span><span class="se">\n</span><span class="s2">      colorPalette {</span><span class="se">\n</span><span class="s2">        tintBackgroundSpectrum {</span><span class="se">\n</span><span class="s2">          ...ThemeUtil_colorSpectrum</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    backgroundImage {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeader_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...MetaHeaderEngagement_publisher</span><span class="se">\n</span><span class="s2">  ...MetaHeaderLogo_publisher</span><span class="se">\n</span><span class="s2">  ...MetaHeaderNavVertical_publisher</span><span class="se">\n</span><span class="s2">  ...MetaHeaderTagline_publisher</span><span class="se">\n</span><span class="s2">  ...MetaHeaderThemeProvider_publisher</span><span class="se">\n</span><span class="s2">  ...MetaHeaderActions_publisher</span><span class="se">\n</span><span class="s2">  ...MetaHeaderTop_publisher</span><span class="se">\n</span><span class="s2">  ...MetaHeaderNavLink_publisher</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    favicon {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    tagline</span><span class="se">\n</span><span class="s2">    ...CollectionNavigationContextProvider_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    bio</span><span class="se">\n</span><span class="s2">    ...UserProfileCatalogsLink_publisher</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderEngagement_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ...MetaHeaderNav_publisher</span><span class="se">\n</span><span class="s2">  ...PublisherAboutLink_publisher</span><span class="se">\n</span><span class="s2">  ...PublisherFollowButton_publisher</span><span class="se">\n</span><span class="s2">  ...PublisherFollowerCount_publisher</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    creator {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    customStyleSheet {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      ...CustomThemeProvider_customStyleSheet</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...UserProfileCatalogsLink_publisher</span><span class="se">\n</span><span class="s2">    ...UserSubscribeButton_user</span><span class="se">\n</span><span class="s2">    customStyleSheet {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      ...CustomThemeProvider_customStyleSheet</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderNav_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...MetaHeaderNavLink_publisher</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderNavLink_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...getNavItemHref_publisher</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getNavItemHref_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...publisherUrl_publisher</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherAboutLink_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...userUrl_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PublisherFollowButton_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    ...CollectionFollowButton_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...UserFollowButton_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment UserProfileCatalogsLink_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    ...userUrl_user</span><span class="se">\n</span><span class="s2">    homePostsPublished: homepagePostsConnection(paging: {limit: 1}) {</span><span class="se">\n</span><span class="s2">      posts {</span><span class="se">\n</span><span class="s2">        id</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderLogo_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    logo {</span><span class="se">\n</span><span class="s2">      ...MetaHeaderLogo_imageMetadata</span><span class="se">\n</span><span class="s2">      ...PublisherLogo_image</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...auroraHooks_publisher</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderNavVertical_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  ...PublisherAboutLink_publisher</span><span class="se">\n</span><span class="s2">  ...MetaHeaderNav_publisher</span><span class="se">\n</span><span class="s2">  ...MetaHeaderNavLink_publisher</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderTagline_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    tagline</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    bio</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderThemeProvider_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  customStyleSheet {</span><span class="se">\n</span><span class="s2">    ...MetaHeaderThemeProvider_customStyleSheet</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    colorPalette {</span><span class="se">\n</span><span class="s2">      ...customDefaultBackgroundTheme_colorPalette</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderActions_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ...MetaHeaderPubMenu_publisher</span><span class="se">\n</span><span class="s2">  ...SearchWidget_publisher</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    creator {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    customStyleSheet {</span><span class="se">\n</span><span class="s2">      navigation {</span><span class="se">\n</span><span class="s2">        navItems {</span><span class="se">\n</span><span class="s2">          name</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    ...CollectionAvatar_collection</span><span class="se">\n</span><span class="s2">    ...CollectionMetabarActionsPopover_collection</span><span class="se">\n</span><span class="s2">    ...MetaHeaderActions_collection_common</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...UserAvatar_user</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment SearchWidget_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    domain</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...algoliaSearch_publisher</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment algoliaSearch_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CollectionMetabarActionsPopover_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  isAuroraEligible</span><span class="se">\n</span><span class="s2">  isAuroraVisible</span><span class="se">\n</span><span class="s2">  newsletterV3 {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...collectionUrl_collection</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderActions_collection_common on Collection {</span><span class="se">\n</span><span class="s2">  creator {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderTop_publisher on Publisher {</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  ... on Collection {</span><span class="se">\n</span><span class="s2">    slug</span><span class="se">\n</span><span class="s2">    ...CollectionMetabarActionsPopover_collection</span><span class="se">\n</span><span class="s2">    ...CollectionAvatar_collection</span><span class="se">\n</span><span class="s2">    ...MetaHeaderTop_collection</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ... on User {</span><span class="se">\n</span><span class="s2">    username</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MetaHeaderTop_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  creator {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CollectionNavigationContextProvider_collection on Collection {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  domain</span><span class="se">\n</span><span class="s2">  slug</span><span class="se">\n</span><span class="s2">  isAuroraVisible</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment useShouldShowEntityDrivenSubscription_creator on User {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n</span><span class="s2">"</span><span class="w">
      </span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">id</code> : 帐号对应的 User Id，上面那个取得追踪者的 Endpoint 有给</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">homepagePostsFrom</code> : 分页参数，可参考回应中的 <code class="language-plaintext highlighter-rouge">from</code> 带入取得所有分页资料</p>
  </li>
</ul>

<p><a href="https://www.postman.com/" target="_blank"><strong>Postman</strong></a> <strong>:</strong></p>

<p><img src="/assets/88f0fb935120/1*dw61NwISVGRbFLlie4Na2w.webp" alt="" loading="lazy" decoding="async" width="1552" height="1325" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTUyIiBoZWlnaHQ9IjEzMjUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/88f0fb935120/1*dw61NwISVGRbFLlie4Na2w.png" /></p>

<p><strong>Response:</strong></p>

<p><img src="/assets/88f0fb935120/1*FEt2xWEjJMqpWjxYVUgVWg.webp" alt="" loading="lazy" decoding="async" width="1070" height="998" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDcwIiBoZWlnaHQ9Ijk5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/88f0fb935120/1*FEt2xWEjJMqpWjxYVUgVWg.png" /></p>

<p>在 <code class="language-plaintext highlighter-rouge">response[0]["data"]["userResult"]["homepagePostsConnection"]["posts"]</code> 可以取得文章列表资讯。</p>

<h4 id="medium-private-api--取得文章内容">Medium Private API — 取得文章内容</h4>

<p>再来就是最关键的，爬取文章原始内容。</p>

<p>Graphql Query Body:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="w">
      </span><span class="p">{</span><span class="w">
        </span><span class="nl">"operationName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PostViewerEdgeContentQuery"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"variables"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"postId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"c008a9e8ceca"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"query"</span><span class="p">:</span><span class="w"> </span><span class="s2">"query PostViewerEdgeContentQuery($postId: ID!, $postMeteringOptions: PostMeteringOptions) {</span><span class="se">\n</span><span class="s2">  post(id: $postId) {</span><span class="se">\n</span><span class="s2">    ... on Post {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      viewerEdge {</span><span class="se">\n</span><span class="s2">        id</span><span class="se">\n</span><span class="s2">        fullContent(postMeteringOptions: $postMeteringOptions) {</span><span class="se">\n</span><span class="s2">          isLockedPreviewOnly</span><span class="se">\n</span><span class="s2">          validatedShareKey</span><span class="se">\n</span><span class="s2">          bodyModel {</span><span class="se">\n</span><span class="s2">            ...PostBody_bodyModel</span><span class="se">\n</span><span class="s2">            __typename</span><span class="se">\n</span><span class="s2">          }</span><span class="se">\n</span><span class="s2">          __typename</span><span class="se">\n</span><span class="s2">        }</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostBody_bodyModel on RichText {</span><span class="se">\n</span><span class="s2">  sections {</span><span class="se">\n</span><span class="s2">    name</span><span class="se">\n</span><span class="s2">    startIndex</span><span class="se">\n</span><span class="s2">    textLayout</span><span class="se">\n</span><span class="s2">    imageLayout</span><span class="se">\n</span><span class="s2">    backgroundImage {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      originalHeight</span><span class="se">\n</span><span class="s2">      originalWidth</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    videoLayout</span><span class="se">\n</span><span class="s2">    backgroundVideo {</span><span class="se">\n</span><span class="s2">      videoId</span><span class="se">\n</span><span class="s2">      originalHeight</span><span class="se">\n</span><span class="s2">      originalWidth</span><span class="se">\n</span><span class="s2">      previewImageId</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    ...PostBodySection_paragraph</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...normalizedBodyModel_richText</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostBodySection_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  ...PostBodyParagraph_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostBodyParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  ...ImageParagraph_paragraph</span><span class="se">\n</span><span class="s2">  ...TextParagraph_paragraph</span><span class="se">\n</span><span class="s2">  ...IframeParagraph_paragraph</span><span class="se">\n</span><span class="s2">  ...MixtapeParagraph_paragraph</span><span class="se">\n</span><span class="s2">  ...CodeBlockParagraph_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ImageParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  href</span><span class="se">\n</span><span class="s2">  layout</span><span class="se">\n</span><span class="s2">  metadata {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    originalHeight</span><span class="se">\n</span><span class="s2">    originalWidth</span><span class="se">\n</span><span class="s2">    focusPercentX</span><span class="se">\n</span><span class="s2">    focusPercentY</span><span class="se">\n</span><span class="s2">    alt</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...Markups_paragraph</span><span class="se">\n</span><span class="s2">  ...ParagraphRefsMapContext_paragraph</span><span class="se">\n</span><span class="s2">  ...PostAnnotationsMarker_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment Markups_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  text</span><span class="se">\n</span><span class="s2">  hasDropCap</span><span class="se">\n</span><span class="s2">  dropCapImage {</span><span class="se">\n</span><span class="s2">    ...MarkupNode_data_dropCapImage</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  markups {</span><span class="se">\n</span><span class="s2">    type</span><span class="se">\n</span><span class="s2">    start</span><span class="se">\n</span><span class="s2">    end</span><span class="se">\n</span><span class="s2">    href</span><span class="se">\n</span><span class="s2">    anchorType</span><span class="se">\n</span><span class="s2">    userId</span><span class="se">\n</span><span class="s2">    linkMetadata {</span><span class="se">\n</span><span class="s2">      httpStatus</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MarkupNode_data_dropCapImage on ImageMetadata {</span><span class="se">\n</span><span class="s2">  ...DropCap_image</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment DropCap_image on ImageMetadata {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  originalHeight</span><span class="se">\n</span><span class="s2">  originalWidth</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment ParagraphRefsMapContext_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  text</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostAnnotationsMarker_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  ...PostViewNoteCard_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment PostViewNoteCard_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment TextParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  hasDropCap</span><span class="se">\n</span><span class="s2">  codeBlockMetadata {</span><span class="se">\n</span><span class="s2">    mode</span><span class="se">\n</span><span class="s2">    lang</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...Markups_paragraph</span><span class="se">\n</span><span class="s2">  ...ParagraphRefsMapContext_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment IframeParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  iframe {</span><span class="se">\n</span><span class="s2">    mediaResource {</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      iframeSrc</span><span class="se">\n</span><span class="s2">      iframeHeight</span><span class="se">\n</span><span class="s2">      iframeWidth</span><span class="se">\n</span><span class="s2">      title</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  layout</span><span class="se">\n</span><span class="s2">  ...getEmbedlyCardUrlParams_paragraph</span><span class="se">\n</span><span class="s2">  ...Markups_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getEmbedlyCardUrlParams_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  iframe {</span><span class="se">\n</span><span class="s2">    mediaResource {</span><span class="se">\n</span><span class="s2">      iframeSrc</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment MixtapeParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  mixtapeMetadata {</span><span class="se">\n</span><span class="s2">    href</span><span class="se">\n</span><span class="s2">    mediaResource {</span><span class="se">\n</span><span class="s2">      mediumCatalog {</span><span class="se">\n</span><span class="s2">        id</span><span class="se">\n</span><span class="s2">        __typename</span><span class="se">\n</span><span class="s2">      }</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...GenericMixtapeParagraph_paragraph</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment GenericMixtapeParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  text</span><span class="se">\n</span><span class="s2">  mixtapeMetadata {</span><span class="se">\n</span><span class="s2">    href</span><span class="se">\n</span><span class="s2">    thumbnailImageId</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  markups {</span><span class="se">\n</span><span class="s2">    start</span><span class="se">\n</span><span class="s2">    end</span><span class="se">\n</span><span class="s2">    type</span><span class="se">\n</span><span class="s2">    href</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment CodeBlockParagraph_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  codeBlockMetadata {</span><span class="se">\n</span><span class="s2">    lang</span><span class="se">\n</span><span class="s2">    mode</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment normalizedBodyModel_richText on RichText {</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    markups {</span><span class="se">\n</span><span class="s2">      type</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    codeBlockMetadata {</span><span class="se">\n</span><span class="s2">      lang</span><span class="se">\n</span><span class="s2">      mode</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    ...getParagraphHighlights_paragraph</span><span class="se">\n</span><span class="s2">    ...getParagraphPrivateNotes_paragraph</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  sections {</span><span class="se">\n</span><span class="s2">    startIndex</span><span class="se">\n</span><span class="s2">    ...getSectionEndIndex_section</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...getParagraphStyles_richText</span><span class="se">\n</span><span class="s2">  ...getParagraphSpaces_richText</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getParagraphHighlights_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getParagraphPrivateNotes_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  name</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getSectionEndIndex_section on Section {</span><span class="se">\n</span><span class="s2">  startIndex</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getParagraphStyles_richText on RichText {</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    text</span><span class="se">\n</span><span class="s2">    type</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  sections {</span><span class="se">\n</span><span class="s2">    ...getSectionEndIndex_section</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getParagraphSpaces_richText on RichText {</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    layout</span><span class="se">\n</span><span class="s2">    metadata {</span><span class="se">\n</span><span class="s2">      originalHeight</span><span class="se">\n</span><span class="s2">      originalWidth</span><span class="se">\n</span><span class="s2">      id</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    type</span><span class="se">\n</span><span class="s2">    ...paragraphExtendsImageGrid_paragraph</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  ...getSeriesParagraphTopSpacings_richText</span><span class="se">\n</span><span class="s2">  ...getPostParagraphTopSpacings_richText</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment paragraphExtendsImageGrid_paragraph on Paragraph {</span><span class="se">\n</span><span class="s2">  layout</span><span class="se">\n</span><span class="s2">  type</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">  id</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getSeriesParagraphTopSpacings_richText on RichText {</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    id</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  sections {</span><span class="se">\n</span><span class="s2">    startIndex</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n\n</span><span class="s2">fragment getPostParagraphTopSpacings_richText on RichText {</span><span class="se">\n</span><span class="s2">  paragraphs {</span><span class="se">\n</span><span class="s2">    layout</span><span class="se">\n</span><span class="s2">    text</span><span class="se">\n</span><span class="s2">    codeBlockMetadata {</span><span class="se">\n</span><span class="s2">      lang</span><span class="se">\n</span><span class="s2">      mode</span><span class="se">\n</span><span class="s2">      __typename</span><span class="se">\n</span><span class="s2">    }</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  sections {</span><span class="se">\n</span><span class="s2">    startIndex</span><span class="se">\n</span><span class="s2">    __typename</span><span class="se">\n</span><span class="s2">  }</span><span class="se">\n</span><span class="s2">  __typename</span><span class="se">\n</span><span class="s2">}</span><span class="se">\n</span><span class="s2">"</span><span class="w">
      </span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">posdId</code> : 文章 ID，上面取得文章列表的 API 有给。</li>
</ul>

<p><a href="https://www.postman.com/" target="_blank"><strong>Postman</strong></a> <strong>:</strong></p>

<p><img src="/assets/88f0fb935120/1*K7ldG92qvdNIMG89NJC3nw.webp" alt="" loading="lazy" decoding="async" width="1200" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwMjQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/88f0fb935120/1*K7ldG92qvdNIMG89NJC3nw.png" /></p>

<p><strong>Response:</strong></p>

<p><img src="/assets/88f0fb935120/1*r3va7Mjc0DTD3pAYkDsozQ.webp" alt="" loading="lazy" decoding="async" width="987" height="1060" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5ODciIGhlaWdodD0iMTA2MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/88f0fb935120/1*r3va7Mjc0DTD3pAYkDsozQ.png" /></p>

<p>文章 Source 如上图：</p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">response[0]["data"]["post"]["viewerEdge"]["fullContent"]["bodyModel"]["paragraphs"]</code> :整篇文章段落，组合起来就是全篇文章</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">["markups"]</code> : 段落的文字样式，例如粗体、超连结…</p>
  </li>
</ul>

<blockquote>
  <p><strong><em>至于如何把这个 JSON 描述格式转换成 Markdown 可以直接参考或使用我之前开发的开源工具 — <a href="https://github.com/ZhgChgLi/ZMediumToMarkdown" target="_blank">ZMediumToMarkdown</a></em></strong></p>
</blockquote>

<p><a href="https://github.com/ZhgChgLi/ZMediumToMarkdown" target="_blank"><img src="https://repository-images.githubusercontent.com/493527574/9b5b7025-cc95-4e81-84a9-b38706093c27" alt="" /></a></p>

<ul>
  <li>如果要爬取自己的付费文章需要带上 sid, uid 登入权杖资讯 (参考下文)</li>
</ul>

<h3 id="medium-x-cloudflare-攻防">Medium x Cloudflare 攻防</h3>

<p>本篇文章的第二个主题，就是 Cloudflare，大约在 2025 下半年开始，Medium 的 Cloudflare 防护设定几乎到了最高等级，所有来自云服务的请求都会被阻挡(我用 Google Apps Script / GitHub Actions 全都会被挡)，导致爬取资料失败。</p>

<p><strong>阻挡讯息：403</strong></p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span><span class="nt">&lt;html</span> <span class="na">lang=</span><span class="s">"en-US"</span><span class="nt">&gt;&lt;head&gt;&lt;title&gt;</span>Just a moment...<span class="nt">&lt;/title&gt;&lt;meta</span> <span class="na">http-equiv=</span><span class="s">"Content-Type"</span> <span class="na">content=</span><span class="s">"text/html; charset=UTF-8"</span><span class="nt">&gt;</span>....
</code></pre></div></div>

<p>这让我非常苦恼，因为我的镜像站 ( <a href="https://zhgchg.li" target="_blank">https://zhgchg.li</a> ) 已经稳定运作了好几年，只要 Medium 有新文章发布，那边就会定时自动执行脚本同步过去 (透过 Private API Graphql)， <strong>如果云端服务会被阻挡，我就只能手动在本地电脑执行脚本</strong> 。</p>

<h4 id="header-cookies-多加上-sid-uid-"><strong>Header Cookies 多加上 sid, uid ❌</strong></h4>

<p><strong>最一开始我在 Header Cookies 多加上 sid, uid 等于是 Medium 登入身份，可以顺利通过，但过了几个月之后连这个方法也行不通了。</strong></p>

<p><img src="/assets/88f0fb935120/1*nKrcxHJP80VHkDUnQLEFFg.webp" alt="" loading="lazy" decoding="async" width="1418" height="474" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDE4IiBoZWlnaHQ9IjQ3NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/88f0fb935120/1*nKrcxHJP80VHkDUnQLEFFg.png" /></p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">uid</code> : 你的使用者 ID</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">sid</code> : 你的 access token <strong>(务必保密)</strong></p>
  </li>
</ul>

<h4 id="cloudflare-worker-桥接请求-">Cloudflare Worker 桥接请求 ✅</h4>

<p>乱试一通后找不到方法，突发奇想用 Cloudflare 的魔法打败魔法，用 Cloudflare，没想到就成功了！不会被 Cloudflare Bot 防护阻挡。</p>

<p><strong>Demo Code:</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="k">default</span> <span class="p">{</span>

  <span class="k">async</span> <span class="nf">fetch</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="nx">env</span><span class="p">,</span> <span class="nx">ctx</span><span class="p">)</span> <span class="p">{</span>

    <span class="kd">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">URL</span><span class="p">(</span><span class="nx">request</span><span class="p">.</span><span class="nx">url</span><span class="p">);</span>
    <span class="kd">const</span> <span class="nx">path</span> <span class="o">=</span> <span class="nx">url</span><span class="p">.</span><span class="nx">pathname</span><span class="p">;</span>

    <span class="k">if </span><span class="p">(</span><span class="nx">path</span> <span class="o">==</span> <span class="dl">"</span><span class="s2">/graphql</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
      <span class="kd">let</span> <span class="nx">body</span><span class="p">;</span>
      <span class="k">try</span> <span class="p">{</span>
        <span class="nx">body</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">request</span><span class="p">.</span><span class="nf">json</span><span class="p">();</span>
      <span class="p">}</span> <span class="k">catch</span> <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nc">Response</span><span class="p">(</span><span class="dl">"</span><span class="s2">Invalid JSON body</span><span class="dl">"</span><span class="p">,</span> <span class="p">{</span> <span class="na">status</span><span class="p">:</span> <span class="mi">400</span> <span class="p">});</span>
      <span class="p">}</span>

      <span class="kd">let</span> <span class="nx">apiURL</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">https://medium.com/_/graphql</span><span class="dl">"</span><span class="p">;</span>

      <span class="kd">const</span> <span class="nx">apiResponse</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">fetch</span><span class="p">(</span><span class="nx">apiURL</span><span class="p">,</span> <span class="p">{</span>
        <span class="na">method</span><span class="p">:</span> <span class="dl">"</span><span class="s2">POST</span><span class="dl">"</span><span class="p">,</span>
        <span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
          <span class="dl">"</span><span class="s2">Accept</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/json</span><span class="dl">"</span><span class="p">,</span>
          <span class="dl">"</span><span class="s2">Content-Type</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/json</span><span class="dl">"</span><span class="p">,</span>
          <span class="dl">"</span><span class="s2">User-Agent</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0</span><span class="dl">"</span><span class="p">,</span>
          <span class="dl">"</span><span class="s2">Cookie</span><span class="dl">"</span><span class="p">:</span> <span class="nx">request</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="dl">"</span><span class="s2">cookie</span><span class="dl">"</span><span class="p">)</span>
        <span class="p">},</span>
        <span class="na">body</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">body</span><span class="p">),</span>
      <span class="p">});</span>

      <span class="kd">const</span> <span class="nx">json</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">apiResponse</span><span class="p">.</span><span class="nf">json</span><span class="p">();</span>
      <span class="k">return</span> <span class="k">new</span> <span class="nc">Response</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">json</span><span class="p">),</span> <span class="p">{</span>
        <span class="na">status</span><span class="p">:</span> <span class="nx">apiResponse</span><span class="p">.</span><span class="nx">status</span><span class="p">,</span>
        <span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
          <span class="dl">"</span><span class="s2">Content-Type</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/json; charset=utf-8</span><span class="dl">"</span><span class="p">,</span>
        <span class="p">},</span>
      <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="k">new</span> <span class="nc">Response</span><span class="p">(</span><span class="dl">"</span><span class="s2">Not Found</span><span class="dl">"</span><span class="p">,</span> <span class="p">{</span> <span class="na">status</span><span class="p">:</span> <span class="mi">404</span> <span class="p">});</span>
  <span class="p">},</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Request:</p>

<p>从 <code class="language-plaintext highlighter-rouge">https://medium.com/_/graphql</code> 改成你部署的 Cloudflare Worker URL 即可。</p>

<h4 id="总结">总结</h4>

<p>以上就是我跟 Medium API 搏斗这么多年的心路历程，目前所有的文章 (Markdown 档)及图片都有备份到 <a href="https://zhgchg.li" target="_blank">https://zhgchg.li</a> 包含所有附加图片档案，GitHub Repo 有一份、电脑硬碟也有一份，非常安全。</p>

<blockquote>
  <p>还是希望 Medium 能长长久久！本文内容只供实验参考，作者不负任何使用责任。</p>
</blockquote>]]></content>
  </entry><entry>
    <title type="html">App Store Connect API Webhook 串接｜提升 iOS CI/CD 自动化效率与通知流程</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/app-store-connect-api-webhook-%E4%B8%B2%E6%8E%A5-%E6%8F%90%E5%8D%87-ios-ci-cd-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%95%88%E7%8E%87%E4%B8%8E%E9%80%9A%E7%9F%A5%E6%B5%81%E7%A8%8B-7c0974856393/" rel="alternate" type="text/html" title="App Store Connect API Webhook 串接｜提升 iOS CI/CD 自动化效率与通知流程" />
    <published>2025-12-27T17:02:01+08:00</published>
    <updated>2025-12-27T17:05:14+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/7c0974856393</id><summary type="html">针对 iOS 开发者面临的建置等待与通知延迟问题，透过 App Store Connect API Webhook 实现即时事件推送，结合 Fastlane 与 CI/CD 工具，打造零等待成本的自动化工作流程，提升团队开发效率与发布准确度。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="ios-app-development" /><category term="cicd" /><category term="webhooks" /><category term="fastlane" /><category term="app-store" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/7c0974856393/1*IqytjX72CmAx9WOx4Rm3gg.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/app-store-connect-api-webhook-%E4%B8%B2%E6%8E%A5-%E6%8F%90%E5%8D%87-ios-ci-cd-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%95%88%E7%8E%87%E4%B8%8E%E9%80%9A%E7%9F%A5%E6%B5%81%E7%A8%8B-7c0974856393/"><![CDATA[<h3 id="cicd-使用-app-store-connect-api-webhook-串接自动化工作流程">[CI/CD] 使用 App Store Connect API Webhook 串接自动化工作流程</h3>

<p>App Store Connect Webhook 应用案例分析与实际串接使用教学。</p>

<p><img src="/assets/7c0974856393/1*IqytjX72CmAx9WOx4Rm3gg.webp" alt="Photo by Volodymyr Hryshchenko" loading="lazy" decoding="async" width="5472" height="3648" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NDcyIiBoZWlnaHQ9IjM2NDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/7c0974856393/1*IqytjX72CmAx9WOx4Rm3gg.jpeg" /></p>

<p>Photo by <a href="https://unsplash.com/@lunarts?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank">Volodymyr Hryshchenko</a></p>

<h4 id="前言">前言</h4>

<p>苹果近年持续扩充 App Store Connect API，对开发者是一大福音。早期连凭证管理都得靠「Hardcore」的 Web Session（有期限、还要收简讯验证码），很难整合进 CI/CD；像商城评价也只能依赖不稳定的 RSS。</p>

<p>这几年几乎每年都有新功能补齐，从开发、测试到部署流程，甚至后期的评价、财务、数据报表都逐步原生支援，另外也强化了使用者管理、群组、TestFlight 等能力；让 <strong>App Store Connect API 可以更好的提升 Apple 开发者开发体验</strong> 。</p>

<blockquote>
  <p><em>延伸阅读：「 <a href="/posts/zrealm-dev/app-store-connect-api-快速读取与管理-customer-reviews-提升-ios-app-评价整合效率-f1365e51902c/">App Store Connect API 现已支援 读取和管理 Customer Reviews</a> 」</em></p>
</blockquote>

<h4 id="wwdc-2025-automate-your-development-process-with-the-app-store-connect-api"><a href="https://developer.apple.com/videos/play/wwdc2025/324/" target="_blank">WWDC 2025 Automate your development process with the App Store Connect API</a></h4>

<p><a href="https://developer.apple.com/videos/play/wwdc2025/324/" target="_blank"><img src="https://devimages-cdn.apple.com/wwdc-services/images/3055294D-836B-4513-B7B0-0BC5666246B0/9859/9859_wide_250x141_2x.jpg" alt="" /></a></p>

<p><strong>2025 WWDC 更带来引颈期盼的重磅功能 — Webhook 通知：</strong></p>

<ul>
  <li>
    <p><strong>建置版本上传状态 (The <a href="https://developer.apple.com/help/app-store-connect/reference/app-uploads/build-upload-statuses" target="_blank">status of a build upload</a> changes. )</strong>
当建置版本上传状态更改时收到相关资料。
<code class="language-plaintext highlighter-rouge">Complete / Failed / Processing</code></p>
  </li>
  <li>
    <p><strong>App 版本状态 (The <a href="https://developer.apple.com/help/app-store-connect/reference/app-information/app-and-submission-statuses#app-statuses" target="_blank">status of an app version</a> changes. )</strong>
当 App 版本状态更改时收到相关资料。
<code class="language-plaintext highlighter-rouge">Prepare for Submission / Ready for Review / Waiting for Review / Ready for Distribution / Rejected…</code></p>
  </li>
  <li>
    <p><strong>TestFlight 版本状态 (New <a href="https://developer.apple.com/help/app-store-connect/test-a-beta-version/view-tester-feedback" target="_blank">TestFlight feedback</a> is submitted by a tester. )</strong>
当测试人员留下回馈(当机回馈/截图回馈)时收到相关资料。</p>
  </li>
  <li>
    <p><strong>Apple-hosted 的资源包状态改变 (The <a href="https://developer.apple.com/help/app-store-connect/reference/app-uploads/apple-hosted-asset-pack-statuses" target="_blank">status of an Apple-hosted asset pack version</a> changes. )</strong>
当 Apple 托管的素材包版本出现特定变更时收到相关资料。</p>
  </li>
</ul>

<h4 id="app-store-connect-api--webhook-notifications-"><a href="https://developer.apple.com/documentation/AppStoreConnectAPI/webhook-notifications" target="_blank">App Store Connect API / Webhook notifications</a> :</h4>

<blockquote>
  <p><em>Webhooks enable a system to send real-time data to another system over the web.</em></p>
</blockquote>

<blockquote>
  <p><em>Webhook 让一个系统能够透过网路即时将资料传送给另一个系统。</em></p>
</blockquote>

<blockquote>
  <p><em>Unlike traditional APIs, where one system must make a request when receiving data, a webhook enables you to push data to the receiving system as soon as an event occurs.</em></p>
</blockquote>

<blockquote>
  <p><em>与传统 API 不同的是，传统 API 需要由接收资料的一方主动发送请求，而 Webhook 则能在事件发生的当下，立即将资料推送给接收系统。</em></p>
</blockquote>

<blockquote>
  <p><em>Webhooks are event-driven, meaning they are triggered by a specific action or event and immediately send the relevant data to a predefined URL, also called the “webhook URL” or “callback URL”.</em></p>
</blockquote>

<blockquote>
  <p><em>Webhook 是事件驱动的，表示它们会在特定动作或事件被触发时，立即将相关资料传送到一个预先设定的 URL，该 URL 也称为「Webhook URL」或「Callback URL」。</em></p>
</blockquote>

<blockquote>
  <p><em>A notification webhook is an endpoint you create on your server.</em></p>
</blockquote>

<blockquote>
  <p><em>通知型 Webhook 是你在自己伺服器上建立的一个端点（endpoint）。</em></p>
</blockquote>

<blockquote>
  <p><em>This webhook endpoint receives HTTP POST requests from App Store Connect.</em></p>
</blockquote>

<blockquote>
  <p><em>这个 Webhook 端点会接收来自 App Store Connect 的 HTTP POST 请求。</em></p>
</blockquote>

<blockquote>
  <p><em>The POST requests describe important events about your app.</em></p>
</blockquote>

<blockquote>
  <p><em>这些 POST 请求会描述与你的 App 相关的重要事件。</em></p>
</blockquote>

<blockquote>
  <p><em>Use the webhooks notifications endpoint to configure the notifications for events happening to your apps.</em></p>
</blockquote>

<blockquote>
  <p><em>你可以使用 Webhook 通知端点，来设定当你的 App 发生各种事件时所要接收的通知。</em></p>
</blockquote>

<h3 id="5-个应用案例">5 个应用案例</h3>

<h4 id="1-建置处理完成后触发送审">1. 建置处理完成后触发送审</h4>

<p><strong>Before:</strong></p>

<p><img src="/assets/7c0974856393/1*usYZtMkzAu-bA4fVX8ZbUQ.webp" alt="" loading="lazy" decoding="async" width="1668" height="647" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjY4IiBoZWlnaHQ9IjY0NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/7c0974856393/1*usYZtMkzAu-bA4fVX8ZbUQ.png" /></p>

<p>以往在实现 App CI/CD 打包送审时，打包上传后 <strong>需要等待 Apple 处理完成</strong> 才能继续送审；Fastlane 默认的做法是 Polling App Store Connect 检查上传的建置状态，直到 Complete 后才会继续执行送审 Lane。</p>

<blockquote>
  <p><strong><em>等待时间大约 20 分钟</em></strong> <em>，如果是 Self-hosted CI/CD 没什么差，但如果是使用云端服务，这 20 分钟的等待非常的浪费资源，以 GitHub Runner mac-OS 1 分钟 US$ 0.062， <strong>光等待送审每次就产生无意义的花费 1.24 US$。</strong></em></p>
</blockquote>

<p><img src="/assets/7c0974856393/1*2-Zn2ApgVYd5S5KzxMLEMQ.webp" alt="Ref: Build Completed Processing 通知信 搭配 Gmail Filter + Google Apps Script" loading="lazy" decoding="async" width="694" height="340" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2OTQiIGhlaWdodD0iMzQwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/7c0974856393/1*2-Zn2ApgVYd5S5KzxMLEMQ.png" /></p>

<p>Ref: <a href="/posts/zrealm-dev/google-apps-script-教学-自动转发-gmail-邮件到-slack-channel-客制化通知-d414bdbdb8c9/">Build Completed Processing 通知信 搭配 Gmail Filter + Google Apps Script</a></p>

<p>在没有 Webhook 可以主动通知的年代，之前曾用过「 <a href="/posts/zrealm-dev/google-apps-script-教学-自动转发-gmail-邮件到-slack-channel-客制化通知-d414bdbdb8c9/">Build Completed Processing 通知信搭配 Gmail Filter + Google Apps Script 来触发</a> 」可以达到效果，但是过程有点 Hardcore。</p>

<p><strong>After:</strong></p>

<p><img src="/assets/7c0974856393/1*ADkNoScFn4M_dIgv3sAKaw.webp" alt="" loading="lazy" decoding="async" width="2250" height="564" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMjUwIiBoZWlnaHQ9IjU2NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/7c0974856393/1*ADkNoScFn4M_dIgv3sAKaw.png" /></p>

<ul>
  <li>
    <p>有了 Webhook 之后，打包上传的步骤上传完毕即可结束。</p>
  </li>
  <li>
    <p><strong>App Store Connect Build Process Complete 后会发 Webhook 通知，我们收到通知后再继续执行送审步骤。</strong></p>
  </li>
  <li>
    <p><strong>零干等成本</strong></p>
  </li>
</ul>

<h4 id="2-gitflow-release-流程对齐-app-release-时机点">2. GitFlow Release 流程对齐 App Release 时机点</h4>

<p><strong>Before:</strong></p>

<blockquote>
  <p><em>GitFlow 最后一步上线时需要把 develop 分支 merge 回 master 分支，master 分支对应的是当前线上版。</em></p>
</blockquote>

<p>以往只能定时手动/自动执行，例如周一 PM 会发布 App，周一固定把 develop 回 master；手动执行很烦、自动执行的话假设延期？周一刚好放假？实际 App 没有 Release 但是 develop 先回 master 了。</p>

<p>在大多数情况不太重要，只有很极端的状况，例如这时间中间又要插 Hotfix 就会有可能有落差；但若要追求完整稳定的 CI/CD 开发流程，这也是一个值得探讨的案例。</p>

<p><strong>另一条思路同上，用「 <a href="/posts/zrealm-dev/google-apps-script-教学-自动转发-gmail-邮件到-slack-channel-客制化通知-d414bdbdb8c9/">App is Ready for Sale 通知信搭配 Gmail Filter + Google Apps Script 来触发</a> 」是可行的。</strong></p>

<p><strong>After:</strong></p>

<p><img src="/assets/7c0974856393/1*6JjHC6GKc4fKXrh-WWCJVA.webp" alt="" loading="lazy" decoding="async" width="1200" height="224" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjIyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/7c0974856393/1*6JjHC6GKc4fKXrh-WWCJVA.png" /></p>

<ul>
  <li>
    <p>有了 Webhook 之后，可以直接在收到 App 发布通知后触发 CI/CD Action (Master to Develop)。</p>
  </li>
  <li>
    <p>可以确保 App 是真的上线才回 Master</p>
  </li>
</ul>

<h4 id="3-app-release-messages">3. App Release Messages</h4>

<blockquote>
  <p><em>App 上线发布给使用者后，还有另一个很常见内部工作流程，发布通知给相关团队、版本包含的任务、Complete 相关任务。</em></p>
</blockquote>

<p><strong>Before:</strong></p>

<p>同上，只能手动或定时自动或使用信件 <a href="/posts/zrealm-dev/google-apps-script-教学-自动转发-gmail-邮件到-slack-channel-客制化通知-d414bdbdb8c9/"><strong>搭配 Gmail Filter + Google Apps Script 来触发</strong></a> 。</p>

<p><strong>After:</strong></p>

<p><img src="/assets/7c0974856393/1*UuGPKonNhXRUMZ71rDQcdw.webp" alt="" loading="lazy" decoding="async" width="1929" height="712" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOTI5IiBoZWlnaHQ9IjcxMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/7c0974856393/1*UuGPKonNhXRUMZ71rDQcdw.png" /></p>

<ul>
  <li>有了 Webhook 之后，可以在收到 App 发布通知后串接 Jira/Asana API 捞取对应版号的单批次 Complete 并且发布包含的任务单完成释出讯息到 Slack。</li>
</ul>

<h4 id="4-build-failed--review-rejected-notifier">4. Build Failed / Review Rejected Notifier</h4>

<blockquote>
  <p><em>前面 1,2 有提到以往有机会透过收信件通知来触发工作流程，但在团队规模很大权限控管严格的组织里， <strong>iOS 开发者只会有「开发者」后台权限，无法释出、管理 App，因此也无法收到任何 App 状态改变的信件通知；其中也包含上传的建置版本被拒或是送审被拒的通知信</strong> 。</em></p>
</blockquote>

<p><strong>Before:</strong></p>

<p>以往只能靠好心人 (a.k.a PM) 转发信件给工程，如果好心人也没注意到可能就真的到要上线时才发现 App 被拒绝了无法上线！</p>

<p><strong>After:</strong></p>

<p><img src="/assets/7c0974856393/1*unKq9zdc8tJEqlNmfXiRYA.webp" alt="" loading="lazy" decoding="async" width="1295" height="628" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjk1IiBoZWlnaHQ9IjYyOCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/7c0974856393/1*unKq9zdc8tJEqlNmfXiRYA.png" /></p>

<ul>
  <li>这个案例相对简单，就是收到 Webhook 通知之后，转发讯息到 Slack。</li>
</ul>

<h4 id="5-testflight-feedback-notifier">5. Testflight Feedback Notifier</h4>

<blockquote>
  <p><em>类似 4. 只是改接 Testflight Feedback Webhook 通知。</em></p>
</blockquote>

<p><strong>Before:</strong></p>

<p>以往开发者只能自己上去 App Store Connect Testflight 后台查看测试使用者的回馈或闪退问题， <strong>非常容易被忽略（甚至曾经发生过一年前回报的建议问题一年后才有人看到）</strong> 。</p>

<p><strong>After:</strong></p>

<ul>
  <li>收到 Testflight Feedback Webhook 通知之后，转发讯息到 Slack 。</li>
</ul>

<p>— — —</p>

<blockquote>
  <p><em>其他应用方式欢迎大家天马行空发想，再来将介绍如何串接使用。</em></p>
</blockquote>

<h3 id="app-store-connect-api-webhook-设定">App Store Connect API Webhook 设定</h3>

<blockquote>
  <p><em>权限要求： <strong>需要 Admin, Account Holder 权限才能设定</strong> 。</em></p>
</blockquote>

<h4 id="建立-app-store-connect-api-webhook-通知">建立 App Store Connect API Webhook 通知</h4>

<ol>
  <li>
    <p><a href="https://appstoreconnect.apple.com/access/users" target="_blank">前往 App Store Connect 管理后台</a></p>
  </li>
  <li>
    <p>前往「使用者与存取权限 (Users and Access)」 -&gt; 「整合 (Integrations)」</p>
  </li>
  <li>
    <p>点击「其他整合 (Additional)」 下的 「Webhooks」</p>
  </li>
  <li>
    <p>点击「建立 Webhook」按钮</p>
  </li>
</ol>

<p><img src="/assets/7c0974856393/1*e_6oin7tJjAB2gXl3txJow.webp" alt="" loading="lazy" decoding="async" width="716" height="767" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MTYiIGhlaWdodD0iNzY3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/7c0974856393/1*e_6oin7tJjAB2gXl3txJow.jpeg" /></p>

<ul>
  <li>
    <p>名称：输入 Webhook 名称</p>
  </li>
  <li>
    <p>承载 URL(Payload URL)：输入你的 Webhook 通知接收服务网址</p>
  </li>
  <li>
    <p>密钥(Secret) 字串：Webhook Request 验证密钥(可 <a href="https://www.random.org/strings/?num=1&amp;len=32&amp;digits=on&amp;upperalpha=on&amp;loweralpha=on&amp;unique=on&amp;format=html&amp;rnd=new" target="_blank">随机产生一个字串</a> 来用)</p>
  </li>
  <li>
    <p>App：选择预接收 Webhook 通知的 App</p>
  </li>
  <li>
    <p><strong>触发事件：</strong></p>
  </li>
</ul>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">TestFlight</span> <span class="nt">回馈</span>
<span class="nt">当测试人员留下回馈时收到相关资料</span><span class="err">。</span>
<span class="o">[]</span> <span class="nt">当机回馈</span>
<span class="o">[]</span> <span class="nt">截图回馈</span>

<span class="o">[]</span> <span class="nt">TestFlight</span> <span class="nt">版本状态</span>
<span class="nt">当</span> <span class="nt">TestFlight</span> <span class="nt">版本状态更改时收到相关资料</span><span class="err">。</span><span class="nt">进一步了解</span>

<span class="o">[]</span><span class="nt">App</span> <span class="nt">版本状态</span>
<span class="nt">当</span> <span class="nt">App</span> <span class="nt">版本状态更改时收到相关资料</span><span class="err">。</span><span class="nt">进一步了解</span>

<span class="o">[]</span><span class="nt">建置版本上传状态</span>
<span class="nt">当建置版本上传状态更改时收到相关资料</span><span class="err">。</span><span class="nt">进一步了解</span>

<span class="nt">背景素材</span>
<span class="nt">当</span> <span class="nt">Apple</span> <span class="nt">托管的素材包版本出现特定变更时收到相关资料</span><span class="err">。</span><span class="nt">进一步了解</span>

<span class="o">[]</span><span class="nt">更新App</span> <span class="nt">Store</span> <span class="nt">发布版本</span>
<span class="o">[]</span><span class="nt">更新外部</span> <span class="nt">TestFlight</span> <span class="nt">发布版本</span>
<span class="o">[]</span><span class="nt">建立内部</span> <span class="nt">TestFlight</span> <span class="nt">发布版本</span>
<span class="o">[]</span><span class="nt">更新素材包版本</span>
</code></pre></div></div>

<p>依照需求勾选，也可以全选收到通知后再判断要不要处理。</p>

<p><strong>最后点击「新增」建立 Webhook。</strong></p>

<h4 id="测试-app-store-connect-api-webhook-通知">测试 App Store Connect API Webhook 通知</h4>

<p>进入 Webhook 页。</p>

<p><img src="/assets/7c0974856393/1*-pEVZ24cpSPBabtzMwll4Q.webp" alt="" loading="lazy" decoding="async" width="979" height="548" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NzkiIGhlaWdodD0iNTQ4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/7c0974856393/1*-pEVZ24cpSPBabtzMwll4Q.png" /></p>

<p>点击右上角「测试」接收测试通知。</p>

<p><strong>测试通知内容如下：</strong></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">Headers:</span><span class="w">
</span><span class="p">{</span><span class="w">
  </span><span class="nl">"content-type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"application/json"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"x-apple-jingle-correlation-key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PNSCHDQW3MY2AX6VSRFHYYNUL4"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"x-apple-request-uuid"</span><span class="p">:</span><span class="w"> </span><span class="s2">"7b64238e-16db-31a0-5fd5-944a7c61b45f"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"x-apple-signature"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hmacsha256=cf50020f0bbd3c5274860594f616f1806965c1f9fb765d8d278f512dff5b4c0e"</span><span class="p">,</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="err">Body:</span><span class="w">
</span><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"webhookPingCreated"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"65726e27-cb79-47f2-a3e4-c8ced9f356e8"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"version"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"timestamp"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-26T15:47:38.472168681Z"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h4 id="app-store-connect-api-webhook-通知发送纪录">App Store Connect API Webhook 通知发送纪录</h4>

<p>Webhook 页下方的「最近的提交项目」会显示最近发送的 Webhook 事件。</p>

<p><img src="/assets/7c0974856393/1*lacj5lpaDwJtN0hgA5EAVg.webp" alt="" loading="lazy" decoding="async" width="1200" height="502" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjUwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/7c0974856393/1*lacj5lpaDwJtN0hgA5EAVg.png" /></p>

<h4 id="验证-app-store-connect-api-webhook-通知">验证 App Store Connect API Webhook 通知</h4>

<p>建立 Webhook 时我们有输入一个「密钥(Secret) 字串」建议对请求进行验证，防止这个 Webhook URL 外泄，有心之人能随意伪造发送 Webhook 事件到你的服务上。</p>

<p><strong>验证方式：</strong></p>

<blockquote>
  <p><em>对 Request Body 用你设定的密钥字串做 HMAC-SHA256 并输出 HEX 进位字串，用这个字串比对 Request Headers 中的 <code class="language-plaintext highlighter-rouge">x-apple-signature</code> 值的 <code class="language-plaintext highlighter-rouge">hmacsha256=</code> 后面带的字串。</em></p>
</blockquote>

<p><strong>实现方式 — Nodejs:</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">crypto</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">crypto</span><span class="dl">'</span><span class="p">;</span>

<span class="kd">function</span> <span class="nf">verifyAppleWebhook</span><span class="p">(</span><span class="nx">rawBody</span><span class="p">,</span> <span class="nx">appleSignature</span><span class="p">,</span> <span class="nx">secret</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">hex</span> <span class="o">=</span> <span class="nx">crypto</span>
    <span class="p">.</span><span class="nf">createHmac</span><span class="p">(</span><span class="dl">'</span><span class="s1">sha256</span><span class="dl">'</span><span class="p">,</span> <span class="nx">secret</span><span class="p">)</span>
    <span class="p">.</span><span class="nf">update</span><span class="p">(</span><span class="nx">rawBody</span><span class="p">,</span> <span class="dl">'</span><span class="s1">utf8</span><span class="dl">'</span><span class="p">)</span>
    <span class="p">.</span><span class="nf">digest</span><span class="p">(</span><span class="dl">'</span><span class="s1">hex</span><span class="dl">'</span><span class="p">);</span>

  <span class="k">return</span> <span class="s2">`hmacsha256=</span><span class="p">${</span><span class="nx">hex</span><span class="p">}</span><span class="s2">`</span> <span class="o">===</span> <span class="nx">appleSignature</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>实现方式 — Cloudflare Worker:</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">bufferToHex</span><span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">return</span> <span class="p">[...</span><span class="k">new</span> <span class="nc">Uint8Array</span><span class="p">(</span><span class="nx">buffer</span><span class="p">)]</span>
    <span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">b</span> <span class="o">=&gt;</span> <span class="nx">b</span><span class="p">.</span><span class="nf">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">).</span><span class="nf">padStart</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="dl">'</span><span class="s1">0</span><span class="dl">'</span><span class="p">))</span>
    <span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="dl">''</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nf">hmacSha256Hex</span><span class="p">(</span><span class="nx">secret</span><span class="p">,</span> <span class="nx">message</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">enc</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TextEncoder</span><span class="p">();</span>

  <span class="kd">const</span> <span class="nx">key</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">crypto</span><span class="p">.</span><span class="nx">subtle</span><span class="p">.</span><span class="nf">importKey</span><span class="p">(</span>
    <span class="dl">'</span><span class="s1">raw</span><span class="dl">'</span><span class="p">,</span>
    <span class="nx">enc</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="nx">secret</span><span class="p">),</span>
    <span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">HMAC</span><span class="dl">'</span><span class="p">,</span> <span class="na">hash</span><span class="p">:</span> <span class="dl">'</span><span class="s1">SHA-256</span><span class="dl">'</span> <span class="p">},</span>
    <span class="kc">false</span><span class="p">,</span>
    <span class="p">[</span><span class="dl">'</span><span class="s1">sign</span><span class="dl">'</span><span class="p">]</span>
  <span class="p">);</span>

  <span class="kd">const</span> <span class="nx">signature</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">crypto</span><span class="p">.</span><span class="nx">subtle</span><span class="p">.</span><span class="nf">sign</span><span class="p">(</span>
    <span class="dl">'</span><span class="s1">HMAC</span><span class="dl">'</span><span class="p">,</span>
    <span class="nx">key</span><span class="p">,</span>
    <span class="nx">enc</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
  <span class="p">);</span>

  <span class="k">return</span> <span class="nf">bufferToHex</span><span class="p">(</span><span class="nx">signature</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nf">verifyAppleWebhook</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="nx">secret</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">appleSignature</span> <span class="o">=</span> <span class="nx">request</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">X-Apple-Signature</span><span class="dl">'</span><span class="p">);</span>

  <span class="kd">const</span> <span class="nx">rawBody</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">request</span><span class="p">.</span><span class="nf">clone</span><span class="p">().</span><span class="nf">text</span><span class="p">();</span>
  <span class="kd">const</span> <span class="nx">calculated</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">hmacSha256Hex</span><span class="p">(</span><span class="nx">secret</span><span class="p">,</span> <span class="nx">rawBody</span><span class="p">);</span>

  <span class="k">return</span> <span class="dl">"</span><span class="s2">hmacsha256=</span><span class="dl">"</span><span class="o">+</span><span class="nx">calculated</span> <span class="o">===</span> <span class="nx">appleSignature</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>Cloudflare Worker 无 crypto module，要使用 Web Crypto API（crypto.subtle）</li>
</ul>

<p><strong>实现方式 — Google Apps Script Web App ❌</strong></p>

<p>碍于技术限制，Google Apps Script Web App <code class="language-plaintext highlighter-rouge">doGet(e)/doPost(e)</code> 无法从中取得 Request Headers，因此无法使用此方法对请求来源进行验证。</p>

<p>最多只能自己在 URL Query 加一些密钥参数做很简单的判断保护。</p>

<h3 id="app-store-connect-api-webhook-通知-payload">App Store Connect API Webhook 通知 Payload</h3>

<p>这边有搜集了几个 App 上传、送审过程会收到的事件 Payload，提供给大家做自动化开发时可以直接参考。</p>

<blockquote>
  <p><em>Webhook 只会发送事件跟状态名称，不会给其他详细资讯，例如：版本号、拒审原因…等等； <strong>我们需要自己再打 App Store Connect API 带上 Event Payload 里的 Relationships Link 才能取得完整资讯。</strong></em></p>
</blockquote>

<h4 id="建置版本上传--process-complete">建置版本上传 — Process Complete</h4>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"buildUploadStateUpdated"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"version"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"oldState"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"PROCESSING"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"newState"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"COMPLETE"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"instance"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"buildUploads"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"links"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/buildUploads/xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h4 id="建置版本上传--process-failed">建置版本上传 — Process Failed</h4>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"buildUploadStateUpdated"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"oldState"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PROCESSING"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"newState"</span><span class="p">:</span><span class="w"> </span><span class="s2">"FAILED"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"instance"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"buildUploads"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/buildUploads/xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>多半为 Binary 遭拒，例如有用到麦克风但是没宣告之类的。</p>

<h4 id="app-版本状态--prepare-for-submission-准备提交">App 版本状态 — Prepare For Submission (准备提交)</h4>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersionAppVersionStateUpdated"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"version"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"newValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"PREPARE_FOR_SUBMISSION"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"oldValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"DEVELOPER_REJECTED"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"timestamp"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-18T05:01:47.118Z"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"instance"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersions"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"links"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>当新版本号建立好，准备提交送审时，这阶段可填写版本资讯、更新内容、选择要送审的 Build。</p>

<h4 id="app-版本状态--ready-for-review-准备送审"><strong>App 版本状态 — Ready For Review (准备送审)</strong></h4>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersionAppVersionStateUpdated"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"version"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"newValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"READY_FOR_REVIEW"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"oldValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"PREPARE_FOR_SUBMISSION"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"timestamp"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-18T03:41:12.516Z"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"instance"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersions"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"links"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>送审资料确定，准备送审时。</p>

<h4 id="app-版本状态--waiting-for-review-已送审等待审核">App 版本状态 — Waiting For Review (已送审，等待审核)</h4>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersionAppVersionStateUpdated"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"version"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"newValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"WAITING_FOR_REVIEW"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"oldValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"READY_FOR_REVIEW"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"timestamp"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-18T03:41:21.179Z"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"instance"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersions"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"links"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>App 已完成送审，正在等待审查。</p>

<h4 id="app-版本状态--developer-rejected-开发者拒绝">App 版本状态 — Developer Rejected (开发者拒绝)</h4>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersionAppVersionStateUpdated"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"version"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"newValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"DEVELOPER_REJECTED"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"oldValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"WAITING_FOR_REVIEW"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"timestamp"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-18T03:50:30.552Z"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"instance"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersions"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"links"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>开发者撤回正在送审的版本。</p>

<h4 id="app-版本状态--in-review-官方正在审核">App 版本状态 — In Review (官方正在审核)</h4>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersionAppVersionStateUpdated"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"version"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"newValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"IN_REVIEW"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"oldValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"WAITING_FOR_REVIEW"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"timestamp"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-18T22:05:50.038Z"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"instance"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersions"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"links"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h4 id="app-版本状态--pending-developer-release-审核完毕等待发布">App 版本状态 — Pending Developer Release (审核完毕等待发布)</h4>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersionAppVersionStateUpdated"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"version"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"newValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"PENDING_DEVELOPER_RELEASE"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"oldValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"IN_REVIEW"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"timestamp"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-18T22:34:18.785Z"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"instance"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersions"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"links"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<blockquote>
  <p><em>Pending Developer Release 事件的时间 减掉 Waiting For Review 事件的时间就 等于 App 送审到可发布状态中间等待的时间了。</em></p>
</blockquote>

<h4 id="app-版本状态--ready-for-distribution-app-准备发布-aka-ready-for-sale">App 版本状态 — Ready for Distribution (App 准备发布) a.k.a Ready For Sale</h4>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersionAppVersionStateUpdated"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"version"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"newValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"READY_FOR_DISTRIBUTION"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"oldValue"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"PENDING_DEVELOPER_RELEASE"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"timestamp"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-23T06:03:50.925Z"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"instance"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"data"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersions"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"links"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xx-xx-xx-xxx"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>App 已准备发布 (几乎等同 Ready For Sale，没有 Ready For Sale 这个事件)。</p>

<blockquote>
  <p><em>Your app has been accepted and is ready for distribution.</em></p>
</blockquote>

<blockquote>
  <p><em>To distribute your app, your <a href="https://developer.apple.com/help/app-store-connect/manage-agreements/view-agreements-status" target="_blank">agreements</a> must be in effect. The Account Holder can accept the latest agreements in the Business section.</em></p>
</blockquote>

<h3 id="app-store-connect-api-webhook-工作流程串接">App Store Connect API Webhook 工作流程串接</h3>

<h4 id="方法-1--借用-fastlane-串接-app-store-connect-api">方法 1 — 借用 Fastlane 串接 App Store Connect API</h4>

<p>这边最快的方式是直接用 CI/CD 服务触发，然后借用 Fastlane 自带的 Spaceship 串接 App Store Connect API。</p>

<blockquote>
  <p><em>如果你本来 <a href="https://docs.fastlane.tools/app-store-connect-api/" target="_blank">Fastlane 就有使用 App Store Connect API</a> 管理 Match 凭证、送审，这个方法可以直接无痛使用；如果没有要先 <a href="https://docs.fastlane.tools/app-store-connect-api/" target="_blank">参考官方文件</a> 产生 API Key 跟安全存放在 CI/CD 服务的密钥中。</em></p>
</blockquote>

<p><img src="/assets/7c0974856393/1*FrJoXtV2lrk09KnAt2Hydg.webp" alt="" loading="lazy" decoding="async" width="1200" height="323" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjMyMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/7c0974856393/1*FrJoXtV2lrk09KnAt2Hydg.png" /></p>

<ul>
  <li><strong>App Store Connect</strong>
    <ol>
      <li>App 有状态改变时</li>
      <li>触发 Webhook</li>
    </ol>
  </li>
  <li><strong>Webhook Endpoint</strong>
<code class="language-plaintext highlighter-rouge">可以是 自架服务/API 或是 简单用 FAAS 服务 (Cloudflare Worker / AWS Lambda / Cloud Functions / Google Apps Script)</code>
    <ol>
      <li>验证 Webhook (optional)</li>
      <li>处理 Webhook 事件、转发事件请求到 CI/CD 服务上执行
<code class="language-plaintext highlighter-rouge">e.g. 透过 GitHub API 触发 GitHub Actions..</code></li>
    </ol>
  </li>
  <li><strong>CI/CD Service</strong>
<code class="language-plaintext highlighter-rouge">GitHub Actions / Bitbucket Pipeline / Gitlab Runner…</code>
    <ol>
      <li>触发 Action</li>
      <li>执行 Fastlane 脚本，复用 Fastlane Spaceship 验证</li>
    </ol>
  </li>
  <li><strong>App Store Connect</strong>
    <ol>
      <li>打 App Store Connect API 取得完整资讯</li>
    </ol>
  </li>
  <li><strong>CI/CD Service</strong>
    <ol>
      <li>后续步骤，例如发通知、触发另一个 Action</li>
    </ol>
  </li>
</ul>

<p><strong>Fastlane Example:</strong></p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1"># Usage:</span>
  <span class="c1">#   bundle exec fastlane appStoreConnectWebhookHandler \</span>
  <span class="c1">#     data:'{"data":{"type":"buildUploadStateUpdated","id":"xxx-xxx-xxx-xx-xxx","version":1,"attributes":{"oldState":"PROCESSING","newState":"COMPLETE"},"relationships":{"instance":{"data":{"type":"buildUploads","id":"xxx-xxx-xxx-xx-xxx"},"links":{"self":"https://api.appstoreconnect.apple.com/v1/buildUploads/xxx-xxx-xxx-xx-xxx"}}}}}'</span>
  <span class="c1"># Notes:</span>
  <span class="c1"># - `data:` must be a JSON string.</span>
  <span class="c1"># - This lane is intended for local debugging (it prints the GET response).</span>
  <span class="n">desc</span> <span class="s2">"[Automation] Handle App Store Connect webhook payload and fetch related instance via ASC API"</span>
  <span class="n">lane</span> <span class="ss">:appStoreConnectWebhookHandler</span> <span class="k">do</span> <span class="p">\\</span><span class="o">|</span><span class="n">options</span><span class="p">\\</span><span class="o">|</span>
    <span class="k">begin</span>
      <span class="n">data</span> <span class="o">=</span> <span class="n">options</span><span class="p">[</span><span class="ss">:data</span><span class="p">]</span>
      <span class="no">UI</span><span class="p">.</span><span class="nf">user_error!</span><span class="p">(</span><span class="s2">"Missing data"</span><span class="p">)</span> <span class="k">if</span> <span class="n">data</span><span class="p">.</span><span class="nf">empty?</span>
      <span class="n">data</span> <span class="o">=</span> <span class="no">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
      <span class="n">url</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="nf">dig</span><span class="p">(</span><span class="s2">"data"</span><span class="p">,</span> <span class="s2">"relationships"</span><span class="p">,</span> <span class="s2">"instance"</span><span class="p">,</span> <span class="s2">"links"</span><span class="p">,</span> <span class="s2">"self"</span><span class="p">).</span><span class="nf">to_s</span><span class="p">.</span><span class="nf">strip</span>
      <span class="no">UI</span><span class="p">.</span><span class="nf">user_error!</span><span class="p">(</span><span class="s2">"Missing instance self url in JSON"</span><span class="p">)</span> <span class="k">if</span> <span class="n">url</span><span class="p">.</span><span class="nf">empty?</span>

      <span class="n">api_key</span> <span class="o">=</span> <span class="n">app_store_connect_api_key</span><span class="p">(</span>
        <span class="ss">key_id: </span><span class="s2">"xxxx"</span><span class="p">,</span>
        <span class="ss">issuer_id: </span><span class="s2">"xxxx-xxxx-xxxx-xxxx-165aa6465141"</span><span class="p">,</span>
        <span class="ss">key_filepath: </span><span class="s2">"./AuthKey_xxxx.p8"</span><span class="p">,</span>
        <span class="ss">duration: </span><span class="mi">1200</span><span class="p">,</span> <span class="c1"># optional (maximum 1200)</span>
        <span class="ss">in_house: </span><span class="kp">false</span> <span class="c1"># optional but may be required if using match/sigh</span>
      <span class="p">)</span>

      <span class="n">loadAppStoreConnectAPIKey</span>
      <span class="c1">#</span>
      <span class="n">uri</span> <span class="o">=</span> <span class="no">URI</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
      <span class="n">http</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">uri</span><span class="p">.</span><span class="nf">host</span><span class="p">,</span> <span class="n">uri</span><span class="p">.</span><span class="nf">port</span><span class="p">)</span>
      <span class="n">http</span><span class="p">.</span><span class="nf">use_ssl</span> <span class="o">=</span> <span class="kp">true</span>
      <span class="n">http</span><span class="p">.</span><span class="nf">verify_mode</span> <span class="o">=</span> <span class="no">OpenSSL</span><span class="o">::</span><span class="no">SSL</span><span class="o">::</span><span class="no">VERIFY_PEER</span>
      <span class="n">store</span> <span class="o">=</span> <span class="no">OpenSSL</span><span class="o">::</span><span class="no">X509</span><span class="o">::</span><span class="no">Store</span><span class="p">.</span><span class="nf">new</span>
      <span class="n">store</span><span class="p">.</span><span class="nf">set_default_paths</span>
      <span class="n">http</span><span class="p">.</span><span class="nf">cert_store</span> <span class="o">=</span> <span class="n">store</span>

      <span class="n">request</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">::</span><span class="no">Get</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">uri</span><span class="p">.</span><span class="nf">request_uri</span><span class="p">)</span>
      <span class="n">token</span> <span class="o">=</span> <span class="no">Spaceship</span><span class="o">::</span><span class="no">ConnectAPI</span><span class="p">.</span><span class="nf">token</span>
      <span class="no">UI</span><span class="p">.</span><span class="nf">user_error!</span><span class="p">(</span><span class="s2">"App Store Connect API token is not available. Make sure app_store_connect_api_key is configured correctly."</span><span class="p">)</span> <span class="k">if</span> <span class="n">token</span><span class="p">.</span><span class="nf">nil?</span>
      <span class="n">request</span><span class="p">[</span><span class="s1">'Authorization'</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"Bearer </span><span class="si">#{</span><span class="n">token</span><span class="p">.</span><span class="nf">text</span><span class="si">}</span><span class="s2">"</span>

      <span class="n">request</span><span class="p">[</span><span class="s1">'Content-Type'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'application/json'</span>
      <span class="n">request</span><span class="p">[</span><span class="s1">'Accept'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'application/json'</span>

      <span class="n">response</span> <span class="o">=</span> <span class="n">http</span><span class="p">.</span><span class="nf">request</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
      <span class="no">UI</span><span class="p">.</span><span class="nf">message</span><span class="p">(</span><span class="s2">"📡 GET </span><span class="si">#{</span><span class="n">url</span><span class="si">}</span><span class="s2"> Response: [</span><span class="si">#{</span><span class="n">response</span><span class="p">.</span><span class="nf">code</span><span class="si">}</span><span class="s2">] </span><span class="si">#{</span><span class="n">response</span><span class="p">.</span><span class="nf">message</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
      <span class="no">UI</span><span class="p">.</span><span class="nf">message</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="nf">body</span><span class="p">)</span>
      <span class="c1">#</span>

      <span class="n">response</span>
      <span class="c1">## handle response...do next actions...</span>
      
    <span class="k">rescue</span> <span class="o">=&gt;</span> <span class="n">e</span>
        <span class="no">UI</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="s2">"❌ Failed handle App Store Connect API Webhook: </span><span class="si">#{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
    <span class="k">end</span>

  <span class="k">end</span>
</code></pre></div></div>

<h4 id="方法-2-在-webhook-endpoint-自行处理">方法 2— 在 Webhook Endpoint 自行处理</h4>

<p>第二个方法就是直接在 Webhook Endpoint 服务上处理完所有事情，但 <strong>缺点是需要把 App Store Connect API Key 放到服务上跟要自己做 Token 验证</strong> 。</p>

<p><img src="/assets/7c0974856393/1*AUw59sLt97RquLhoRBp5Rw.webp" alt="" loading="lazy" decoding="async" width="1491" height="590" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDkxIiBoZWlnaHQ9IjU5MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/7c0974856393/1*AUw59sLt97RquLhoRBp5Rw.png" /></p>

<p><strong>Ruby Example:</strong></p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">require</span> <span class="s1">'jwt'</span>
<span class="k">require</span> <span class="s1">'net/http'</span>
<span class="k">require</span> <span class="s1">'time'</span>

<span class="n">keyFile</span> <span class="o">=</span> <span class="nc">File</span><span class="mf">.</span><span class="nf">read</span><span class="p">(</span><span class="s1">'./AuthKey_XXXX.p8'</span><span class="p">)</span> <span class="c1"># replace to your .p8 private key file (donwload from app stroe connect)</span>
<span class="n">privateKey</span> <span class="o">=</span> <span class="nc">OpenSSL</span><span class="o">::</span><span class="nc">PKey</span><span class="o">::</span><span class="no">EC</span><span class="mf">.</span><span class="k">new</span><span class="p">(</span><span class="n">keyFile</span><span class="p">)</span>

<span class="n">payload</span> <span class="o">=</span> <span class="p">{</span>
            <span class="n">iss</span><span class="o">:</span> <span class="s1">'YOUR_ISSUE_ID'</span><span class="p">,</span> <span class="c1"># replace to your issue id (get in app store connect user access-&gt;key-&gt;app store connect api page)</span>
            <span class="n">iat</span><span class="o">:</span> <span class="nc">Time</span><span class="mf">.</span><span class="n">now</span><span class="mf">.</span><span class="n">to_i</span><span class="p">,</span>
            <span class="n">exp</span><span class="o">:</span> <span class="nc">Time</span><span class="mf">.</span><span class="n">now</span><span class="mf">.</span><span class="n">to_i</span> <span class="o">+</span> <span class="mi">60</span><span class="o">*</span><span class="mi">20</span><span class="p">,</span>
            <span class="n">aud</span><span class="o">:</span> <span class="s1">'appstoreconnect-v1'</span>
          <span class="p">}</span>

<span class="n">token</span> <span class="o">=</span> <span class="no">JWT</span><span class="mf">.</span><span class="n">encode</span> <span class="n">payload</span><span class="p">,</span> <span class="n">privateKey</span><span class="p">,</span> <span class="s1">'ES256'</span><span class="p">,</span> <span class="n">header_fields</span><span class="o">=</span><span class="p">{</span><span class="n">kid</span><span class="o">:</span><span class="s2">"YOUR_KEY_ID"</span><span class="p">,</span> <span class="n">typ</span><span class="o">:</span><span class="s2">"JWT"</span><span class="p">}</span> <span class="c1"># replace to your key id (get in app store connect user access-&gt;key-&gt;app store connect api page)</span>
<span class="n">puts</span> <span class="n">token</span>

<span class="n">decoded_token</span> <span class="o">=</span> <span class="no">JWT</span><span class="mf">.</span><span class="n">decode</span> <span class="n">token</span><span class="p">,</span> <span class="n">privateKey</span><span class="p">,</span> <span class="kc">true</span><span class="p">,</span> <span class="p">{</span> <span class="n">algorithm</span><span class="o">:</span> <span class="s1">'ES256'</span> <span class="p">}</span>
<span class="n">puts</span> <span class="n">decoded_token</span>

<span class="c1"># 替换成 Webhook Payload 中的 relationships link</span>
<span class="n">uri</span> <span class="o">=</span> <span class="nf">URI</span><span class="p">(</span><span class="s2">"https://api.appstoreconnect.apple.com/v1/apps/APPID/customerReviews"</span><span class="p">)</span> <span class="c1"># repleace APPID to your app id in app store connect -&gt; your app -&gt; app information -&gt; apple id</span>
<span class="n">https</span> <span class="o">=</span> <span class="nc">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="mf">.</span><span class="k">new</span><span class="p">(</span><span class="n">uri</span><span class="mf">.</span><span class="n">host</span><span class="p">,</span> <span class="n">uri</span><span class="mf">.</span><span class="n">port</span><span class="p">)</span>
<span class="n">https</span><span class="mf">.</span><span class="n">use_ssl</span> <span class="o">=</span> <span class="kc">true</span>

<span class="n">request</span> <span class="o">=</span> <span class="nc">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">::</span><span class="nc">Get</span><span class="mf">.</span><span class="k">new</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
<span class="n">request</span><span class="p">[</span><span class="s1">'Authorization'</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"Bearer #</span><span class="si">{</span><span class="nv">token</span><span class="si">}</span><span class="s2">"</span><span class="p">;</span>

<span class="n">response</span> <span class="o">=</span> <span class="n">https</span><span class="mf">.</span><span class="nf">request</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
<span class="n">puts</span> <span class="n">response</span><span class="mf">.</span><span class="n">read_body</span>
</code></pre></div></div>

<blockquote>
  <p><em>App Store Connect API Key 产生方式、Token 产生方式、API 使用请参考「 <a href="/posts/zrealm-dev/app-store-connect-api-快速读取与管理-customer-reviews-提升-ios-app-评价整合效率-f1365e51902c/">App Store Connect API 现已支援 读取和管理 Customer Reviews</a> 」。</em></p>
</blockquote>

<h3 id="app-store-connect-api-response">App Store Connect API Response</h3>

<p>这里附上一些收到 Webhook Event 后再打 Relationships Link 取得完整资讯的一些 Response 范例。</p>

<h4 id="建置版本上传--process-complete-1">建置版本上传 — Process Complete</h4>

<p><code class="language-plaintext highlighter-rouge">https://api.appstoreconnect.apple.com/v1/buildUploads/xxx-xx-xx-xx-xxx</code></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"buildUploads"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xx-xx-xx-xxx-xx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"cfBundleShortVersionString"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.101.0"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"cfBundleVersion"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"createdDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-25T08:26:43-08:00"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"state"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"errors"</span><span class="p">:</span><span class="w"> </span><span class="p">[],</span><span class="w">
        </span><span class="nl">"warnings"</span><span class="p">:</span><span class="w"> </span><span class="p">[],</span><span class="w">
        </span><span class="nl">"infos"</span><span class="p">:</span><span class="w"> </span><span class="p">[],</span><span class="w">
        </span><span class="nl">"state"</span><span class="p">:</span><span class="w"> </span><span class="s2">"COMPLETE"</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"platform"</span><span class="p">:</span><span class="w"> </span><span class="s2">"IOS"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"uploadedDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-25T08:28:35-08:00"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"buildUploadFiles"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/buildUploads/xx-xx-xx-xxx-xx/relationships/buildUploadFiles"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/buildUploads/xx-xx-xx-xxx-xx/buildUploadFiles"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/buildUploads/xx-xx-xx-xxx-xx"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/buildUploads/xx-xx-xx-xxx-xx"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h4 id="建置版本上传--process-failed-1">建置版本上传 — Process Failed</h4>

<p><code class="language-plaintext highlighter-rouge">https://api.appstoreconnect.apple.com/v1/buildUploads/xxx-xx-xx-xx-xxx</code></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"buildUploads"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xx-xx-xx-xx-xxx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"cfBundleShortVersionString"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.101.0"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"cfBundleVersion"</span><span class="p">:</span><span class="w"> </span><span class="s2">"3"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"createdDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-12T09:03:32-08:00"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"state"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"errors"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
          </span><span class="p">{</span><span class="w">
            </span><span class="nl">"code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"90683"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Missing purpose string in Info.plist. Your app’s code references one or more APIs that access sensitive user data, or the app has one or more entitlements that permit such access. The Info.plist file for the “My.app” bundle should contain a NSMicrophoneUsageDescription key with a user-facing purpose string explaining clearly and completely why your app needs the data. If you’re using external libraries or SDKs, they may reference APIs that require a purpose string. While your app might not use these APIs, a purpose string is still required. For details, visit: https://developer.apple.com/documentation/uikit/protecting_the_user_s_privacy/requesting_access_to_protected_resources."</span><span class="w">
          </span><span class="p">}</span><span class="w">
        </span><span class="p">],</span><span class="w">
        </span><span class="nl">"warnings"</span><span class="p">:</span><span class="w"> </span><span class="p">[],</span><span class="w">
        </span><span class="nl">"infos"</span><span class="p">:</span><span class="w"> </span><span class="p">[],</span><span class="w">
        </span><span class="nl">"state"</span><span class="p">:</span><span class="w"> </span><span class="s2">"FAILED"</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"platform"</span><span class="p">:</span><span class="w"> </span><span class="s2">"IOS"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"uploadedDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-12T09:05:26-08:00"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"buildUploadFiles"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/buildUploads/xx-xx-xx-xx-xxx/relationships/buildUploadFiles"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/buildUploads/xx-xx-xx-xx-xxx/buildUploadFiles"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/buildUploads/xx-xx-xx-xx-xxx"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/buildUploads/xx-xx-xx-xx-xxx"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>ITMS-90683 为例。</p>

<h4 id="app-版本状态">App 版本状态</h4>

<p><code class="language-plaintext highlighter-rouge">https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xx-xx-xx-xxx</code></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"appStoreVersions"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx-xxx-xxx-xxx"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"attributes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"platform"</span><span class="p">:</span><span class="w"> </span><span class="s2">"IOS"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"versionString"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.101.0"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"appStoreState"</span><span class="p">:</span><span class="w"> </span><span class="s2">"READY_FOR_SALE"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"appVersionState"</span><span class="p">:</span><span class="w"> </span><span class="s2">"READY_FOR_DISTRIBUTION"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"copyright"</span><span class="p">:</span><span class="w"> </span><span class="s2">"© 2025 ZhgChgLi."</span><span class="p">,</span><span class="w">
      </span><span class="nl">"reviewType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"APP_STORE"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"releaseType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"MANUAL"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"earliestReleaseDate"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"usesIdfa"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
      </span><span class="nl">"downloadable"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
      </span><span class="nl">"createdDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-12-15T19:12:55-08:00"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"relationships"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"ageRatingDeclaration"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/ageRatingDeclaration"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/ageRatingDeclaration"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"appStoreVersionLocalizations"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/appStoreVersionLocalizations"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/appStoreVersionLocalizations"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"build"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/build"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/build"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"appStoreVersionPhasedRelease"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/appStoreVersionPhasedRelease"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/appStoreVersionPhasedRelease"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"gameCenterAppVersion"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/gameCenterAppVersion"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/gameCenterAppVersion"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"routingAppCoverage"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/routingAppCoverage"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/routingAppCoverage"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"appStoreReviewDetail"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/appStoreReviewDetail"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/appStoreReviewDetail"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"appStoreVersionSubmission"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/appStoreVersionSubmission"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/appStoreVersionSubmission"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"appClipDefaultExperience"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/appClipDefaultExperience"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/appClipDefaultExperience"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"appStoreVersionExperiments"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/appStoreVersionExperiments"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/appStoreVersionExperiments"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"appStoreVersionExperimentsV2"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/appStoreVersionExperimentsV2"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/appStoreVersionExperimentsV2"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"customerReviews"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/customerReviews"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/customerReviews"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"alternativeDistributionPackage"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/relationships/alternativeDistributionPackage"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx/alternativeDistributionPackage"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.appstoreconnect.apple.com/v1/appStoreVersions/xxx-xxx-xxx-xxx"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<blockquote>
  <p><em>如前述，详细 App 资讯、版号、错误原因都要打 API 才会拿到。</em></p>
</blockquote>

<h3 id="done">Done</h3>

<p>至此我们已经可以透过 App Store Connect API Webhook 更好地完善 App CI/CD 及自动化工作流程，提升团队开发效率。</p>

<h4 id="延伸阅读">延伸阅读</h4>

<ul>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-是什么-打造高效稳定开发团队的关键流程与工具选择-c008a9e8ceca/"><strong>CI/CD 实战指南（一）：CI/CD 是什么？如何透过 CI/CD 打造稳定高效的开发团队？工具选择？</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/zreviewtender-免费开源-app-评价监控机器人-自动整合-slack-与-google-sheet-e36e48bb9265/">ZReviewTender — 免费开源的 App Reviews 监控机器人</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/app-store-connect-api-快速读取与管理-customer-reviews-提升-ios-app-评价整合效率-f1365e51902c/">App Store Connect API 现已支援 读取和管理 Customer Reviews</a></p>
  </li>
</ul>]]></content>
  </entry><entry>
    <title type="html">iOS Timer 与 DispatchSourceTimer 选择与安全封装技巧｜有限状态机防止闪退</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/ios-timer-%E4%B8%8E-dispatchsourcetimer-%E9%80%89%E6%8B%A9%E4%B8%8E%E5%AE%89%E5%85%A8%E5%B0%81%E8%A3%85%E6%8A%80%E5%B7%A7-%E6%9C%89%E9%99%90%E7%8A%B6%E6%80%81%E6%9C%BA%E9%98%B2%E6%AD%A2%E9%97%AA%E9%80%80-62f68ebeecd3/" rel="alternate" type="text/html" title="iOS Timer 与 DispatchSourceTimer 选择与安全封装技巧｜有限状态机防止闪退" />
    <published>2025-12-14T16:17:06+08:00</published>
    <updated>2025-12-15T00:24:36+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/62f68ebeecd3</id><summary type="html">iOS 开发必备 Timer 使用指南，解析 Timer 与 DispatchSourceTimer 优缺点，并提供有限状态机封装 DispatchSourceTimer，避免闪退及 Race Condition，实现高精度且安全的定时任务管理。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="ios-app-development" /><category term="design-patterns" /><category term="timer" /><category term="swift" /><category term="finite-state-machine" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/62f68ebeecd3/1*2CWJW1fPOAZdU3nqeJ2JeQ.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/ios-timer-%E4%B8%8E-dispatchsourcetimer-%E9%80%89%E6%8B%A9%E4%B8%8E%E5%AE%89%E5%85%A8%E5%B0%81%E8%A3%85%E6%8A%80%E5%B7%A7-%E6%9C%89%E9%99%90%E7%8A%B6%E6%80%81%E6%9C%BA%E9%98%B2%E6%AD%A2%E9%97%AA%E9%80%80-62f68ebeecd3/"><![CDATA[<h3 id="ios-timer-与-dispatchsourcetimer-如何选择与安全的使用">[iOS] Timer 与 DispatchSourceTimer 如何选择与安全的使用?</h3>

<p>使用有限状态机与 Design Patterns 封装 DispatchSourceTimer，使其更安全易用。</p>

<p><img src="/assets/62f68ebeecd3/1*2CWJW1fPOAZdU3nqeJ2JeQ.webp" alt="Photo by Ralph Hutter" loading="lazy" decoding="async" width="1400" height="933" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjkzMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/62f68ebeecd3/1*2CWJW1fPOAZdU3nqeJ2JeQ.jpeg" /></p>

<p>Photo by <a href="https://unsplash.com/@pixelfreund?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank">Ralph Hutter</a></p>

<h4 id="关于-timer">关于 Timer</h4>

<p>在 iOS 开发中一定会遇到的需求场景「Timer 定时触发器」；从 UI 层面上显示倒数计时、Banner 轮播到资料逻辑层面上的定时发送 Events、定时清除释放资料；我们都需要 Timer 来帮助我们达成目标。</p>

<h3 id="foundation--timer-nstimer"><a href="https://developer.apple.com/documentation/foundation/timer" target="_blank">Foundation — Timer (NSTimer)</a></h3>

<p>Timer 应该是大家最直觉会先想到的 API，但是在选择及使用 Timer 上我们需要注意以下几个点。</p>

<h4 id="优缺点">优缺点</h4>

<p><strong>Timer 的优点：</strong></p>

<ul>
  <li>
    <p>默认与 UI 工作整合，不需要特别切 Main Thread 执行</p>
  </li>
  <li>
    <p>自动调整触发时机优化使用电量</p>
  </li>
  <li>
    <p>使用复杂度较低，最多只会发生 Retain Cycle 或忘记停止 Timer，但不会直接造成 Crash</p>
  </li>
</ul>

<p><strong>Timer 的缺点：</strong></p>

<ul>
  <li>
    <p>精确度受 RunLoop 状态影响，在 UI 高互动或 Mode 切换时可能延后触发</p>
  </li>
  <li>
    <p>不支援 <code class="language-plaintext highlighter-rouge">suspend</code> , <code class="language-plaintext highlighter-rouge">resume</code> , <code class="language-plaintext highlighter-rouge">activate</code> …等进阶操作</p>
  </li>
</ul>

<h4 id="适合场景">适合场景</h4>

<p>UI 层面需求，例如轮播 Banners (Auto Scroll ScrollView)或是优惠券领取倒数计时；这些只要求使用者在前景当前画面能响应内容的场景，我会选择直接用 Timer，方便、快速、安全的达成目的。</p>

<h4 id="生命周期">生命周期</h4>

<p><img src="/assets/62f68ebeecd3/1*rQrIoCxCdwoFCgqZc1zE8A.webp" alt="" loading="lazy" decoding="async" width="1187" height="1237" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTg3IiBoZWlnaHQ9IjEyMzciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/62f68ebeecd3/1*rQrIoCxCdwoFCgqZc1zE8A.png" /></p>

<p>在 UI Main Thread 上建立 Timer，Timer 会被 Main Thread 的 RunLoop 强持有、并透过 RunLoop 轮询机制定期触发，直到 Timer invalidate( ) 才会被释放；因此我们需要在 ViewController 上强持有 Timer 并在 deinit 时呼叫 Timer invalidate( )，才能在画面退出后正确终止释放 Timer。</p>

<ul>
  <li>
    <p>⭐️️️View Controller 强持有 Timer， <strong>Timer 的 Execution Block (handler / closure)务必为 Weak Self；否则会 Retain Cycle。</strong></p>
  </li>
  <li>
    <p>⭐️️️务必在 View Controller 生命周期结束时呼叫 Timer invalidate( )，否则 RunLoop 仍会持有 Timer 继续执行。</p>
  </li>
</ul>

<blockquote>
  <p><em>RunLoop 是 Thread 内的事件处理回圈，会轮询接收处理事件； <strong>Main Thread 系统会自动建立 RunLoop (RunLoop.main)</strong> ，除此之外其他 Thread 不一定会有 RunLoop。</em></p>
</blockquote>

<h4 id="使用">使用</h4>

<p>我们可以直接使用 <code class="language-plaintext highlighter-rouge">Timer.scheduledTimer</code> 宣告一个 Timer (会自动加入 RunLoop.main &amp; <strong>Mode: .default</strong> ):</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">final</span> <span class="kd">class</span> <span class="kt">HomeViewController</span><span class="p">:</span> <span class="kt">UIViewController</span> <span class="p">{</span>
    
    <span class="kd">private</span> <span class="k">var</span> <span class="nv">timer</span><span class="p">:</span> <span class="kt">Timer</span><span class="p">?</span>
    
    <span class="kd">deinit</span> <span class="p">{</span>
        <span class="k">self</span><span class="o">.</span><span class="n">timer</span><span class="p">?</span><span class="o">.</span><span class="nf">invalidate</span><span class="p">()</span>
        <span class="k">self</span><span class="o">.</span><span class="n">timer</span> <span class="o">=</span> <span class="kc">nil</span>
    <span class="p">}</span>

    <span class="k">override</span> <span class="kd">func</span> <span class="nf">viewDidLoad</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">super</span><span class="o">.</span><span class="nf">viewDidLoad</span><span class="p">()</span>
        <span class="nf">startCarousel</span><span class="p">()</span>
    <span class="p">}</span>
    
    <span class="kd">private</span> <span class="kd">func</span> <span class="nf">startCarousel</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">self</span><span class="o">.</span><span class="n">timer</span> <span class="o">=</span> <span class="kt">Timer</span><span class="o">.</span><span class="nf">scheduledTimer</span><span class="p">(</span><span class="nv">withTimeInterval</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nv">repeats</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nv">block</span><span class="p">:</span> <span class="p">{</span> <span class="p">[</span><span class="k">weak</span> <span class="k">self</span><span class="p">]</span> <span class="n">_</span> <span class="k">in</span>
            <span class="k">self</span><span class="p">?</span><span class="o">.</span><span class="nf">doSomething</span><span class="p">()</span>
        <span class="p">})</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kd">func</span> <span class="nf">doSomething</span><span class="p">()</span> <span class="p">{</span>
        <span class="nf">print</span><span class="p">(</span><span class="s">"Hello World!"</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>也可以自行宣告 Timer 物件加入到 RunLoop:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">timer</span><span class="o">=</span> <span class="kt">Timer</span><span class="p">(</span><span class="nv">timeInterval</span><span class="p">:</span> <span class="mf">1.0</span><span class="p">,</span> <span class="nv">repeats</span><span class="p">:</span> <span class="kc">true</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="k">weak</span> <span class="k">self</span><span class="p">]</span> <span class="n">_</span> <span class="k">in</span>
  <span class="c1">// do something..</span>
<span class="p">}</span>
<span class="k">self</span><span class="o">.</span><span class="n">timer</span> <span class="o">=</span> <span class="n">timer</span>
<span class="c1">// 加入 RunLoop 后才会开始执行</span>
<span class="kt">RunLoop</span><span class="o">.</span><span class="n">main</span><span class="o">.</span><span class="nf">add</span><span class="p">(</span><span class="n">timer</span><span class="p">,</span> <span class="nv">forMode</span><span class="p">:</span> <span class="o">.</span><span class="k">default</span><span class="p">)</span>
</code></pre></div></div>

<h4 id="timer-的操作方法">Timer 的操作方法</h4>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">invalidate()</code> 终止 Timer</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">fire()</code> 立即触发一次</p>
  </li>
</ul>

<h4 id="runloop-mode-的影响">RunLoop <strong>Mode 的影响</strong></h4>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">.default</code> ：预设加入的 Mode，主要是处理 UI 显示。
<strong>会在切换到 <code class="language-plaintext highlighter-rouge">.tracking</code> Mode 时先暂停</strong></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">.tracking</code> ：处理 ScrollView 滚动、Gesture 手势。</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">.common</code> ： <code class="language-plaintext highlighter-rouge">.default</code> + <code class="language-plaintext highlighter-rouge">.tracking</code> 都会处理。</p>
  </li>
</ul>

<blockquote>
  <p><em>⭐️️️⭐️️️⭐️️️因此在默认情况下，我们的 Timer 是加到 <code class="language-plaintext highlighter-rouge">.default</code> Mode， <strong>会在使用者滚动 ScrollView 或是手势操作时自动暂停</strong> ，等到操作结束后才会继续，可能造成 Timer 延后触发或是次数低于预期。</em></p>
</blockquote>

<p><strong>对此，我们可以把 Timer 改加入到 .common Mode 就能解决以上问题:</strong></p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">RunLoop</span><span class="o">.</span><span class="n">main</span><span class="o">.</span><span class="nf">add</span><span class="p">(</span><span class="n">timer</span><span class="p">,</span> <span class="nv">forMode</span><span class="p">:</span> <span class="o">.</span><span class="n">common</span><span class="p">)</span>
</code></pre></div></div>

<h3 id="grand-central-dispatch--dispatchsourcetimer"><a href="https://developer.apple.com/documentation/dispatch/dispatchsourcetimer" target="_blank">Grand Central Dispatch — DispatchSourceTimer</a></h3>

<p>除了 Timer 之外，GCD 也提供了另一个 DispatchSourceTimer 方法可供选择。</p>

<h4 id="优缺点-1">优缺点</h4>

<p><strong>DispatchSourceTimer 的优点：</strong></p>

<ul>
  <li>
    <p>操作弹性(支援 <code class="language-plaintext highlighter-rouge">suspend</code> , <code class="language-plaintext highlighter-rouge">resume</code> ) 较好</p>
  </li>
  <li>
    <p>精确度与可靠程度较高：依赖 GCD Queue</p>
  </li>
  <li>
    <p>可自行设定 leeway 控制耗电量</p>
  </li>
  <li>
    <p>可稳定常驻任务 (GCD Queue)</p>
  </li>
</ul>

<p><strong>DispatchSourceTimer 的缺点：</strong></p>

<ul>
  <li>
    <p>UI 操作需自行切换回 Main Thread</p>
  </li>
  <li>
    <p>API 使用复杂且有顺序， <strong>用错会 Crash</strong></p>
  </li>
  <li>
    <p>需要封装才能安全使用</p>
  </li>
</ul>

<h4 id="适合场景-1">适合场景</h4>

<p>相较 Timer 适合 UI 层面的场景，DispatchSourceTimer 比较适合做那些跟 UI 或使用者当前画面无关的任务场景；最常见的就是发送 Tracking 事件，我们会定时把使用者操作产生的事件发送到伺服器，或是定时清理无用的 CoreData 资料；这些就很适合使用 DispatchSourceTimer。</p>

<h4 id="生命周期-1">生命周期</h4>

<p><img src="/assets/62f68ebeecd3/1*2hIwImzm6ubpc5zK_roI3Q.webp" alt="" loading="lazy" decoding="async" width="1289" height="914" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjg5IiBoZWlnaHQ9IjkxNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/62f68ebeecd3/1*2hIwImzm6ubpc5zK_roI3Q.png" /></p>

<p>DispatchSourceTimer 的生命周期取决于是否仍被外部物件持有；GCD queue 本身不会强持有 timer 的 owner，只负责调度与执行事件。</p>

<h4 id="闪退问题">闪退问题</h4>

<p>DispatchSourceTimer 虽然提供更多可操作方法： <code class="language-plaintext highlighter-rouge">activate</code> , <code class="language-plaintext highlighter-rouge">suspend</code> , <code class="language-plaintext highlighter-rouge">resume</code> , <code class="language-plaintext highlighter-rouge">cancel</code> ；但是它极其敏感，只要呼叫的顺序不对就会直闪退 (EXC_BREAKPOINT/DispatchSourceTimer) 非常危险。</p>

<p><img src="/assets/62f68ebeecd3/1*04cApJDt29a-98zgb9Wd2A.webp" alt="" loading="lazy" decoding="async" width="683" height="185" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2ODMiIGhlaWdodD0iMTg1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/62f68ebeecd3/1*04cApJDt29a-98zgb9Wd2A.png" /></p>

<p><strong>以下情况均会直接闪退：</strong></p>

<ul>
  <li>
    <p>❌ suspend( ) 与 resume( ) 没有成对使用
suspend( ) 后又呼叫一次 suspend( )
resume( ) 后又呼叫一次 resume( )</p>
  </li>
  <li>
    <p>❌ suspend( ) 后呼叫 cancel( )
需要先 resume( ) 才能 cancel( )</p>
  </li>
  <li>
    <p>❌ suspend( ) 状态下 Timer 被释放 (nil)</p>
  </li>
  <li>
    <p>❌ cancel( ) 后再呼叫其他操作</p>
  </li>
</ul>

<h4 id="使用-finite-state-machine-有限状态机封装操作">使用 Finite-State Machine 有限状态机封装操作</h4>

<p>进入本篇文章的另一个重点，该如何安全的使用 DispatchSourceTimer?</p>

<p><img src="/assets/62f68ebeecd3/1*S33K4OWFUPMocZvM4dLWvw.webp" alt="" loading="lazy" decoding="async" width="1200" height="987" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk4NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/62f68ebeecd3/1*S33K4OWFUPMocZvM4dLWvw.png" /></p>

<p>如上图所示，我们使用有限状态机封装 DispatchSourceTimer 的操作，使其可以更安全、更容易的使用:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">final</span> <span class="kd">class</span> <span class="kt">DispatchSourceTimerMachine</span> <span class="p">{</span>
    <span class="c1">// 有限状态机有哪些状态</span>
    <span class="kd">private</span> <span class="kd">enum</span> <span class="kt">TimerState</span> <span class="p">{</span>
        <span class="c1">// 初始状态</span>
        <span class="k">case</span> <span class="n">idle</span>
        <span class="c1">// 执行中</span>
        <span class="k">case</span> <span class="n">running</span>
        <span class="c1">// 暂停中</span>
        <span class="k">case</span> <span class="n">suspended</span>
        <span class="c1">// 终止中</span>
        <span class="k">case</span> <span class="n">cancelled</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="k">var</span> <span class="nv">timer</span><span class="p">:</span> <span class="kt">DispatchSourceTimer</span><span class="p">?</span>
    <span class="kd">private</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">timerQueue</span><span class="p">:</span> <span class="kt">DispatchQueue</span> <span class="o">=</span> <span class="p">{</span>
        <span class="kt">DispatchQueue</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="s">"li.zhgchg.DispatchSourceTimerMachine"</span><span class="p">,</span> <span class="nv">qos</span><span class="p">:</span> <span class="o">.</span><span class="n">background</span><span class="p">)</span>
    <span class="p">}()</span>

    <span class="kd">private</span> <span class="k">var</span> <span class="nv">_state</span><span class="p">:</span> <span class="kt">TimerState</span> <span class="o">=</span> <span class="o">.</span><span class="n">idle</span>
    
    <span class="kd">deinit</span> <span class="p">{</span>
        <span class="c1">// Owner 物件消失时，同步 cancel timer</span>
        <span class="c1">// 虽不做也不影响(handler 是 weak)，但是可以确保流程符合预期</span>
        <span class="k">if</span> <span class="n">_state</span> <span class="o">==</span> <span class="o">.</span><span class="n">suspended</span> <span class="p">{</span>
            <span class="n">timer</span><span class="p">?</span><span class="o">.</span><span class="nf">resume</span><span class="p">()</span>
            <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">running</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="n">_state</span> <span class="o">==</span> <span class="o">.</span><span class="n">running</span> <span class="p">{</span>
            <span class="n">timer</span><span class="p">?</span><span class="o">.</span><span class="nf">cancel</span><span class="p">()</span>
            <span class="n">timer</span> <span class="o">=</span> <span class="kc">nil</span>
            <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">cancelled</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 启动 Timer</span>
    <span class="kd">func</span> <span class="nf">activate</span><span class="p">(</span><span class="nv">repeatTimeInterval</span><span class="p">:</span> <span class="kt">DispatchTimeInterval</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="kt">DispatchSource</span><span class="o">.</span><span class="kt">DispatchSourceHandler</span><span class="p">?)</span> <span class="p">{</span>
        <span class="c1">// 只有 idle, cancelled 状态可以启用 Timer</span>
        <span class="k">guard</span> <span class="p">[</span><span class="o">.</span><span class="n">idle</span><span class="p">,</span> <span class="o">.</span><span class="n">cancelled</span><span class="p">]</span><span class="o">.</span><span class="nf">contains</span><span class="p">(</span><span class="n">_state</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
        
        <span class="c1">// 建立 Timer and activate()</span>
        <span class="k">let</span> <span class="nv">timer</span> <span class="o">=</span> <span class="nf">makeTimer</span><span class="p">(</span><span class="nv">repeatTimeInterval</span><span class="p">:</span> <span class="n">repeatTimeInterval</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="n">handler</span><span class="p">)</span>
        <span class="k">self</span><span class="o">.</span><span class="n">timer</span> <span class="o">=</span> <span class="n">timer</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">activate</span><span class="p">()</span>
        
        <span class="c1">// 切换到 running 状态</span>
        <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">running</span>
    <span class="p">}</span>

    <span class="c1">// 暂停 Timer</span>
    <span class="kd">func</span> <span class="nf">suspend</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// 只有在 running 状态可以暂停 Timer</span>
        <span class="k">guard</span> <span class="p">[</span><span class="o">.</span><span class="n">running</span><span class="p">]</span><span class="o">.</span><span class="nf">contains</span><span class="p">(</span><span class="n">_state</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
        
        <span class="c1">// 暂停 Timer</span>
        <span class="n">timer</span><span class="p">?</span><span class="o">.</span><span class="nf">suspend</span><span class="p">()</span>
        
        <span class="c1">// 切换到 suspended 状态</span>
        <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">suspended</span>
    <span class="p">}</span>

    <span class="c1">// 恢复 Timer</span>
    <span class="kd">func</span> <span class="nf">resume</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// 只有在 suspended 状态可以恢复 Timer</span>
        <span class="k">guard</span> <span class="p">[</span><span class="o">.</span><span class="n">suspended</span><span class="p">]</span><span class="o">.</span><span class="nf">contains</span><span class="p">(</span><span class="n">_state</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
        
        <span class="c1">// 恢复 Timer</span>
        <span class="n">timer</span><span class="p">?</span><span class="o">.</span><span class="nf">resume</span><span class="p">()</span>
        
        <span class="c1">// 切换到 running 状态</span>
        <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">running</span>
    <span class="p">}</span>

    <span class="c1">// 终止 Timer</span>
    <span class="kd">func</span> <span class="nf">cancel</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// 只有在 suspended, running 状态可以终止 Timer</span>
        <span class="k">guard</span> <span class="p">[</span><span class="o">.</span><span class="n">suspended</span><span class="p">,</span> <span class="o">.</span><span class="n">running</span><span class="p">]</span><span class="o">.</span><span class="nf">contains</span><span class="p">(</span><span class="n">_state</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
        
        <span class="c1">// 如果当前是 suspended 状态，先 resume() 再终止</span>
        <span class="c1">// 此为 DispatchSourceTimer 的限制，只能在 running 才能 cancel()</span>
        <span class="k">if</span> <span class="n">_state</span> <span class="o">==</span> <span class="o">.</span><span class="n">suspended</span> <span class="p">{</span>
            <span class="k">self</span><span class="o">.</span><span class="nf">resume</span><span class="p">()</span>
        <span class="p">}</span>

        <span class="c1">// 终止 Timer</span>
        <span class="n">timer</span><span class="p">?</span><span class="o">.</span><span class="nf">cancel</span><span class="p">()</span>
        <span class="n">timer</span> <span class="o">=</span> <span class="kc">nil</span>
        
        <span class="c1">// 切换到 cancelled 状态</span>
        <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">cancelled</span>
    <span class="p">}</span>
    
    <span class="kd">private</span> <span class="kd">func</span> <span class="nf">makeTimer</span><span class="p">(</span><span class="nv">repeatTimeInterval</span><span class="p">:</span> <span class="kt">DispatchTimeInterval</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="kt">DispatchSourceProtocol</span><span class="o">.</span><span class="kt">DispatchSourceHandler</span><span class="p">?)</span> <span class="o">-&gt;</span> <span class="kt">DispatchSourceTimer</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">timer</span> <span class="o">=</span> <span class="kt">DispatchSource</span><span class="o">.</span><span class="nf">makeTimerSource</span><span class="p">(</span><span class="nv">queue</span><span class="p">:</span> <span class="n">timerQueue</span><span class="p">)</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">schedule</span><span class="p">(</span><span class="nv">deadline</span><span class="p">:</span> <span class="o">.</span><span class="nf">now</span><span class="p">(),</span> <span class="nv">repeating</span><span class="p">:</span> <span class="n">repeatTimeInterval</span><span class="p">)</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">setEventHandler</span><span class="p">(</span><span class="nv">qos</span><span class="p">:</span> <span class="o">.</span><span class="n">background</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="n">handler</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">timer</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>我们简单使用有限状态机「封装了状态可以转换成什么状态」与「状态需要做什么」的逻辑，如果在错误的状态下呼叫会被忽略(不会闪退)，我们还多做了一些优化，例如 suspended 状态也能 cancel、cancelled 状态能重新 activate。</p>

<blockquote>
  <p><strong><em>延伸阅读：</em></strong></p>
</blockquote>

<blockquote>
  <p><em>之前写过另一篇文章「 <a href="https://zhgchg.li/posts/pinkoi-engineering/design-patterns-%E5%AF%A6%E6%88%B0%E6%87%89%E7%94%A8-%E5%B0%81%E8%A3%9D-socket-io-%E5%8D%B3%E6%99%82%E9%80%9A%E8%A8%8A%E6%9E%B6%E6%A7%8B%E8%88%87%E4%B8%83%E5%A4%A7%E8%A8%AD%E8%A8%88%E6%A8%A1%E5%BC%8F%E8%A7%A3%E6%9E%90-78507a8de6a5/#%E9%9C%80%E6%B1%82%E5%A0%B4%E6%99%AF-3" target="_blank">Design Patterns 实战应用｜封装 Socket.IO 即时通讯架构</a> 」中也有使用到有限状态机，另外还多使用了 State Pattern。</em></p>
</blockquote>

<blockquote>
  <p><em>Finite-State Machine 有限状态机: 关注的是状态之间的转换控制与该做什么。</em></p>
</blockquote>

<blockquote>
  <p><em>State Pattern: 关注的是每个状态内的行为逻辑。</em></p>
</blockquote>

<h4 id="使用-serial-queue-操作有限状态机状态转换">使用 Serial Queue 操作有限状态机状态转换</h4>

<p>有了状态机确保 DispatchSourceTimer 能安全使用之后还没结束，我们无法保证在外部呼叫使用 DispatchSourceTimerMachine 的地方是在同个 Thread，如果不同 Thread 都操作了这个物件就会造成 Race Condition 一样会引发闪退。</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">final</span> <span class="kd">class</span> <span class="kt">DispatchSourceTimerMachine</span> <span class="p">{</span>
    <span class="c1">// 有限状态机有哪些状态</span>
    <span class="kd">private</span> <span class="kd">enum</span> <span class="kt">TimerState</span> <span class="p">{</span>
        <span class="c1">// 初始状态</span>
        <span class="k">case</span> <span class="n">idle</span>
        <span class="c1">// 执行中</span>
        <span class="k">case</span> <span class="n">running</span>
        <span class="c1">// 暂停中</span>
        <span class="k">case</span> <span class="n">suspended</span>
        <span class="c1">// 终止中</span>
        <span class="k">case</span> <span class="n">cancelled</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="k">var</span> <span class="nv">timer</span><span class="p">:</span> <span class="kt">DispatchSourceTimer</span><span class="p">?</span>
    <span class="kd">private</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">timerQueue</span><span class="p">:</span> <span class="kt">DispatchQueue</span> <span class="o">=</span> <span class="p">{</span>
        <span class="kt">DispatchQueue</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="s">"li.zhgchg.DispatchSourceTimerMachine"</span><span class="p">,</span> <span class="nv">qos</span><span class="p">:</span> <span class="o">.</span><span class="n">background</span><span class="p">)</span>
    <span class="p">}()</span>

    <span class="kd">private</span> <span class="k">var</span> <span class="nv">_state</span><span class="p">:</span> <span class="kt">TimerState</span> <span class="o">=</span> <span class="o">.</span><span class="n">idle</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="k">let</span> <span class="nv">operationQueueSpecificKey</span> <span class="o">=</span> <span class="kt">DispatchSpecificKey</span><span class="o">&lt;</span><span class="kt">ObjectIdentifier</span><span class="o">&gt;</span><span class="p">()</span>
    <span class="kd">private</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">operationQueueSpecificValue</span><span class="p">:</span> <span class="kt">ObjectIdentifier</span> <span class="o">=</span> <span class="kt">ObjectIdentifier</span><span class="p">(</span><span class="k">self</span><span class="p">)</span>
    <span class="kd">private</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">operationQueue</span><span class="p">:</span> <span class="kt">DispatchQueue</span> <span class="o">=</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">queue</span> <span class="o">=</span> <span class="kt">DispatchQueue</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="s">"li.zhgchg.DispatchSourceTimerMachine.operationQueue"</span><span class="p">)</span>
        <span class="n">queue</span><span class="o">.</span><span class="nf">setSpecific</span><span class="p">(</span><span class="nv">key</span><span class="p">:</span> <span class="k">Self</span><span class="o">.</span><span class="n">operationQueueSpecificKey</span><span class="p">,</span> <span class="nv">value</span><span class="p">:</span> <span class="n">operationQueueSpecificValue</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">queue</span>
    <span class="p">}()</span>
    <span class="kd">private</span> <span class="kd">func</span> <span class="nf">operation</span><span class="p">(</span><span class="nv">async</span><span class="p">:</span> <span class="kt">Bool</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span> <span class="n">_</span> <span class="nv">work</span><span class="p">:</span> <span class="kd">@escaping</span> <span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">Void</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="kt">DispatchQueue</span><span class="o">.</span><span class="nf">getSpecific</span><span class="p">(</span><span class="nv">key</span><span class="p">:</span> <span class="k">Self</span><span class="o">.</span><span class="n">operationQueueSpecificKey</span><span class="p">)</span> <span class="o">==</span> <span class="n">operationQueueSpecificValue</span> <span class="p">{</span>
            <span class="nf">work</span><span class="p">()</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">if</span> <span class="k">async</span> <span class="p">{</span>
                <span class="n">operationQueue</span><span class="o">.</span><span class="nf">async</span><span class="p">(</span><span class="nv">execute</span><span class="p">:</span> <span class="n">work</span><span class="p">)</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">operationQueue</span><span class="o">.</span><span class="nf">sync</span><span class="p">(</span><span class="nv">execute</span><span class="p">:</span> <span class="n">work</span><span class="p">)</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    
    <span class="kd">deinit</span> <span class="p">{</span>
        <span class="c1">// Owner 物件消失时，同步 cancel timer</span>
        <span class="c1">// 虽不做也不影响(handler 是 weak)，但是可以确保流程符合预期</span>
        <span class="c1">// 确保 sync 执行完毕</span>
        <span class="nf">operation</span><span class="p">(</span><span class="nv">async</span><span class="p">:</span> <span class="kc">false</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="k">self</span><span class="p">]</span> <span class="k">in</span>
            <span class="k">if</span> <span class="n">_state</span> <span class="o">==</span> <span class="o">.</span><span class="n">suspended</span> <span class="p">{</span>
                <span class="n">timer</span><span class="p">?</span><span class="o">.</span><span class="nf">resume</span><span class="p">()</span>
                <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">running</span>
            <span class="p">}</span>
            <span class="k">if</span> <span class="n">_state</span> <span class="o">==</span> <span class="o">.</span><span class="n">running</span> <span class="p">{</span>
                <span class="n">timer</span><span class="p">?</span><span class="o">.</span><span class="nf">cancel</span><span class="p">()</span>
                <span class="n">timer</span> <span class="o">=</span> <span class="kc">nil</span>
                <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">cancelled</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 启动 Timer</span>
    <span class="kd">func</span> <span class="nf">activate</span><span class="p">(</span><span class="nv">repeatTimeInterval</span><span class="p">:</span> <span class="kt">DispatchTimeInterval</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="kt">DispatchSource</span><span class="o">.</span><span class="kt">DispatchSourceHandler</span><span class="p">?)</span> <span class="p">{</span>
        <span class="n">operation</span> <span class="p">{</span> <span class="p">[</span><span class="k">weak</span> <span class="k">self</span><span class="p">]</span> <span class="k">in</span>
            <span class="k">guard</span> <span class="k">let</span> <span class="nv">self</span> <span class="o">=</span> <span class="k">self</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
            <span class="c1">// 只有 idle, cancelled 状态可以启用 Timer</span>
            <span class="k">guard</span> <span class="p">[</span><span class="o">.</span><span class="n">idle</span><span class="p">,</span> <span class="o">.</span><span class="n">cancelled</span><span class="p">]</span><span class="o">.</span><span class="nf">contains</span><span class="p">(</span><span class="n">_state</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
            
            <span class="c1">// 建立 Timer and activate()</span>
            <span class="k">let</span> <span class="nv">timer</span> <span class="o">=</span> <span class="nf">makeTimer</span><span class="p">(</span><span class="nv">repeatTimeInterval</span><span class="p">:</span> <span class="n">repeatTimeInterval</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="n">handler</span><span class="p">)</span>
            <span class="k">self</span><span class="o">.</span><span class="n">timer</span> <span class="o">=</span> <span class="n">timer</span>
            <span class="n">timer</span><span class="o">.</span><span class="nf">activate</span><span class="p">()</span>
            
            <span class="c1">// 切换到 running 状态</span>
            <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">running</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 暂停 Timer</span>
    <span class="kd">func</span> <span class="nf">suspend</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">operation</span> <span class="p">{</span> <span class="p">[</span><span class="k">weak</span> <span class="k">self</span><span class="p">]</span> <span class="k">in</span>
            <span class="k">guard</span> <span class="k">let</span> <span class="nv">self</span> <span class="o">=</span> <span class="k">self</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
            <span class="c1">// 只有在 running 状态可以暂停 Timer</span>
            <span class="k">guard</span> <span class="p">[</span><span class="o">.</span><span class="n">running</span><span class="p">]</span><span class="o">.</span><span class="nf">contains</span><span class="p">(</span><span class="n">_state</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
            
            <span class="c1">// 暂停 Timer</span>
            <span class="n">timer</span><span class="p">?</span><span class="o">.</span><span class="nf">suspend</span><span class="p">()</span>
            
            <span class="c1">// 切换到 suspended 状态</span>
            <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">suspended</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 恢复 Timer</span>
    <span class="kd">func</span> <span class="nf">resume</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">operation</span> <span class="p">{</span> <span class="p">[</span><span class="k">weak</span> <span class="k">self</span><span class="p">]</span> <span class="k">in</span>
            <span class="k">guard</span> <span class="k">let</span> <span class="nv">self</span> <span class="o">=</span> <span class="k">self</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
            <span class="c1">// 只有在 suspended 状态可以恢复 Timer</span>
            <span class="k">guard</span> <span class="p">[</span><span class="o">.</span><span class="n">suspended</span><span class="p">]</span><span class="o">.</span><span class="nf">contains</span><span class="p">(</span><span class="n">_state</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
            
            <span class="c1">// 恢复 Timer</span>
            <span class="n">timer</span><span class="p">?</span><span class="o">.</span><span class="nf">resume</span><span class="p">()</span>
            
            <span class="c1">// 切换到 running 状态</span>
            <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">running</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 终止 Timer</span>
    <span class="kd">func</span> <span class="nf">cancel</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">operation</span> <span class="p">{</span> <span class="p">[</span><span class="k">weak</span> <span class="k">self</span><span class="p">]</span> <span class="k">in</span>
            <span class="k">guard</span> <span class="k">let</span> <span class="nv">self</span> <span class="o">=</span> <span class="k">self</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
            <span class="c1">// 只有在 suspended, running 状态可以终止 Timer</span>
            <span class="k">guard</span> <span class="p">[</span><span class="o">.</span><span class="n">suspended</span><span class="p">,</span> <span class="o">.</span><span class="n">running</span><span class="p">]</span><span class="o">.</span><span class="nf">contains</span><span class="p">(</span><span class="n">_state</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
            
            <span class="c1">// 如果当前是 suspended 状态，先 resume() 再终止</span>
            <span class="c1">// 此为 DispatchSourceTimer 的限制，只能在 running 才能 cancel()</span>
            <span class="k">if</span> <span class="n">_state</span> <span class="o">==</span> <span class="o">.</span><span class="n">suspended</span> <span class="p">{</span>
                <span class="k">self</span><span class="o">.</span><span class="nf">resume</span><span class="p">()</span>
            <span class="p">}</span>
            
            <span class="c1">// 终止 Timer</span>
            <span class="n">timer</span><span class="p">?</span><span class="o">.</span><span class="nf">cancel</span><span class="p">()</span>
            <span class="n">timer</span> <span class="o">=</span> <span class="kc">nil</span>
            
            <span class="c1">// 切换到 cancelled 状态</span>
            <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">cancelled</span>
        <span class="p">}</span>
    <span class="p">}</span>
    
    <span class="kd">private</span> <span class="kd">func</span> <span class="nf">makeTimer</span><span class="p">(</span><span class="nv">repeatTimeInterval</span><span class="p">:</span> <span class="kt">DispatchTimeInterval</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="kt">DispatchSourceProtocol</span><span class="o">.</span><span class="kt">DispatchSourceHandler</span><span class="p">?)</span> <span class="o">-&gt;</span> <span class="kt">DispatchSourceTimer</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">timer</span> <span class="o">=</span> <span class="kt">DispatchSource</span><span class="o">.</span><span class="nf">makeTimerSource</span><span class="p">(</span><span class="nv">queue</span><span class="p">:</span> <span class="n">timerQueue</span><span class="p">)</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">schedule</span><span class="p">(</span><span class="nv">deadline</span><span class="p">:</span> <span class="o">.</span><span class="nf">now</span><span class="p">(),</span> <span class="nv">repeating</span><span class="p">:</span> <span class="n">repeatTimeInterval</span><span class="p">)</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">setEventHandler</span><span class="p">(</span><span class="nv">qos</span><span class="p">:</span> <span class="o">.</span><span class="n">background</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="n">handler</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">timer</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>现在，我们可以安全无忧的使用 <code class="language-plaintext highlighter-rouge">DispatchSourceTimerMachine</code> 物件作为 Timer 了:</p>

<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">final</span> <span class="kd">class</span> <span class="nc">TrackingEventSender</span> <span class="p">{</span>

    <span class="k">private</span> <span class="kd">let</span> <span class="nx">timerMachine</span> <span class="o">=</span> <span class="nc">DispatchSourceTimerMachine</span><span class="p">()</span>
    <span class="k">public</span> <span class="kd">var</span> <span class="nx">events</span><span class="p">:</span> <span class="p">[</span><span class="nb">String</span><span class="p">:</span> <span class="nb">String</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="c1">// 启动定期 tracking</span>
    <span class="nx">func</span> <span class="nf">startTracking</span><span class="p">()</span> <span class="p">{</span>
        <span class="nx">timerMachine</span><span class="p">.</span><span class="nf">activate</span><span class="p">(</span><span class="nx">repeatTimeInterval</span><span class="p">:</span> <span class="p">.</span><span class="nf">seconds</span><span class="p">(</span><span class="mi">30</span><span class="p">))</span> <span class="p">{</span> <span class="p">[</span><span class="nx">weak</span> <span class="nb">self</span><span class="p">]</span> <span class="k">in</span>
            <span class="nb">self</span><span class="p">?.</span><span class="nf">sendTrackingEvent</span><span class="p">()</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 暂停 tracking（例如 App 进背景）</span>
    <span class="nx">func</span> <span class="nf">pauseTracking</span><span class="p">()</span> <span class="p">{</span>
        <span class="nx">timerMachine</span><span class="p">.</span><span class="nf">suspend</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="c1">// 恢复 tracking（例如 App 回前景）</span>
    <span class="nx">func</span> <span class="nf">resumeTracking</span><span class="p">()</span> <span class="p">{</span>
        <span class="nx">timerMachine</span><span class="p">.</span><span class="nf">resume</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="c1">// 停止 tracking（例如页面离开）</span>
    <span class="nx">func</span> <span class="nf">stopTracking</span><span class="p">()</span> <span class="p">{</span>
        <span class="nx">timerMachine</span><span class="p">.</span><span class="nf">cancel</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="nx">func</span> <span class="nf">sendTrackingEvent</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// send events to server...</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>到此如何安全的使用 DispatchSourceTimer 环节已结束，再来延伸几个 Design Patterns 的使用，方便我们抽象物件进行测试跟 DispatchSourceHandler 执行逻辑抽象。</p>

<h4 id="延伸--使用-adapter-pattern--factory-pattern-产生-dispatchsourcetimer-利于抽象测试">延伸 — 使用 Adapter Pattern + Factory Pattern 产生 DispatchSourceTimer (利于抽象测试)</h4>

<p>DispatchSourceTimer 是 GCD 的 Objective-C 物件，在测试环节我们很难对其 Mock (无 Protocol)；因此我们需要自己定义一层 Protocol + Factory Pattern 产生，让 TimerStateMachine 是能写测试的。</p>

<p><strong>Adapter Pattern— 封装 DispatchSourceTimer 操作:</strong></p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">protocol</span> <span class="kt">TimerAdapter</span> <span class="p">{</span>
    <span class="kd">func</span> <span class="nf">schedule</span><span class="p">(</span><span class="nv">repeating</span><span class="p">:</span> <span class="kt">DispatchTimeInterval</span><span class="p">)</span>
    <span class="kd">func</span> <span class="nf">setEventHandler</span><span class="p">(</span><span class="nv">handler</span><span class="p">:</span> <span class="kt">DispatchSourceProtocol</span><span class="o">.</span><span class="kt">DispatchSourceHandler</span><span class="p">?)</span>
    <span class="kd">func</span> <span class="nf">activate</span><span class="p">()</span>
    <span class="kd">func</span> <span class="nf">suspend</span><span class="p">()</span>
    <span class="kd">func</span> <span class="nf">resume</span><span class="p">()</span>
    <span class="kd">func</span> <span class="nf">cancel</span><span class="p">()</span>
<span class="p">}</span>

<span class="c1">// DispatchSourceTimer 的 Adapter 实现</span>
<span class="kd">final</span> <span class="kd">class</span> <span class="kt">DispatchSourceTimerAdapter</span><span class="p">:</span> <span class="kt">TimerAdapter</span> <span class="p">{</span>
    <span class="c1">// 原始的 DispatchSourceTimer</span>
    <span class="kd">private</span> <span class="k">let</span> <span class="nv">timer</span><span class="p">:</span> <span class="kt">DispatchSourceTimer</span>

    <span class="nf">init</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="s">"li.zhgchg.DispatchSourceTimerAdapter"</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">queue</span> <span class="o">=</span> <span class="kt">DispatchQueue</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="n">label</span><span class="p">,</span> <span class="nv">qos</span><span class="p">:</span> <span class="o">.</span><span class="n">background</span><span class="p">)</span>
        <span class="k">let</span> <span class="nv">timer</span> <span class="o">=</span> <span class="kt">DispatchSource</span><span class="o">.</span><span class="nf">makeTimerSource</span><span class="p">(</span><span class="nv">queue</span><span class="p">:</span> <span class="n">queue</span><span class="p">)</span>
        <span class="k">self</span><span class="o">.</span><span class="n">timer</span> <span class="o">=</span> <span class="n">timer</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">schedule</span><span class="p">(</span><span class="nv">repeating</span><span class="p">:</span> <span class="kt">DispatchTimeInterval</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">schedule</span><span class="p">(</span><span class="nv">deadline</span><span class="p">:</span> <span class="o">.</span><span class="nf">now</span><span class="p">(),</span> <span class="nv">repeating</span><span class="p">:</span> <span class="n">repeating</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">setEventHandler</span><span class="p">(</span><span class="nv">handler</span><span class="p">:</span> <span class="kt">DispatchSourceProtocol</span><span class="o">.</span><span class="kt">DispatchSourceHandler</span><span class="p">?)</span> <span class="p">{</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">setEventHandler</span><span class="p">(</span><span class="nv">qos</span><span class="p">:</span> <span class="o">.</span><span class="n">background</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="n">handler</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">activate</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">activate</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">suspend</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">suspend</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">resume</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">resume</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">cancel</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">cancel</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Factory Pattern — 抽象产生 TimerAdapter 的方法:</strong></p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">protocol</span> <span class="kt">DispatchSourceTimerAdapterFactorySpec</span> <span class="p">{</span>
    <span class="kd">func</span> <span class="nf">makeTimer</span><span class="p">(</span><span class="nv">repeatTimeInterval</span><span class="p">:</span> <span class="kt">DispatchTimeInterval</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="kt">DispatchSourceProtocol</span><span class="o">.</span><span class="kt">DispatchSourceHandler</span><span class="p">?)</span> <span class="o">-&gt;</span> <span class="kt">TimerAdapter</span>
<span class="p">}</span>

<span class="c1">// 封装 DispatchSourceTimerAdapter 产生步骤</span>
<span class="kd">final</span> <span class="kd">class</span> <span class="kt">DispatchSourceTimerAdapterFactory</span><span class="p">:</span> <span class="kt">DispatchSourceTimerAdapterFactorySpec</span> <span class="p">{</span>
    <span class="kd">public</span> <span class="kd">func</span> <span class="nf">makeTimer</span><span class="p">(</span><span class="nv">repeatTimeInterval</span><span class="p">:</span> <span class="kt">DispatchTimeInterval</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="kt">DispatchSourceProtocol</span><span class="o">.</span><span class="kt">DispatchSourceHandler</span><span class="p">?)</span> <span class="o">-&gt;</span> <span class="kt">TimerAdapter</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">timer</span> <span class="o">=</span> <span class="kt">DispatchSourceTimerAdapter</span><span class="p">()</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">schedule</span><span class="p">(</span><span class="nv">repeating</span><span class="p">:</span> <span class="n">repeatTimeInterval</span><span class="p">)</span>
        <span class="n">timer</span><span class="o">.</span><span class="nf">setEventHandler</span><span class="p">(</span><span class="nv">handler</span><span class="p">:</span> <span class="n">handler</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">timer</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>组合使用:</strong></p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="nv">stateMachine</span> <span class="o">=</span> <span class="kt">DispatchSourceTimerMachine</span><span class="p">(</span><span class="nv">timerFactory</span><span class="p">:</span> <span class="kt">DispatchSourceTimerAdapterFactory</span><span class="p">())</span>

<span class="c1">//</span>
<span class="kd">final</span> <span class="kd">class</span> <span class="kt">DispatchSourceTimerMachine</span> <span class="p">{</span>
    <span class="c1">// 略..</span>
    <span class="kd">private</span> <span class="k">var</span> <span class="nv">timer</span><span class="p">:</span> <span class="kt">TimerAdapter</span><span class="p">?</span>
    <span class="kd">private</span> <span class="k">let</span> <span class="nv">timerFactory</span><span class="p">:</span> <span class="kt">DispatchSourceTimerAdapterFactorySpec</span>
    <span class="kd">public</span> <span class="nf">init</span><span class="p">(</span><span class="nv">timerFactory</span><span class="p">:</span> <span class="kt">DispatchSourceTimerAdapterFactorySpec</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="o">.</span><span class="n">timerFactory</span> <span class="o">=</span> <span class="n">timerFactory</span>
    <span class="p">}</span>
    <span class="c1">// 略..</span>

    <span class="kd">func</span> <span class="nf">activate</span><span class="p">(</span><span class="nv">repeatTimeInterval</span><span class="p">:</span> <span class="kt">DispatchTimeInterval</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="kt">DispatchSource</span><span class="o">.</span><span class="kt">DispatchSourceHandler</span><span class="p">?)</span> <span class="p">{</span>
        <span class="n">onQueue</span> <span class="p">{</span> <span class="p">[</span><span class="k">weak</span> <span class="k">self</span><span class="p">]</span> <span class="k">in</span>
            <span class="k">guard</span> <span class="k">let</span> <span class="nv">self</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
            <span class="k">guard</span> <span class="p">[</span><span class="o">.</span><span class="n">idle</span><span class="p">,</span> <span class="o">.</span><span class="n">cancelled</span><span class="p">]</span><span class="o">.</span><span class="nf">contains</span><span class="p">(</span><span class="n">_state</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
            <span class="c1">// 使用 Factory MakeTimer</span>
            <span class="k">let</span> <span class="nv">timer</span> <span class="o">=</span> <span class="n">timerFactory</span><span class="o">.</span><span class="nf">makeTimer</span><span class="p">(</span><span class="nv">repeatTimeInterval</span><span class="p">:</span> <span class="n">repeatTimeInterval</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="n">handler</span><span class="p">)</span>
            <span class="k">self</span><span class="o">.</span><span class="n">timer</span> <span class="o">=</span> <span class="n">timer</span>

            <span class="n">timer</span><span class="o">.</span><span class="nf">activate</span><span class="p">()</span>
            <span class="n">_state</span> <span class="o">=</span> <span class="o">.</span><span class="n">running</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 略..</span>
<span class="p">}</span>
</code></pre></div></div>

<p>这样我们就能对 <code class="language-plaintext highlighter-rouge">TimerAdapter</code> / <code class="language-plaintext highlighter-rouge">DispatchSourceTimerAdapterFactorySpec</code> 在测试环节撰写 Mock Object 跑单元测试。</p>

<h4 id="延伸--使用-strategy-pattern-封装-dispatchsourcehandler-工作">延伸 — 使用 <strong><em>Strategy</em></strong> Pattern 封装 DispatchSourceHandler 工作</h4>

<p>假设我们的 DispatchSourceHandler 希望执行的事能动态改变，可以使用 Strategy Pattern 来封装工作内容。</p>

<p><strong>TrackingHandlerStrategy:</strong></p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">protocol</span> <span class="kt">TrackingHandlerStrategy</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="k">var</span> <span class="nv">target</span><span class="p">:</span> <span class="kt">String</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
    <span class="kd">func</span> <span class="nf">execute</span><span class="p">()</span>
<span class="p">}</span>

<span class="c1">// Home Event</span>
<span class="kd">final</span> <span class="kd">class</span> <span class="kt">HomeTrackingHandlerStrategy</span><span class="p">:</span> <span class="kt">TrackingHandlerStrategy</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="k">var</span> <span class="nv">target</span><span class="p">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="s">"home"</span>
    <span class="kd">func</span> <span class="nf">execute</span><span class="p">()</span> <span class="p">{</span>
       <span class="c1">// fetch home event logs..and send</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// Product Event</span>
<span class="kd">final</span> <span class="kd">class</span> <span class="kt">ProductTrackingHandlerStrategy</span><span class="p">:</span> <span class="kt">TrackingHandlerStrategy</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="k">var</span> <span class="nv">target</span><span class="p">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="s">"product"</span>
    <span class="kd">func</span> <span class="nf">execute</span><span class="p">()</span> <span class="p">{</span>
       <span class="c1">// fetch product event logs..and send</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>组合使用：</strong></p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="nv">sender</span> <span class="o">=</span> <span class="kt">TrackingEventSender</span><span class="p">()</span>
<span class="n">sender</span><span class="o">.</span><span class="nf">register</span><span class="p">(</span><span class="nv">event</span><span class="p">:</span> <span class="kt">HomeTrackingHandlerStrategy</span><span class="p">())</span>
<span class="n">sender</span><span class="o">.</span><span class="nf">register</span><span class="p">(</span><span class="nv">event</span><span class="p">:</span> <span class="kt">ProductTrackingHandlerStrategy</span><span class="p">())</span>
<span class="n">sender</span><span class="o">.</span><span class="nf">startTracking</span><span class="p">()</span>

<span class="c1">// ...</span>

<span class="c1">//</span>

<span class="kd">final</span> <span class="kd">class</span> <span class="kt">TrackingEventSender</span> <span class="p">{</span>

    <span class="kd">private</span> <span class="k">let</span> <span class="nv">timerMachine</span> <span class="o">=</span> <span class="kt">DispatchSourceTimerMachine</span><span class="p">()</span>
    <span class="kd">private</span> <span class="k">var</span> <span class="nv">events</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">TrackingHandlerStrategy</span><span class="p">]</span> <span class="o">=</span> <span class="p">[:]</span>

    <span class="c1">// 注册需要的 Event 策略</span>
    <span class="kd">func</span> <span class="nf">register</span><span class="p">(</span><span class="nv">event</span><span class="p">:</span> <span class="kt">TrackingHandlerStrategy</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">events</span><span class="p">[</span><span class="nf">type</span><span class="p">(</span><span class="nv">of</span><span class="p">:</span> <span class="n">event</span><span class="p">)</span><span class="o">.</span><span class="n">target</span><span class="p">]</span> <span class="o">=</span> <span class="n">event</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="n">retrive</span><span class="o">&lt;</span><span class="kt">T</span><span class="p">:</span> <span class="kt">TrackingHandlerStrategy</span><span class="o">&gt;</span><span class="p">(</span><span class="nv">event</span><span class="p">:</span> <span class="kt">T</span><span class="o">.</span><span class="k">Type</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">T</span><span class="p">?</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">events</span><span class="p">[</span><span class="n">event</span><span class="o">.</span><span class="n">target</span><span class="p">]</span> <span class="k">as?</span> <span class="kt">T</span>
    <span class="p">}</span>

    <span class="c1">// 启动定期 tracking</span>
    <span class="kd">func</span> <span class="nf">startTracking</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">timerMachine</span><span class="o">.</span><span class="nf">activate</span><span class="p">(</span><span class="nv">repeatTimeInterval</span><span class="p">:</span> <span class="o">.</span><span class="nf">seconds</span><span class="p">(</span><span class="mi">30</span><span class="p">))</span> <span class="p">{</span> <span class="p">[</span><span class="k">weak</span> <span class="k">self</span><span class="p">]</span> <span class="k">in</span>
            <span class="k">self</span><span class="p">?</span><span class="o">.</span><span class="n">events</span><span class="o">.</span><span class="n">values</span><span class="o">.</span><span class="n">forEach</span> <span class="p">{</span> <span class="n">event</span> <span class="k">in</span>
                <span class="n">event</span><span class="o">.</span><span class="nf">execute</span><span class="p">()</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 暂停 tracking（例如 App 进背景）</span>
    <span class="kd">func</span> <span class="nf">pauseTracking</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">timerMachine</span><span class="o">.</span><span class="nf">suspend</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="c1">// 恢复 tracking（例如 App 回前景）</span>
    <span class="kd">func</span> <span class="nf">resumeTracking</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">timerMachine</span><span class="o">.</span><span class="nf">resume</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="c1">// 停止 tracking（例如页面离开）</span>
    <span class="kd">func</span> <span class="nf">stopTracking</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">timerMachine</span><span class="o">.</span><span class="nf">cancel</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="鸣谢">鸣谢</h4>

<p>感谢 <a href="https://medium.com/u/e13f6afcf9b9" target="_blank">Ethan Huang</a> 大大 Donate 的 <strong>5 Beers</strong> :</p>

<p><a href="https://www.patreon.com/cw/ethanhuang13/home?vanity=ethanhuang13" target="_blank"><img src="https://c7.patreon.com/https%3A%2F%2Fwww.patreon.com%2F%2Fcard-teaser-image%2Fcreator%2F6512681%3Fc=4366071272298850039/selector/%23creator-teaser%2C.png" alt="" /></a></p>

<blockquote>
  <p><em>的确快半年没写什么了，新工作刚到职，持续找寻灵感中！💪</em></p>
</blockquote>

<blockquote>
  <p>下一篇可能分享 Fastlane Match 凭证管理跟 Self-hosted Runner 的建置过程. .或是 Bitbucket Pipeline. .或是 AppStoreConnect API…</p>
</blockquote>

<h3 id="延伸阅读">延伸阅读</h3>

<ul>
  <li>
    <p><a href="/posts/pinkoi-engineering/design-patterns-实战应用-封装-socket-io-即时通讯架构与七大设计模式解析-78507a8de6a5/"><strong>Design Patterns 的实战应用纪录 (封装 Sockiet.io)</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/kkday-tech-blog/wkwebview-设计模式实战-builder-strategy-与责任链模式最佳应用技巧-f4b02ee342a4/">Design Patterns 的实战应用纪录 (封装 WKWebView)</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/visitor-pattern-在-ios-swift-分享功能应用-设计模式实务解析与最佳架构优化-ba5773a7bfea/">Visitor Pattern in Swift</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/visitor-pattern-提升-tableview-可扩充性与可维护性设计范例-60473cb47550/">Visitor Pattern in TableView</a></p>
  </li>
</ul>]]></content>
  </entry><entry>
    <title type="html">日本乐天集运教学｜快速购买Horie钛杯与Amazon商品寄送台湾全攻略</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-life/%E6%97%A5%E6%9C%AC%E4%B9%90%E5%A4%A9%E9%9B%86%E8%BF%90%E6%95%99%E5%AD%A6-%E5%BF%AB%E9%80%9F%E8%B4%AD%E4%B9%B0horie%E9%92%9B%E6%9D%AF%E4%B8%8Eamazon%E5%95%86%E5%93%81%E5%AF%84%E9%80%81%E5%8F%B0%E6%B9%BE%E5%85%A8%E6%94%BB%E7%95%A5-bea62c251f1b/" rel="alternate" type="text/html" title="日本乐天集运教学｜快速购买Horie钛杯与Amazon商品寄送台湾全攻略" />
    <published>2025-10-26T17:58:35+08:00</published>
    <updated>2025-10-27T08:41:53+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-life/bea62c251f1b</id><summary type="html">想从日本乐天市场及Amazon购买Horie钛杯并寄回台湾？详细注册、集运设定、运费计算与禁运品说明，实测最快4天收货，运费省钱技巧一次掌握，轻松避开购物与物流风险。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Life." /><category term="生活" /><category term="開箱" /><category term="樂天" /><category term="鈦杯" /><category term="集運" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/bea62c251f1b/1*bXj9-XVgjfsVta6cZg8Fpw.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-life/%E6%97%A5%E6%9C%AC%E4%B9%90%E5%A4%A9%E9%9B%86%E8%BF%90%E6%95%99%E5%AD%A6-%E5%BF%AB%E9%80%9F%E8%B4%AD%E4%B9%B0horie%E9%92%9B%E6%9D%AF%E4%B8%8Eamazon%E5%95%86%E5%93%81%E5%AF%84%E9%80%81%E5%8F%B0%E6%B9%BE%E5%85%A8%E6%94%BB%E7%95%A5-bea62c251f1b/"><![CDATA[<h3 id="日本海外购物寄送台湾教学--使用乐天转运购买乐天拍卖与-amazon-商品-horie-钛杯-最快-4-天到货">日本海外购物寄送台湾教学 — 使用乐天转运购买乐天拍卖与 Amazon 商品 (Horie 钛杯) 最快 4 天到货</h3>

<p>想要的东西自己买，用乐天转运购买日本商品寄回台湾的纪录与教学，以购买 Horie 钛杯为例。</p>

<h3 id="horie-钛杯"><a href="https://a.r10.to/hkPx9m" target="_blank">Horie 钛杯</a></h3>

<p>上次去日本被烧到，Horie 钛杯的主要特色：</p>

<p><img src="/assets/bea62c251f1b/1*7m-tH8lB3Sx0yxtdc9Bn_g.webp" alt="官方 Horie 乐天卖场" loading="lazy" decoding="async" width="776" height="970" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NzYiIGhlaWdodD0iOTcwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*7m-tH8lB3Sx0yxtdc9Bn_g.png" /></p>

<p><a href="https://a.r10.to/hkPx9m" target="_blank">官方 Horie 乐天卖场</a></p>

<ul>
  <li>
    <p>独家的氧化上色花纹技术，色彩斑斓璀璨、颜色多元可选</p>
  </li>
  <li>
    <p>独家的双隔层保温结构，保冷不流汗、保温不烫手</p>
  </li>
  <li>
    <p>独家特殊内杯面设计，喝啤酒时可以自动产生持久的绵密泡泡</p>
  </li>
  <li>
    <p>杯口收密，不刮嘴</p>
  </li>
  <li>
    <p>纯钛材质，非常轻、抗菌、不残留味道</p>
  </li>
</ul>

<p>最吸引我的是前三项独家技术 <strong>＋它是保温杯</strong> ，况且我目前没有任何钛杯，对保温杯容易残留味道的问题也很苦恼，因此很想买一个来用用。</p>

<h4 id="欲购买的商品"><strong>欲购买的商品：</strong></h4>

<blockquote>
  <p><em>品牌：Horie 钛杯</em></p>
</blockquote>

<blockquote>
  <p><em>型号：窑创り ブースター/400ml</em></p>
</blockquote>

<blockquote>
  <p><em>样式： G4B</em></p>
</blockquote>

<p><a href="https://a.r10.to/hkPx9m" target="_blank">官方售价</a> <strong>¥19,800 円 (约 NT $4,080 台币)</strong> ，日本国内免运费。</p>

<p>查了一下在台湾买，不管是电商平台或是个人卖家价格都在 NT $5,500 台币上下；偶有团购或展览活动价格可以压到 NT$4,200 左右，才适合入手。</p>

<h3 id="乐天转运集运回台湾总花费时间及金额">乐天转运集运回台湾总花费时间及金额</h3>

<p>结果写在前面。</p>

<p><img src="/assets/bea62c251f1b/1*n3ahp0WYgvO36vendy3GEQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="664" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjY2NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*n3ahp0WYgvO36vendy3GEQ.png" /></p>

<ul>
  <li>
    <p>因为我要刻字，所以需要 7–10 天制作，另外又买了杂志多等了杂志到乐天转运的时间。</p>
  </li>
  <li>
    <p>单纯看转运时间，转运站收到货只花 1 天、转运从打包出货到收到只花 3 天，可以说是非常快速！</p>
  </li>
  <li>
    <p>花费总计含运费：NT $4,744 入手。(细节请看内文，因为买的少所以运费较贵)</p>
  </li>
</ul>

<h3 id="乐天转运--rakuten-global-express"><a href="https://secure.globalexpress.rakuten.co.jp/mypage/register/invite?key=a6nn9r3fq6j4sskcsOrXE%2Bgdygp0zER%2FMe83%2FUDPw6k7LFkMFZBfgN0hX48E%3D" target="_blank">乐天转运 — Rakuten Global Express</a></h3>

<p>想说既然都要买日本乐天市场的东西，就直接试用乐天的转运/集运服务；当然乐天转运也不只局限于购买乐天的东西，其他电商平台例如：日本亚马逊(Amazon JP)、日本 Yahoo 购物 / Yahoo 拍卖、Mercari、Biccamera…等等都能寄送。</p>

<ul>
  <li>可以累积乐天点数！及使用点数抵付！</li>
</ul>

<h4 id="使用乐天转运购买乐天商品的特殊保障">使用乐天转运购买乐天商品的特殊保障</h4>

<p>除了提供转运/集运服务之外， <strong>使用乐天</strong> 转 <strong>运购买乐天市场的商品</strong> 还额外提供以下保障：</p>

<ul>
  <li>
    <p>赔偿服务：已付款但商品未送达</p>
  </li>
  <li>
    <p>赔偿服务：商品损坏 (请取得物流公司开立之损坏报告)</p>
  </li>
  <li>
    <p>赔偿服务：收到与商品页商品说明明显相异的商品或瑕疵品</p>
  </li>
  <li>
    <p>赔偿服务：收到的品牌商品是仿冒品，即侵害商标权之物品（在安心购物保障范围内的 1,000+ 个品牌）</p>
  </li>
  <li>
    <p>赔偿金额：上限为 30 万日圆</p>
  </li>
  <li>
    <p>无需手续费、年费</p>
  </li>
</ul>

<p>细节请 <a href="https://event.rakuten.co.jp/anshin/anshinshopping/zh-tw/top/" target="_blank">参考官方说明</a> 。</p>

<h4 id="购买非乐天的保障">购买非乐天的保障</h4>

<p>如购买的商品非乐天市场，提供基础的转运寄送保障：</p>

<ul>
  <li>
    <p>赔偿服务：已付款但商品未送达</p>
  </li>
  <li>
    <p>赔偿服务：商品损坏 (请取得物流公司开立之损坏报告)</p>
  </li>
</ul>

<p>细节请 <a href="https://globalexpress.rakuten.co.jp/help/insurance?l-id=help_tw_insurance" target="_blank">参考官方说明</a> 。</p>

<h4 id="运费计算报价">运费计算、报价</h4>

<p>可以使用 <a href="https://globalexpress.rakuten.co.jp/estimate/?l-id=top_estimate" target="_blank">官方工具</a> 试算转运运费价格。</p>

<p><img src="/assets/bea62c251f1b/1*4mfK-p6n2FUgWpDCq8xisQ.webp" alt="&lt;https://globalexpress.rakuten.co.jp/estimate/?l-id=top_estimate&gt;" loading="lazy" decoding="async" width="949" height="596" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDkiIGhlaWdodD0iNTk2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*4mfK-p6n2FUgWpDCq8xisQ.png" /></p>

<p><a href="https://globalexpress.rakuten.co.jp/estimate/?l-id=top_estimate" target="_blank">https://globalexpress.rakuten.co.jp/estimate/?l-id=top_estimate</a></p>

<p><strong>配送方式与台湾运费表</strong></p>

<p><img src="/assets/bea62c251f1b/1*Bi9oS0C32l8Mhvtwfdg-zg.webp" alt="&lt;https://globalexpress.rakuten.co.jp/help/delivery&gt;" loading="lazy" decoding="async" width="947" height="670" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDciIGhlaWdodD0iNjcwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*Bi9oS0C32l8Mhvtwfdg-zg.png" /></p>

<p><a href="https://globalexpress.rakuten.co.jp/help/delivery" target="_blank">https://globalexpress.rakuten.co.jp/help/delivery</a></p>

<p><img src="/assets/bea62c251f1b/1*k4M0QBRRDbPQZ7BSyB6c4A.webp" alt="&lt;https://globalexpress.rakuten.co.jp/help/country/fee?country=TW&gt;" loading="lazy" decoding="async" width="980" height="943" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5ODAiIGhlaWdodD0iOTQzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*k4M0QBRRDbPQZ7BSyB6c4A.png" /></p>

<p><a href="https://globalexpress.rakuten.co.jp/help/country/fee?country=TW" target="_blank">https://globalexpress.rakuten.co.jp/help/country/fee?country=TW</a></p>

<blockquote>
  <p><em>请注意这里的大小跟重量是最终集货后的数字。</em></p>
</blockquote>

<h3 id="日本乐天帐号注册">日本乐天帐号注册</h3>

<p>前往 <a href="https://login.account.rakuten.com/sso/register?client_id=rakuten_ichiba_top_web&amp;service_id=s245&amp;response_type=code&amp;scope=openid&amp;redirect_uri=https%3A%2F%2Fwww.rakuten.co.jp%2F#/registration/1" target="_blank"><strong>注册页面</strong></a> ：</p>

<p><img src="/assets/bea62c251f1b/1*b3acAhAfqIrsIe7-hHuQLA.webp" alt="" loading="lazy" decoding="async" width="1069" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDY5IiBoZWlnaHQ9IjEyMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/bea62c251f1b/1*b3acAhAfqIrsIe7-hHuQLA.png" /></p>

<p>输入电子邮件信箱、密码、英文姓名，送出后即可完成注册。</p>

<blockquote>
  <p><em>这边有发现一个随机的网站问题， <strong>如果在乐天网站上一直出现伺服器错误，可以把语系改成日文</strong> ，就能正常使用了。(疑似是多语系错误)</em></p>
</blockquote>

<h4 id="先前往乐天转运完成实名认证">先前往乐天转运完成实名认证</h4>

<p><img src="/assets/bea62c251f1b/1*roub7uHzS2bUtIP5qIg8pA.webp" alt="" loading="lazy" decoding="async" width="1200" height="830" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgzMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*roub7uHzS2bUtIP5qIg8pA.png" /></p>

<p>注册完乐天到 <a href="https://secure.globalexpress.rakuten.co.jp/mypage/register/invite?key=aanar03e62e0ckog4nWPIFcV7FTuy6JGEeCL1HwxrPgcSjKRlGHs1GY6PkH0%3D" target="_blank">乐天转运</a> 预设就是已登入状态。</p>

<ol>
  <li>
    <p>先点击语言换成繁体中文方便操作</p>
  </li>
  <li>
    <p>点击我的页面开通转运</p>
  </li>
</ol>

<p><img src="/assets/bea62c251f1b/1*LtS88oCvn5XKCHImq_8Twg.webp" alt="" loading="lazy" decoding="async" width="537" height="715" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MzciIGhlaWdodD0iNzE1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*LtS88oCvn5XKCHImq_8Twg.png" /></p>

<p><img src="/assets/bea62c251f1b/1*EBb5vLI574judf0zb4up9Q.webp" alt="" loading="lazy" decoding="async" width="522" height="701" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MjIiIGhlaWdodD0iNzAxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*EBb5vLI574judf0zb4up9Q.png" /></p>

<p>前往信箱收取验证码完成信箱验证。</p>

<p><img src="/assets/bea62c251f1b/1*caABYLKqpF995bAS9QULpQ.webp" alt="" loading="lazy" decoding="async" width="530" height="692" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MzAiIGhlaWdodD0iNjkyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*caABYLKqpF995bAS9QULpQ.png" /></p>

<p>下一步，补填姓名资讯。</p>

<ul>
  <li>
    <p>姓(汉字)、名(汉字)：填写中文姓名</p>
  </li>
  <li>
    <p>姓(片假名)、名(片假名)：填写姓名片假名，可以 <a href="https://dokochina.com/katakana.php" target="_blank">用这网站翻译</a> ，或用暱称，例如我是：リー, ハリー。</p>
  </li>
</ul>

<h4 id="开通乐天转运地址完成实名验证">开通乐天转运地址、完成实名验证</h4>

<p><img src="/assets/bea62c251f1b/1*XH92Vc8EmKSvvF3RH7hYJg.webp" alt="" loading="lazy" decoding="async" width="1400" height="835" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjgzNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*XH92Vc8EmKSvvF3RH7hYJg.png" /></p>

<p>第一步同意使用者条款， <strong>部分商品如易燃物、喷雾、生鲜食品禁止寄送</strong> 。</p>

<p><img src="/assets/bea62c251f1b/1*WOxQ8TpaXdOS_BJqyWeZYg.webp" alt="" loading="lazy" decoding="async" width="892" height="1109" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4OTIiIGhlaWdodD0iMTEwOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*WOxQ8TpaXdOS_BJqyWeZYg.png" /></p>

<p>第二步输入本人资讯，务必输入真实护照英文姓名、与生日。</p>

<h4 id="取得专属乐天转运地址">取得专属乐天转运地址</h4>

<p><img src="/assets/bea62c251f1b/1*u8ObmbBY2rsVw93cS8ADDA.webp" alt="" loading="lazy" decoding="async" width="880" height="1180" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4ODAiIGhlaWdodD0iMTE4MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*u8ObmbBY2rsVw93cS8ADDA.png" /></p>

<ul>
  <li>
    <p>转运仓地址务必要输入到最后的 <code class="language-plaintext highlighter-rouge">白石町6–1 RGXセンター XXXXXXX</code> 英文数字编号，那才是你的专属识别地址。</p>
  </li>
  <li>
    <p>可点击「立即新增」直接把地址新增到乐天帐户</p>
  </li>
</ul>

<blockquote>
  <p><em>有了这个地址跟电话号码就能在日本各大电商网站进行购物跟寄送啰！不过为了确保转运能安全寄回到你手上， <strong>请先「继续完成本人认证手续」再去购物网站购买、寄送商品。</strong></em></p>
</blockquote>

<h4 id="继续完成本人认证手续">继续完成本人认证手续</h4>

<p><img src="/assets/bea62c251f1b/1*Fv2V7TPlqTBQHTeo3bPuWg.webp" alt="" loading="lazy" decoding="async" width="860" height="941" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjAiIGhlaWdodD0iOTQxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*Fv2V7TPlqTBQHTeo3bPuWg.png" /></p>

<ul>
  <li>准备好身分证正本跟手机后，点透过脸部脸部认证进行认证，直接线上 24 小时自助完成认证手续。</li>
</ul>

<blockquote>
  <p><em>但我的身分证照片可能跟本人已经差太多，线上认证失败自动转人工，隔天才收到官方通知人工审核完成。</em></p>
</blockquote>

<h4 id="我的页面">我的页面</h4>

<p>点击上方「我的页面」或「我的页面顶端」前往我的页面主页：</p>

<p><img src="/assets/bea62c251f1b/1*MhXfS0YfDj4TVZC_h1uBmA.webp" alt="" loading="lazy" decoding="async" width="950" height="584" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTAiIGhlaWdodD0iNTg0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*MhXfS0YfDj4TVZC_h1uBmA.png" /></p>

<p><img src="/assets/bea62c251f1b/1*_qPCZpRDpfbrNfytEsjBGA.webp" alt="" loading="lazy" decoding="async" width="1200" height="541" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjU0MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*_qPCZpRDpfbrNfytEsjBGA.png" /></p>

<p>如果认证手续未完成会有以下警告提示：</p>

<p><img src="/assets/bea62c251f1b/1*qkgvVofPd8uI6CLH_0rnhw.webp" alt="" loading="lazy" decoding="async" width="694" height="200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2OTQiIGhlaWdodD0iMjAwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*qkgvVofPd8uI6CLH_0rnhw.png" /></p>

<blockquote>
  <p><strong><em>请务必先完成认证再进行购物。</em></strong></p>
</blockquote>

<h4 id="您专属的收件地址与资讯">您专属的收件地址与资讯</h4>

<p>我的页面右下方会显示专属您资讯。</p>

<p><img src="/assets/bea62c251f1b/1*_qsR1A94i83sEDAVpGxgbg.webp" alt="" loading="lazy" decoding="async" width="1200" height="990" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk5MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*_qsR1A94i83sEDAVpGxgbg.png" /></p>

<h3 id="寄送台湾的禁运商品">寄送台湾的禁运商品</h3>

<p>购买任何物品想寄回台湾时请确认是否为禁止商品。</p>

<p><img src="/assets/bea62c251f1b/1*c7qamfTN89ipGwM9LZUblQ.webp" alt="&lt;https://globalexpress.rakuten.co.jp/help/country/detail?country=TW&gt;" loading="lazy" decoding="async" width="959" height="873" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTkiIGhlaWdodD0iODczIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*c7qamfTN89ipGwM9LZUblQ.png" /></p>

<p><a href="https://globalexpress.rakuten.co.jp/help/country/detail?country=TW" target="_blank">https://globalexpress.rakuten.co.jp/help/country/detail?country=TW</a></p>

<p>不同寄送方式有不同限制， <a href="https://globalexpress.rakuten.co.jp/help/country/detail?country=TW" target="_blank">务必详阅</a> 。</p>

<blockquote>
  <p><em>如果要买酒买烟之类的务必先上网查好别人的教学，我看大略是寄回台湾后要拿通知信去补交税金，才能放行。</em></p>
</blockquote>

<h3 id="乐天市场购物--horie-钛杯-下单教学"><a href="https://a.r10.to/hkPx9m" target="_blank">乐天市场购物 — Horie 钛杯</a> 下单教学</h3>

<blockquote>
  <p><em>1055℃の窑から生まれた高保冷チタン2重タンブラー 。アレルギーフリーで清洁、锖びずに軽く丈夫で长持ちします。大切な方への赠り物や自分へのご褒美に最适です。【无料ラッピング対応実施】HORIE 公式ショップ/ 窑创り 名入れ 纯チタン制二重タンブラー horie チタンタンブラー 母の日 父の日 敬老の日 ギフト ビールグラス ホリエ 燕三条 诞生日プレゼント お饯别 退职祝 内祝 结婚祝 SDGs クリスマス</em></p>
</blockquote>

<blockquote>
  <p><em>13,200〜19,800円送料无料</em></p>
</blockquote>

<h4 id="前往商品页-"><a href="https://a.r10.to/hkPx9m" target="_blank">前往商品页</a> ：</h4>

<p><img src="/assets/bea62c251f1b/1*8aYksm9WZ5UUkmSKSI_5EA.webp" alt="商品页" loading="lazy" decoding="async" width="938" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzgiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*8aYksm9WZ5UUkmSKSI_5EA.png" /></p>

<p><a href="https://a.r10.to/hkPx9m" target="_blank">商品页</a></p>

<p>这是窑创系列的商品页，要选择其他系列 <a href="https://a.r10.to/hkG3CK" target="_blank">可以点 HORIE 商城首页</a> 查看。</p>

<p>拉到最下方商品规格选择 (商品详细を选択)。</p>

<ul>
  <li>
    <p><strong>形状/サイズ</strong> ：选择你要的款式 (请参考商品页的图片，有广口、窄口、容量大小也不同)</p>
  </li>
  <li>
    <p><strong>カラー</strong> ：选择你要的样式(请参考商品页的图片)</p>
  </li>
</ul>

<p><strong>我是买：窑创り ブースター/400ml &amp; G4B：</strong></p>

<p><img src="/assets/bea62c251f1b/1*rwCNpways8AGJZ3DglI0qw.webp" alt="" loading="lazy" decoding="async" width="727" height="1016" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MjciIGhlaWdodD0iMTAxNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*rwCNpways8AGJZ3DglI0qw.png" /></p>

<p><strong>名入れオプション</strong> ：有没有要刻字(网路商城限定， <strong>免费刻字</strong> )，需要 7–10 个工作天：</p>

<p><img src="/assets/bea62c251f1b/1*8Zfq6b9q2X2jORa51cjm1w.webp" alt="" loading="lazy" decoding="async" width="657" height="825" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NTciIGhlaWdodD0iODI1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*8Zfq6b9q2X2jORa51cjm1w.png" /></p>

<p><strong>ラッピングの有无</strong> ：包装纸样式，A or B or 无样式。</p>

<p><img src="/assets/bea62c251f1b/1*TeJNyUkr6nsAapTC9H504A.webp" alt="" loading="lazy" decoding="async" width="640" height="623" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NDAiIGhlaWdodD0iNjIzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*TeJNyUkr6nsAapTC9H504A.png" /></p>

<p><strong>桐箱デザインの选択</strong> ：包装盒样式，WakuWaku惊喜版(左，限单入)或是一般版(右)</p>

<p><strong>2个セット用桐箱 (※2个以上ご注文・必要な场合のみチェックを入れる)：</strong> 购买两个杯子以上才需勾选， <strong>勾选放同一个盒子</strong> (如下图右下)。
只买一个可跳过。</p>

<p><strong>2个セットの场合の组み合わせ (记入例:プレミアムとライト) (※2セット以上ご注文の场合は必ず明记)：</strong> 购买两组以上该怎么组合盒子的描述，嫌麻烦的话直接分开加入购物车比较快。
只买一个可跳过。</p>

<p><img src="/assets/bea62c251f1b/1*49fEtjiRRBvNyEGxdFeE3A.webp" alt="" loading="lazy" decoding="async" width="645" height="621" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NDUiIGhlaWdodD0iNjIxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*49fEtjiRRBvNyEGxdFeE3A.png" /></p>

<p><strong>名入れタイプ※単品名入れ商品を2个以上ご注文の场合は、お手数ですが1个づつ买い物かごに入れてください：</strong> 名入れ不要 (不要刻字)，可跳过以下栏位，要刻字就照商品页图上资讯选择样式跟填入每一行的文字：</p>

<ul>
  <li>
    <p><strong>名入れ1行目</strong></p>
  </li>
  <li>
    <p><strong>名入れ2行目</strong></p>
  </li>
  <li>
    <p><strong>名入れ3行目</strong></p>
  </li>
  <li>
    <p><strong>名入れ4行目</strong></p>
  </li>
</ul>

<blockquote>
  <p><strong><em>请注意如果要刻字要分开一笔一笔加入购物车，不要写在刻字内容。</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>我是选择 B 样式刻字(文末有图)。</em></strong></p>
</blockquote>

<p><img src="/assets/bea62c251f1b/1*i50V97FHogvQ4PVCFTLX7Q.webp" alt="" loading="lazy" decoding="async" width="625" height="630" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MjUiIGhlaWdodD0iNjMwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*i50V97FHogvQ4PVCFTLX7Q.png" /></p>

<p><strong>送礼包装贺签样式、内容：</strong></p>

<ul>
  <li>
    <p>のしの内容：贺签类型，例如御祝、祝寿. .等等，不用就选「のし不要」</p>
  </li>
  <li>
    <p>のしの种类：贺签样式，如下图，不用就选「のし不要」</p>
  </li>
  <li>
    <p>のしの水引きの种类：贺签绑线样式，如下图，不用就选「のし不要」</p>
  </li>
</ul>

<p><img src="/assets/bea62c251f1b/1*uLCkqmso0Ad9MTynZL0T-w.webp" alt="" loading="lazy" decoding="async" width="626" height="854" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MjYiIGhlaWdodD0iODU0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*uLCkqmso0Ad9MTynZL0T-w.png" /></p>

<p><strong>のしに记入するお名前(赠り主)※连名の场合は间に・を入力。内祝い等でふりがなをご希望の际はふりがなもご入力ください。20文字以上の场合は备考栏にお愿いします：</strong> 请填写将印在贺礼外包装（熨斗）上的赠送者姓名、若为多人联名，请在姓名间加入「・」、不用则留空。</p>

<h4 id="加入购物车完成结帐">加入购物车、完成结帐</h4>

<p><img src="/assets/bea62c251f1b/1*UCbosHBXeND4C0Q7hoX38A.webp" alt="" loading="lazy" decoding="async" width="627" height="711" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MjciIGhlaWdodD0iNzExIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*UCbosHBXeND4C0Q7hoX38A.png" /></p>

<p>都填好规格内容后点「かごに追加」加入购物车，お届け先 收件人资讯选我们乐天转运的「神奈川县」，下方也会显示预计配送到乐天转运的时间、免运费；都加好后点上方购物车结帐：</p>

<p><img src="/assets/bea62c251f1b/1*XP6gv2xNgplYY_IvQyKNCQ.webp" alt="" loading="lazy" decoding="async" width="1048" height="615" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDQ4IiBoZWlnaHQ9IjYxNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*XP6gv2xNgplYY_IvQyKNCQ.png" /></p>

<p>确认商品规格无误之后，点右方「购入手続き」</p>

<p><img src="/assets/bea62c251f1b/1*lsPBGTQGkyJ_RAG0VjayAw.webp" alt="" loading="lazy" decoding="async" width="1049" height="989" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDQ5IiBoZWlnaHQ9Ijk4OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*lsPBGTQGkyJ_RAG0VjayAw.png" /></p>

<ul>
  <li>
    <p><strong>お届け先：</strong> 寄送资讯，可以直接选择刚乐天转运新增的转运地址，或自行新增转运地址(转运地址请务必输入到最后编号部分)</p>
  </li>
  <li>
    <p><strong>支払い方法：</strong> 支付方式，我直接刷卡(算是日本购物，可以看有哪个银行有优惠)。</p>
  </li>
</ul>

<p>都没问题后点「注文を确定する」完成下单。</p>

<h4 id="horie-刻字确认">HORIE 刻字确认</h4>

<p><img src="/assets/bea62c251f1b/1*Q8t3tiej00RrQqsEBVsOLg.webp" alt="" loading="lazy" decoding="async" width="921" height="1190" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjEiIGhlaWdodD0iMTE5MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*Q8t3tiej00RrQqsEBVsOLg.png" /></p>

<p>如果有选择要刻字，HORIE 会再收到订单后传送确认结果给你，没问题可以回复「ご送付いただいたレイアウトを确认しました。问题ございませんので制作を进めてください。」让他们开始制作。</p>

<p>他也会传讯息告知出货时间。</p>

<h4 id="商家出货乐天转运到货通知">商家出货、乐天转运到货通知</h4>

<p><img src="/assets/bea62c251f1b/1*DGN-R9yxdnrjEMlSR5W0Bw.webp" alt="" loading="lazy" decoding="async" width="850" height="761" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NTAiIGhlaWdodD0iNzYxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*DGN-R9yxdnrjEMlSR5W0Bw.png" /></p>

<p><img src="/assets/bea62c251f1b/1*j5pKRcNpLfuiToRzoNG-bg.webp" alt="" loading="lazy" decoding="async" width="894" height="642" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4OTQiIGhlaWdodD0iNjQyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*j5pKRcNpLfuiToRzoNG-bg.png" /></p>

<p>收到 HORIE 出货通知后约 1–3 天就送达乐天转运仓库了。</p>

<h3 id="从日本亚马逊-amazon-jp-寄送到乐天转运">从日本亚马逊 Amazon JP 寄送到乐天转运</h3>

<p>这次除了买 HORIE 钛杯之外，还从 日本亚马逊 Amazon JP 买了一个杂志，打算一起转运寄回台湾。</p>

<p><img src="/assets/bea62c251f1b/1*70bmfM40fgui1EptFuLylA.webp" alt="" loading="lazy" decoding="async" width="1200" height="606" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjYwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*70bmfM40fgui1EptFuLylA.png" /></p>

<p>在购物网站上同样的操作只要记得照乐天转运的你的收件资讯填写寄送地址、联络电话(填转运的)。</p>

<h4 id="非乐天市场购物-货件到货事前登记">(非乐天市场购物) 货件到货事前登记</h4>

<p>非乐天本家买的商品寄送到转运建议在下单后登记一下。</p>

<p><img src="/assets/bea62c251f1b/1*hbc4AK4PyGSScxgg8Q9OWg.webp" alt="" loading="lazy" decoding="async" width="1217" height="716" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjE3IiBoZWlnaHQ9IjcxNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*hbc4AK4PyGSScxgg8Q9OWg.png" /></p>

<p>点击「货物一览表」 → 「登录/确认」</p>

<p><img src="/assets/bea62c251f1b/1*IYs0xH6f-y55OFHDGmWpHQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="492" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQ5MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*IYs0xH6f-y55OFHDGmWpHQ.png" /></p>

<p>输入其他平台购买的店家、商品资讯跟金额。</p>

<h4 id="日本亚马逊-amazon-jp-购买商品-乐天转运到货通知">日本亚马逊 Amazon JP 购买商品-乐天转运到货通知</h4>

<p><img src="/assets/bea62c251f1b/1*eWxfcNY_Wsr7VT9-5ZuFtQ.webp" alt="" loading="lazy" decoding="async" width="610" height="437" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MTAiIGhlaWdodD0iNDM3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*eWxfcNY_Wsr7VT9-5ZuFtQ.png" /></p>

<p>都完成后等商家出货，寄送到达乐天转运也会收到通知。</p>

<h3 id="乐天转运寄回台湾">乐天转运寄回台湾</h3>

<p><a href="https://globalexpress.rakuten.co.jp/faq/detail?id=99" target="_blank">乐天转运最长可以免费保管货物 30 天</a> ，东西都寄到集合好之后就可以请求包装发货啰。</p>

<p><img src="/assets/bea62c251f1b/1*m3TCoxNu_7ltuthkRAXFBg.webp" alt="" loading="lazy" decoding="async" width="1400" height="774" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijc3NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*m3TCoxNu_7ltuthkRAXFBg.png" /></p>

<p>已送达商品：总共三样。</p>

<p>点击「货物一览表」：</p>

<p><img src="/assets/bea62c251f1b/1*4YRX_1LsNWvrExJAeoQ0nQ.webp" alt="" loading="lazy" decoding="async" width="795" height="831" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3OTUiIGhlaWdodD0iODMxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*4YRX_1LsNWvrExJAeoQ0nQ.png" /></p>

<p>点击「提出包装委托」</p>

<p><img src="/assets/bea62c251f1b/1*gUgWUivN-7jH9wNcFn-Y6g.webp" alt="" loading="lazy" decoding="async" width="1400" height="637" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjYzNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*gUgWUivN-7jH9wNcFn-Y6g.png" /></p>

<p>确认合并包装(寄送)的货品内容，无误后点「确认发货之包裹」。</p>

<p><img src="/assets/bea62c251f1b/1*PVcM448g7pTwBjOeKh3n0Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="481" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQ4MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*PVcM448g7pTwBjOeKh3n0Q.png" /></p>

<p>点击「选择其他付费包装服务」。</p>

<p><img src="/assets/bea62c251f1b/1*5tmccDXzlPpxIvo1CMNIow.webp" alt="" loading="lazy" decoding="async" width="1400" height="603" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjYwMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*5tmccDXzlPpxIvo1CMNIow.png" /></p>

<p>可以选择包装服务：(可点 i 有图文说明)</p>

<ul>
  <li>
    <p>去除包装盒、鞋盒、广告单、目录、出货单. .等等：让重量体积减少，省运费。</p>
  </li>
  <li>
    <p>包裹防水处理</p>
  </li>
  <li>
    <p>使用国际配送专用加固箱：我有勾，实际就是再用个大纸箱+防撞纸包装你的东西。</p>
  </li>
</ul>

<h4 id="包装委托-选择寄送地点">包装委托 (选择寄送地点)</h4>

<p><img src="/assets/bea62c251f1b/1*uJDDeUEF1kAT3thtzpzwDw.webp" alt="" loading="lazy" decoding="async" width="1400" height="333" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjMzMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*uJDDeUEF1kAT3thtzpzwDw.png" /></p>

<p><img src="/assets/bea62c251f1b/1*yrnzSlMcUafXAIhIaJy4Hw.webp" alt="" loading="lazy" decoding="async" width="743" height="797" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NDMiIGhlaWdodD0iNzk3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*yrnzSlMcUafXAIhIaJy4Hw.png" /></p>

<p>输入寄送地址：</p>

<ul>
  <li>护照英文姓名、 <a href="https://www.post.gov.tw/post/internet/SearchZone/index.jsp?ID=130112" target="_blank">英文地址</a> 、 <strong>你的手机号码(去掉开头0改成886)</strong></li>
</ul>

<p><img src="/assets/bea62c251f1b/1*3o3wRZOd4t8lldmdU-NObw.webp" alt="" loading="lazy" decoding="async" width="1200" height="676" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY3NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*3o3wRZOd4t8lldmdU-NObw.png" /></p>

<p>送出后状态会变成：包装作业中，等作业完成再付款跟出货。</p>

<p><img src="/assets/bea62c251f1b/1*5ogwtSaFBNCO3r2gJIA48w.webp" alt="" loading="lazy" decoding="async" width="1215" height="544" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjE1IiBoZWlnaHQ9IjU0NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*5ogwtSaFBNCO3r2gJIA48w.png" /></p>

<p>大约隔天早上就收到包装完成通知了。</p>

<h4 id="付转运运费寄送请求">付转运运费、寄送请求</h4>

<p><img src="/assets/bea62c251f1b/1*lA5p3upIWTdp6FTDrOdtqA.webp" alt="" loading="lazy" decoding="async" width="1160" height="725" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTYwIiBoZWlnaHQ9IjcyNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*lA5p3upIWTdp6FTDrOdtqA.png" /></p>

<p>状态：待付款。</p>

<p><img src="/assets/bea62c251f1b/1*psFozqxO72KXbbEKY0k37g.webp" alt="" loading="lazy" decoding="async" width="1098" height="887" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDk4IiBoZWlnaHQ9Ijg4NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*psFozqxO72KXbbEKY0k37g.png" /></p>

<p>点「货物一览」 → 「待付款」 货物 → 「前往付款」。</p>

<p><img src="/assets/bea62c251f1b/1*XC-tScyTBFqb-XGTedttWA.webp" alt="" loading="lazy" decoding="async" width="1200" height="530" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjUzMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*XC-tScyTBFqb-XGTedttWA.png" /></p>

<blockquote>
  <p><strong><em>最终大小、重量：2,330 g, 38 x 30 x 21 cm</em></strong></p>
</blockquote>

<p>确认货物内容跟收件人资讯，无误后点「选择运送方法」。</p>

<p><img src="/assets/bea62c251f1b/1*q9ImvJKflcvx1uHFSxS4pw.webp" alt="" loading="lazy" decoding="async" width="1200" height="577" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjU3NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*q9ImvJKflcvx1uHFSxS4pw.png" /></p>

<p>可以选择：</p>

<ul>
  <li>
    <p>DHL 快递 (超级特快空运)：1–3 天 9,100 日圆
据朋友提供的意见，如果用 DHL 记得 <a href="https://roo.cash/blog/dhl-introduction/#DHL_%E5%85%88%E7%A8%85%E5%BE%8C%E6%94%BE%E6%98%AF%E4%BB%80%E9%BA%BC%EF%BC%9F" target="_blank">先申请先税后放</a> 以免被海关抽检后补关税时还要被多收处理费。</p>
  </li>
  <li>
    <p><strong>EMS 特快空运：3–8 天 6,550 日圆 (我选这个，实际2天就收到，很快)</strong></p>
  </li>
  <li>
    <p>ECMS 经济空运：6–11 天 6,280 日圆</p>
  </li>
  <li>
    <p>船运：20–40 天, 5,620 日圆</p>
  </li>
</ul>

<blockquote>
  <p><em>价格跟 <a href="https://globalexpress.rakuten.co.jp/estimate/" target="_blank">费用报价工具</a> 报的差不多。</em></p>
</blockquote>

<p>下一步，输入信用卡 or Paypal 完成付款：</p>

<p><img src="/assets/bea62c251f1b/1*uPqI-nncfu_uToP6427_Jw.webp" alt="" loading="lazy" decoding="async" width="1262" height="590" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjYyIiBoZWlnaHQ9IjU5MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*uPqI-nncfu_uToP6427_Jw.png" /></p>

<p><img src="/assets/bea62c251f1b/1*ydX1HyUTXvumBk__QH4UJw.webp" alt="" loading="lazy" decoding="async" width="1200" height="569" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjU2OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*ydX1HyUTXvumBk__QH4UJw.png" /></p>

<p>运费也能获得乐天积分(1%)！</p>

<h4 id="出货委托完成">出货委托完成</h4>

<p><img src="/assets/bea62c251f1b/1*2jZefbTEBHYcnc8szKlx6Q.webp" alt="" loading="lazy" decoding="async" width="1208" height="492" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjA4IiBoZWlnaHQ9IjQ5MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*2jZefbTEBHYcnc8szKlx6Q.png" /></p>

<p><img src="/assets/bea62c251f1b/1*_f1zLXqHYGcWXdgzxCfL_g.webp" alt="" loading="lazy" decoding="async" width="1161" height="777" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTYxIiBoZWlnaHQ9Ijc3NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*_f1zLXqHYGcWXdgzxCfL_g.png" /></p>

<p>状态会到：出货作业中。</p>

<h4 id="完成注册-ezway">完成注册 EZWay</h4>

<p>如果你没有从海外买东西回来的经验， <a href="https://www.rakuten.com.tw/magazine/life/2022/012802/#D" target="_blank">务必要完成 EZWay 实名验证，下载 EZWay App、完成注册、完成实名认证即可</a> 。</p>

<h4 id="乐天转运出货">乐天转运出货</h4>

<p><img src="/assets/bea62c251f1b/1*ZNzn3Zpuk_HN0kbmo_zEzg.webp" alt="" loading="lazy" decoding="async" width="849" height="698" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NDkiIGhlaWdodD0iNjk4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/bea62c251f1b/1*ZNzn3Zpuk_HN0kbmo_zEzg.png" /></p>

<p>乐天完成出货后也会收到通知，有追踪码可以确认货物状态。</p>

<blockquote>
  <p><em>刚出货点可能会找不到，过阵子再查就会有了。</em></p>
</blockquote>

<p><img src="/assets/bea62c251f1b/1*U0L23fpYbBKTeoPtZcLsBA.webp" alt="" loading="lazy" decoding="async" width="909" height="1207" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDkiIGhlaWdodD0iMTIwNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*U0L23fpYbBKTeoPtZcLsBA.png" /></p>

<h4 id="等待收货">等待收货！</h4>

<p>到此从日本乐天网站注册、乐天转运使用、下单购物、出货、寄回台湾、EZWay，都完成了，就等货物到手！</p>

<h3 id="乐天转运-horie-钛杯-开箱">乐天转运、 <a href="https://a.r10.to/hkPx9m" target="_blank">Horie 钛杯</a> 开箱</h3>

<p>10/14 请求乐天转运出货，10/16 就收到了！</p>

<p><img src="/assets/bea62c251f1b/1*LnzDj0-qp5JrhXe40RiewQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1088" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwODgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/bea62c251f1b/1*LnzDj0-qp5JrhXe40RiewQ.png" /></p>

<p>两个杯子＋一本杂之实际箱子并不大。</p>

<p><img src="/assets/bea62c251f1b/1*x7NZZf3oWLDLAqZzktyYoA.webp" alt="" loading="lazy" decoding="async" width="1200" height="1052" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwNTIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/bea62c251f1b/1*x7NZZf3oWLDLAqZzktyYoA.png" /></p>

<p>贴满日系注意贴纸。</p>

<p><img src="/assets/bea62c251f1b/1*Rub-oAEfRnZjpn4eIAhPHg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1157" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjExNTciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/bea62c251f1b/1*Rub-oAEfRnZjpn4eIAhPHg.png" /></p>

<p>国际配送专用加固箱就是多这个纸箱＋周围跟底部防撞纸包装。</p>

<p><img src="/assets/bea62c251f1b/1*sR3X_vfh6_7VH8x7jTA4GQ.webp" alt="" loading="lazy" decoding="async" width="913" height="1102" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTMiIGhlaWdodD0iMTEwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*sR3X_vfh6_7VH8x7jTA4GQ.png" /></p>

<p><img src="/assets/bea62c251f1b/1*a2ZQxQbXhyFm790bAqnZ4Q.webp" alt="" loading="lazy" decoding="async" width="931" height="1184" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzEiIGhlaWdodD0iMTE4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*a2ZQxQbXhyFm790bAqnZ4Q.png" /></p>

<p>上方是 Amazon 买的杂志(邮寄的纸包装已破，不过内容物没事)，下方才是 Horie 钛杯。</p>

<p><img src="/assets/bea62c251f1b/1*jDdIWaMN0U_l0KrULJjk7g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1079" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNzkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/bea62c251f1b/1*jDdIWaMN0U_l0KrULJjk7g.png" /></p>

<p>Horie 钛杯寄送的纸箱原封不动放在乐天转运的纸箱中。</p>

<blockquote>
  <p><em>感觉可以在转运包装时勾选去除原本的包装减少体积与重量，节省运费。</em></p>
</blockquote>

<p><img src="/assets/bea62c251f1b/1*ZVCaomYElKOQktBAGerrkg.webp" alt="" loading="lazy" decoding="async" width="1400" height="953" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk1MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*ZVCaomYElKOQktBAGerrkg.png" /></p>

<p>内容物：2 个钛杯。</p>

<h3 id="horie-钛杯-1"><a href="https://a.r10.to/hkPx9m" target="_blank">Horie 钛杯</a></h3>

<p><img src="/assets/bea62c251f1b/1*bXj9-XVgjfsVta6cZg8Fpw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/bea62c251f1b/1*bXj9-XVgjfsVta6cZg8Fpw.jpeg" /></p>

<p><img src="/assets/bea62c251f1b/1*z2CIeS7Y4Z65SV2WXSv-1Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/bea62c251f1b/1*z2CIeS7Y4Z65SV2WXSv-1Q.jpeg" /></p>

<p><img src="/assets/bea62c251f1b/1*EZAkrzE5WkIEF0YMSoT3CA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*EZAkrzE5WkIEF0YMSoT3CA.jpeg" /></p>

<p>整体色彩跟纹路及渐层非常鲜艳魔幻，美的很不真实。</p>

<p><img src="/assets/bea62c251f1b/1*F_L3JKPr1kd-Ljs9c2TA2Q.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/bea62c251f1b/1*F_L3JKPr1kd-Ljs9c2TA2Q.jpeg" /></p>

<p>马上开一瓶生啤酒加冰块测试，保冰效果确实好、啤酒也有绵密的气泡，很好喝、 <strong>而且真的不会流汗</strong> 。</p>

<h3 id="最终花费计算">最终花费计算</h3>

<ul>
  <li>
    <p><a href="https://a.r10.to/hkPx9m" target="_blank">Horie 钛杯</a> 窑创り ブースター/400ml ¥19,800 円 — NT $4,079</p>
  </li>
  <li>
    <p>运费分担/人：NT$665</p>
  </li>
  <li>
    <p>关税：未被收取</p>
  </li>
</ul>

<p>总计：NT $4,744 入手。</p>

<blockquote>
  <p><strong><em>因为钛杯非常轻感觉可以多找几个人一起买分担运费，应该可以把价格压到 NT4,200 左右，我只买两个因此运费有点太贵。</em></strong></p>
</blockquote>

<blockquote>
  <p>当然最划算还是亲自去日本百货公司买＋退税！价格猜测在 NT$ 3,600 左右。</p>
</blockquote>]]></content>
  </entry><entry>
    <title type="html">东京自由行攻略｜川越小江户一日游与热海海上花火大会全纪录</title>
    <link href="https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E4%B8%9C%E4%BA%AC%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E5%B7%9D%E8%B6%8A%E5%B0%8F%E6%B1%9F%E6%88%B7%E4%B8%80%E6%97%A5%E6%B8%B8%E4%B8%8E%E7%83%AD%E6%B5%B7%E6%B5%B7%E4%B8%8A%E8%8A%B1%E7%81%AB%E5%A4%A7%E4%BC%9A%E5%85%A8%E7%BA%AA%E5%BD%95-958599363857/" rel="alternate" type="text/html" title="东京自由行攻略｜川越小江户一日游与热海海上花火大会全纪录" />
    <published>2025-10-10T19:01:28+08:00</published>
    <updated>2025-10-16T23:55:33+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/958599363857</id><summary type="html">规划东京5天4夜自由行，深入川越小江户文化与热海烟火大会，详细交通票券购买、必访景点与美食推荐，助你避开人潮、掌握行程节奏，享受无忧旅游体验。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="Z 度旅行遊記" /><category term="生活" /><category term="travel" /><category term="japan" /><category term="tokyo" /><category term="travel-writing" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/958599363857/1*E-ZA-OYCi5vsTBGlsxyS0g.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E4%B8%9C%E4%BA%AC%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E5%B7%9D%E8%B6%8A%E5%B0%8F%E6%B1%9F%E6%88%B7%E4%B8%80%E6%97%A5%E6%B8%B8%E4%B8%8E%E7%83%AD%E6%B5%B7%E6%B5%B7%E4%B8%8A%E8%8A%B1%E7%81%AB%E5%A4%A7%E4%BC%9A%E5%85%A8%E7%BA%AA%E5%BD%95-958599363857/"><![CDATA[<h3 id="游记-2025-东京地区--川越小江户与热海海上花火大会-5-日自由行">[游记] 2025 东京地区 — 川越小江户与热海海上花火大会 5 日自由行</h3>

<p>东京市区+近郊 5 天 4 夜自由行，热海花火大会与川越一日游交通、体验全攻略</p>

<p><img src="/assets/958599363857/1*E-ZA-OYCi5vsTBGlsxyS0g.webp" alt="夏日的热海花火" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*E-ZA-OYCi5vsTBGlsxyS0g.jpeg" /></p>

<p>夏日的热海花火</p>

<p>趁著新工作刚上工先把电充饱， <a href="/posts/z-度旅行遊記/东京自由行攻略-5-天食住行全记录与必访景点推荐-9da2c51fa4f2/">再访东京</a> — 来场一生必看一次的日本花火大会及前往东京近郊川越一日游。</p>

<h4 id="上次行程">上次行程</h4>

<blockquote>
  <p><em>上次「 <a href="/posts/z-度旅行遊記/东京自由行攻略-5-天食住行全记录与必访景点推荐-9da2c51fa4f2/"><strong>[游记] 2023 东京 5 日自由行</strong></a> 」 是 2023/06 月来东京的，没有 9 月来这么热，上次主要去了：东京铁塔、Shibuya Sky、晴空塔、浅草雷门、迪士尼海洋、横滨钢弹、横滨缆车、台场、新宿、皇居。</em></p>
</blockquote>

<blockquote>
  <p><em>有兴趣的朋友可以 <a href="/posts/z-度旅行遊記/东京自由行攻略-5-天食住行全记录与必访景点推荐-9da2c51fa4f2/">移步阅览</a> 。</em></p>
</blockquote>

<h3 id="乐">乐</h3>

<ul>
  <li>
    <p>Day 1 (09/13 六) — 抵达东京、涩谷、Shibuya Sky</p>
  </li>
  <li>
    <p>Day 2 (09/14 日) —川越一日游、晚上池袋逛街</p>
  </li>
  <li>
    <p>Day 3 (09/15 一) —东京车站地下街、热海花火大会</p>
  </li>
  <li>
    <p>Day 4 (09/16 二) — 麻布台 Teamlab、原宿逛街、原宿 HARRY 水獭咖啡厅</p>
  </li>
  <li>
    <p>Day 5 (09/17 三) —上野逛逛、返程</p>
  </li>
</ul>

<h4 id="shibuya-sky">Shibuya Sky</h4>

<ul>
  <li>
    <p><strong>Shibuya Sky 门票很热门，务必提前购买。</strong></p>
  </li>
  <li>
    <p><a href="https://www.shibuya-scramble-square.com.t.apy.hp.transer.com/sky/ticket/" target="_blank">官网</a> 开卖时间：台湾时间晚间 11:00 可购买 +2 周后的入场日门票
官网购买请先注册会员跟先熟悉购买流程，票券使用人姓名可以填暱称，不用真的填写详细护照姓名。</p>
  </li>
  <li>
    <p>我们是买 18:40~18:59 夜景的时段，也可以选择早一点看夕阳或是最末场 21:00 吃完晚餐再去。</p>
  </li>
  <li>
    <p>其他购买渠道： <a href="https://www.kkday.com/zh-tw/product/133300-shibuya-sky-observatory-e-ticket-tokyo?cid=19365" target="_blank">KKday 涩谷SHIBUYA SKY展望台门票｜即买即用</a></p>
  </li>
</ul>

<blockquote>
  <p><em>价格：¥3,400 日币/人</em></p>
</blockquote>

<h4 id="热海花火大会">[热海花火大会</h4>

<p>热海烟花大会](https://hoshinoresorts.com/zh_tw/hotels/risonareatami/activities/13288/){:target=”_blank”} 官网。</p>

<ul>
  <li>
    <p>2025 施放日：3/23、4/20、4/28、5/31、7/25、8/5、8/8、8/18、8/25、 <strong>9/15</strong> 、9/23、10/13、11/3、11/24、12/7、12/19。</p>
  </li>
  <li>
    <p>7、8 月施放时间：8:15 PM~8:40 PM 25分钟</p>
  </li>
  <li>
    <p><strong>其他月份施放时间：8:20 PM~8:40 PM 20分钟</strong></p>
  </li>
</ul>

<p>在海滩释放、免费入场、无付费席，从 JR 热海站走路会到， <strong>保险起见只需要提前预约好来回的 JR 或热海的住宿就好</strong> 。</p>

<p><strong>建议要自备野餐垫！建议要自备野餐垫！建议要自备野餐垫！</strong></p>

<blockquote>
  <p><em>我们是去 9/15 8:20 PM 施放的场次。</em></p>
</blockquote>

<h4 id="麻布台-teamlab-teamlab-borderless-mori-building-digital-art-museum"><a href="https://borderless-azabudai.ticket.teamlab.art/#/" target="_blank">麻布台 TeamLab (teamLab Borderless: MORI Building DIGITAL ART MUSEUM)</a></h4>

<ul>
  <li>
    <p>票蛮多的，不过还是建议出发前提前购买。</p>
  </li>
  <li>
    <p>其他购买渠道： <a href="https://affiliate.klook.com/redirect?aid=99683&amp;aff_adid=1134759&amp;k_site=https%3A%2F%2Fwww.klook.com%2Fzh-TW%2Factivity%2F20707-teamlab-borderless-admission-ticket-tokyo%2F" target="_blank">东京teamLab Borderless数位艺术美术馆门票</a></p>
  </li>
</ul>

<blockquote>
  <p><em>价格：¥4,800 日币/人</em></p>
</blockquote>

<h4 id="ｈａｒｒｙ原宿テラス店-水獭咖啡厅"><a href="https://harinezumi-cafe.com/store/harajuku-terrace/" target="_blank">ＨＡＲＲＹ原宿テラス店</a> 水獭咖啡厅</h4>

<p>之前在 ig 被烧到的可以跟水獭互动的 <a href="https://harinezumi-cafe.com/store/harajuku-terrace/" target="_blank">咖啡厅</a> 。</p>

<p><img src="/assets/958599363857/1*gV6F9gn_uu9pYeVZSlPQbQ.webp" alt="&lt;https://www.instagram.com/p/DPBKurVD99c/&gt;" loading="lazy" decoding="async" width="1213" height="1268" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjEzIiBoZWlnaHQ9IjEyNjgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*gV6F9gn_uu9pYeVZSlPQbQ.png" /></p>

<p><a href="https://www.instagram.com/p/DPBKurVD99c/" target="_blank">https://www.instagram.com/p/DPBKurVD99c/</a></p>

<ul>
  <li>
    <p><a href="https://book.squareup.com/appointments/3kuc83ozz99u5q/location/G3XVJ4FPKRGCP/services/5TOZDR3PNU7X52TOXELQN575" target="_blank">官网预约</a></p>
  </li>
  <li>
    <p>东京其他地方也有分店可以去 <a href="https://harinezumi-cafe.com/store/" target="_blank">官网查看</a> 。</p>
  </li>
  <li>
    <p><strong>建议要提前预约，当日去会扑空。</strong></p>
  </li>
  <li>
    <p>如果日期前行程有异动可以免费取消。</p>
  </li>
  <li>
    <p>时间：16:30–17:30</p>
  </li>
</ul>

<blockquote>
  <p><em>价格：¥3,080 日币/人一小时基本费 + 到现场后加 ¥880/人 跟水獭亲密互动 5 分钟。</em></p>
</blockquote>

<p><a href="https://kantenlife.tw/2024/04/18/house-of-otters-japan/#%E6%97%A5%E6%9C%AC%E6%B0%B4%E7%8D%BA%E5%92%96%E5%95%A1%E5%BB%B3%EF%BD%9C%E3%82%AB%E3%83%AF%E3%82%A6%E3%82%BD_%E8%8B%A5%E6%9E%97%E3%81%AE%E5%AE%B6%E3%80%81HARRY_HARAJUKU_terrace%E6%AF%94%E8%BC%83%E5%88%86%E4%BA%AB" target="_blank"><strong>不过后来查资料，感觉另一家 カワウソ_若林の家 比较好，互动时间较长。</strong></a></p>

<h3 id="行">行</h3>

<h4 id="机票--日本航空-japan-airlines">机票 — 日本航空 Japan Airlines</h4>

<ul>
  <li>
    <p>去程 9月13日：JL802日本航空 —10:00 TPE 桃园国际机场 T2 -&gt; 14:25 NRT成田机场 T2</p>
  </li>
  <li>
    <p>回程 9月17日：JL809日本航空 — 18:10 NRT成田机场T2 -&gt; 18:10 TPE桃园国际机场 T2</p>
  </li>
</ul>

<blockquote>
  <p><em>价格：NT $12,324/人</em></p>
</blockquote>

<p><a href="https://www.jal.co.jp/tw/zhtw/inter/baggage/checked/" target="_blank">另外日本航空的托运额度蛮多的，经济舱： <strong>2 件23 公斤/件</strong></a></p>

<h4 id="jr-新干线-东京---热海--45-分钟">JR 新干线 东京 &lt;-&gt; 热海 (~= 45 分钟)</h4>

<p>因为怕当天没有车来回所以提前先买好车票。</p>

<ul>
  <li>
    <p>开卖时间：台湾时间晚间 11:00 可购买 +4 周后日期的车票</p>
  </li>
  <li>
    <p>可以从 <a href="https://e5489.jr-odekake.net/e5489/ibpc/CBTrainEntryExternalPC?LANG=tc" target="_blank">官网购买</a> 或是透过 <a href="https://www.kkday.com/zh-tw/transportation/japan-rail?cid=19365" target="_blank">KKday</a> / <a href="https://affiliate.klook.com/redirect?aid=99683&amp;aff_adid=1134759&amp;k_site=https%3A%2F%2Fwww.klook.com%2Fzh-TW%2Fjapan-rail%2F" target="_blank">Klook</a> 购买 (自行比价)</p>
  </li>
</ul>

<blockquote>
  <p><em>我们买的是：</em></p>
</blockquote>

<blockquote>
  <p><em>- <strong>东京 14:57 -&gt; 热海 15:42</strong> — こだま Kodama 735</em></p>
</blockquote>

<blockquote>
  <p><em>- <strong>热海 22:02 -&gt; 东京 22:48 —</strong> こだま Kodama 752</em></p>
</blockquote>

<blockquote>
  <p><em>价格：NT $1,882+NT $56 (代订平台的座位偏好费)/人</em></p>
</blockquote>

<h4 id="skyliner-京成电铁车票--41-分钟"><a href="https://www.kkday.com/zh-tw/product/7913-keisei-skyliner-narita-airport-express-ticket?cid=19365" target="_blank">Skyliner 京成电铁车票</a> (~= 41 分钟)</h4>

<p>应该是目前最快从成田机场到东京市区(上野)的方式。</p>

<ul>
  <li>
    <p>无自由席</p>
  </li>
  <li>
    <p>KKday 购买： <a href="https://www.kkday.com/zh-tw/product/7913-keisei-skyliner-narita-airport-express-ticket?cid=19365" target="_blank">Skyliner 京成电铁车票</a></p>
  </li>
  <li>
    <p>从网路先买比较便宜，到车站再划位，弹性好用</p>
  </li>
</ul>

<blockquote>
  <p><em>价格：NT $912 (来回两张票)/人</em></p>
</blockquote>

<blockquote>
  <p><em>要注意的是 KKday 买来回，就是出两张票，不要误会买错了。</em></p>
</blockquote>

<h4 id="川越周游券-电车巴士--30-分钟"><a href="https://affiliate.klook.com/redirect?aid=99683&amp;aff_adid=1134759&amp;k_site=https%3A%2F%2Fwww.klook.com%2Fzh-TW%2Factivity%2F100464-kawagoe-pass-digital-ticket%2F" target="_blank">川越周游券 (电车+巴士)</a> (~= 30 分钟)</h4>

<ul>
  <li>
    <p>东武东上线往返：池袋站 -&gt; 川越站或川越市站</p>
  </li>
  <li>
    <p>全天无限次搭乘东武巴士 (包括东武小江户循环巴士)</p>
  </li>
  <li>
    <p>请注意：巴士有西武跟东武，此票券为东武</p>
  </li>
  <li>
    <p>KLook 购买： <a href="https://affiliate.klook.com/redirect?aid=99683&amp;aff_adid=1134759&amp;k_site=https%3A%2F%2Fwww.klook.com%2Fzh-TW%2Factivity%2F100464-kawagoe-pass-digital-ticket%2F" target="_blank">川越优惠周游券 Kawagoe Discount Pass</a></p>
  </li>
  <li>
    <p>无需兑换，只需要要使用前线上点兑换，出示 QRCode 进入电车或巴士司机即可。</p>
  </li>
</ul>

<blockquote>
  <p><em>价格：NT $214/人</em></p>
</blockquote>

<h4 id="机场接送">机场接送</h4>

<ul>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/airport-transfer?cid=19365" target="_blank">KKday 机场接送预约</a> / <a href="https://affiliate.klook.com/redirect?aid=99683&amp;aff_adid=1134759&amp;k_site=https%3A%2F%2Fwww.klook.com%2Fzh-TW%2Fairport-transfers%2F" target="_blank">Klook 机场接送预约</a></p>
  </li>
  <li>
    <p>目前双 K 都在打机场接送，便宜安全又快速，可以自行比价选择。</p>
  </li>
</ul>

<blockquote>
  <p><em>双北 -&gt; 桃机</em></p>
</blockquote>

<blockquote>
  <p><em>价格：NT $752/台</em></p>
</blockquote>

<h4 id="esim">eSIM</h4>

<p>同样直接在 KKday 购买 5G 吃到饱 eSIM，这次在东京、热海、川越使用上没遇到特别问题或被降速。</p>

<ul>
  <li>KKday 购买： <a href="https://www.kkday.com/zh-tw/product/121004-unlimited-data-esim-card-japan?cid=19365" target="_blank">日本 eSIM 无限流量 KDDI / Softbank</a></li>
</ul>

<blockquote>
  <p><em>价格：NT $309/5 日/无限流量</em></p>
</blockquote>

<h4 id="vist-japan">Vist Japan</h4>

<p><a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E4%BA%AC%E9%98%AA%E7%A5%9E%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E4%BA%AC%E9%83%BD%E5%A4%A7%E9%98%AA%E7%A5%9E%E6%88%B68%E6%97%A5%E9%81%8A%E5%85%A8%E7%B4%80%E9%8C%84%E8%88%87%E5%AF%A6%E7%94%A8%E4%BA%A4%E9%80%9A%E4%BD%8F%E5%AE%BF%E6%8C%87%E5%8D%97-76d66c2e34af/#20241125-%E6%9B%B4%E6%96%B0%E5%85%A5%E5%A2%83%E5%AF%A9%E6%9F%A5%E8%88%87%E6%B5%B7%E9%97%9C%E7%94%B3%E5%A0%B1qr-code-%E5%B7%B2%E5%90%88%E4%BD%B5%E6%88%90%E5%90%8C%E4%B8%80%E5%80%8B%E5%85%A5%E5%A2%83%E5%AE%A1%E6%9F%A5%E5%8F%8A%E6%B5%B7%E5%85%B3%E7%94%B3%E6%8A%A5%E7%9A%84qr%E7%A0%81%E6%B2%92%E6%9C%89%E8%97%8D%E7%A2%BC%E9%BB%83%E7%A2%BC%E5%8D%80%E5%88%A5%E4%BB%A5%E4%B8%8B%E5%85%A7%E5%AE%B9%E5%8F%AA%E7%95%B6%E7%B4%80%E9%8C%84%E5%8F%AF%E4%BB%A5%E5%BF%BD%E7%95%A5" target="_blank">请参考之前的文章，事前完成登录就好，目前入境审查与海关审查 QRCode 以合成同一个。</a></p>

<h3 id="住">住</h3>

<p>因为找的时间接近出发日，综合比较了价格跟便利性之后选择住在新桥站附近。(上次住汐留觉得新桥更方便一些)</p>

<h4 id="东京新桥大和-roynet-饭店-4-晚"><a href="https://affiliate.klook.com/redirect?aid=99683&amp;aff_adid=1134759&amp;k_site=https%3A%2F%2Fwww.klook.com%2Fzh-TW%2Fhotels%2Fdetail%2F127656-daiwa-roynet-hotel-shimbashi%2F" target="_blank">东京新桥大和 ROYNET 饭店</a> (4 晚)</h4>

<p><img src="/assets/958599363857/1*FPa2l4mYfm_ApuJt_LqSag.webp" alt="东京新桥大和 ROYNET 饭店" loading="lazy" decoding="async" width="579" height="539" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NzkiIGhlaWdodD0iNTM5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/958599363857/1*FPa2l4mYfm_ApuJt_LqSag.png" /></p>

<p><a href="https://affiliate.klook.com/redirect?aid=99683&amp;aff_adid=1134759&amp;k_site=https%3A%2F%2Fwww.klook.com%2Fzh-TW%2Fhotels%2Fdetail%2F127656-daiwa-roynet-hotel-shimbashi%2F" target="_blank">东京新桥大和 ROYNET 饭店</a></p>

<ul>
  <li>
    <p><a href="https://affiliate.klook.com/redirect?aid=99683&amp;aff_adid=1134759&amp;k_site=https%3A%2F%2Fwww.klook.com%2Fzh-TW%2Fhotels%2Fdetail%2F127656-daiwa-roynet-hotel-shimbashi%2F" target="_blank">一样直接从 Klook 订，累积点数</a></p>
  </li>
  <li>
    <p>距离新桥站走路约 2 分钟，很近。</p>
  </li>
  <li>
    <p>五天四夜住到底，不更换饭店。</p>
  </li>
</ul>

<blockquote>
  <p><em>价格：NT$ 18,404/4晚/2人/标准双人房，约 NT$ 2,300/每人每晚。</em></p>
</blockquote>

<blockquote>
  <p>准备就绪！出发！</p>
</blockquote>

<p><a href="https://digital.jal.co.jp/ssci/identification?lang=zh-tw" target="_blank"><strong>起飞前 24 小时可先完成网路报到、选位，到机场就可以直接排行李托运，加快流程。</strong></a></p>

<h3 id="day-1-0913-六--抵达东京shibuya-sky">Day 1 (09/13 六) — 抵达东京、Shibuya Sky</h3>

<h4 id="0650-搭乘机场接送">06:50 搭乘机场接送</h4>

<h4 id="0720-抵达桃园机场第二航厦">07:20 抵达桃园机场第二航厦</h4>

<p><img src="/assets/958599363857/1*TkF8qP3e1-iladiHOZgERQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*TkF8qP3e1-iladiHOZgERQ.jpeg" /></p>

<h4 id="0730-排行李托运">07:30 排行李托运</h4>

<p><img src="/assets/958599363857/1*sNzgznqv8RxRYfwyCaIntg.webp" alt="" loading="lazy" decoding="async" width="1200" height="843" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*sNzgznqv8RxRYfwyCaIntg.png" /></p>

<p>分配到 1 号边边角角的柜位， <a href="https://digital.jal.co.jp/ssci/identification?lang=zh-tw" target="_blank">已事先完成网路报到</a> 直接排托运行李，但是前面的人卡了很久，所以大概排了 30 多分钟才完成托运手续。</p>

<h4 id="-0820-完成安检出境">~= 08:20 完成安检、出境</h4>

<p><img src="/assets/958599363857/1*lKRxUWP4BGQA1q97X3jJJg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*lKRxUWP4BGQA1q97X3jJJg.jpeg" /></p>

<p>一早人蛮多的，大约 8:20 左右完成安检出境，先去二楼吃个摩斯当早餐；分配到的登机门也是最远的 D1。</p>

<h4 id="二航出境免税店-le-labo">二航出境免税店 Le Labo</h4>

<p><img src="/assets/958599363857/1*wyJNusrf7ElLdfZ33YaPWA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*wyJNusrf7ElLdfZ33YaPWA.jpeg" /></p>

<p>意外发现二航出境免税店有 Le Labo，柜姐有介绍现在有活动，新会员领券折抵后 50ml 价格 NT $5,500，比去日本境内买便宜(约 NT $5,800)。</p>

<p><strong>2025 年最新搜集的价格表 — 50ml：</strong></p>

<ul>
  <li>
    <p>台湾门市价：NT $7,600</p>
  </li>
  <li>
    <p>台湾机场门市免税价：NT $5,500 (活动价)</p>
  </li>
  <li>
    <p>日本门市退完税价格：约 NT $5,700</p>
  </li>
  <li>
    <p><a href="https://www.fasola.jp/en/searchByBrand.aspx" target="_blank"><strong>日本机场门市</strong></a> <strong>免税价：约 NT $5,200 🤩 — 我这次就是最后在成田机场</strong> T2 <strong>航厦出境后才买。</strong></p>
  </li>
</ul>

<p><img src="/assets/958599363857/1*4AU39FGOzbR7TnCVzCCjKg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*4AU39FGOzbR7TnCVzCCjKg.jpeg" /></p>

<p><img src="/assets/958599363857/1*sgPd1BrkZsr2F37f1m1Dlg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*sgPd1BrkZsr2F37f1m1Dlg.jpeg" /></p>

<p><img src="/assets/958599363857/1*I6HuL5NdPzQxp3lu43fiUw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*I6HuL5NdPzQxp3lu43fiUw.jpeg" /></p>

<p><img src="/assets/958599363857/1*gkCuhDtktYmN6ed170fRZg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*gkCuhDtktYmN6ed170fRZg.jpeg" /></p>

<p>在机场乱逛等登机，在 D1 The North Face 旁有两排免费的按摩椅可以体验(跟附近店家拿免费代币即可使用)。</p>

<h4 id="0940-前往登机口准备登机">09:40 前往登机口准备登机</h4>

<p><img src="/assets/958599363857/1*U5QpF19SbJlVAllxZZiQMA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*U5QpF19SbJlVAllxZZiQMA.jpeg" /></p>

<p><img src="/assets/958599363857/1*izSSFMEAPqbhFtTgt13ndw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*izSSFMEAPqbhFtTgt13ndw.jpeg" /></p>

<p>这次搭到的飞机是 BOEING 737–800 机型有点老旧。</p>

<blockquote>
  <p><em>但我回来才发现，机上有提供免费一小时机上 WiFi。</em></p>
</blockquote>

<h4 id="1006-起飞">10:06 起飞</h4>

<p><img src="/assets/958599363857/1*McNWkLo576Z3uJTm9QgYWA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*McNWkLo576Z3uJTm9QgYWA.jpeg" /></p>

<h4 id="japan-airlines-飞机餐">JAPAN AIRLINES 飞机餐</h4>

<p><img src="/assets/958599363857/1*VoM9bEiz7mMma7fAwp48tw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*VoM9bEiz7mMma7fAwp48tw.jpeg" /></p>

<p><img src="/assets/958599363857/1*tu0L7uohZIqsd9V4JlKGFg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*tu0L7uohZIqsd9V4JlKGFg.jpeg" /></p>

<p><img src="/assets/958599363857/1*s69aVqVz7J7wXFSNi66SsQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*s69aVqVz7J7wXFSNi66SsQ.jpeg" /></p>

<p>虽然飞机有点年纪，但是飞机餐真的不错，汉堡肉肉酱斜管面，还有一碗小荞麦豆皮凉面跟甜点柠檬布丁(好吃! )。</p>

<h4 id="1439-降落日本成田国际机场-误点-14-分钟">14:39 降落日本成田国际机场 (误点 14 分钟)</h4>

<p><img src="/assets/958599363857/1*0Dvy2jcY6ED8uW6NgmxcXw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*0Dvy2jcY6ED8uW6NgmxcXw.jpeg" /></p>

<p><img src="/assets/958599363857/1*W_bKd7fHb6kBH3uKPqepPg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*W_bKd7fHb6kBH3uKPqepPg.jpeg" /></p>

<p>地板有点湿润，天气多云，看来稍早下过大雨；抵达后就开始成田机场大地游戏(下机走到入境审查大概要 5 分钟吧…)。</p>

<h4 id="-1505-完成入境手续提领行李出机场">~= 15:05 完成入境手续＋提领行李出机场</h4>

<p><img src="/assets/958599363857/1*Xru5o3DBU_GZyTlVW8Wfcw.webp" alt="" loading="lazy" decoding="async" width="937" height="1016" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzciIGhlaWdodD0iMTAxNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Xru5o3DBU_GZyTlVW8Wfcw.png" /></p>

<p><img src="/assets/958599363857/1*oD9JhXDuh47h4aBYxepu7Q.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*oD9JhXDuh47h4aBYxepu7Q.jpeg" /></p>

<p>出机场后直接搭乘手扶梯到楼下往「铁道」方向，找到「SKYLINER &amp; KEISEI INFORMATION CENTER」柜台出示预先在网上购买的 <a href="https://www.kkday.com/zh-tw/product/7913-keisei-skyliner-narita-airport-express-ticket?cid=19365" target="_blank">Skyliner 京成电铁车票</a> QRCode 给站务员，就能兑换化为下一班的车票。</p>

<blockquote>
  <p><em>要注意，车站这边还有其他铁路的 INFORMATION CENTER，请认明图上的 INFORMATION CENTER 才是。</em></p>
</blockquote>

<p><img src="/assets/958599363857/1*yvMJw_HeZ9Mk8qXaFj6gKw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*yvMJw_HeZ9Mk8qXaFj6gKw.jpeg" /></p>

<p><img src="/assets/958599363857/1*3rXtVnwanfORgy2DPDrKAA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*3rXtVnwanfORgy2DPDrKAA.jpeg" /></p>

<p>没划到 15:16 的班次，只能搭 15:42 的。</p>

<p>车站这边有卖 <a href="https://www.jreast.co.jp/zh-CHT/multi/welcomesuica/welcomesuica.html" target="_blank">Welcome Suica (28 天内要用完)</a> 跟一般 Suica 卡加值机器，可以趁等车空档先把这次旅程需要花的交通费用储一储 ( <a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E4%BA%AC%E9%98%AA%E7%A5%9E%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E4%BA%AC%E9%83%BD%E5%A4%A7%E9%98%AA%E7%A5%9E%E6%88%B68%E6%97%A5%E9%81%8A%E5%85%A8%E7%B4%80%E9%8C%84%E8%88%87%E5%AF%A6%E7%94%A8%E4%BA%A4%E9%80%9A%E4%BD%8F%E5%AE%BF%E6%8C%87%E5%8D%97-76d66c2e34af/#-2" target="_blank">但我自己是用 iPhone 的 Suica 方便简单好用！</a> )</p>

<p><img src="/assets/958599363857/1*Rx_dIfNqzUwhc21VzUvIkw.webp" alt="" loading="lazy" decoding="async" width="954" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Rx_dIfNqzUwhc21VzUvIkw.png" /></p>

<p>看「京成线」指示牌进站后找到对应的月台候车。</p>

<h4 id="-1542-上车">~= 15:42 上车</h4>

<p><img src="/assets/958599363857/1*gM-xQihcfGhbEXFv8_uxIg.webp" alt="" loading="lazy" decoding="async" width="949" height="1081" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDkiIGhlaWdodD0iMTA4MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*gM-xQihcfGhbEXFv8_uxIg.png" /></p>

<p>这月台有很多种车次会经过停靠，请务必确认后再上车；工作人员也会沿途宣导，可以给他看车票确认， <a href="https://www.jreast.co.jp/tc/downloads/pdf/ntrt10_tc.pdf" target="_blank"><strong>成田特快全车指定席，无自由座</strong></a> <strong>，无车票请勿上车</strong> 。</p>

<p><img src="/assets/958599363857/1*IEQNy3qmUMrm_GaBAFqUTw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*IEQNy3qmUMrm_GaBAFqUTw.jpeg" /></p>

<p>成田特快的位子够大，28 寸行李箱放得下；如果觉得卡可以放在车前车后的区域，或是放行李架(要拿小心就是)。</p>

<p><img src="/assets/958599363857/1*Z0UWLv0qvBf77Ue0xfUQ4w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Z0UWLv0qvBf77Ue0xfUQ4w.jpeg" /></p>

<p>天气阴阴。</p>

<h4 id="1623-抵达京成上野站">16:23 抵达京成上野站</h4>

<p><img src="/assets/958599363857/1*Z8aKd12JgWIzCE7qtBsgiQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Z8aKd12JgWIzCE7qtBsgiQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*NEojh1UeOaVynhrnp_d7bQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*NEojh1UeOaVynhrnp_d7bQ.jpeg" /></p>

<p>下车后依照指示走地下道到 G 银座线搭车，涩谷方向上野广小路到新桥站。</p>

<h4 id="1650-抵达-东京新桥大和-roynet-饭店">16:50 抵达 东京新桥大和 ROYNET 饭店</h4>

<p><img src="/assets/958599363857/1*b1FSV2C8ZsLRq_A_PHnI5Q.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*b1FSV2C8ZsLRq_A_PHnI5Q.jpeg" /></p>

<p><img src="/assets/958599363857/1*09O3hfLEqGKXuUjmv5ALMA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*09O3hfLEqGKXuUjmv5ALMA.jpeg" /></p>

<p>新桥站出来走一下就到了，非常方便！</p>

<p>饭店提供的免费备品非常多，还有面膜、入浴剂、耳塞、随身携带的漱口水…等</p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/jKsZna0d38c" title="東京新橋大和 ROYNET 飯店" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p><img src="/assets/958599363857/1*JXSKiQeoOOtAlQt946SXiw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*JXSKiQeoOOtAlQt946SXiw.jpeg" /></p>

<p>有点像 <a href="/posts/z-度旅行遊記/山阳地区广岛冈山自由行攻略-6日行程-交通-住宿全解析-31b9b3a63abc/"><strong>前年去广岛、冈山</strong></a> 住的「 <a href="https://www.youtube.com/watch?v=gmwHRihsyXI" target="_blank">利夫马克斯冈山仓敷站前饭店</a> 」，房间很小，感觉是单人房只是放了一张双人床。</p>

<blockquote>
  <p><em>缺点除了小，还有房间冰箱没有冷冻功能。</em></p>
</blockquote>

<p>东西放完就出发去涩谷。</p>

<h4 id="1830-排队入场-shibuya-sky">18:30 排队入场 Shibuya SKY</h4>

<p>在 涩谷 Scramble Square 一楼找到上去「Shibuya SKY」展望设施的电梯，排队搭电梯上去后给验票人员看 QRCode 就能排队等入场。(入场时核销)</p>

<p><img src="/assets/958599363857/1*XTalH3d03U4tmBXD-iK5yw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*XTalH3d03U4tmBXD-iK5yw.jpeg" /></p>

<p>这边看得到涩谷十字路口。</p>

<blockquote>
  <p><em>上来后先去免费置物柜寄物，自拍杆之类的是不能带的。</em></p>
</blockquote>

<p><img src="/assets/958599363857/1*y5jXwXKVIcG5Df9BxPTHew.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*y5jXwXKVIcG5Df9BxPTHew.jpeg" /></p>

<p><img src="/assets/958599363857/1*DcQwikjwYR6G4JQ9c22cIQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*DcQwikjwYR6G4JQ9c22cIQ.jpeg" /></p>

<blockquote>
  <p><a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E6%9D%B1%E4%BA%AC%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-5-%E5%A4%A9%E9%A3%9F%E4%BD%8F%E8%A1%8C%E5%85%A8%E8%A8%98%E9%8C%84%E8%88%87%E5%BF%85%E8%A8%AA%E6%99%AF%E9%BB%9E%E6%8E%A8%E8%96%A6-9da2c51fa4f2/#%E6%B8%8B%E8%B0%B7--shibuya-sky" target="*blank"><em>旧地重游</em></a> _，相较两年前发福了不少。*</p>
</blockquote>

<blockquote>
  <p><em>手扶梯有两边，一边上一边下都蛮好拍的。</em></p>
</blockquote>

<p><img src="/assets/958599363857/1*cRbCKPoZF8FPxklnYTtZ0A.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*cRbCKPoZF8FPxklnYTtZ0A.jpeg" /></p>

<p><img src="/assets/958599363857/1*Bzn4qBq4UfpqSXbcf8Gk-A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*Bzn4qBq4UfpqSXbcf8Gk-A.jpeg" /></p>

<p>顶楼夜景，不过相较上次，这次天气比较差，雾蒙蒙还带点毛毛细雨。</p>

<p><img src="/assets/958599363857/1*dinKHMOg-9bNoG3Chn5HWA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*dinKHMOg-9bNoG3Chn5HWA.jpeg" /></p>

<p><img src="/assets/958599363857/1*WNjqJ1VyhKnBzWEgV2lGfg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*WNjqJ1VyhKnBzWEgV2lGfg.jpeg" /></p>

<p>看完一路往下走，经过 Bar，这边的景也不错：</p>

<p><img src="/assets/958599363857/1*gsgDlAcVwHQ-pG49di-PIQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*gsgDlAcVwHQ-pG49di-PIQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*Hfioo92OP-JnADRbPH4oMA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*Hfioo92OP-JnADRbPH4oMA.jpeg" /></p>

<h4 id="1945-回到涩谷十字路口">19:45 回到涩谷十字路口</h4>

<p><img src="/assets/958599363857/1*kLQ5R8LmFXiOduVRoXC-Jw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*kLQ5R8LmFXiOduVRoXC-Jw.jpeg" /></p>

<p><img src="/assets/958599363857/1*OOV8P-Wd_qcLWKvUcPdj_A.webp" alt="" loading="lazy" decoding="async" width="1200" height="854" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*OOV8P-Wd_qcLWKvUcPdj_A.png" /></p>

<p>刚好今际之国的闯关者第三季即将开播，来回味一下场景；体感上人比之前还多很多。</p>

<p><img src="/assets/958599363857/1*nSlNoHtXjCcmZwLJdhK5Wg.webp" alt="" loading="lazy" decoding="async" width="955" height="1222" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTUiIGhlaWdodD0iMTIyMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*nSlNoHtXjCcmZwLJdhK5Wg.png" /></p>

<p>过马路一路往 涩谷 Parco 走，想去吃 <a href="https://maps.app.goo.gl/B11rcg3MLFRgJLqT8" target="_blank">极味屋</a> 。</p>

<blockquote>
  <p><a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E6%9D%B1%E4%BA%AC%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-5-%E5%A4%A9%E9%A3%9F%E4%BD%8F%E8%A1%8C%E5%85%A8%E8%A8%98%E9%8C%84%E8%88%87%E5%BF%85%E8%A8%AA%E6%99%AF%E9%BB%9E%E6%8E%A8%E8%96%A6-9da2c51fa4f2/#%E6%B8%8B%E8%B0%B7-parco--%E6%A5%B5%E5%91%B3%E5%B1%8B" target="_blank"><em>上次来吃过一次，念念不忘。</em></a></p>
</blockquote>

<h4 id="2000-抵达涩谷-parco">20:00 抵达涩谷 Parco</h4>

<p><img src="/assets/958599363857/1*5UmVsCAy5wcJHCK9h8xQvg.webp" alt="" loading="lazy" decoding="async" width="1400" height="984" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*5UmVsCAy5wcJHCK9h8xQvg.png" /></p>

<p>很可惜 <a href="https://maps.app.goo.gl/B11rcg3MLFRgJLqT8" target="_blank">极味屋</a> 已售罄（过几天再来吃），在同样的美食街吃了另一家炸串店。</p>

<h4 id="2015-串カツあらた-渋谷パルコ店-kushikatsu-arata">20:15 <a href="https://maps.app.goo.gl/PTZVZEqdZayWUiap9" target="_blank">串カツあらた 渋谷パルコ店 Kushikatsu Arata</a></h4>

<p><img src="/assets/958599363857/1*cbSR83bqt56GgvT8gTYRQw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*cbSR83bqt56GgvT8gTYRQw.jpeg" /></p>

<p>点了几个招牌炸串跟肉加倍炸串还有一碗牛腩饭跟两杯酒，一共 ¥6,340 日币。</p>

<blockquote>
  <p><em>日式粉粉的炸串好吃不腻，牛腩饭很入味垫垫胃。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>要注意炸串店会多收高丽菜基本费(お通し)</em></strong> <em>，实际忘了多少，应该是一人</em> ¥ <em>300 日币左右。</em></p>
</blockquote>

<h4 id="2130-c-pla-shibuya">21:30 <a href="https://maps.app.goo.gl/bTwvHKkbxHofxnig6" target="_blank">C-pla Shibuya</a></h4>

<p><img src="/assets/958599363857/1*G0pG6izsdcwUT_Pnfr7xYQ.webp" alt="" loading="lazy" decoding="async" width="954" height="1205" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTQiIGhlaWdodD0iMTIwNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*G0pG6izsdcwUT_Pnfr7xYQ.png" /></p>

<p><img src="/assets/958599363857/1*a8oZSBgBI3ZIOftsOxSH5A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*a8oZSBgBI3ZIOftsOxSH5A.jpeg" /></p>

<p>吃饱走回车站的路上经过一家很大的 C-pla 扭蛋店，进去寻宝。</p>

<blockquote>
  <p><em>没看到想扭的，撤退！</em></p>
</blockquote>

<h4 id="晚安东京">晚安！东京</h4>

<p><img src="/assets/958599363857/1*WwT578CuW9uDdF6FEoJogA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*WwT578CuW9uDdF6FEoJogA.jpeg" /></p>

<p>买个宵夜回饭店休息。</p>

<h3 id="day-20914-日--川越一日游池袋逛街">Day 2(09/14 日) — 川越一日游、池袋逛街</h3>

<h4 id="0930-出门先去吃麦当劳早餐--mcdonalds-麦当劳新桥日比谷口店">09:30 出门，先去吃麦当劳早餐 — <a href="https://maps.app.goo.gl/7kZzxwNhtNjBKdZC9" target="_blank">McDonald’s 麦当劳新桥日比谷口店</a></h4>

<p><img src="/assets/958599363857/1*ylLKnhvJGSh1inGDz4QPXw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*ylLKnhvJGSh1inGDz4QPXw.jpeg" /></p>

<p><img src="/assets/958599363857/1*PBCIcEtyaPLO7bcKEr_X9A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*PBCIcEtyaPLO7bcKEr_X9A.jpeg" /></p>

<p>一样的松饼火腿起司蛋堡！</p>

<blockquote>
  <p><em>这家麦当劳 <a href="/posts/z-度旅行遊記/东京自由行攻略-5-天食住行全记录与必访景点推荐-9da2c51fa4f2/">上次也来过</a> ，缺点是很旧、环境没有很干净、没有自动点餐机。</em></p>
</blockquote>

<h4 id="1050-抵达-池袋站-搭-山手线">10:50 抵达 池袋站 (搭 山手线)</h4>

<p><img src="/assets/958599363857/1*1V90DtPc7kU51PnAhjgL8A.webp" alt="" loading="lazy" decoding="async" width="1200" height="663" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY2MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*1V90DtPc7kU51PnAhjgL8A.png" /></p>

<p>转搭 东武东上线 前往川越。</p>

<p><strong>我们有在线上先买好 <a href="https://affiliate.klook.com/redirect?aid=99683&amp;aff_adid=1134759&amp;k_site=https%3A%2F%2Fwww.klook.com%2Fzh-TW%2Factivity%2F100464-kawagoe-pass-digital-ticket%2F" target="_blank">川越周游券 (电车+巴士)</a> ，线上点击启用开始计算时间：</strong></p>

<p><img src="/assets/958599363857/1*-RIG2ZudPZbbPykqbqCb0g.webp" alt="" loading="lazy" decoding="async" width="935" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzUiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*-RIG2ZudPZbbPykqbqCb0g.png" /></p>

<p><img src="/assets/958599363857/1*hD_LqigAsv0lTWLS4uI1uA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*hD_LqigAsv0lTWLS4uI1uA.jpeg" /></p>

<p>直接进最旁边的 駅事务室，给车站人员看 QRCode 就能直接进出站。(无需划位)</p>

<h4 id="1100-搭乘-东武东上线川越特急--往小川町埼玉县--经川越">11:00 搭乘 东武东上线川越特急 — 往小川町(埼玉县) — 经川越</h4>

<p><img src="/assets/958599363857/1*3oFkNAprNiko_GHcF4r-3A.webp" alt="" loading="lazy" decoding="async" width="1200" height="837" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgzNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*3oFkNAprNiko_GHcF4r-3A.png" /></p>

<h4 id="1126-抵达-川越站">11:26 抵达 川越站</h4>

<p><img src="/assets/958599363857/1*TxaLPPDw4GDqEEWfRnOx7Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="850" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*TxaLPPDw4GDqEEWfRnOx7Q.png" /></p>

<p><img src="/assets/958599363857/1*fnZcZ9Ct4iNfcWq9Kog7jw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*fnZcZ9Ct4iNfcWq9Kog7jw.jpeg" /></p>

<p><img src="/assets/958599363857/1*pxQYLZnHM7-UA6B7RisQnw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*pxQYLZnHM7-UA6B7RisQnw.jpeg" /></p>

<p>一样从最旁边的 駅事务室出站后，先去拿了一份观光手册，决定先搭公车去最远的 <a href="https://maps.app.goo.gl/3vVRnikJQL3zYuGi6" target="_blank">冰川神社</a> ，再一路逛回来。</p>

<p><img src="/assets/958599363857/1*h0c9y56GEfHWTrtP7q8kOQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="848" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*h0c9y56GEfHWTrtP7q8kOQ.png" /></p>

<p>直接从二楼天桥出站往巴士搭乘处下楼。</p>

<h4 id="1135-川越巴士站等车">11:35 川越巴士站等车</h4>

<p><img src="/assets/958599363857/1*Z92lcpTR1OitKAL3LRVrtw.webp" alt="" loading="lazy" decoding="async" width="1200" height="853" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Z92lcpTR1OitKAL3LRVrtw.png" /></p>

<p>一号月台、三号月台都有很多车会到冰川神社，最后是在三号月台搭 名 01。</p>

<blockquote>
  <p><strong><em>只要认明「东武</em> バス <em>」，使用 <a href="https://affiliate.klook.com/redirect?aid=99683&amp;aff_adid=1134759&amp;k_site=https%3A%2F%2Fwww.klook.com%2Fzh-TW%2Factivity%2F100464-kawagoe-pass-digital-ticket%2F" target="_blank">川越周游券 (电车+巴士)</a> ，不用特别兑换；只要下车的时候给司机看 QRCode 画面即可。</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>用周游券不要上车刷到 Suica 哦。</em></strong></p>
</blockquote>

<h4 id="1155-抵达-冰川神社">11:55 抵达 冰川神社</h4>

<p><img src="/assets/958599363857/1*ebEe1SnjEeYVieePNBdmuw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*ebEe1SnjEeYVieePNBdmuw.jpeg" /></p>

<h4 id="冰川神社">冰川神社</h4>

<p><img src="/assets/958599363857/1*ouWflkODbhhc7t8gRUwhwA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1009" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMDkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*ouWflkODbhhc7t8gRUwhwA.png" /></p>

<p><img src="/assets/958599363857/1*9W_Haty-iabNIwCd3m7Hiw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*9W_Haty-iabNIwCd3m7Hiw.jpeg" /></p>

<p>神社不大，有很多风车风铃。</p>

<p><strong>除秽气的人形流：</strong></p>

<p><img src="/assets/958599363857/1*ZzDJul6maBw4Km4g3ixHeQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*ZzDJul6maBw4Km4g3ixHeQ.jpeg" /></p>

<p><strong>风铃祈福跟绘马区</strong></p>

<p><img src="/assets/958599363857/1*Xj_rvn15hT9p2t9Xte8Q7w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*Xj_rvn15hT9p2t9Xte8Q7w.jpeg" /></p>

<p><img src="/assets/958599363857/1*ZnfYoNsMDNVNt1-pDg-jaQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*ZnfYoNsMDNVNt1-pDg-jaQ.jpeg" /></p>

<h4 id="鲷鱼御神签">鲷鱼御神签</h4>

<p><img src="/assets/958599363857/1*QJZOlovCi13dIiAQuwobDw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*QJZOlovCi13dIiAQuwobDw.jpeg" /></p>

<p><img src="/assets/958599363857/1*0R_KFD3lJnrkfxQTxXt82w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*0R_KFD3lJnrkfxQTxXt82w.jpeg" /></p>

<p><img src="/assets/958599363857/1*U6w5eGph85nVYP5rAAR76w.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*U6w5eGph85nVYP5rAAR76w.jpeg" /></p>

<p>有好几个鱼池可以自己钓鲷鱼御神签XD，我是钓红色的一年安鲷。</p>

<p><img src="/assets/958599363857/1*FHiQfCIBVx-EY93PQKur-Q.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*FHiQfCIBVx-EY93PQKur-Q.jpeg" /></p>

<p><img src="/assets/958599363857/1*rKug8yofs-uBooqelaIEMQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*rKug8yofs-uBooqelaIEMQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*wA2-rSUSEQ-5ad0L2A2RCw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*wA2-rSUSEQ-5ad0L2A2RCw.jpeg" /></p>

<p>大吉！</p>

<p><img src="/assets/958599363857/1*wPAUnu2NWojn3xDCq2Bb4Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="853" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*wPAUnu2NWojn3xDCq2Bb4Q.png" /></p>

<p><img src="/assets/958599363857/1*W0t4XZQ14zTYCb6k-84daA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*W0t4XZQ14zTYCb6k-84daA.jpeg" /></p>

<p>如果零钱不够可以跟神社人员换钱、旁边有志工可以免费帮忙英文解签，如果抽到不好的签就直接绑在神社就好(意即消灾解厄)。</p>

<h4 id="1245-离开冰川神社">12:45 离开冰川神社</h4>

<p>拍拍照逛了一圈大约 12:45 离开冰川神社，准备搭车去小江户街跟 吉伊卡哇 MOGUMOGU 本舗 川越店。</p>

<h4 id="西武--小江户巡回巴士">西武 — 小江户巡回巴士</h4>

<p><img src="/assets/958599363857/1*lbJXQmrjFElNnSoh_Rtc2g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*lbJXQmrjFElNnSoh_Rtc2g.jpeg" /></p>

<p>在候车的时候看到一台很酷的观光巴士，还有音乐 — 是 <a href="https://eaglebus.group/co-edo/zh/" target="_blank">西武运输的小江户巡回巴士</a> ； <strong>不能使用东武的周游券</strong> ，可以刷交通卡付费搭乘或购买西武铁道发行的 「 <a href="https://eaglebus.group/co-edo/2025/06/18/ryde0624/" target="_blank">周游卷</a> 」。</p>

<h4 id="1320-chiikawa-mogumogu-hompo-kawagoe-吉伊卡哇-mogumogu-本舗-川越店">13:20 <a href="https://maps.app.goo.gl/ccQP8s28jfD9iVne6" target="_blank">Chiikawa Mogumogu Hompo Kawagoe 吉伊卡哇 MOGUMOGU 本舗 川越店</a></h4>

<p><img src="/assets/958599363857/1*cRVbxgypDnyUhkdduGQrGQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="993" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*cRVbxgypDnyUhkdduGQrGQ.png" /></p>

<p><img src="/assets/958599363857/1*s1n-pLkMRKHB9LSTegvrsw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*s1n-pLkMRKHB9LSTegvrsw.jpeg" /></p>

<p>门口有很多可爱的宝宝，川越限定的地瓜系列。</p>

<p><img src="/assets/958599363857/1*f1PB498M6RshUWre7oxG9w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1935" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE5MzUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*f1PB498M6RshUWre7oxG9w.jpeg" /></p>

<p>虽然还是实行全天人数管制，但人潮没有刚开幕的时候多了，我们是到现场才扫 QRCode 直接预约下一个时段 13:40 (还有空位)；如果怕扑空可以提早在线上预约。</p>

<blockquote>
  <p><em>吉伊卡哇 MOGUMOGU 本舗 川越店 预约、预先抽 <a href="https://reurl.cc/ekrR5x" target="_blank">整理券网址(点我)</a> 。</em></p>
</blockquote>

<blockquote>
  <p><em>请注意：一只手机一个帐号就是一个人，一天只能预约一次、一个时段</em></p>
</blockquote>

<p><strong>13:40 准时回到店门口排队入场</strong></p>

<p><img src="/assets/958599363857/1*NtS_w3kiOP3Z_zdVg45duQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*NtS_w3kiOP3Z_zdVg45duQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*vEMmOWjXOAfNvjloEDclgA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*vEMmOWjXOAfNvjloEDclgA.jpeg" /></p>

<p>商品货量都很充足，部分商品有限制每人最多购买数量，消费可以加价扭扭蛋。</p>

<p><strong>我的战利品：</strong></p>

<p><img src="/assets/958599363857/1*E4oKILRhstaUJTIRX-912Q.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*E4oKILRhstaUJTIRX-912Q.jpeg" /></p>

<p><img src="/assets/958599363857/1*Ctanxv2irMlgQ0HSQnwMNQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Ctanxv2irMlgQ0HSQnwMNQ.jpeg" /></p>

<blockquote>
  <p><em>地瓜兔兔是垂耳的，超级可爱！</em></p>
</blockquote>

<blockquote>
  <p><em>商品列表跟价格可 <a href="https://chiikawamogumogu.shop/collections/nuigurumimasukoxtuto" target="_blank">参考官网</a> 。</em></p>
</blockquote>

<blockquote>
  <p><em>大地瓜兔兔：¥2,970 日币 / 小地瓜吉伊卡哇：¥1,870 日币</em></p>
</blockquote>

<p><strong>其他还有 Miffy 米飞兔跟 Snoopy 专卖店</strong></p>

<p><img src="/assets/958599363857/1*8_7sCUHDuYn4_vMIl54Rcg.webp" alt="" loading="lazy" decoding="async" width="1200" height="846" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*8_7sCUHDuYn4_vMIl54Rcg.png" /></p>

<p><img src="/assets/958599363857/1*O9rii8mVXEZKpzy1wGqsuA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*O9rii8mVXEZKpzy1wGqsuA.jpeg" /></p>

<h4 id="在路上伴手礼店买了川越仙贝跟黑糖地瓜条">在路上伴手礼店买了川越仙贝跟黑糖地瓜条</h4>

<p><img src="/assets/958599363857/1*-l022L-y7yY7hAeZpzwOVg.webp" alt="" loading="lazy" decoding="async" width="1400" height="624" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjYyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*-l022L-y7yY7hAeZpzwOVg.png" /></p>

<blockquote>
  <p><em>海鲜的好吃，原味的很硬，黑糖地瓜条就是台湾的黑糖地瓜片饼干只是是条状。</em></p>
</blockquote>

<p>逛完时间接近 14:00，实在太饿太累了。</p>

<h4 id="旧第八十五银行本店本馆"><a href="https://maps.app.goo.gl/y9z4S4ApsRjsREY37" target="_blank">旧第八十五银行本店本馆</a></h4>

<p><img src="/assets/958599363857/1*BpgkEdsDYYvqfpgVuZBKgQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*BpgkEdsDYYvqfpgVuZBKgQ.jpeg" /></p>

<p>走到一个古迹建筑的二楼咖啡厅随便吃个东西再出发。</p>

<p><img src="/assets/958599363857/1*QcyUQuLZg3kb-TuYqJzERg.webp" alt="" loading="lazy" decoding="async" width="1200" height="857" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*QcyUQuLZg3kb-TuYqJzERg.png" /></p>

<blockquote>
  <p><em>如果不是因为太饿跟时间晚，应该会想去排荞麦面。</em></p>
</blockquote>

<p>吃完走到外面露台拍照：</p>

<p><img src="/assets/958599363857/1*ndOuiIyVVmYi3e5gCyr2Fw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*ndOuiIyVVmYi3e5gCyr2Fw.jpeg" /></p>

<p><strong>这里可以鸟瞰一番街商店，很美：</strong></p>

<p><img src="/assets/958599363857/1*4Q0Q_xZ45C5_xCsYbZp-Wg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*4Q0Q_xZ45C5_xCsYbZp-Wg.jpeg" /></p>

<blockquote>
  <p><em>露台这边是公共区域，不需要消费就可以进入。</em></p>
</blockquote>

<h4 id="1530-时之钟">15:30 <a href="https://maps.app.goo.gl/5zsx2vLHKZvrKmp3A" target="_blank">时之钟</a></h4>

<p>继续漫步小江户商店街到时之钟。</p>

<p><img src="/assets/958599363857/1*gqfXKCkDR8r32kbh52lX3w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*gqfXKCkDR8r32kbh52lX3w.jpeg" /></p>

<p><img src="/assets/958599363857/1*uPy0lTzewXYdF-GwaOSgrw.webp" alt="" loading="lazy" decoding="async" width="959" height="1225" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTkiIGhlaWdodD0iMTIyNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*uPy0lTzewXYdF-GwaOSgrw.png" /></p>

<p>买了旁边摊贩的章鱼烧仙贝当点心。</p>

<h4 id="大正浪漫梦通-商店街"><a href="https://maps.app.goo.gl/nyidMKyz3L48WvNA7" target="_blank">大正浪漫梦通</a> (商店街)</h4>

<p><img src="/assets/958599363857/1*SVz_ZtnmAp_L_yK-DFRJSQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*SVz_ZtnmAp_L_yK-DFRJSQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*gfbr5A94--q0WEdldobPsg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*gfbr5A94--q0WEdldobPsg.jpeg" /></p>

<p>最后再一路经过大正浪漫通，搭公车回川越站，准备回池袋。</p>

<h4 id="1625-回到川越站搭-东武东上线-回-池袋">16:25 回到川越站，搭 东武东上线 回 池袋</h4>

<p><img src="/assets/958599363857/1*geGRZVP6HHBY9TKrjrUSqQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="984" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*geGRZVP6HHBY9TKrjrUSqQ.png" /></p>

<h4 id="1710-池袋站-parco">17:10 池袋站 Parco</h4>

<p><img src="/assets/958599363857/1*w50-WxlZgKpVvH5aIQR7BQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="985" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*w50-WxlZgKpVvH5aIQR7BQ.png" /></p>

<p>回池袋后先在池袋站逛逛百货公司，这边有 Parco、东武百货，很多东西可以逛。</p>

<h4 id="吉伊卡哇咖啡厅the-guest-cafe--diner-ikebukuro--吉伊卡哇拉面chikawa-ramen-pork"><a href="https://maps.app.goo.gl/tGxXYhytPWoMXzY6A" target="_blank">吉伊卡哇咖啡厅(THE GUEST cafe &amp; diner Ikebukuro)</a> 、 <a href="https://maps.app.goo.gl/Xjj1pvnPpyyvUGH48" target="_blank">吉伊卡哇拉面(Chikawa Ramen Pork)</a></h4>

<p><img src="/assets/958599363857/1*DrWhK8JSk5XfcqqefpV_jA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*DrWhK8JSk5XfcqqefpV_jA.jpeg" /></p>

<p><img src="/assets/958599363857/1*cbhgmbw3iv1dQ6rB6c0VPA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*cbhgmbw3iv1dQ6rB6c0VPA.jpeg" /></p>

<p>这里楼上有两间吉伊卡哇餐厅，咖啡厅路过看预约全满、拉面是现场排队就能入场。</p>

<p><strong>排边还有一间周边转卖店，可以买餐厅系列吉伊卡哇:</strong></p>

<p><img src="/assets/958599363857/1*AsMwLutWXcmRiXED4rVSuA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*AsMwLutWXcmRiXED4rVSuA.jpeg" /></p>

<p><img src="/assets/958599363857/1*cOPdUeltj43X_CKspzfxCg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*cOPdUeltj43X_CKspzfxCg.jpeg" /></p>

<h4 id="1745-牛たん焼き-仙台辺见-池袋パルコ店">17:45 <a href="https://maps.app.goo.gl/PEMEHM7uMc8K5i6c8" target="_blank">牛たん焼き 仙台辺见 池袋パルコ店</a></h4>

<p><img src="/assets/958599363857/1*AInBZ1mRnIZ3T2US8N7r2Q.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*AInBZ1mRnIZ3T2US8N7r2Q.jpeg" /></p>

<p>接近晚餐时间，想说先在百货公司吃一吃，最后直接在 Parco 选择吃牛舌。</p>

<blockquote>
  <p><a href="https://www.n-rs.co.jp/brand/menu/en/henmi_menu_1565.pdf" target="_blank"><em>线上菜单：点此查看</em></a></p>
</blockquote>

<h4 id="1800-抽抽-隔天的-chiikawa-tokyo-station-吉伊卡哇东京车站-整理券想看宝宝-baby-系列">18:00 抽抽 隔天的 Chiikawa TOKYO Station 吉伊卡哇东京车站 整理券(想看宝宝 baby 系列)</h4>

<blockquote>
  <p><a href="https://chiikawa-info.jp/chiikawaland/tokyo/" target="_blank"><em>整理券网址：点此</em></a></p>
</blockquote>

<p><img src="/assets/958599363857/1*tEZULMHIAdtguLKCJzaZDw.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*tEZULMHIAdtguLKCJzaZDw.jpeg" /></p>

<p>Loading 转完….没抽到QQ，非常热门。</p>

<p><strong>抽完开始用餐：</strong></p>

<p><img src="/assets/958599363857/1*NKh1itXkvzs63EAiPtCZ6Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*NKh1itXkvzs63EAiPtCZ6Q.jpeg" /></p>

<blockquote>
  <p><em>这家店应该 <a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E5%B1%B1%E9%99%B0%E9%97%9C%E8%A5%BF%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E5%B3%B6%E6%A0%B9%E5%87%BA%E9%9B%B2%E6%9D%BE%E6%B1%9F%E9%B3%A5%E5%8F%96%E5%A7%AC%E8%B7%AF%E5%A4%A7%E9%98%AA%E7%A5%9E%E6%88%B67%E6%97%A5%E7%8D%A8%E6%97%85%E5%85%A8%E8%A8%98%E9%8C%84-aacd5f5cacd1/#%E8%A6%93%E9%A3%9F" target="_blank">曾经在别的地方外带吃过</a> ，牛舌口感跟味道都很好，汤有点像牛肉汤很好喝！</em></p>
</blockquote>

<h4 id="1900-池袋逛街">19:00 池袋逛街</h4>

<p>吃饱继续逛街。</p>

<p><img src="/assets/958599363857/1*VJ9rPJWTSgULeGzvtPEMFg.webp" alt="" loading="lazy" decoding="async" width="939" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzkiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*VJ9rPJWTSgULeGzvtPEMFg.png" /></p>

<p><img src="/assets/958599363857/1*BeovdjRzqdZdRxU1086meg.webp" alt="" loading="lazy" decoding="async" width="942" height="1273" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDIiIGhlaWdodD0iMTI3MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*BeovdjRzqdZdRxU1086meg.png" /></p>

<p><img src="/assets/958599363857/1*XAtHfdnJdmXLQGFJxxyHaA.webp" alt="" loading="lazy" decoding="async" width="929" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjkiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*XAtHfdnJdmXLQGFJxxyHaA.png" /></p>

<p>池袋这边也很热闹，人很多店也很多。</p>

<h4 id="chiikawa-park"><a href="https://maps.app.goo.gl/H9nivHDc5i8ySG18A" target="_blank">Chiikawa Park</a></h4>

<p><img src="/assets/958599363857/1*15SBRn2tB_oNRXAztKzWdQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*15SBRn2tB_oNRXAztKzWdQ.jpeg" /></p>

<p>Chiikawa Park 也在这边，不过时间晚已经关门了。</p>

<h4 id="1915-太阳城--gashapon-ikebukuro-main-store-扭蛋百货公司--世界最大扭蛋店3000台">19:15 <a href="https://maps.app.goo.gl/sMrThaudF2VwjBGP8" target="_blank">太阳城</a> — <a href="https://maps.app.goo.gl/6JgukBwhaJmmoAFQ7" target="_blank">Gashapon Ikebukuro Main Store 扭蛋百货公司 — 世界最大扭蛋店(3000+台)</a></h4>

<p><img src="/assets/958599363857/1*HFUXnWbMb_i-gSmgTzNdZQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1006" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMDYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*HFUXnWbMb_i-gSmgTzNdZQ.png" /></p>

<p>一路走到世界最大扭蛋店，寻觅战利品。</p>

<blockquote>
  <p><em>最后没扭什么，这边机台虽然多但是没看到什么特别的而且分类蛮乱的逛得眼花撩乱。</em></p>
</blockquote>

<h4 id="2010-回池袋站--回饭店休息">20:10 回池袋站 — 回饭店休息</h4>

<p><img src="/assets/958599363857/1*N6AmcHvBHP0LeQswh9iXSQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*N6AmcHvBHP0LeQswh9iXSQ.jpeg" /></p>

<p><strong>本日宵夜：</strong></p>

<p><img src="/assets/958599363857/1*pjTtrIIs2qmtQmlun7-P1A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*pjTtrIIs2qmtQmlun7-P1A.jpeg" /></p>

<p>经典豆皮泡面＋超商炸鸡＋酒。</p>

<h3 id="day-30915-一--东京车站一番街热海烟花大会">Day 3(09/15 一) — 东京车站一番街、热海烟花大会</h3>

<p>预计搭乘下午 14:57 的新干线前往热海。</p>

<p><strong>此行的重点行程 — 热海花火大会</strong> ；一早睡到饱才出门。</p>

<h4 id="1110-东京车站">11:10 东京车站</h4>

<p><img src="/assets/958599363857/1*pohebZUwh5jI-z7iyBsUfQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="860" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*pohebZUwh5jI-z7iyBsUfQ.png" /></p>

<p>接近中午，先在车站内觅食。</p>

<p><img src="/assets/958599363857/1*lUVuLvW3e19wluc4X3LupA.webp" alt="" loading="lazy" decoding="async" width="1200" height="865" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*lUVuLvW3e19wluc4X3LupA.png" /></p>

<p><strong>东京车站也有一家 <a href="https://maps.app.goo.gl/vkmPHf4j6SgRGprb8" target="_blank">极味屋</a></strong> ，不过人超多，11:00 才开始营业就很多人在排队了，目测应该要排个一小时左右。</p>

<p>转头去吃对面的神户牛。</p>

<h4 id="kobebeef-daia-tokyo-station-store--神戸牛ダイア-东京駅店"><a href="https://maps.app.goo.gl/K1grYFDpH52WxMkdA" target="_blank">Kobebeef Daia tokyo station store — 神戸牛ダイア 东京駅店</a></h4>

<p><img src="/assets/958599363857/1*67WiU_TZIuxie7OBx31Z6w.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*67WiU_TZIuxie7OBx31Z6w.jpeg" /></p>

<p><img src="/assets/958599363857/1*ybIjFMLqTTSnvUne_N2qwA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*ybIjFMLqTTSnvUne_N2qwA.jpeg" /></p>

<blockquote>
  <p><em>怀念的好滋味， <a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E5%B1%B1%E9%99%B0%E9%97%9C%E8%A5%BF%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E5%B3%B6%E6%A0%B9%E5%87%BA%E9%9B%B2%E6%9D%BE%E6%B1%9F%E9%B3%A5%E5%8F%96%E5%A7%AC%E8%B7%AF%E5%A4%A7%E9%98%AA%E7%A5%9E%E6%88%B67%E6%97%A5%E7%8D%A8%E6%97%85%E5%85%A8%E8%A8%98%E9%8C%84-aacd5f5cacd1/#1700-%E7%A5%9E%E6%88%B8%E7%89%9B-%E5%90%89%E7%A5%A5%E5%90%89" target="_blank">上次去神户也特别去吃神户牛</a> (吉祥吉)，价格上东京大约比神户产地约贵 ¥8,000 日币 (Prime Kobe beef 沙朗 220g 东京 ¥39,160 / 神户 ¥31,600)。</em></p>
</blockquote>

<p><img src="/assets/958599363857/1*d8dRk0mNMIBZ2WRlRvxdpQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*d8dRk0mNMIBZ2WRlRvxdpQ.jpeg" /></p>

<p>跟怀念中的滋味一样，肉很嫩、没有异味只有牛肉该有的香气；不知不觉一下就吃完了！</p>

<h4 id="1220-开逛东京车站地下一番街">12:20 开逛东京车站地下一番街</h4>

<p><img src="/assets/958599363857/1*L0hqu-EQj9j98YtOCGqfWw.webp" alt="" loading="lazy" decoding="async" width="942" height="1214" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDIiIGhlaWdodD0iMTIxNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*L0hqu-EQj9j98YtOCGqfWw.png" /></p>

<p><img src="/assets/958599363857/1*8RfVcL7vNuaLnQ8RTqx77Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="995" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*8RfVcL7vNuaLnQ8RTqx77Q.png" /></p>

<p>地下街人很多，什么 IP 几乎都有，三丽鸥、航海王、Jump Store、拉拉熊、橡子共和国、Snoopy、Chiikawa. .等等</p>

<h4 id="chiikawa-baby-tokyto-station"><a href="https://maps.app.goo.gl/ujTHi4i1YM2Jhq7u6" target="_blank">Chiikawa baby Tokyto station</a></h4>

<p><img src="/assets/958599363857/1*5FO6T-tcqFfmD6qWrHfhTw.webp" alt="" loading="lazy" decoding="async" width="953" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*5FO6T-tcqFfmD6qWrHfhTw.png" /></p>

<p><img src="/assets/958599363857/1*c2ParIuNtMQ0WReypFW_AQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*c2ParIuNtMQ0WReypFW_AQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*14U3tJHvWtVDyF7A2XM3Gg.webp" alt="" loading="lazy" decoding="async" width="1400" height="995" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*14U3tJHvWtVDyF7A2XM3Gg.png" /></p>

<p>没抽到 <a href="https://chiikawa-info.jp/chiikawaland/tokyo/" target="_blank">整理券</a> ，只能路过拍拍照，货量看起来很充足、人很少(感觉又控制太少人了？)</p>

<p><img src="/assets/958599363857/1*RhUU4XWAV_mo818lqez6qw.webp" alt="" loading="lazy" decoding="async" width="1200" height="843" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*RhUU4XWAV_mo818lqez6qw.png" /></p>

<p>逛不够还可以去隔壁大丸百货或继续走到其他周围地下街。</p>

<h4 id="1400-东京车站退税寄物">14:00 东京车站退税、寄物</h4>

<p><img src="/assets/958599363857/1*V1V-6jaK-XgaIJtFUqaUTQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="857" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*V1V-6jaK-XgaIJtFUqaUTQ.png" /></p>

<p>在东京车站购物要退税可以直接回到一楼，找到东海道山阳新干线日本桥口对面的退税柜台退税。</p>

<p><img src="/assets/958599363857/1*Y0o7PYsSkdhHB0F-pdG6jQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Y0o7PYsSkdhHB0F-pdG6jQ.jpeg" /></p>

<p>买了一些东西，因为寄物柜台只开到晚上 20:00，所以找置物柜寄物，这边也有很多置物柜可以使用。</p>

<blockquote>
  <p><em>寄物完又去逛美食街买了一些吃的准备在路上吃。</em></p>
</blockquote>

<h4 id="1430-准备搭车前往热海">14:30 准备搭车前往热海</h4>

<p><img src="/assets/958599363857/1*PgBfGRbUfgWsyh1i24C8Mw.webp" alt="" loading="lazy" decoding="async" width="947" height="1057" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDciIGhlaWdodD0iMTA1NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*PgBfGRbUfgWsyh1i24C8Mw.png" /></p>

<p>ㄧ样是在东海道山阳新干线日本桥口进站。</p>

<p><img src="/assets/958599363857/1*0PMsHuVFQWeAGUgHwpO7pA.webp" alt="" loading="lazy" decoding="async" width="950" height="1160" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTAiIGhlaWdodD0iMTE2MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*0PMsHuVFQWeAGUgHwpO7pA.png" /></p>

<p><img src="/assets/958599363857/1*OKIhEwPPdSa-tDFMyiHC_A.webp" alt="" loading="lazy" decoding="async" width="854" height="1262" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NTQiIGhlaWdodD0iMTI2MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*OKIhEwPPdSa-tDFMyiHC_A.png" /></p>

<p>在 <a href="https://www.kkday.com/zh-tw/transportation/japan-rail?cid=19365" target="_blank">KKday</a> / <a href="https://affiliate.klook.com/redirect?aid=99683&amp;aff_adid=1134759&amp;k_site=https%3A%2F%2Fwww.klook.com%2Fzh-TW%2Fjapan-rail%2F" target="_blank">Klook</a> 预先购买的电子车票，不用再去换票，直接走蓝色闸门把手机 QRCode 紧贴感应区域即可进站。</p>

<p><img src="/assets/958599363857/1*8XhMmWSYamkoIpZcrcexiw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*8XhMmWSYamkoIpZcrcexiw.jpeg" /></p>

<p>进站成功会吐出车票(纯方便看资讯或车上遇到验票用)，出入站还是要用手机 QRCode。</p>

<p><img src="/assets/958599363857/1*VjszDJiQ3FvhmPZ6lezlaQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*VjszDJiQ3FvhmPZ6lezlaQ.jpeg" /></p>

<h4 id="1457-东京出发前往热海">14:57 东京出发前往热海</h4>

<p><img src="/assets/958599363857/1*LtxEb2m13uqztgio8zrwrA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*LtxEb2m13uqztgio8zrwrA.jpeg" /></p>

<p><img src="/assets/958599363857/1*zEZdPMxvFTM1ZdGGClg_SQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*zEZdPMxvFTM1ZdGGClg_SQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*lMSwYOhx4zEClwuaRJqpnw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*lMSwYOhx4zEClwuaRJqpnw.jpeg" /></p>

<p>小吃小憩一下。</p>

<h4 id="1542-抵达热海">15:42 抵达热海</h4>

<p><img src="/assets/958599363857/1*6snvQ0gvBAze0Z4Poh7ywg.webp" alt="" loading="lazy" decoding="async" width="1200" height="868" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*6snvQ0gvBAze0Z4Poh7ywg.png" /></p>

<p><img src="/assets/958599363857/1*bMpYH8-Dvf2iqufVYC1w0w.webp" alt="" loading="lazy" decoding="async" width="954" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*bMpYH8-Dvf2iqufVYC1w0w.png" /></p>

<p><img src="/assets/958599363857/1*ECAXngp1TSBZehMFgTfruw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*ECAXngp1TSBZehMFgTfruw.jpeg" /></p>

<p>欢迎莅临 2025 热海海上花火大会！</p>

<blockquote>
  <p><em>官方温馨提醒：花火大会结束会很多人，请提前购买新干线车票。</em></p>
</blockquote>

<p>新干线出站后还要再通过在来线闸口(给工作人员看车票 QRCode 即可出来)。</p>

<p><img src="/assets/958599363857/1*MzafXGx-5W__v6ER9L55qg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*MzafXGx-5W__v6ER9L55qg.jpeg" /></p>

<p>天气阴阴，但优点是不会太晒！</p>

<p><img src="/assets/958599363857/1*sfEvxO-r_6o1zXerVBmmxw.webp" alt="光荣的烧肉之路" loading="lazy" decoding="async" width="1200" height="675" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY3NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*sfEvxO-r_6o1zXerVBmmxw.png" /></p>

<p>光荣的烧肉之路</p>

<p><img src="/assets/958599363857/1*7-Gke4s_SdS3Ak7FshhbYw.webp" alt="" loading="lazy" decoding="async" width="942" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDIiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*7-Gke4s_SdS3Ak7FshhbYw.png" /></p>

<p><img src="/assets/958599363857/1*klSuH4wuVQev1vAE8uhrzg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*klSuH4wuVQev1vAE8uhrzg.jpeg" /></p>

<p><img src="/assets/958599363857/1*NoN8BV-7HvjIqgoMvrNo_Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*NoN8BV-7HvjIqgoMvrNo_Q.jpeg" /></p>

<p>穿过商店街出来一路往下走就会到海滩了。</p>

<p><img src="/assets/958599363857/1*xsPseN91hTY7i51fJPjcTA.webp" alt="" loading="lazy" decoding="async" width="963" height="1126" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjMiIGhlaWdodD0iMTEyNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*xsPseN91hTY7i51fJPjcTA.png" /></p>

<p><a href="https://maps.app.goo.gl/xZ6QHf3UAWu4iXtD8" target="_blank">路线如上图</a> ，先走去 Lawson 买一些吃的喝的再去海滩野餐＋等烟火。</p>

<p><img src="/assets/958599363857/1*x0YEr4v70zdBu1cMZyq7zw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*x0YEr4v70zdBu1cMZyq7zw.jpeg" /></p>

<p><img src="/assets/958599363857/1*OSrew6n7pXgiQMkmz6TFrw.webp" alt="" loading="lazy" decoding="async" width="1200" height="880" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg4MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*OSrew6n7pXgiQMkmz6TFrw.png" /></p>

<p>烟火大约在上图位置释放，可以走到 <a href="https://maps.app.goo.gl/XZmFfi3wDBJFERyQ8" target="_blank">Higashikaigancho</a> 靠后面的位置沙滩等待，这里海滩也能下去玩水、附近也有共用厕所、卫浴可以换洗。(但建议先查一下，有些设备感觉年久失修了)</p>

<p><img src="/assets/958599363857/1*93jLDQa0cb1jewFvsazD9Q.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*93jLDQa0cb1jewFvsazD9Q.jpeg" /></p>

<p>热海沙滩还能远眺热海城。</p>

<h4 id="1700-热海阳光沙滩">17:00 热海阳光沙滩</h4>

<p><img src="/assets/958599363857/1*MaQ6luHYefGS_EdREO8Z8A.webp" alt="" loading="lazy" decoding="async" width="960" height="1706" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjAiIGhlaWdodD0iMTcwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*MaQ6luHYefGS_EdREO8Z8A.jpeg" /></p>

<p>感觉不用这么早到热海，人没有想像中多；大概 18:30 之前来都还有沙滩位子，即使是到 20:20 烟火释放，要来看都还有位。</p>

<p><img src="/assets/958599363857/1*7TaD649tgt3KS0hfcDNuzg.webp" alt="" loading="lazy" decoding="async" width="1200" height="675" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY3NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*7TaD649tgt3KS0hfcDNuzg.jpeg" /></p>

<h4 id="1800-热海烟火大会-海滩人潮">18:00 热海烟火大会 海滩人潮</h4>

<p><img src="/assets/958599363857/1*_FH0OfAii22pyLOikGi2Tg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*_FH0OfAii22pyLOikGi2Tg.jpeg" /></p>

<p><img src="/assets/958599363857/1*ET9HOKp_AUG6BXKz9YFRfQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*ET9HOKp_AUG6BXKz9YFRfQ.jpeg" /></p>

<p>可以看到 18:00 还有很多位子，或是很多人是先来放野餐垫占位就去周围逛逛，快到烟火再回来。</p>

<p><strong>再往后面走一点 <a href="https://maps.app.goo.gl/fYK3FxCFxZ8oMzRj6" target="_blank">大约在 Sky Deck 的地方</a> ，有一个小夜市有卖吃的(CP值不高就是了)：</strong></p>

<p><img src="/assets/958599363857/1*ABMNXDPrn2rHZ_BT_q6piA.webp" alt="" loading="lazy" decoding="async" width="1200" height="841" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*ABMNXDPrn2rHZ_BT_q6piA.png" /></p>

<p>海滩周围也都有厕所，不怕没得上。</p>

<h4 id="2015-接近烟火释放时间的海滩人潮">20:15 接近烟火释放时间的海滩人潮</h4>

<p><img src="/assets/958599363857/1*MhEq7Oix6_1SHWcLHWXxLg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*MhEq7Oix6_1SHWcLHWXxLg.jpeg" /></p>

<p><img src="/assets/958599363857/1*GltFsKbSIEPBGCU0tujfHQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*GltFsKbSIEPBGCU0tujfHQ.jpeg" /></p>

<p>后面(步道)的人很多。</p>

<h4 id="2020-花火大会开始">20:20 花火大会开始</h4>

<p><img src="/assets/958599363857/1*tQkiAdu0D5xhrsRaSwx2ow.webp" alt="" loading="lazy" decoding="async" width="1400" height="788" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijc4OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*tQkiAdu0D5xhrsRaSwx2ow.jpeg" /></p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/mI8vaJUpAzY" title="2025/09/15 熱海煙花大會" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p><img src="/assets/958599363857/1*qsOMKdPSeRp3svZjdxg0bw.webp" alt="" loading="lazy" decoding="async" width="1200" height="831" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgzMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*qsOMKdPSeRp3svZjdxg0bw.png" /></p>

<p>烟火有好几 Part 一路放到 20:40 (20分钟)，最喜欢的 Part 是一整面的壮丽烟火，可惜今天湿气太重，到后面烟有点散不太开。</p>

<h4 id="2045-开始离场">20:45 开始离场</h4>

<p><img src="/assets/958599363857/1*Is19CY4ydHSl6o_koAwUxw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Is19CY4ydHSl6o_koAwUxw.jpeg" /></p>

<p><img src="/assets/958599363857/1*-Op_qDpZVTPamDHpMjrLGA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*-Op_qDpZVTPamDHpMjrLGA.jpeg" /></p>

<p>离场的人潮非常多，不过大家都很有秩序地慢慢往车站移动；来的时候是下坡，回去是上坡（累）。</p>

<h4 id="2105-回到热海站">21:05 回到热海站</h4>

<p><img src="/assets/958599363857/1*0YVBx1LVIM38oZnnFl-uHw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*0YVBx1LVIM38oZnnFl-uHw.jpeg" /></p>

<p><img src="/assets/958599363857/1*AAk3JHAyjLZtD47VozQxhQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="856" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*AAk3JHAyjLZtD47VozQxhQ.png" /></p>

<p>回程人多大约要 20–25 分钟才能走回热海站，进站人数也超多；如果是搭在来线(当地铁路)要排队慢慢进站， <strong>如果是你已经买好新干线车票可以直接走右边人工通道穿过再来线上去新干线搭乘。</strong></p>

<blockquote>
  <p><em>本来怕时间太赶，所以买 22:02 分热海回东京的车票；看现场情况应该早一班的 21:26 时间也是绰绰有余</em></p>
</blockquote>

<h4 id="2120-进站候车">21:20 进站候车</h4>

<p><img src="/assets/958599363857/1*FlXrgL64tIESh9YANzlCgA.webp" alt="" loading="lazy" decoding="async" width="1400" height="864" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijg2NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*FlXrgL64tIESh9YANzlCgA.png" /></p>

<p><img src="/assets/958599363857/1*P8UbBT810VfOu1d-FjmGfQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*P8UbBT810VfOu1d-FjmGfQ.jpeg" /></p>

<p>新干线这里很空旷、冷气很凉。</p>

<p><img src="/assets/958599363857/1*1yTYNHadfcjXGCssVCOYuQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*1yTYNHadfcjXGCssVCOYuQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*Xh7kHOo5wLCsZq0HsfcxjA.webp" alt="" loading="lazy" decoding="async" width="1200" height="882" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg4MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Xh7kHOo5wLCsZq0HsfcxjA.png" /></p>

<p>投了一罐苹果汽水续命，遇到其他地区大雨影响，所有班次都误点。</p>

<h4 id="2225-上车延误近-20-分钟">~=22:25 上车(延误近 20 分钟)</h4>

<p><img src="/assets/958599363857/1*ffvGyMO0-1naq-JFmy9kfw.webp" alt="" loading="lazy" decoding="async" width="941" height="1192" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDEiIGhlaWdodD0iMTE5MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*ffvGyMO0-1naq-JFmy9kfw.png" /></p>

<h4 id="-2310-抵达东京">~= 23:10 抵达东京</h4>

<p>转搭山手线回新桥。</p>

<p><img src="/assets/958599363857/1*JUzg76hP_ZQMXHzkFKDmdA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*JUzg76hP_ZQMXHzkFKDmdA.jpeg" /></p>

<h4 id="-2340-回到饭店休息">~= 23:40 回到饭店休息</h4>

<p><img src="/assets/958599363857/1*xcMi52GR3TaBBuVYXjAVjg.webp" alt="" loading="lazy" decoding="async" width="1200" height="846" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*xcMi52GR3TaBBuVYXjAVjg.png" /></p>

<p><img src="/assets/958599363857/1*TZma2hnWNg9KTatodIad5w.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*TZma2hnWNg9KTatodIad5w.jpeg" /></p>

<p>真是充实的一天！</p>

<h3 id="day-40916-二-麻布台-teamlab原宿逛街水獭咖啡厅">Day 4(09/16 二) —麻布台 Teamlab、原宿逛街、水獭咖啡厅</h3>

<p>睡饱搭公车出门。</p>

<h4 id="1010-抵达-麻布台之森">10:10 抵达 <a href="https://maps.app.goo.gl/PbjLmES23cBRVRwK6" target="_blank">麻布台之森</a></h4>

<p><img src="/assets/958599363857/1*Vxi-ROH7326xUK1Q_RaSSA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Vxi-ROH7326xUK1Q_RaSSA.jpeg" /></p>

<p>我以为麻布台之森只有 <a href="https://maps.app.goo.gl/yyYwwHoZbHBmysqN6" target="_blank">JP Tower</a> ，原来是一整片的碎片建筑群，有很多百货柜位、吃的。</p>

<p><img src="/assets/958599363857/1*l04M339xYWoaX0St4PmTGA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*l04M339xYWoaX0St4PmTGA.jpeg" /></p>

<p>先去咖啡厅吃早餐跟醒脑。</p>

<h4 id="1050-前往-teamlab-borderless-mori-building-digital-art-museum-azabudai-hills-garden-plaza-b-b1">10:50 <a href="https://maps.app.goo.gl/a1VeYdbgBhvPCPXC7" target="_blank">前往 teamLab Borderless: MORI Building DIGITAL ART MUSEUM (Azabudai Hills Garden Plaza B, B1)</a></h4>

<p><img src="/assets/958599363857/1*G2WDXXLUhC1r2oueJDxDcQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*G2WDXXLUhC1r2oueJDxDcQ.jpeg" /></p>

<p>里面没有地图，如果想全部探索可以先在外面拿官方手册。</p>

<p><img src="/assets/958599363857/1*GKfgsOIo0qXpIshU_0N3UA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*GKfgsOIo0qXpIshU_0N3UA.jpeg" /></p>

<p><img src="/assets/958599363857/1*6BC5_ZTb1w6zcBWf5mNeng.webp" alt="" loading="lazy" decoding="async" width="1400" height="982" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*6BC5_ZTb1w6zcBWf5mNeng.png" /></p>

<p>右转有免费置物区，置物完给工作人员验票就能入场。</p>

<h4 id="1100-teamlab-borderless">11:00 <a href="https://maps.app.goo.gl/a1VeYdbgBhvPCPXC7" target="_blank">teamLab Borderless</a></h4>

<p><img src="/assets/958599363857/1*ZgsR6mKRK6TjNZkS22p_7A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*ZgsR6mKRK6TjNZkS22p_7A.jpeg" /></p>

<p><img src="/assets/958599363857/1*UXRiHpWae9wvx-9kSnGZjQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*UXRiHpWae9wvx-9kSnGZjQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*w3vwhwr_94ICABHOe_z46Q.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*w3vwhwr_94ICABHOe_z46Q.jpeg" /></p>

<p><img src="/assets/958599363857/1*nMWtkgSZwXV7BDd0PHLNig.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*nMWtkgSZwXV7BDd0PHLNig.jpeg" /></p>

<p><img src="/assets/958599363857/1*kTlH8oGRnbrMmf3L_nWSrg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*kTlH8oGRnbrMmf3L_nWSrg.jpeg" /></p>

<p>teamlab 真的很赞，里有各种很魔幻、有创意，让人觉得不像是真实世界能有的场景，互动包括光影、镜面、球体、柱状、叶子、气雾…等等，而且几乎都是 360 度全场景，很有沈浸感。</p>

<blockquote>
  <p><em>没有地图，所有展场房间要自己探索，如果女生穿裙子怕走光也会在入口贴心提供围裙可以使用。</em></p>
</blockquote>

<blockquote>
  <p><em>每个房间入场前几乎都会有工作人员说明，几乎都是请勿触碰、小心走路。</em></p>
</blockquote>

<blockquote>
  <p><em>里面有厕所但要自己找指标或问工作人员。</em></p>
</blockquote>

<p><img src="/assets/958599363857/1*rOQik1WqrSYIlOlNE8GCNg.webp" alt="" loading="lazy" decoding="async" width="665" height="1182" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NjUiIGhlaWdodD0iMTE4MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*rOQik1WqrSYIlOlNE8GCNg.jpeg" /></p>

<p>拍照起来也很魔幻。</p>

<p><img src="/assets/958599363857/1*-QUcAm5LHPzXTaNqzEe-2g.webp" alt="To have seen something, is to not have seen something else" loading="lazy" decoding="async" width="1200" height="515" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjUxNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*-QUcAm5LHPzXTaNqzEe-2g.png" /></p>

<p>To have seen something, is to not have seen something else</p>

<blockquote>
  <p><em>大约逛到 12:15 才离场，但不能保证都有逛到；要不是肚子饿要在里面玩了两三个小时应该不是问题。</em></p>
</blockquote>

<h4 id="harbs-麻布台之丘店"><a href="https://maps.app.goo.gl/GYvhb3ucV6Xykrtr9" target="_blank">HARBS 麻布台之丘店</a></h4>

<p><img src="/assets/958599363857/1*H3hzyw1S7R8QJqGClj7-Kg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*H3hzyw1S7R8QJqGClj7-Kg.jpeg" /></p>

<p>teamlab 逛完出来就有一家 HARBS，先吃个水果千层蛋糕垫垫胃。</p>

<blockquote>
  <p><a href="https://www.harbs.co.jp/zh-TW/allmenu/flag/" target="_blank"><em>线上菜单：点我查看。</em></a></p>
</blockquote>

<p><img src="/assets/958599363857/1*KofxiaB6kF2_MBL4_xSMJA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*KofxiaB6kF2_MBL4_xSMJA.jpeg" /></p>

<p>招牌水果千层蛋糕(Mille Crepes/ミルクレープ) 1カット ￥1,050 ＋ 低消一杯饮料。</p>

<blockquote>
  <p><em>里面有哈密瓜(好甜好好吃) +香蕉+奇异果。</em></p>
</blockquote>

<h4 id="1320-东京铁塔">13:20 东京铁塔</h4>

<p><img src="/assets/958599363857/1*bxUphy3A0fYyf5koQkTQNw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*bxUphy3A0fYyf5koQkTQNw.jpeg" /></p>

<p><a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E6%9D%B1%E4%BA%AC%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-5-%E5%A4%A9%E9%A3%9F%E4%BD%8F%E8%A1%8C%E5%85%A8%E8%A8%98%E9%8C%84%E8%88%87%E5%BF%85%E8%A8%AA%E6%99%AF%E9%BB%9E%E6%8E%A8%E8%96%A6-9da2c51fa4f2/#%E6%9D%B1%E4%BA%AC%E9%90%B5%E5%A1%94" target="_blank">上次有来过还有上去 <strong>(请参考之前的游记)</strong></a> ，这次只有路过拍拍照就走了。</p>

<p>搭车前往原宿。</p>

<h4 id="1400-原宿">14:00 原宿</h4>

<p><img src="/assets/958599363857/1*6SJEx_1Xe1cRtxNtxCACUw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*6SJEx_1Xe1cRtxNtxCACUw.jpeg" /></p>

<p>一出来又又又看到吉伊卡哇， <a href="https://maps.app.goo.gl/Qo9uS7tVHoRda1MQ7" target="_blank">东急Plaza表参道原宿</a> 楼上有 <a href="https://maps.app.goo.gl/7rPeXTvCVEtWonMd7" target="_blank">吉伊卡哇面包店</a> 。</p>

<h4 id="伊卡哇面包店-chiikawa-bakery"><a href="https://maps.app.goo.gl/7rPeXTvCVEtWonMd7" target="_blank">伊卡哇面包店</a> Chiikawa Bakery</h4>

<p><img src="/assets/958599363857/1*z3t6dt_iKNpI2quFtdIylg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*z3t6dt_iKNpI2quFtdIylg.jpeg" /></p>

<p><img src="/assets/958599363857/1*AZPe4DkecEm5YCnjvnokvA.webp" alt="" loading="lazy" decoding="async" width="879" height="1157" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzkiIGhlaWdodD0iMTE1NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*AZPe4DkecEm5YCnjvnokvA.png" /></p>

<p>左边真的吃的面包、果酱店需要抽整理券入场；右边周边娃娃店则不用。</p>

<p>(因为只是刚好路过就不进去了)</p>

<blockquote>
  <p><a href="https://airwait.jp/WCSP/storeDetail?storeNo=AKR3416883372&amp;langType=KeyTW" target="_blank"><em>点此线上排队，领取号码牌</em></a></p>
</blockquote>

<p><img src="/assets/958599363857/1*W-7h4iIZMQRL6yk5WL7IQQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*W-7h4iIZMQRL6yk5WL7IQQ.jpeg" /></p>

<p>吃的，面包店的部分。</p>

<p><img src="/assets/958599363857/1*zPGCxhXve2PB8gO21lFyLg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*zPGCxhXve2PB8gO21lFyLg.jpeg" /></p>

<p><img src="/assets/958599363857/1*AQGlxwc5OIDgwn8dJ62YRw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*AQGlxwc5OIDgwn8dJ62YRw.jpeg" /></p>

<p><img src="/assets/958599363857/1*BAveEbCyszfKzZc3L7CE9w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*BAveEbCyszfKzZc3L7CE9w.jpeg" /></p>

<p>周边商店这边货源蛮充足的，不过我已经了地瓜不能再买了，只有看看没买。</p>

<h4 id="kiddy-land-キデイランド-原宿店"><a href="https://maps.app.goo.gl/JBGBKiEBNdcycYPz8" target="_blank">Kiddy Land キデイランド 原宿店</a></h4>

<p>出来之后又去附近另一家 Kiddy Land 逛逛。( <a href="https://www.kiddyland.co.jp/harajuku/" target="_blank">但这家没有吉伊卡哇</a> )</p>

<p><img src="/assets/958599363857/1*WTTkpsTLZ9_35_KVXD01wQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*WTTkpsTLZ9_35_KVXD01wQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*KG4Y3IlpSLIcD-SOBxb4Ug.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*KG4Y3IlpSLIcD-SOBxb4Ug.jpeg" /></p>

<p>有很多 Snoopy、三丽鸥、宝可梦、拉拉熊…等等 IP</p>

<p>逛一逛时间接近下午 15:00 了，中午只吃了一块水果千层，有点饥饿，随便找了一家路过评价蛮高的美式汉堡店吃吃。</p>

<h4 id="1450-the-great-burger"><a href="https://maps.app.goo.gl/xgoLanLfSSYFC5jP9" target="_blank">14:50 The Great Burger</a></h4>

<p><img src="/assets/958599363857/1*CxJhjOkE7NSkV2wwiZWlWA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*CxJhjOkE7NSkV2wwiZWlWA.jpeg" /></p>

<p><img src="/assets/958599363857/1*0wzaWAsar2xUmujgMfHVUg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*0wzaWAsar2xUmujgMfHVUg.jpeg" /></p>

<p>特色是和牛小汉堡。</p>

<p><img src="/assets/958599363857/1*Anb4bgPGloM3oNkV6btS-g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*Anb4bgPGloM3oNkV6btS-g.jpeg" /></p>

<p><img src="/assets/958599363857/1*2x_JAyGUZmJ58CSR30Rr7A.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*2x_JAyGUZmJ58CSR30Rr7A.jpeg" /></p>

<p>味道还不错，只是吃太多会很腻。</p>

<h4 id="1540-原宿逛街">15:40 原宿逛街</h4>

<p>吃完继续在原宿逛逛等傍晚(16:30)去预约的水獭咖啡厅。</p>

<p><img src="/assets/958599363857/1*sWQbbQUfLq3EWzMhJrvTng.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*sWQbbQUfLq3EWzMhJrvTng.jpeg" /></p>

<p><img src="/assets/958599363857/1*XyVXantdzPWEZA0pYpTXKA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*XyVXantdzPWEZA0pYpTXKA.jpeg" /></p>

<p><img src="/assets/958599363857/1*EfEP8VdYHAbuyxi2C6EFSA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*EfEP8VdYHAbuyxi2C6EFSA.jpeg" /></p>

<p>随便乱逛又走来上次就是在这家 Le Labo 买香水的店，2025 日本境内价格 50ml 香水：¥31,350 日币，退税完差不多 ¥28,500。</p>

<h4 id="1630-harry-harajuku-terrace-水獭咖啡厅">16:30 <a href="https://maps.app.goo.gl/WHyJ88K5hRVc4vnk9" target="_blank">HARRY HARAJUKU terrace 水獭咖啡厅</a></h4>

<p><img src="/assets/958599363857/1*b20FSUf7uuIrFFNRLP6vwQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*b20FSUf7uuIrFFNRLP6vwQ.jpeg" /></p>

<p>在这栋建筑的顶楼，走旁边的楼梯上去。</p>

<p><img src="/assets/958599363857/1*eoDe1nHReBDY4bv070eEBQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*eoDe1nHReBDY4bv070eEBQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*x3phhvrHJ3ocidaw3glJLw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*x3phhvrHJ3ocidaw3glJLw.jpeg" /></p>

<p><img src="/assets/958599363857/1*CpEDCXiZ8Js_st4tzrXtGA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*CpEDCXiZ8Js_st4tzrXtGA.jpeg" /></p>

<p>场地不大，外面有三个水池有三只水獭在里面趴趴走，可以买零食喂他(¥880)。 (会伸手手)</p>

<p><img src="/assets/958599363857/1*U30ypE-233jdjvcR0aejGA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*U30ypE-233jdjvcR0aejGA.jpeg" /></p>

<p>咖啡就是贩卖机自己按的咖啡。(买 30 分钟附赠 1 杯)</p>

<p><img src="/assets/958599363857/1*fBpOYC967t_nalgHfuGCEg.webp" alt="" loading="lazy" decoding="async" width="1200" height="872" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg3MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*fBpOYC967t_nalgHfuGCEg.png" /></p>

<p><img src="/assets/958599363857/1*3dL7ITdswBmvR6KUU9MQSw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*3dL7ITdswBmvR6KUU9MQSw.jpeg" /></p>

<p>里面的话场地也不大，中间一曲水獭付费互动区(要加价)、旁边是龙猫互动区(要加价)，另一边是免费的刺猬互动区，跟几只在栅栏里的水獭。</p>

<p><img src="/assets/958599363857/1*L1tbx1lOqgPbpgBmEhGkVA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*L1tbx1lOqgPbpgBmEhGkVA.jpeg" /></p>

<p>我们加了 ¥880/人 跟水獭亲密互动 5 分钟，不然其实都摸不到。</p>

<h4 id="1720-摸摸水獭">17:20 <a href="https://maps.app.goo.gl/WHyJ88K5hRVc4vnk9" target="_blank">摸摸水獭</a></h4>

<blockquote>
  <p><em>跟水獭互动的游客蛮多的，到 17:20 才轮到我们，店员会计时。</em></p>
</blockquote>

<p><img src="/assets/958599363857/1*BNyIXI7P-rccj0dy7yeXeg.webp" alt="" loading="lazy" decoding="async" width="1200" height="704" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjcwNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*BNyIXI7P-rccj0dy7yeXeg.png" /></p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/-h9OupA3kCY" title="HARRY HARAJUKU terrace 水獺咖啡廳 ＨＡＲＲＹ原宿テラス店" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>可以趁他吃东西翻肚肚的时候摸摸，毛很柔顺。</p>

<blockquote>
  <p><strong><em>整体来说：评价可能只有 2.5–3 颗星吧</em></strong></p>
</blockquote>

<blockquote>
  <p><em>整体场地太小，只付 ¥3,080 日币/人一小时基本费除了刺猬可以互动其他都没有，咖啡也只是贩卖机；虽然店员对动物都蛮温柔的，但在一旁休息的其他水獭或露天水池的水獭可以活动的范围都不大，觉得有点可怜。</em></p>
</blockquote>

<blockquote>
  <p><em>好像跟想像中正常咖啡厅门市的大小＋有水獭跑来跑去不太一样。</em></p>
</blockquote>

<p><a href="https://kantenlife.tw/2024/04/18/house-of-otters-japan/#%E6%97%A5%E6%9C%AC%E6%B0%B4%E7%8D%BA%E5%92%96%E5%95%A1%E5%BB%B3%EF%BD%9C%E3%82%AB%E3%83%AF%E3%82%A6%E3%82%BD_%E8%8B%A5%E6%9E%97%E3%81%AE%E5%AE%B6%E3%80%81HARRY_HARAJUKU_terrace%E6%AF%94%E8%BC%83%E5%88%86%E4%BA%AB" target="_blank"><strong>后来查资料，感觉另一家 カワウソ_若林の家 比较好，互动时间较长。</strong></a></p>

<h4 id="1800-前往涩谷">18:00 前往涩谷</h4>

<p><img src="/assets/958599363857/1*Do_SdWdOCG8ZhXXDVcyEtg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*Do_SdWdOCG8ZhXXDVcyEtg.jpeg" /></p>

<h4 id="1820-排-极味屋">18:20 排 <a href="https://maps.app.goo.gl/oZR5RprBErWbkAjq8" target="_blank">极味屋</a></h4>

<p>时间还很早，再次来到涩谷，先来吃极味屋。</p>

<p><img src="/assets/958599363857/1*bA7IPZZUq2LVdCbFs9H5lw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1005" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMDUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*bA7IPZZUq2LVdCbFs9H5lw.png" /></p>

<p>这时间来人没有太多，稍微排队一下就吃到了。</p>

<h4 id="1855-入座-极味屋">18:55 入座 <a href="https://maps.app.goo.gl/oZR5RprBErWbkAjq8" target="_blank">极味屋</a></h4>

<p><img src="/assets/958599363857/1*WRCSVqkiXQFWZcMWKs8GPw.webp" alt="" loading="lazy" decoding="async" width="711" height="1220" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MTEiIGhlaWdodD0iMTIyMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*WRCSVqkiXQFWZcMWKs8GPw.png" /></p>

<p><img src="/assets/958599363857/1*hb9il-B-7Hh_BJccl-OfyQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*hb9il-B-7Hh_BJccl-OfyQ.jpeg" /></p>

<p>中午吃太多汉堡排很腻，我是点左边的纯牛排套餐，juice 好吃。</p>

<blockquote>
  <p><a href="https://zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E6%9D%B1%E4%BA%AC%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-5-%E5%A4%A9%E9%A3%9F%E4%BD%8F%E8%A1%8C%E5%85%A8%E8%A8%98%E9%8C%84%E8%88%87%E5%BF%85%E8%A8%AA%E6%99%AF%E9%BB%9E%E6%8E%A8%E8%96%A6-9da2c51fa4f2/#%E6%B8%8B%E8%B0%B7-parco--%E6%A5%B5%E5%91%B3%E5%B1%8B" target="*blank"><em>上次是吃汉堡排＋牛排套餐</em></a> _， <strong>一样只要记得两双筷子，铁筷负责煎、木筷负责吃。</strong>*</p>
</blockquote>

<p><strong>招牌 — 伊万里牛排＋极味屋汉堡牛肉价格：</strong></p>

<ul>
  <li>
    <p>Small (120g): ¥2,480 日币</p>
  </li>
  <li>
    <p>Medium (160g): ¥2,850 日币</p>
  </li>
  <li>
    <p>Large (200g): ¥3,180 日币</p>
  </li>
</ul>

<p><strong>纯伊万里牛排价格：</strong></p>

<ul>
  <li>
    <p>Medium (130g): ¥2,480 日币</p>
  </li>
  <li>
    <p>Large (180g): ¥3,280 日币</p>
  </li>
</ul>

<p><strong>升级套餐：</strong> ¥450 日币</p>

<ul>
  <li>
    <p>多汤、沙拉、冰淇淋</p>
  </li>
  <li>
    <p>个人觉得普普</p>
  </li>
</ul>

<blockquote>
  <p><em>价格非常实惠。</em></p>
</blockquote>

<h4 id="逛街采购药妆">逛街、采购药妆</h4>

<p><img src="/assets/958599363857/1*mOCaZv_M3wUL_shhpsklRw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*mOCaZv_M3wUL_shhpsklRw.jpeg" /></p>

<p>在百货公司逛到香氛，买了两瓶跟枕头喷雾回去试试。</p>

<p><img src="/assets/958599363857/1*hHziMmw8-TXZgTU96AaLAQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*hHziMmw8-TXZgTU96AaLAQ.jpeg" /></p>

<p>吃完在涩谷又逛了一下，然后回饭店钱去药妆店买个药妆，回饭店休息，准备要跟东京说再见了。</p>

<p><img src="/assets/958599363857/1*3F0Blw-rzDL6OCLtVJQJtA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*3F0Blw-rzDL6OCLtVJQJtA.jpeg" /></p>

<p><img src="/assets/958599363857/1*p8osyPhc0M_e21JVJLnmbQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*p8osyPhc0M_e21JVJLnmbQ.jpeg" /></p>

<p>吃太多肉今晚就吃甜点就好吧！</p>

<blockquote>
  <p><em>还有同事在 <a href="https://maps.app.goo.gl/ptoRy58awP8gVibR6" target="_blank">原宿 I’m donut? Harajuku</a> 买来请我们的甜甜圈。(台湾排爆日本不用排)</em></p>
</blockquote>

<h3 id="day-50917-三-上野站回程">Day 5(09/17 三) —上野站、回程</h3>

<h4 id="1050-最后退房时间前出门">10:50 最后退房时间前出门</h4>

<p><img src="/assets/958599363857/1*_fnEVTQzT63qUc3tmEtY5A.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*_fnEVTQzT63qUc3tmEtY5A.jpeg" /></p>

<p>再会新桥。</p>

<p><img src="/assets/958599363857/1*9iw9U6X2Rih37WcuoITOPw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*9iw9U6X2Rih37WcuoITOPw.jpeg" /></p>

<p>搭山手线到上野。</p>

<h4 id="1110-抵达上野站">11:10 抵达上野站</h4>

<p><img src="/assets/958599363857/1*O_gvBqPHvCHYXyWu3h2sjw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*O_gvBqPHvCHYXyWu3h2sjw.jpeg" /></p>

<p>没特别逛，怕找不到地方寄物，就在车站内的寄物柜台寄物了。</p>

<blockquote>
  <p><em>后来发现挺不划算的，因为要取物又要付钱进站，而且也贵；重点是不顺路。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>后来才知道 Skyliner 京成上野在 上野站 山下口 或 不忍改</em></strong> <em>出口那边，走站内就会到，不用出站晒太阳(但是站内很容易迷路就是)；在这边寄物要再走回来(约 15 分钟)，那边也有很多投币寄物柜。</em></p>
</blockquote>

<p><img src="/assets/958599363857/1*stvzWK4vvJ2IxguPptM3Bg.webp" alt="" loading="lazy" decoding="async" width="1400" height="980" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*stvzWK4vvJ2IxguPptM3Bg.png" /></p>

<p>这边走出来就是上野动物园，左转， <strong>准备先去 Skyliner 京成上野 划位。</strong></p>

<p><img src="/assets/958599363857/1*8sL69lXMh1Mzhs05TclHqQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*8sL69lXMh1Mzhs05TclHqQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*R8RkmEqHQLr_405KQIulcg.webp" alt="" loading="lazy" decoding="async" width="942" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDIiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*R8RkmEqHQLr_405KQIulcg.png" /></p>

<p>终于看到 Skyliner 京成上野 站了。</p>

<p><img src="/assets/958599363857/1*9_ErGzabreeyy-qw0P8zVQ.webp" alt="" loading="lazy" decoding="async" width="945" height="1198" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDUiIGhlaWdodD0iMTE5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*9_ErGzabreeyy-qw0P8zVQ.png" /></p>

<blockquote>
  <p><em>因为 Skyliner 全车指定席，所以建议还是提早划位比较保险。</em></p>
</blockquote>

<blockquote>
  <p><em>站务员会讲中文(只是我一开始没听出来他讲中文就是了)。</em></p>
</blockquote>

<p>抓准最后的时间在上野逛逛。</p>

<h4 id="yodobashi-上野"><a href="https://maps.app.goo.gl/KfAz3oU7DBQpXrUc8" target="_blank">Yodobashi 上野</a></h4>

<p><img src="/assets/958599363857/1*dBKdSU8BqKOanuALBUEesQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*dBKdSU8BqKOanuALBUEesQ.jpeg" /></p>

<p><img src="/assets/958599363857/1*DDnDqOR4o8G6Jg60AospOg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*DDnDqOR4o8G6Jg60AospOg.jpeg" /></p>

<p>旁边还有一间二号店。</p>

<h4 id="一路走到-上野丸井百货公司-逛街"><a href="https://maps.app.goo.gl/E3EfJWipQzSuC2Uv5" target="_blank">一路走到 上野丸井百货公司 逛街</a></h4>

<p><img src="/assets/958599363857/1*O5JJZtfdU1OyJlD1_b8UPw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*O5JJZtfdU1OyJlD1_b8UPw.jpeg" /></p>

<p><img src="/assets/958599363857/1*jmnShS8jUrzCbG0vej3Ksw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*jmnShS8jUrzCbG0vej3Ksw.jpeg" /></p>

<blockquote>
  <p><em>对面是上野站另一个出口，上野站真的好大…</em></p>
</blockquote>

<p><img src="/assets/958599363857/1*Ziu-Golfdiu6XpDVxun10g.webp" alt="" loading="lazy" decoding="async" width="1200" height="1017" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwMTciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*Ziu-Golfdiu6XpDVxun10g.png" /></p>

<p>地理位置大致如上图。</p>

<h4 id="1200-逛-丸井百货">12:00 逛 <a href="https://maps.app.goo.gl/DvPAhnaEz8HYGSQs7" target="_blank">丸井百货</a></h4>

<p><img src="/assets/958599363857/1*GsKiVACufVHtpDYxncJ40A.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*GsKiVACufVHtpDYxncJ40A.jpeg" /></p>

<p><img src="/assets/958599363857/1*XoxAFbNqAcwJ8YDPjQlQxw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*XoxAFbNqAcwJ8YDPjQlQxw.jpeg" /></p>

<p>二楼有一区扭蛋可以逛。</p>

<p><img src="/assets/958599363857/1*37rlYGSdZtckKzwgv9gLWw.webp" alt="" loading="lazy" decoding="async" width="495" height="491" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0OTUiIGhlaWdodD0iNDkxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/958599363857/1*37rlYGSdZtckKzwgv9gLWw.png" /></p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/jyFapci9NxY" title="東海道新幹線 チケット音声キーホルダー 新幹線 車票 廣播 扭蛋 Gotcha" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>扭了一个 <a href="https://www.so-ta.com/products_detail/capsuletoy/tokaido_shinkansen/" target="_blank">新干线车票扭蛋</a> 。</p>

<p><img src="/assets/958599363857/1*rysyBldMgjEOuR__7hQuOg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*rysyBldMgjEOuR__7hQuOg.jpeg" /></p>

<p>也被推坑在 Loft 买了一个 ReFa 心型按摩梳。</p>

<p><img src="/assets/958599363857/1*sGjazwQmnuqRKWbTubIZXA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1000" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*sGjazwQmnuqRKWbTubIZXA.png" /></p>

<p>在这里吃了面包可颂果腹。</p>

<h4 id="1320-回到上野车站">13:20 回到上野车站</h4>

<p><img src="/assets/958599363857/1*Ht4JmIU70nKQWu560yEM2A.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Ht4JmIU70nKQWu560yEM2A.jpeg" /></p>

<p>顺便先去买 Sugar Butter Tree 当伴手礼。</p>

<p>最后回到公园口提领了行李走了一大圈才又回到京成上野。</p>

<p><img src="/assets/958599363857/1*oR_x1HqE9qwg094sF-uygA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*oR_x1HqE9qwg094sF-uygA.jpeg" /></p>

<p><img src="/assets/958599363857/1*maLcXgZQHSKZdJB2CQngZg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*maLcXgZQHSKZdJB2CQngZg.jpeg" /></p>

<p>路线有点奇妙，需要先下到月台再从另一个出口上去，出来才会是不忍改口。</p>

<p><img src="/assets/958599363857/1*XLFR3n_fxsGWBK6sU5Lkhw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*XLFR3n_fxsGWBK6sU5Lkhw.jpeg" /></p>

<p>这个地下道有很多投币式置物柜，而且很空。</p>

<p><img src="/assets/958599363857/1*TyOvYS_0FCfSujRBojgRvg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*TyOvYS_0FCfSujRBojgRvg.jpeg" /></p>

<p>从不忍口出来过马路就是 Skyliner 京成上野了。(不确定有没有其他更近的出口，怕迷路就没乱走了)</p>

<h4 id="1410-回到-skyliner-京成上野-准备搭车前往-成田机场">14:10 回到 Skyliner 京成上野 准备搭车前往 成田机场</h4>

<p><img src="/assets/958599363857/1*j-oOGCBRflbJWVfkQLrA_Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="873" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg3MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*j-oOGCBRflbJWVfkQLrA_Q.png" /></p>

<h4 id="1420-出发前往-成田机场">14:20 出发前往 成田机场</h4>

<p><img src="/assets/958599363857/1*vV-Yxbd2JQ9acITed5qGpw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*vV-Yxbd2JQ9acITed5qGpw.jpeg" /></p>

<p><img src="/assets/958599363857/1*-bEzz-shmaBClAhFkmjf8A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*-bEzz-shmaBClAhFkmjf8A.jpeg" /></p>

<p>刚在路上又去超商买了一些吃的喝的补充体力。</p>

<h4 id="1503-抵达-成田机场-第二航厦">15:03 抵达 成田机场 第二航厦</h4>

<p><img src="/assets/958599363857/1*6thsMc0VyilD-DBmtf85Aw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*6thsMc0VyilD-DBmtf85Aw.jpeg" /></p>

<p><img src="/assets/958599363857/1*jaAOzbQTRmETdiie_Vi7Zg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*jaAOzbQTRmETdiie_Vi7Zg.jpeg" /></p>

<p><img src="/assets/958599363857/1*lpge7uQIA81oEOD9JjK3pQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*lpge7uQIA81oEOD9JjK3pQ.jpeg" /></p>

<p>出来一路往上就会到国际线出发了。</p>

<blockquote>
  <p><em>本来有打算去一航吃 <a href="https://matcha-jp.com/tw/25632" target="_blank">新开幕的 Shake Shack 汉堡</a> ，不过实在太累了懒得去。</em></p>
</blockquote>

<h4 id="1540-完成托运">15:40 完成托运</h4>

<p><img src="/assets/958599363857/1*qtNeXNg2HuWhOQBd0YqnyQ.webp" alt="" loading="lazy" decoding="async" width="946" height="1207" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDYiIGhlaWdodD0iMTIwNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*qtNeXNg2HuWhOQBd0YqnyQ.png" /></p>

<blockquote>
  <p><a href="https://digital.jal.co.jp/ssci/identification?lang=zh-tw" target="_blank"><em>起飞前 24 小时可先完成网路报到、划位，到机场就可以直接排行李托运，加快流程。</em></a></p>
</blockquote>

<p>托运完就直接去排出境了(累)。</p>

<h4 id="1600-完成安检出境">16:00 完成安检、出境</h4>

<p><img src="/assets/958599363857/1*41hw6bw7XnkIpESE-es7iw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*41hw6bw7XnkIpESE-es7iw.jpeg" /></p>

<p><img src="/assets/958599363857/1*XksioltS7RRgmtf4Gz-N3A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*XksioltS7RRgmtf4Gz-N3A.jpeg" /></p>

<p>往数字越来越小的方向走就会到中间连接大厅，吃的买的都在这。</p>

<h4 id="先去-japan-food-hall-b1-吃个东西">先去 JAPAN FOOD HALL B1 吃个东西</h4>

<p><img src="/assets/958599363857/1*xj-6KVdDgwx_GPgGF0bHqQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*xj-6KVdDgwx_GPgGF0bHqQ.jpeg" /></p>

<h4 id="1625-吃吃">16:25 吃吃</h4>

<p><img src="/assets/958599363857/1*Khh3IUrvCCYk1Ccx_fiF7w.webp" alt="" loading="lazy" decoding="async" width="1400" height="982" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*Khh3IUrvCCYk1Ccx_fiF7w.png" /></p>

<p><img src="/assets/958599363857/1*bgttA6-L8uW93zM7TpwOmw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*bgttA6-L8uW93zM7TpwOmw.jpeg" /></p>

<blockquote>
  <p><em>点了一份天妇罗炸虾荞麦面加生啤。</em></p>
</blockquote>

<blockquote>
  <p><em>实刷 $955 台币 (机场就是贵啊…)</em></p>
</blockquote>

<h4 id="1650-免税店伴手礼店逛街">16:50 免税店、伴手礼店逛街</h4>

<p><img src="/assets/958599363857/1*39UCCUtGuFBVV1FEBQG-9A.webp" alt="" loading="lazy" decoding="async" width="1400" height="921" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjkyMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*39UCCUtGuFBVV1FEBQG-9A.png" /></p>

<p><img src="/assets/958599363857/1*UrCaiyBHekSvy0tzTbM5Gw.webp" alt="" loading="lazy" decoding="async" width="1200" height="848" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*UrCaiyBHekSvy0tzTbM5Gw.png" /></p>

<p><img src="/assets/958599363857/1*_ID9YTxBia4tz-CaQrGcEw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*_ID9YTxBia4tz-CaQrGcEw.jpeg" /></p>

<p><img src="/assets/958599363857/1*DubJNBeqI-tWI5amx_VbbQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*DubJNBeqI-tWI5amx_VbbQ.jpeg" /></p>

<p>成田机场免税店真的什么都有，除了精品保养品烟酒外，也有很玩整的伴手礼店，什么有，而且价格其实跟外面差不多或更便宜；没买够的可以把握最后登机前采买。</p>

<h4 id="1705-le-labo">17:05 Le Labo</h4>

<p><img src="/assets/958599363857/1*J2hChay4G6BPHCItaueHFA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*J2hChay4G6BPHCItaueHFA.jpeg" /></p>

<p>其实没特别找，意外发现成田机场有 La Lebo 在 <a href="https://www.fasola.jp/en/searchByBrand.aspx" target="_blank">Fa-So-La DUTY FREE Cosmetics &amp; Perfumery</a> 看官网一二航厦都有。</p>

<p><img src="/assets/958599363857/1*9XCr-56Q5AlUCDRedP1cBA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*9XCr-56Q5AlUCDRedP1cBA.jpeg" /></p>

<blockquote>
  <p><em>更意外的是价格， <strong>50ml — ¥25,700</strong> 比日本境内退完税的价格 ¥28,500 还便宜。</em></p>
</blockquote>

<p><img src="/assets/958599363857/1*ar416ZWoAliERsR_Fg1GJQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*ar416ZWoAliERsR_Fg1GJQ.jpeg" /></p>

<p>最后手痒买了一瓶 26–30ml (机场限定 Size)，实刷 $3,720 台币。</p>

<h4 id="1730-前往登机门候机">17:30 前往登机门候机</h4>

<p><img src="/assets/958599363857/1*5PiE4fENJsi1dynUUL08OQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*5PiE4fENJsi1dynUUL08OQ.jpeg" /></p>

<p>登机门 67B 在很角落，很远；遗憾是一路上的贩卖机都没看到卖桃子水。</p>

<p><img src="/assets/958599363857/1*K8V9RnmpGnx--VJ8HTZOaw.webp" alt="" loading="lazy" decoding="async" width="945" height="1202" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDUiIGhlaWdodD0iMTIwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*K8V9RnmpGnx--VJ8HTZOaw.png" /></p>

<h4 id="1750-登机东京再会">17:50 登机，东京再会！</h4>

<p><img src="/assets/958599363857/1*OxCGLuV_XrFB_c-BHM10gA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*OxCGLuV_XrFB_c-BHM10gA.jpeg" /></p>

<p><img src="/assets/958599363857/1*0qZy2nb8aXRxB1fmR-uCUA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*0qZy2nb8aXRxB1fmR-uCUA.jpeg" /></p>

<p>机型 BOEING 737–800 跟来的时候ㄧ样。</p>

<h4 id="成田机场大塞机本来预计-1810-起飞最后排队等到快-1900-才飞">成田机场大塞机，本来预计 18:10 起飞，最后排队等到快 19:00 才飞</h4>

<p><img src="/assets/958599363857/1*LbcG5trqHcp_4GejuI6iDg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*LbcG5trqHcp_4GejuI6iDg.jpeg" /></p>

<h4 id="日本航空免费机上-wifi">日本航空免费机上 WiFi</h4>

<p><img src="/assets/958599363857/1*1sP5H5jRMsQxm02W2TG6QA.webp" alt="" loading="lazy" decoding="async" width="553" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*1sP5H5jRMsQxm02W2TG6QA.jpeg" /></p>

<p><img src="/assets/958599363857/1*eZ9beWgHlSQufFt-2Mnegg.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*eZ9beWgHlSQufFt-2Mnegg.jpeg" /></p>

<p>无意间发现机上有提供免费一小时的 WiFi 上网。</p>

<p><img src="/assets/958599363857/1*jnrR9EmlSy0PcQkKe1eOGA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*jnrR9EmlSy0PcQkKe1eOGA.jpeg" /></p>

<p><img src="/assets/958599363857/1*5CozWE6P0BhIjE6vksu9cQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*5CozWE6P0BhIjE6vksu9cQ.jpeg" /></p>

<p>飞机餐一样很优秀，是咖喱猪排饭跟甜点哈根达斯。</p>

<h4 id="2107-回到台湾">21:07 回到台湾</h4>

<h4 id="战利品">战利品</h4>

<p><img src="/assets/958599363857/1*ILt_i5ONuyBnDnJXMg0BTw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/958599363857/1*ILt_i5ONuyBnDnJXMg0BTw.jpeg" /></p>

<p><img src="/assets/958599363857/1*SUJ70ie42fbD9Y5_LL86Sg.webp" alt="" loading="lazy" decoding="async" width="1200" height="1089" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwODkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/958599363857/1*SUJ70ie42fbD9Y5_LL86Sg.jpeg" /></p>

<h4 id="感谢阅读">感谢阅读</h4>

<p>感谢您跟我一起体验这次的东京五日游，希望文中的资讯对您的下一次旅行有所帮助。</p>

<h4 id="更多游记">更多游记</h4>

<ul>
  <li>
    <p><a href="/posts/z-度旅行遊記/釜山自由行攻略-8天7夜必去景点-美食与交通全解析-釜山通行证省钱秘诀-8ace34a1a3d8/">[游记] 2025 韩国釜山 8 天 7 夜自由行</a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/九州自由行攻略-釜山新山茶花号邮轮入境日本博多-深入由布院-大分-福冈等地-cb65fd5ab770/">[游记] 2024 二访九州 9 日自由行，经釜山→博多邮轮入境</a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/山阴关西自由行攻略-岛根出云松江鸟取姬路大阪神户7日独旅全记录-aacd5f5cacd1/">[游记] 2024 山阴广域地区 岛根 出云 松江 鸟取 姬路 大阪 神户 7 日独旅自由行</a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/九州自由行攻略-福冈-长崎-熊本10日独旅全纪录与交通住宿实战经验-d78e0b15a08a/">[游记] 2023 九州 10 日自由行独旅</a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/山阳地区广岛冈山自由行攻略-6日行程-交通-住宿全解析-31b9b3a63abc/">[游记] 2023 广岛冈山 6 日自由行</a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/名古屋一日快闪自由行-乐桃航空红眼班机省钱攻略与行程规划-7b8a0563c157/">[游记] 9/11 名古屋一日快闪</a></p>
  </li>
  <li>
    <p>[游记] <a href="/posts/z-度旅行遊記/东京自由行攻略-5-天食住行全记录与必访景点推荐-9da2c51fa4f2/">2023 东京 5 日自由行</a></p>
  </li>
  <li>
    <p>[游记] <a href="/posts/z-度旅行遊記/京阪神自由行攻略-京都大阪神户8日游全纪录与实用交通住宿指南-76d66c2e34af/">2023 京阪神 8 日自由行</a></p>
  </li>
</ul>]]></content>
  </entry><entry>
    <title type="html">LINE Bank 入金 Firstrade 教学｜快速到帐、低手续费150元、帐户升级与手续费补助申请全攻略</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-life/line-bank-%E5%85%A5%E9%87%91-firstrade-%E6%95%99%E5%AD%A6-%E5%BF%AB%E9%80%9F%E5%88%B0%E5%B8%90-%E4%BD%8E%E6%89%8B%E7%BB%AD%E8%B4%B9150%E5%85%83-%E5%B8%90%E6%88%B7%E5%8D%87%E7%BA%A7%E4%B8%8E%E6%89%8B%E7%BB%AD%E8%B4%B9%E8%A1%A5%E5%8A%A9%E7%94%B3%E8%AF%B7%E5%85%A8%E6%94%BB%E7%95%A5-e4d139fe0685/" rel="alternate" type="text/html" title="LINE Bank 入金 Firstrade 教学｜快速到帐、低手续费150元、帐户升级与手续费补助申请全攻略" />
    <published>2025-09-02T15:09:54+08:00</published>
    <updated>2026-01-04T11:45:25+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-life/e4d139fe0685</id><summary type="html">投资美股遇到汇款繁琐与高手续费问题？透过 LINE Bank 入金 Firstrade，享受手续费只要150元、快速到帐，搭配帐户升级与约定转帐设定，还能申请每月最高25美元手续费补助，让海外汇款更省时省钱，轻松开启美股投资之路。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Life." /><category term="line-bank" /><category term="firstrade" /><category term="nasdaq" /><category term="line" /><category term="入金" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/e4d139fe0685/1*u5qqz4o0pCvUTF16sYHNCg.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-life/line-bank-%E5%85%A5%E9%87%91-firstrade-%E6%95%99%E5%AD%A6-%E5%BF%AB%E9%80%9F%E5%88%B0%E5%B8%90-%E4%BD%8E%E6%89%8B%E7%BB%AD%E8%B4%B9150%E5%85%83-%E5%B8%90%E6%88%B7%E5%8D%87%E7%BA%A7%E4%B8%8E%E6%89%8B%E7%BB%AD%E8%B4%B9%E8%A1%A5%E5%8A%A9%E7%94%B3%E8%AF%B7%E5%85%A8%E6%94%BB%E7%95%A5-e4d139fe0685/"><![CDATA[<h3 id="手把手教学--line-bank-入金-firstrade-快速到帐手续费只要-150-元及帐户升级约定转帐手续费补助申请教学">手把手教学 — LINE Bank 入金 Firstrade 快速到帐、手续费只要 150 元及帐户升级/约定转帐/手续费补助申请教学</h3>

<p>Line Bank 入金 Firstrade 及帐户升级约定与手续费补助完整图文教学</p>

<h3 id="line-bank-的优势">LINE Bank 的优势</h3>

<ul>
  <li>
    <p>开户简单：有其他银行联征纪录只需网路填写资料就能开户</p>
  </li>
  <li>
    <p>跨行转帐免手续费：最高 50次/月</p>
  </li>
  <li>
    <p><strong>无痛整合 Line 转帐：</strong> 好友之间转帐不用在透过 iPASS MONEY</p>
  </li>
  <li>
    <p>24 小时都能换汇</p>
  </li>
  <li>
    <p>多种弹性高利率存款方案可自行搭配选择</p>
  </li>
  <li>
    <p>信贷：快速/整合/10年轻松付</p>
  </li>
  <li>
    <p>证券：100元起投资台股</p>
  </li>
</ul>

<h4 id="line-bank-美国汇款优惠--汇出手续费150元汇入手续费50元"><a href="https://www.linebank.com.tw/wealth-investment/promotions/10" target="_blank">Line Bank 美国汇款优惠 — 汇出手续费150元、汇入手续费50元</a></h4>

<p><strong>[2026/01/01 加码再次延长]:</strong></p>

<blockquote>
  <p><em>活动期间：原活动期间为2026/1/1~2026/6/30</em></p>
</blockquote>

<blockquote>
  <p><em>活动内容：外币汇出手续费优惠价每笔NT$150元(原价NT$600元)、外币汇入手续费优惠价每笔NT$50元（原价NT$400元）</em></p>
</blockquote>

<blockquote>
  <p><em>活动产品：外币汇出汇款、外币汇入汇款</em></p>
</blockquote>

<p>这是我们使用 LINE Bank 最大的诱因，到 2026/06/30 之前用 LINE Bank 帐户入金 Firstrade 只收取 150 元手续费，不用电报费或其他费用。</p>

<blockquote>
  <p><em>Memo: 这活动从 2025/01–06 就开始，目前已好评延长两次 (2025/06 延长至 2025/12、2025/12 再次延长至 2026/06)， <strong>敬请把时间！</strong></em></p>
</blockquote>

<h4 id="点我前往申办"><a href="https://www.linebank.com.tw/R/mgm-portal?campaignId=2&amp;uid=bfQqph" target="_blank">点我前往申办</a></h4>

<p><img src="/assets/e4d139fe0685/1*u5qqz4o0pCvUTF16sYHNCg.webp" alt="点我前往申办" loading="lazy" decoding="async" width="1200" height="632" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjYzMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*u5qqz4o0pCvUTF16sYHNCg.png" /></p>

<p><a href="https://www.linebank.com.tw/R/mgm-portal?campaignId=2&amp;uid=bfQqph" target="_blank">点我前往申办</a></p>

<h4 id="缺点">缺点</h4>

<p>这次遇到要设定约定帐户，因为 LINE Bank 没有实体银行，只能透过自然人凭证认证；所以变成要跑一趟户政事务所申办自然人凭证才能使用，比直接去银行还麻烦。</p>

<h3 id="firstrade-的优势">Firstrade 的优势</h3>

<ul>
  <li>
    <p>开户、介面、功能简单，美股小白友善</p>
  </li>
  <li>
    <p>支援中文介面</p>
  </li>
  <li>
    <p>交易 0 手续费</p>
  </li>
  <li>
    <p>老牌券商</p>
  </li>
</ul>

<blockquote>
  <p><em>开户姓名请务必使用护照名。</em></p>
</blockquote>

<h4 id="入金-10000-美元以上可以申请最高为-25-美元手续费补助"><a href="https://www.firstrade.com/zh-TW/accounts/wire-fee-rebate" target="_blank">入金 $10,000 美元以上，可以申请最高为 $25 美元手续费补助</a></h4>

<p><img src="/assets/e4d139fe0685/1*-4JN2hY_QP3oZaon2BES0A.webp" alt="入金 $10,000 美元以上，可以申请最高为 $25 美元手续费补助 (每月最多三次)" loading="lazy" decoding="async" width="464" height="441" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NjQiIGhlaWdodD0iNDQxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*-4JN2hY_QP3oZaon2BES0A.png" /></p>

<p><a href="https://www.firstrade.com/zh-TW/accounts/wire-fee-rebate" target="_blank">入金 $10,000 美元以上，可以申请最高为 $25 美元手续费补助</a> (每月最多三次)</p>

<blockquote>
  <p>帐户一切准备就绪之后我们就能开始入金啰。</p>
</blockquote>

<h3 id="入金花费时间轴参考最快-2-天入金到帐">入金花费时间轴参考(最快 2 天入金到帐)</h3>

<p><img src="/assets/e4d139fe0685/1*mhmGifQYaJacIOXwPqIC_A.webp" alt="这边以我 10/14 入金到 Firstrade 到最后拿到汇款补贴的时间轴。" loading="lazy" decoding="async" width="1200" height="657" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY1NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*mhmGifQYaJacIOXwPqIC_A.png" /></p>

<p>这边以我 10/14 入金到 Firstrade 到最后拿到汇款补贴的时间轴。</p>

<ul>
  <li>
    <p>请注意以上是建立在约定帐户都已绑定完成或是金额小于 5 万的情况，第一次绑定约定帐户要等 +2 天才会生效。</p>
  </li>
  <li>
    <p>Line Bank 显示受款银行已收到 到 Firstrade 真的收到钱会有时间差。(应该是要等 Firstrade 营业时间处理完才会显示已收到)</p>
  </li>
  <li>
    <p>Firstrade 收到钱要申请汇款补贴(单笔超过一万镁)也会有时间差，没看到纪录的话可以稍后或隔天再看。</p>
  </li>
</ul>

<h3 id="line-bank-入金-firstrade">LINE Bank 入金 Firstrade</h3>

<p>首先来介绍 Line Bank 如何入金到 Firstrade。</p>

<h4 id="将您的资产存入第一证券"><a href="https://invest.firstrade.com/cgi-bin/main#/content/customerservice/fundaccount/" target="_blank">将您的资产存入第一证券</a></h4>

<p><img src="/assets/e4d139fe0685/1*QEJlVLLykQrqTB2UACx95Q.webp" alt="" loading="lazy" decoding="async" width="1015" height="506" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDE1IiBoZWlnaHQ9IjUwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*QEJlVLLykQrqTB2UACx95Q.png" /></p>

<p>(请使用电脑版) 登入 Firstrade 后选择：</p>

<ol>
  <li>
    <p>客户服务</p>
  </li>
  <li>
    <p>账户注资</p>
  </li>
</ol>

<blockquote>
  <p><em>如果页面是英文可以在上方选择「繁体中文」更改语言。</em></p>
</blockquote>

<h4 id="取得汇款讯息"><a href="https://invest.firstrade.com/scripts/fundmgt/wire_instruction/" target="_blank">取得汇款讯息</a></h4>

<p><img src="/assets/e4d139fe0685/1*66aA2JSjEWOLHdj4P6JwVA.webp" alt="" loading="lazy" decoding="async" width="1000" height="426" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjQyNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*66aA2JSjEWOLHdj4P6JwVA.png" /></p>

<p>选择「汇款」 → 「汇款信息」，会开启一个 PDF 档案，可以把这个档案储存下来方便之后入金填写：</p>

<p><img src="/assets/e4d139fe0685/1*11qj5ItxI9rxNrOqCVBw8g.webp" alt="" loading="lazy" decoding="async" width="781" height="1109" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3ODEiIGhlaWdodD0iMTEwOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*11qj5ItxI9rxNrOqCVBw8g.png" /></p>

<ol>
  <li>
    <p>受款银行资讯 — SWIFT 代码</p>
  </li>
  <li>
    <p>受款人户名</p>
  </li>
  <li>
    <p>受款人英文地址</p>
  </li>
  <li>
    <p>受款人帐号</p>
  </li>
  <li>
    <p><strong>附言</strong></p>
  </li>
</ol>

<h4 id="line-bank-app--汇款至海外">LINE Bank App — 汇款至海外</h4>

<p><img src="/assets/e4d139fe0685/1*8zCXdiJWyPNCFW_NuIKNhQ.webp" alt="" loading="lazy" decoding="async" width="683" height="749" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2ODMiIGhlaWdodD0iNzQ5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*8zCXdiJWyPNCFW_NuIKNhQ.png" /></p>

<ol>
  <li>
    <p>点击「更多」</p>
  </li>
  <li>
    <p>下滑找到「外汇」区块 → 点击「汇款至海外」</p>
  </li>
  <li>
    <p>扣款金额选择「台币 or 美元」、输入要汇款的金额
<strong>请先参考下方 Line Bank 帐户升级与约定帐户绑定教学。</strong>
<strong>请先参考下方 Line Bank 帐户升级与约定帐户绑定教学。</strong>
<strong>请先参考下方 Line Bank 帐户升级与约定帐户绑定教学。</strong>
<strong>否则只能汇款 1 万台币。</strong></p>
  </li>
  <li>
    <p>点击「前往汇款」</p>
  </li>
</ol>

<h4 id="手续费比率-20260630-前均一价-150">手续费比率 (2026/06/30 前均一价 $150)</h4>

<ul>
  <li>
    <p>汇款 NTD $10,000 / 手续费 NTD $150 = 1.5%</p>
  </li>
  <li>
    <p>汇款 NTD $50,000 / 手续费 NTD $150 = 0.3%</p>
  </li>
  <li>
    <p>汇款 NTD $300,000 / 手续费 NTD $150 = 0.05%</p>
  </li>
  <li>
    <p>汇款 NTD $500,000 / 手续费 NTD $150 = 0.03%</p>
  </li>
</ul>

<blockquote>
  <p><em>一次汇款的金额越多，比率越低， <strong>Firstrade 单笔入金超过 $10,000 美金 (约 $310,000 台币)，还可再申请最高 $25 美元、每月最多三次入金手续费补贴、需在汇款后 30 天内申请(参考文末教学)</strong> 。</em></p>
</blockquote>

<h4 id="输入汇款资料">输入汇款资料</h4>

<p><img src="/assets/e4d139fe0685/1*5Bc1Gogt-HJRVdh_ygOPbg.webp" alt="" loading="lazy" decoding="async" width="791" height="789" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3OTEiIGhlaWdodD0iNzg5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*5Bc1Gogt-HJRVdh_ygOPbg.png" /></p>

<p><strong>输入上一步 <a href="https://invest.firstrade.com/scripts/fundmgt/wire_instruction/" target="_blank">汇款讯息</a> 的资讯：</strong></p>

<ol>
  <li>
    <p>受款人英文户名： <code class="language-plaintext highlighter-rouge">Apex Clearing Corporation</code></p>
  </li>
  <li>
    <p>受款银行资讯 — 直接填写 SWIFT 代码自动带入</p>
  </li>
  <li>
    <p>输入搜寻： <code class="language-plaintext highlighter-rouge">HATRUS44</code></p>
  </li>
  <li>
    <p>选择第一个： <code class="language-plaintext highlighter-rouge">HATRUS44 — BMO Bank N.A CHICAGO</code></p>
  </li>
  <li>
    <p>受款人帐号： <code class="language-plaintext highlighter-rouge">1617711</code> <strong>(可能会变，请以实际资讯为主)</strong></p>
  </li>
</ol>

<p><strong>往下滑继续输入：</strong></p>

<p><img src="/assets/e4d139fe0685/1*i2kQnOFRD-azviSj3fCfyA.webp" alt="" loading="lazy" decoding="async" width="358" height="762" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTgiIGhlaWdodD0iNzYyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*i2kQnOFRD-azviSj3fCfyA.png" /></p>

<ol>
  <li>
    <p>受款人身份别： <code class="language-plaintext highlighter-rouge">民间(法人、个人)</code></p>
  </li>
  <li>
    <p>受款人英文地址 — 国家：选择 <code class="language-plaintext highlighter-rouge">United States</code></p>
  </li>
  <li>
    <p>受款人英文地址 — 城市/区：填写 <code class="language-plaintext highlighter-rouge">Texas</code></p>
  </li>
  <li>
    <p>受款人英文地址 — 详细地址： <code class="language-plaintext highlighter-rouge">One Dallas Center 350 N. St Paul, Suite 1300, Dallas, TX 75201</code> (参考上一步汇款资讯)</p>
  </li>
  <li>
    <p><strong>⭐️️️️️️ 最重要的附言，请务必填写</strong>
<strong>⭐️️️️️️ 最重要的附言，请务必填写</strong>
<strong>⭐️️️️️️ 最重要的附言，请务必填写</strong>
<strong>参考上一步汇款资讯输入：</strong> <code class="language-plaintext highlighter-rouge">8 码帐户数字 + 账户姓名</code>
如上图所示： <code class="language-plaintext highlighter-rouge">12345678 ZXXXG CXXXG LI</code></p>
  </li>
  <li>
    <p>点击「下一步」</p>
  </li>
</ol>

<h4 id="汇款性质">汇款性质</h4>

<p><img src="/assets/e4d139fe0685/1*jrDAKxcP5jxjHQ41Wf5LWQ.webp" alt="" loading="lazy" decoding="async" width="841" height="794" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NDEiIGhlaWdodD0iNzk0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*jrDAKxcP5jxjHQ41Wf5LWQ.png" /></p>

<ul>
  <li>
    <p>选择「262 投资国外股权证券」</p>
  </li>
  <li>
    <p>点击「同意」申报注意事项</p>
  </li>
</ul>

<h4 id="汇款确认">汇款确认</h4>

<p><img src="/assets/e4d139fe0685/1*yiYOU7hagogCvHF1AUxEHQ.webp" alt="" loading="lazy" decoding="async" width="743" height="686" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NDMiIGhlaWdodD0iNjg2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*yiYOU7hagogCvHF1AUxEHQ.png" /></p>

<p>最后一部，确认一下资讯是否输入正确，尤其是受款人帐户资讯跟 <strong>附言部分</strong> 。</p>

<ul>
  <li>
    <p>如果 60 秒内无法确认交易内容，汇率报价可能会进行更新。</p>
  </li>
  <li>
    <p>没问题点击「下一步」就 <strong>完成汇款申请了</strong></p>
  </li>
</ul>

<h4 id="完成">完成</h4>

<p><img src="/assets/e4d139fe0685/1*jaADV3k1wdNZuz2zpogLQA.webp" alt="" loading="lazy" decoding="async" width="869" height="1884" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjkiIGhlaWdodD0iMTg4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*jaADV3k1wdNZuz2zpogLQA.jpeg" /></p>

<p>看到这画面代表汇款申请已完成，请静待到帐通知。</p>

<blockquote>
  <p><em>本文图片中的汇款金额仅共参考。(有的图是 5万、有的是 10 万)</em></p>
</blockquote>

<h3 id="line-bank-汇款入金-firstrade-进度查询">LINE Bank 汇款入金 Firstrade 进度查询</h3>

<p><img src="/assets/e4d139fe0685/1*nEUD0C8nOO1E2uS9p6u8rw.webp" alt="" loading="lazy" decoding="async" width="1114" height="774" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTE0IiBoZWlnaHQ9Ijc3NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*nEUD0C8nOO1E2uS9p6u8rw.png" /></p>

<p>可以从 LINE Bank App 右上角通知找到，外币汇出通知，点击进入查看汇款进度。</p>

<ul>
  <li>
    <p>非假日最快当天就汇款成功，假日就要等 2 天后上班日才会处理</p>
  </li>
  <li>
    <p><strong>如果资料有填错受款单位会拒收，需要支付退汇手续费重新汇款</strong></p>
  </li>
</ul>

<h4 id="申请汇款单交易纪录水单">申请汇款单(交易纪录/水单)</h4>

<p><img src="/assets/e4d139fe0685/1*EH8g25Pxoewchc5gt7qK_w.webp" alt="" loading="lazy" decoding="async" width="1179" height="2556" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTc5IiBoZWlnaHQ9IjI1NTYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/e4d139fe0685/1*EH8g25Pxoewchc5gt7qK_w.jpeg" /></p>

<p><img src="/assets/e4d139fe0685/1*DMrWpw9JdcFVOYuEWgNmkw.webp" alt="" loading="lazy" decoding="async" width="790" height="1031" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3OTAiIGhlaWdodD0iMTAzMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*DMrWpw9JdcFVOYuEWgNmkw.png" /></p>

<p>Line Bank App 进度查询通知(如前文)，往下滑有一个「申请水单/交易凭证」按钮，点击后就会寄送汇款单到你的 Email，用身分证字号就能开启档案查看。</p>

<h4 id="受款行已收到款项但是-firstrade-没看到资金">受款行已收到款项但是 Firstrade 没看到资金？</h4>

<p>这是正常的，虽然在 Line Bank 上看到汇款状态是「受款行已收到款项」汇款完成，但是 Firstrade 那边还要再等美国上班日(时间)才会确认款项。</p>

<p>如上图虽然 8/27 AM 09:00 就已收到款项，但是到 8/28 AM 02:10 Firstrade 才确认款项，并收到入帐通知信：</p>

<p><img src="/assets/e4d139fe0685/1*7g0qrnxcoE5aYYz0erJrpw.webp" alt="" loading="lazy" decoding="async" width="625" height="715" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MjUiIGhlaWdodD0iNzE1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*7g0qrnxcoE5aYYz0erJrpw.png" /></p>

<p>这时候再登入 Firstrade 就能看到资金进来啰，可以开始操作美股投资：</p>

<p><img src="/assets/e4d139fe0685/1*83_EXDsxQpwqgfmkHogYbw.webp" alt="" loading="lazy" decoding="async" width="980" height="704" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5ODAiIGhlaWdodD0iNzA0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*83_EXDsxQpwqgfmkHogYbw.png" /></p>

<p>「我的账户」 →「账户记录」也会有存款纪录可查询。</p>

<h3 id="line-bank-帐户升级绑定约定帐户教学">Line Bank 帐户升级、绑定约定帐户教学</h3>

<p><img src="/assets/e4d139fe0685/1*ZbYDlcVZlCEE4fdKgeaWWQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="410" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQxMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*ZbYDlcVZlCEE4fdKgeaWWQ.png" /></p>

<p><strong>权益比较：</strong></p>

<ul>
  <li>
    <p>(开户后即享) 基本帐户：单笔最高 1 万、每日最高 3 万、每月最高 5 万。</p>
  </li>
  <li>
    <p>(客服视讯后) 升级帐户：单笔最高 5 万、每日最高 10万、每月最高 20 万。</p>
  </li>
  <li>
    <p>(自然人凭证+客服视讯后) 约定帐户：单笔最高 50 万。</p>
  </li>
</ul>

<h4 id="line-bank-帐户升级">Line Bank 帐户升级</h4>

<p>其实就是提升到其他银行的基础限额。 <strong>(这一步不用自然人凭证。)</strong></p>

<p><img src="/assets/e4d139fe0685/1*aFqGx67be74ZZr75wUvT-w.webp" alt="" loading="lazy" decoding="async" width="1117" height="779" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTE3IiBoZWlnaHQ9Ijc3OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*aFqGx67be74ZZr75wUvT-w.png" /></p>

<p>打开 LINE Bank App 在「更多」下滑找到「其他」 → 「帐户升级」，选择要升级的帐户类型 → 选择 <strong>2. 视讯验证「开始验证 &gt;」。</strong></p>

<ul>
  <li>
    <p>请先确保网路正常稳定</p>
  </li>
  <li>
    <p>确保当前可以视讯通话</p>
  </li>
</ul>

<p>点击后就会播视讯电话给客服人员，会需要跟客服对话视讯，可能会再跟你确认一下帐户资讯(例如：问你当前余额?) 确认无误之后；就完成帐户升级啰。</p>

<h3 id="约定-firstrade-汇款帐户">约定 Firstrade 汇款帐户</h3>

<p>比较推荐的是直接约定 Firstrade 汇款帐户为约定帐户，方便快速又安全。</p>

<ul>
  <li>
    <p>约定帐户需要 2 天后才会生效</p>
  </li>
  <li>
    <p>约定帐户需要先通过自然人凭证验证</p>
  </li>
  <li>
    <p><strong>自然人凭证验证只支援 TP07 开头，里面有 NFC 感应晶片的卡片</strong></p>
  </li>
</ul>

<h4 id="自然人凭证申请">自然人凭证申请</h4>

<p>请先在线上 <a href="https://moica.nat.gov.tw/rac_form.html" target="_blank">完成填写自然人申请表格</a> ：</p>

<p><img src="/assets/e4d139fe0685/1*4xi8pHeUNAPZKijWiXfj1Q.webp" alt="自然人申请表格" loading="lazy" decoding="async" width="705" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDUiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*4xi8pHeUNAPZKijWiXfj1Q.png" /></p>

<p><a href="https://moica.nat.gov.tw/rac_form.html" target="_blank">自然人申请表格</a></p>

<p>送出后，7 天内到任何地方户政事务所(不用是户籍地)柜台都能办理。</p>

<ul>
  <li>
    <p><strong>工本费： $250 元</strong></p>
  </li>
  <li>
    <p>现场办理现场发放</p>
  </li>
  <li>
    <p>户政事务所办理自然人凭证的人不多、中午一般不休息</p>
  </li>
</ul>

<p><img src="/assets/e4d139fe0685/1*zrmIss8K7vrn18f_CGffDg.webp" alt="" loading="lazy" decoding="async" width="1200" height="873" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg3MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*zrmIss8K7vrn18f_CGffDg.png" /></p>

<h4 id="line-bank-新增约定-firstrade-海外汇款帐户">Line Bank 新增约定 Firstrade 海外汇款帐户</h4>

<p><img src="/assets/e4d139fe0685/1*Mi9tRTDMpubsVfWF6AXidg.webp" alt="" loading="lazy" decoding="async" width="1127" height="767" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTI3IiBoZWlnaHQ9Ijc2NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*Mi9tRTDMpubsVfWF6AXidg.png" /></p>

<p>打开 LINE Bank App →「更多」 → 下滑找到外汇，点击「我的汇款纪录」 → 「汇款约定帐号」 → 「新增约定帐号」。</p>

<h4 id="第一次使用--完成帐户验证">第一次使用 — 完成帐户验证</h4>

<p><img src="/assets/e4d139fe0685/1*nLPxsTJ1ALuv4hLZPcdqmw.webp" alt="" loading="lazy" decoding="async" width="1179" height="1199" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTc5IiBoZWlnaHQ9IjExOTkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/e4d139fe0685/1*nLPxsTJ1ALuv4hLZPcdqmw.jpeg" /></p>

<p>第一次绑定需要完成「自然人凭证验证」与「视讯验证」，视讯验证同帐户升级需要跟客服视讯完成帐户资料验证。</p>

<p><strong>自然人凭证则需要拿出我们刚申办的自然人凭证卡靠卡完成验证：</strong></p>

<p><img src="/assets/e4d139fe0685/1*-N0scmyLMlqgPHbuDpmD-Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="675" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjY3NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*-N0scmyLMlqgPHbuDpmD-Q.png" /></p>

<blockquote>
  <p><em>自然人凭证的感应范围有一点小，我重新试了好几次才成功；iPhone 用镜头中间靠近卡片中间，卡片左右横移，尝试几次就能验证成功。</em></p>
</blockquote>

<h4 id="新增约定帐户">新增约定帐户</h4>

<p><img src="/assets/e4d139fe0685/1*RvHTvjTzjap4M09RG5Q8xQ.webp" alt="" loading="lazy" decoding="async" width="749" height="765" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NDkiIGhlaWdodD0iNzY1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*RvHTvjTzjap4M09RG5Q8xQ.png" /></p>

<p>帐户资讯同前文介绍的汇款资讯，依序填入，确认无误后点击「下一步」。</p>

<p><img src="/assets/e4d139fe0685/1*2VbwWyl9zQCY9p2fVVoL2w.webp" alt="" loading="lazy" decoding="async" width="1143" height="786" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTQzIiBoZWlnaHQ9Ijc4NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*2VbwWyl9zQCY9p2fVVoL2w.png" /></p>

<p>需要完成双相简讯验证，跳到刚收到的简讯输入四位数验证码；等待约 1–2 分钟，收到确认成功简讯代表验证完成。</p>

<p><img src="/assets/e4d139fe0685/1*WmXzGCmOWMkOxwMhYJ-mfQ.webp" alt="" loading="lazy" decoding="async" width="715" height="791" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MTUiIGhlaWdodD0iNzkxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*WmXzGCmOWMkOxwMhYJ-mfQ.png" /></p>

<p>验证成功后，约定帐户就新增成功啰！</p>

<ul>
  <li>
    <p>刚新增完，右上角会有一个惊叹号，提示尚未生效。</p>
  </li>
  <li>
    <p><strong>需要 2 日后才会生效。</strong></p>
  </li>
</ul>

<h4 id="line-bank-firstrade-约定帐户汇款">Line Bank Firstrade 约定帐户汇款</h4>

<p><img src="/assets/e4d139fe0685/1*TfcH3RFr1wR7XKjKjqnvJQ.webp" alt="" loading="lazy" decoding="async" width="740" height="766" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NDAiIGhlaWdodD0iNzY2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*TfcH3RFr1wR7XKjKjqnvJQ.png" /></p>

<p>「我的汇款纪录」 → 「汇款约定帐号」 → 选择帐户 → 输入金额 → 选择「以约定帐户进行汇款」 → 资料会自动都带好。</p>

<h3 id="firstrade-手续费补助申请教学">Firstrade 手续费补助申请教学</h3>

<ul>
  <li>
    <p>汇款金额要求： <strong>单笔</strong> 大于 $10,000 美元</p>
  </li>
  <li>
    <p>补贴金额上限：$25 美元</p>
  </li>
  <li>
    <p>次数限制：每月最多 3 次</p>
  </li>
  <li>
    <p>申请时间：汇款后 30 天内提出申请</p>
  </li>
</ul>

<p><img src="/assets/e4d139fe0685/1*TFU213ZsLmlrAt7Wj7Vmtw.webp" alt="" loading="lazy" decoding="async" width="1032" height="450" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDMyIiBoZWlnaHQ9IjQ1MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*TFU213ZsLmlrAt7Wj7Vmtw.png" /></p>

<p><img src="/assets/e4d139fe0685/1*JbqxnPqZkNsZuqvSGpkRqw.webp" alt="" loading="lazy" decoding="async" width="1025" height="695" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI1IiBoZWlnaHQ9IjY5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*JbqxnPqZkNsZuqvSGpkRqw.png" /></p>

<p><a href="https://invest.firstrade.com/cgi-bin/main#/content/customerservice/promos/wirerebate/" target="_blank">登入 Firstrade 后选择「客户服务」 → 「特惠活动」→ 「汇费补贴」。</a></p>

<p><img src="/assets/e4d139fe0685/1*3UDeTN3dnh3fnM9HMdIurw.webp" alt="" loading="lazy" decoding="async" width="866" height="674" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjYiIGhlaWdodD0iNjc0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*3UDeTN3dnh3fnM9HMdIurw.png" /></p>

<p>选择汇款资料。</p>

<blockquote>
  <p><strong><em>如果没出现汇款资料可选择，请再等几天汇款资料进来。(刚到帐不一定会马上出现)</em></strong></p>
</blockquote>

<p><img src="/assets/e4d139fe0685/1*U598Ew1kBCBC4fxCjLVv_w.webp" alt="" loading="lazy" decoding="async" width="872" height="918" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzIiIGhlaWdodD0iOTE4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*U598Ew1kBCBC4fxCjLVv_w.png" /></p>

<p><img src="/assets/e4d139fe0685/1*-KOs-E0FQ_Wy80GLl581OA.webp" alt="" loading="lazy" decoding="async" width="866" height="766" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjYiIGhlaWdodD0iNzY2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*-KOs-E0FQ_Wy80GLl581OA.png" /></p>

<p><strong>选择汇款纪录资料：</strong></p>

<ul>
  <li>
    <p>汇款金融机构名称： <code class="language-plaintext highlighter-rouge">LINE Bank Taiwan Limited</code></p>
  </li>
  <li>
    <p>金融机构所收汇款费用： <code class="language-plaintext highlighter-rouge">25</code></p>
  </li>
</ul>

<p>点击「送出」 → 「确定」完成申请。</p>

<p><img src="/assets/e4d139fe0685/1*RYYu26VBBJhxT76Ht1toMQ.webp" alt="" loading="lazy" decoding="async" width="691" height="388" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2OTEiIGhlaWdodD0iMzg4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*RYYu26VBBJhxT76Ht1toMQ.png" /></p>

<p>大约在 2–3 个工作天左右就能收到汇款补贴啰。</p>

<p><img src="/assets/e4d139fe0685/1*L-g13ZQ2uS2PqHRyomDD4g.webp" alt="" loading="lazy" decoding="async" width="976" height="124" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NzYiIGhlaWdodD0iMTI0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*L-g13ZQ2uS2PqHRyomDD4g.png" /></p>

<p>可以去「我的账户」 →「账户记录」中查看汇费补贴记录。</p>

<blockquote>
  <p><em>Firstrade 有点问题，大约会有一天的空档期：申请状态消失、账户纪录没看到补贴进来；大约再过了一天之后就出现入帐记录了！</em></p>
</blockquote>

<blockquote>
  <p><strong><em>虽然 LINE Bank 只跟我们收 TWD $150，但实际汇费是超过 USD $25，所以还是补贴 USD $25。</em></strong></p>
</blockquote>

<h3 id="免责声明">免责声明</h3>

<p>本文仅为个人操作分享，不保证完全正确，一切使用请以实际为主，作者不为使用上的损失负任何责任。</p>

<h3 id="反诈专区">反诈专区</h3>

<h4 id="两阶段验证">两阶段验证</h4>

<p><img src="/assets/e4d139fe0685/1*jPfNxJGPBCY20do8y8Pz_g.webp" alt="" loading="lazy" decoding="async" width="1016" height="736" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDE2IiBoZWlnaHQ9IjczNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/e4d139fe0685/1*jPfNxJGPBCY20do8y8Pz_g.png" /></p>

<p>务必到「我的账户」 → 「设定」 → 启用「身份验证应用」。</p>

<p>这样在陌生装置登入都需要先完成两阶段验证才能登入。</p>

<h4 id="信件与连结网域">信件与连结网域</h4>

<p><img src="/assets/e4d139fe0685/1*Rqr5E1ptXgjXh686EAr_UQ.webp" alt="" loading="lazy" decoding="async" width="922" height="646" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjIiIGhlaWdodD0iNjQ2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/e4d139fe0685/1*Rqr5E1ptXgjXh686EAr_UQ.png" /></p>

<p><img src="/assets/e4d139fe0685/1*R_zbtsoMNVK6ryeSjkMzIQ.webp" alt="" loading="lazy" decoding="async" width="564" height="56" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NjQiIGhlaWdodD0iNTYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/e4d139fe0685/1*R_zbtsoMNVK6ryeSjkMzIQ.png" /></p>

<p>不管信件的样式如何跟真的一样，请注意寄件人是否为 <strong>firstrade.com</strong> 及不要点及信件中任何网址， <strong>若一定要点也请多确认网址是否为 firstrade.com。</strong></p>

<blockquote>
  <p><em>技术上 <strong>诈骗信件、假网站能做到一模ㄧ样</strong> ，真假难辨；网址部分：</em></p>
</blockquote>

<blockquote>
  <p><strong><em>只要不是 firstrade.com 都是诈骗！都是诈骗！都是诈骗！</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>只要不是 firstrade.com 都是诈骗！都是诈骗！都是诈骗！</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>只要不是 firstrade.com 都是诈骗！都是诈骗！都是诈骗！</em></strong></p>
</blockquote>]]></content>
  </entry><entry>
    <title type="html">釜山自由行攻略｜8天7夜必去景点、美食与交通全解析｜釜山通行证省钱秘诀</title>
    <link href="https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E9%87%9C%E5%B1%B1%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-8%E5%A4%A97%E5%A4%9C%E5%BF%85%E5%8E%BB%E6%99%AF%E7%82%B9-%E7%BE%8E%E9%A3%9F%E4%B8%8E%E4%BA%A4%E9%80%9A%E5%85%A8%E8%A7%A3%E6%9E%90-%E9%87%9C%E5%B1%B1%E9%80%9A%E8%A1%8C%E8%AF%81%E7%9C%81%E9%92%B1%E7%A7%98%E8%AF%80-8ace34a1a3d8/" rel="alternate" type="text/html" title="釜山自由行攻略｜8天7夜必去景点、美食与交通全解析｜釜山通行证省钱秘诀" />
    <published>2025-08-13T12:38:54+08:00</published>
    <updated>2025-08-17T10:55:29+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/8ace34a1a3d8</id><summary type="html">规划釜山自由行？掌握8天7夜釜山必玩景点、热门美食与交通卡使用技巧，搭配釜山通行证节省旅费，享受顺畅交通与深度体验，让你的釜山行程更高效精彩。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="Z 度旅行遊記" /><category term="simplified-chinese" /><category term="生活" /><category term="travel" /><category term="busan" /><category term="korea" /><category term="travel-writing" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/8ace34a1a3d8/1*06AC2xvA-jb4pjaIQg6fbQ.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E9%87%9C%E5%B1%B1%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-8%E5%A4%A97%E5%A4%9C%E5%BF%85%E5%8E%BB%E6%99%AF%E7%82%B9-%E7%BE%8E%E9%A3%9F%E4%B8%8E%E4%BA%A4%E9%80%9A%E5%85%A8%E8%A7%A3%E6%9E%90-%E9%87%9C%E5%B1%B1%E9%80%9A%E8%A1%8C%E8%AF%81%E7%9C%81%E9%92%B1%E7%A7%98%E8%AF%80-8ace34a1a3d8/"><![CDATA[<h3 id="游记-2025-韩国釜山-8-天-7-夜自由行">[游记] 2025 韩国釜山 8 天 7 夜自由行</h3>

<p>从南到北，使用釜山通行证 VISIT BUSAN PASS，畅游美景、品味美食，开启专属你的釜山之旅。</p>

<p><img src="/assets/8ace34a1a3d8/1*06AC2xvA-jb4pjaIQg6fbQ.webp" alt="广安大桥" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*06AC2xvA-jb4pjaIQg6fbQ.jpeg" /></p>

<p>广安大桥</p>

<h4 id="背景">背景</h4>

<p>去年 <a href="/posts/z-度旅行遊記/九州自由行攻略-釜山新山茶花号邮轮入境日本博多-深入由布院-大分-福冈等地-cb65fd5ab770/"><strong>2024 年「二访九州 9 日自由行，经釜山→博多邮轮入境」</strong></a> ，从韩国釜山入境再搭船前往日本福冈，那次短暂在釜山待了一个早上，只走马看花去了海东龙宫寺跟海云台而已；今年 7–8 月有一些工作空档，因此再次出发、更深入的探索釜山，这次跟同样是闲人的 Pinkoi 好同事 Sean 一同前往。</p>

<p>日期：2025/07/29–08/05</p>

<h3 id="tldr">TL;DR</h3>

<p>一样把总结写在前面「韩国釜山虽然没有日本的宁静跟秩序，但是有随性跟人情味」。</p>

<p><strong>必去景点：</strong></p>

<ul>
  <li>
    <p>[北] <a href="https://www.kkday.com/zh-tw/product/152412-gijang-skyline-luge-ticket-busan-south-korea?cid=19365" target="_blank">Skyline Luge 滑坡车</a></p>
  </li>
  <li>
    <p>[北] <a href="https://www.kkday.com/zh-tw/product/134684-yacht-holic-busan-yacht-public-tour-gwangan-ri-haeundae-south-korea" target="_blank">釜山游艇之旅 Y Holic</a></p>
  </li>
  <li>
    <p>[北] <a href="https://www.kkday.com/zh-tw/product/123012-haeundae-blueline-park-sky-capsule-beach-train-ticket?cid=19365" target="_blank">胶囊列车</a></p>
  </li>
  <li>
    <p>[北] <a href="https://www.kkday.com/zh-tw/product/12213-busan-spa-land-centum-city-ticket?cid=19365" target="_blank">汗蒸幕</a></p>
  </li>
  <li>
    <p>[北] 海东龙宫寺</p>
  </li>
  <li>
    <p>[北] 新世界百货</p>
  </li>
  <li>
    <p>[南] 影岛大桥</p>
  </li>
</ul>

<p><strong>必吃：</strong></p>

<ul>
  <li>
    <p>[北] <a href="https://naver.me/GEiuqenG" target="_blank">烤鳗鱼 — PUNGCHEONMAN</a></p>
  </li>
  <li>
    <p>[北] <a href="https://naver.me/x9zcuKNm" target="_blank">盐面包 — Jayeondo saltbread</a></p>
  </li>
  <li>
    <p>[南] <a href="https://naver.me/xHmnku7F" target="_blank">喉咙锅盖烤肉 — Moggumung Nampo Branch</a></p>
  </li>
  <li>
    <p>[南] <a href="https://naver.me/GEiuXPsf" target="_blank">Milgot</a> 红豆奶油艾草糯米糕</p>
  </li>
</ul>

<p><strong>必备：</strong></p>

<ul>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/138477-visit-busan-pass-discount-free-attractions?cid=19365" target="_blank"><strong>韩国釜山通行证 VISIT BUSAN PASS</strong></a> <strong>(绝对要用，可以省很多钱)</strong></p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/138477-visit-busan-pass-discount-free-attractions?cid=19365" target="_blank"><strong>韩国釜山通行证 VISIT BUSAN PASS</strong></a> <strong>(绝对要用，可以省很多钱)</strong></p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/138477-visit-busan-pass-discount-free-attractions?cid=19365" target="_blank"><strong>韩国釜山通行证 VISIT BUSAN PASS</strong></a> <strong>(绝对要用，可以省很多钱)</strong></p>
  </li>
</ul>

<blockquote>
  <p><em>这次没吃到的东西：海鲜煎饼(错过)、猪肉汤饭( <a href="/posts/z-度旅行遊記/九州自由行攻略-釜山新山茶花号邮轮入境日本博多-深入由布院-大分-福冈等地-cb65fd5ab770/">上次吃过</a> )、生章鱼(不吃生的，看 ig 很多人吃完食物中毒)、酱蟹(不吃生的)</em></p>
</blockquote>

<h3 id="行前准备">行前准备</h3>

<h4 id="行">行</h4>

<h4 id="机票">机票</h4>

<p><img src="/assets/8ace34a1a3d8/1*UkWjvZsjTVT4z6IbvwBBFQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="634" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjYzNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*UkWjvZsjTVT4z6IbvwBBFQ.png" /></p>

<p>釜山航空 ( <strong>含托运 15KG</strong> )。</p>

<p>价格： <strong>NT$6,728 / 人</strong> 。</p>

<ul>
  <li>
    <p>出发：07/29(二) 台北桃园(TPE) 16:25 -&gt; 釜山金海(PUS) 19:55</p>
  </li>
  <li>
    <p>回程：08/05(二) 釜山金海(PUS) 10:50 -&gt; 台北桃园(TPE) 12:35</p>
  </li>
</ul>

<p>总天数 8 天，实际天数 6 天 (第一天跟最后一天基本上就是搭飞机而已)。</p>

<h4 id="交通卡">交通卡</h4>

<p><img src="/assets/8ace34a1a3d8/1*AnOi_kWaK4ET_udnUwB6nQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="602" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjYwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*AnOi_kWaK4ET_udnUwB6nQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*TwuSm6wAS-J7_s6nLrnKLg.webp" alt="KKday 实体交通卡" loading="lazy" decoding="async" width="554" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*TwuSm6wAS-J7_s6nLrnKLg.png" /></p>

<p><a href="https://www.kkday.com/zh-tw/product/18161-t-money-public-transit-card-pick-up-at-taiwan-taoyuan-international-airport-south-korea?cid=19365" target="_blank">KKday 实体交通卡</a></p>

<p>今年 iPhone 可以直接用 Apple 钱包交通卡里的 Tmoney，可以直接储值使用很方便；但是我已经 <a href="https://www.kkday.com/zh-tw/product/18161-t-money-public-transit-card-pick-up-at-taiwan-taoyuan-international-airport-south-korea?cid=19365" target="_blank">加值了去年买的实体卡</a> 所以就没用了。</p>

<p>另外今年开始也能直接透过 <a href="https://wowpass.io/zh-TW" target="_blank">Wowpass App</a> 加值交通卡，流程是先用信用卡储值 Wowpass 再从 Wowpass 入金到 Tmoney，流程较多而且需要支付手续费。</p>

<p><img src="/assets/8ace34a1a3d8/1*Sz8gh4I3s8sx5_0fsyT4oA.webp" alt="" loading="lazy" decoding="async" width="553" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Sz8gh4I3s8sx5_0fsyT4oA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*PzzH6uT3djtj-egP-1A3YA.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*PzzH6uT3djtj-egP-1A3YA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*C5s-bq9vOTiwDkIIbGHQig.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*C5s-bq9vOTiwDkIIbGHQig.jpeg" /></p>

<blockquote>
  <p>不管是哪一种都建议行前先在台湾用信用卡(因为有可能只支援某些发卡机构)先加值好或是携带一些现金到韩国用机台加值。 <a href="https://map.naver.com/p/" target="_blank">Naver Map</a></p>
</blockquote>

<blockquote>
  <p><a href="https://map.naver.com/p/" target="_blank"><strong><em>韩国务必使用 Naver Map。</em></strong></a></p>
</blockquote>

<blockquote>
  <p><strong><em><a href="https://map.naver.com/p/" target="_blank">韩国务必使用 Naver Map。</a></em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em><a href="https://map.naver.com/p/" target="_blank">韩国务必使用 Naver Map。</a></em></strong></p>
</blockquote>

<h4 id="公车规定">公车规定</h4>

<p><img src="/assets/8ace34a1a3d8/1*SdjC7IxAtx08bLLFngwnzA.webp" alt="" loading="lazy" decoding="async" width="928" height="720" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjgiIGhlaWdodD0iNzIwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*SdjC7IxAtx08bLLFngwnzA.png" /></p>

<ul>
  <li>
    <p><strong>釜山公车规定，大于 20 吋行李箱、手持手摇杯禁止搭乘(拿著不喝也不行，真的会拦)</strong></p>
  </li>
  <li>
    <p>公车一律 <strong>前门上车，后门下车</strong> ；前门刷卡处一般在司机座位侧后方</p>
  </li>
  <li>
    <p><strong>另外商店也不收外来的垃圾，因此如果有自己调冰杯饮料最好在景点、百货喝完丢掉再走，不然很麻烦。</strong></p>
  </li>
  <li>
    <p>两人以上其实可以直接计程车搭到爽，釜山计程车很多又便宜又都很新很方便</p>
  </li>
  <li>
    <p>地铁请确认方向后再进站</p>
  </li>
</ul>

<h4 id="韩国釜山通行证-visit-busan-pass"><a href="https://www.kkday.com/zh-tw/product/138477-visit-busan-pass-discount-free-attractions?cid=19365" target="_blank">韩国釜山通行证 VISIT BUSAN PASS</a></h4>

<p>Busan Pass 有分限时(24/48 HR)无限量型跟限制次数型(180天内用完)。</p>

<p><img src="/assets/8ace34a1a3d8/1*87TkvJQSQbrD1GcZsN3i7w.webp" alt="" loading="lazy" decoding="async" width="1200" height="1077" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwNzciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*87TkvJQSQbrD1GcZsN3i7w.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ujmSSMVX5IINmCmCknawlQ.webp" alt="KKday 2025/08 釜山 Pass 资讯" loading="lazy" decoding="async" width="1024" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9IjEyMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*ujmSSMVX5IINmCmCknawlQ.png" /></p>

<p><a href="https://www.kkday.com/zh-tw/product/138477-visit-busan-pass-discount-free-attractions?cid=19365" target="_blank">KKday 2025/08 釜山 Pass 资讯</a></p>

<ul>
  <li>
    <p>因为行程安排分散在这 8 天，加上想去的景点就那些，我们 <strong>选择买两张 BIG5。</strong></p>
  </li>
  <li>
    <p>价格： <strong>NT$1,380 *2 张 = NT$2,760</strong></p>
  </li>
  <li>
    <p>电子版直接出示订单 QRCode 使用</p>
  </li>
</ul>

<p><strong>实际使用状况如下：</strong></p>

<p><img src="/assets/8ace34a1a3d8/1*ItIzgsZFoDEzwSLJK870Dw.webp" alt="" loading="lazy" decoding="async" width="1020" height="826" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDIwIiBoZWlnaHQ9IjgyNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*ItIzgsZFoDEzwSLJK870Dw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*Q1L0AgRhDM9Eh2WiByj06w.webp" alt="KKday 2025/08 釜山 Pass 资讯" loading="lazy" decoding="async" width="1000" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEyMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*Q1L0AgRhDM9Eh2WiByj06w.png" /></p>

<p><a href="https://www.kkday.com/zh-tw/product/138477-visit-busan-pass-discount-free-attractions?cid=19365" target="_blank">KKday 2025/08 釜山 Pass 资讯</a></p>

<ul>
  <li>
    <p>蓝色少一次(太宗台没去)</p>
  </li>
  <li>
    <p>海云台海岸列车两天各坐了一次</p>
  </li>
</ul>

<h4 id="釜山游艇之旅-y-holic-预约️">釜山游艇之旅 Y Holic 预约⚠️</h4>

<p>使用釜山 Pass 欲搭乘釜山游艇之旅，需要先跟船家预约，我们是选 Y Holic，以这家为例。</p>

<p><strong>买完 Pass 之后透过以下管道传讯息给船家：</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>IG：@yachtholic_info (我们是透过 Line)
LINE：@yachtholic
Email：yh@yachtholic.com
WeChat：yachtholic
</code></pre></div></div>

<p>告知人数、日期、时段、Email 或联系方式跟 釜山 Pass 的 QR Code。</p>

<p>等待确认回复，没问题就预约成功啰！</p>

<ul>
  <li>
    <p>夜间场次 (18:00) 开始 <strong>每个人需要另外收 $5,000 韩元</strong> ，可以现场给或是提前转帐</p>
  </li>
  <li>
    <p><strong>需要提前 30 分钟到场排队确认身份</strong></p>
  </li>
  <li>
    <p>我们是约 18:30 看夕阳</p>
  </li>
</ul>

<blockquote>
  <p><a href="https://www.kkday.com/zh-tw/product/134684-yacht-holic-busan-yacht-public-tour-gwangan-ri-haeundae-south-korea?cid=19365" target="_blank"><em>如果你不想买 Pass 也能直接预约购买游艇行。</em></a></p>
</blockquote>

<h4 id="韩国釜山海云台蓝线公园海岸列车天空胶囊列车票"><a href="https://www.kkday.com/zh-tw/product/123012-haeundae-blueline-park-sky-capsule-beach-train-ticket?cid=19365" target="_blank">韩国釜山｜海云台蓝线公园海岸列车・天空胶囊列车票</a></h4>

<p>请注意： <strong>海岸列车跟胶囊列车不一样</strong> 不要买错，美美的胶囊列车不包含在釜山 Pass 中，需要另外购买车票；而且 <strong>非常热门，务必要在出发前购买预约</strong> 。</p>

<ul>
  <li>
    <p>天空胶囊 尾浦出发</p>
  </li>
  <li>
    <p>2 人座 (1 张 2 人使用)</p>
  </li>
  <li>
    <p><strong>价格：NT$861</strong></p>
  </li>
</ul>

<h4 id="韩国网卡韩国-高速无限流量-esim"><a href="https://www.kkday.com/zh-tw/product/138273-korea-network-card-korea-express-esim-500mb-5gb-50gb-unlimited-plan-south-korea?cid=19365" target="_blank">韩国网卡｜韩国 高速无限流量 eSIM</a></h4>

<ul>
  <li>7 日无限流量方案 (最后一天早上就去机场，所以就不买了)</li>
</ul>

<h4 id="naver-map"><a href="https://map.naver.com/p/" target="_blank">Naver Map</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*PrUwaqdQWWW0uvNzc6NnLQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1119" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjExMTkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*PrUwaqdQWWW0uvNzc6NnLQ.png" /></p>

<blockquote>
  <p><a href="https://map.naver.com/p/" target="_blank"><strong><em>韩国务必使用 Naver Map。</em></strong></a></p>
</blockquote>

<blockquote>
  <p><strong><em><a href="https://map.naver.com/p/" target="_blank">韩国务必使用 Naver Map。</a></em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em><a href="https://map.naver.com/p/" target="_blank">韩国务必使用 Naver Map。</a></em></strong></p>
</blockquote>

<p><strong>插曲 — 出发前一天要登入 Naver Map 发现帐号被锁</strong></p>

<p><img src="/assets/8ace34a1a3d8/1*0SzoLbnn_g-Nu1Gx0aYF9Q.webp" alt="" loading="lazy" decoding="async" width="456" height="616" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NTYiIGhlaWdodD0iNjE2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*0SzoLbnn_g-Nu1Gx0aYF9Q.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*vjnO23ajw0h8XUZ5LBhryw.webp" alt="&lt;https://help.naver.com/service/5640/contents/20783?lang=en&amp;osType=COMMONOS&gt;" loading="lazy" decoding="async" width="440" height="616" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NDAiIGhlaWdodD0iNjE2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*vjnO23ajw0h8XUZ5LBhryw.png" /></p>

<p><a href="https://help.naver.com/service/5640/contents/20783?lang=en&amp;osType=COMMONOS" target="_blank">https://help.naver.com/service/5640/contents/20783?lang=en&amp;osType=COMMONOS</a></p>

<p><strong>原因疑似是在台湾登入被认为是可疑活动触发 Naver 帐号保护机制。</strong></p>

<p>可以透过身份认证重新启用帐号，不过我不确定是忘记名字填什么还是因为外国人无法通过实名验证，反正不管怎么输入都显示输入资讯错误，最后直接被锁死。</p>

<p>爬 <a href="https://www.dcard.tw/f/korea_study/p/257877877" target="_blank">网路资料</a> 说可以填写表单申请取消保护机制「 <a href="https://help.naver.com/inquiry/input.help?categoryNo=18202&amp;serviceNo=5640&amp;lang=en" target="_blank">Members residing outside of Korea_Request to lift account protection measures</a> 」，但是我不太确定名字的问题，因此第一次申请被拒：</p>

<p><img src="/assets/8ace34a1a3d8/1*lc5k61s4A4CBsVQ7ZYBOKg.webp" alt="申诉失败" loading="lazy" decoding="async" width="1114" height="1214" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTE0IiBoZWlnaHQ9IjEyMTQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*lc5k61s4A4CBsVQ7ZYBOKg.png" /></p>

<p>申诉失败</p>

<p>第二封我 <a href="https://help.naver.com/inquiry/input.help?categoryNo=14955&amp;serviceNo=5640&amp;lang=ko" target="_blank">直接去 Help Center</a> 填写申请表单：</p>

<p><img src="/assets/8ace34a1a3d8/1*Mn_YZfHr9U8tXKYCjySHVg.webp" alt="" loading="lazy" decoding="async" width="1200" height="1071" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwNzEiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*Mn_YZfHr9U8tXKYCjySHVg.png" /></p>

<p>申诉内容我输入：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. Your NAVER ID.
你的 Naver 帐号，如果连帐号都忘记可以先从忘记帐号用信像、手机找回

2. The registered name, date of birth, and contact information (mobile phone number or email address) of your NAVER ID.
Date of birth: YYYY/MM/DD 你注册填的生日
Mobile Number: +886XXXXXXXXX 你注册填的手机
Email: 你注册填的 Email
Registered Name: Sorry I really forget which name I've input, it may be one of down below:
你想得到的姓名组合
XXXXX LI
LI XXXXX
XXX
李XX
but my real first name is XXXX, last name is Li

3. Attach your overseas identification card.
as attached file.

4. The details of your request to the NAVER Help Center.
I forgot my name which I input and I want lift the account protection measures.
</code></pre></div></div>

<p>能提供的资讯越多越好，最后附加档案附上护照个人资料页图片。</p>

<p><strong>然后就成功解锁了：</strong></p>

<p><img src="/assets/8ace34a1a3d8/1*uvUo0CgFkqTfuOp87UtahQ.webp" alt="" loading="lazy" decoding="async" width="1038" height="1122" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDM4IiBoZWlnaHQ9IjExMjIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*uvUo0CgFkqTfuOp87UtahQ.png" /></p>

<p>会再收到一封临时密码信，用临时密码就能登入 Naver Map 了， <strong>记得去更改密码跟加绑两阶段验证登入(因为 Naver 登入保护机制我们取消了)</strong> 。</p>

<blockquote>
  <p><em>Naver 的回信速度蛮快的，都在半天内解决；如果怕意外被锁可以先申请「 <a href="https://help.naver.com/inquiry/input.help?categoryNo=18202&amp;serviceNo=5640&amp;lang=en" target="_blank">Members residing outside of Korea_Request to lift account protection measures</a> 」(</em> <a href="https://www.dcard.tw/f/korea_study/p/257877877" target="*blank">参考这篇填写</a> _)。*</p>
</blockquote>

<h4 id="食">食</h4>

<p>提前预约的只有 西面的韩牛烤肉 <a href="https://www.catchtable.net/zh-TW/shop/busan_kosaljip?operationType=REMOTE_WAITING_GLOBAL" target="_blank">花肉店 田浦店</a> 。</p>

<p><img src="/assets/8ace34a1a3d8/1*oXyIDJJvynQfqfD_-Yb8cw.webp" alt="CatchTable" loading="lazy" decoding="async" width="998" height="1198" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5OTgiIGhlaWdodD0iMTE5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*oXyIDJJvynQfqfD_-Yb8cw.png" /></p>

<p>CatchTable</p>

<p>是说 <a href="https://www.catchtable.net/zh-TW/" target="_blank">Catchtable</a> 这个平台还蛮方便的，可以提前预约韩国美食餐厅。</p>

<h4 id="乐">乐</h4>

<ul>
  <li>
    <p>Day 1 07/29 (二)：落地釜山、直奔海云台饭店</p>
  </li>
  <li>
    <p>Day 2 07/30 (三)：早上 Skyline Luge 滑坡车、海东龙宫寺，下午海岸列车＋胶囊列车、回海云台、釜山 BUSAN X the SKY，晚上味赞王烤肉</p>
  </li>
  <li>
    <p>Day 3 07/31 (四)：早上青沙浦、蜂蜜奶油吐司、海岸列车回海云台、下午 Spa Land、晚上釜山游艇之旅、晚上烤鳗鱼</p>
  </li>
  <li>
    <p>Day 4 08/01 (五)： 移动到南浦洞、松岛海上缆车、龙宫云桥、甘川洞文化村、晚上喉咙锅盖烤肉、釜山塔看夜景</p>
  </li>
  <li>
    <p>Day 5 08/02 (六)：乐天百货、影岛大桥开桥(只有周六有)。</p>
  </li>
  <li>
    <p>Day 6 08/03 (日)：乐天百货、富平罐头市场、白浅湾文化村、福泉寺夜景。</p>
  </li>
  <li>
    <p>Day 7 08/04 (一)：移动到西面、晚上吃韩牛。</p>
  </li>
  <li>
    <p>Day 8 08/05 (二)：釜山金海国际机场，回程。</p>
  </li>
</ul>

<h4 id="住">住</h4>

<h4 id="海云台高丽良宵酒店-day-1--day-4-三晚-"><a href="https://www.booking.com/hotel/kr/benikea-haeundae.zh-tw.html?label=gen173nr-10CAEoggI46AdIM1gEaOcBiAEBmAEzuAEHyAEM2AED6AEB-AEBiAIBqAIBuAKWo-bEBsACAdICJGZjZWEwODk4LTZkNzAtNGY0MS04OGViLTE1ZmUxZmJkOGQwZtgCAeACAQ&amp;sid=594a3964e5a18310cf9a473a9d09eb36&amp;aid=304142" target="_blank">海云台高丽良宵酒店 (Day 1 — Day 4 三晚</a> )</h4>

<p><img src="/assets/8ace34a1a3d8/1*f5NuKjYVcPd6G78lEtIncQ.webp" alt="" loading="lazy" decoding="async" width="1090" height="872" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDkwIiBoZWlnaHQ9Ijg3MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*f5NuKjYVcPd6G78lEtIncQ.png" /></p>

<p>地点还算方便，走路到海云台大街大约 10 分钟，有窗但无海景、双人双床房。</p>

<ul>
  <li><strong>价格：实刷 NT$12,032，一晚一人约 NT$2,000。</strong></li>
</ul>

<h4 id="hotel-noah-day-4--day-7-三晚"><a href="https://www.agoda.com/zh-cn/hotel-noah_3/hotel/busan-kr.html" target="_blank">Hotel Noah (Day 4 — Day 7 三晚)</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*UgPFi5UgawBzJbgluC5Vdw.webp" alt="" loading="lazy" decoding="async" width="1100" height="652" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTAwIiBoZWlnaHQ9IjY1MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*UgPFi5UgawBzJbgluC5Vdw.png" /></p>

<p>地铁札嘎其站出来走路约 5 分钟、对街就是 BIFF 广场，有窗户、双人双床房。</p>

<ul>
  <li><strong>价格：实刷 NT$7,783，一晚一人约 NT$1,298。</strong></li>
</ul>

<h4 id="air-sky-hotel-day-7--day-8-一晚"><a href="https://www.booking.com/hotel/kr/eeoseukaigwangwanghotel.zh-tw.html" target="_blank">Air Sky Hotel (Day 7 — Day 8 一晚)</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*mosy-Q7nQzyOIfPmAi3twQ.webp" alt="" loading="lazy" decoding="async" width="1124" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*mosy-Q7nQzyOIfPmAi3twQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*26rsk_MCYmlbNhmKiTKqKw.webp" alt="" loading="lazy" decoding="async" width="553" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*26rsk_MCYmlbNhmKiTKqKw.jpeg" /></p>

<p>距离机场只有一站，等车＋搭车＋走路时间大约只要 10 分钟就能到机场，有窗、双人双床房。</p>

<ul>
  <li><strong>价格：实刷 NT$2,835，一晚一人约 NT$1,418。</strong></li>
</ul>

<blockquote>
  <p><em>题外话：这间饭店在完成预订后会传罐头讯息要求支付订金，如果本就已经在当下全额刷付可以无需理会。</em></p>
</blockquote>

<h4 id="签证">签证</h4>

<p>韩国免签证，只需出发前三天提前在 <a href="https://www.e-arrivalcard.go.kr/portal/apply/agreementPolicy.do?applyType=P" target="_blank">线上填好入境申请表</a> ，就能在落地后直接凭护照完成入境。</p>

<blockquote>
  <p>准备就绪，出发！</p>
</blockquote>

<h3 id="day-1-0729-二-台湾前往海云台">Day 1 07/29 (二) 台湾前往海云台</h3>

<h4 id="1330-抵达桃园国际机场第二航厦">~=13:30 抵达桃园国际机场第二航厦</h4>

<p><img src="/assets/8ace34a1a3d8/1*V9fB_UU_9T-t0Z4QN1WE4g.webp" alt="" loading="lazy" decoding="async" width="1200" height="807" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*V9fB_UU_9T-t0Z4QN1WE4g.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ZQfPfUI56V4EI_U2vgPj5A.webp" alt="" loading="lazy" decoding="async" width="1204" height="1498" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjA0IiBoZWlnaHQ9IjE0OTgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*ZQfPfUI56V4EI_U2vgPj5A.png" /></p>

<p>大约 13:50 开柜报到，约 14:10 完成报到＋托运。</p>

<blockquote>
  <p><em>可以先在釜山航空官网 <a href="https://mtw.airbusan.com/mw/checkin/checkinList" target="_blank">线上完成报到＋选位(免费)</a> 。</em></p>
</blockquote>

<h4 id="1430-完成出境吃东西">14:30 完成出境＋吃东西</h4>

<p><img src="/assets/8ace34a1a3d8/1*QzSioHsBFjr_LBpX2NlgWw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*QzSioHsBFjr_LBpX2NlgWw.jpeg" /></p>

<p>因为落地釜山后就要直接赶去饭店，所以在台湾先吃饱饱。</p>

<h4 id="1500-开始候机启用-esim">15:00 开始候机、启用 eSIM</h4>

<p><img src="/assets/8ace34a1a3d8/1*AXE6WNQdcgDXCFuGn7k5PA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*AXE6WNQdcgDXCFuGn7k5PA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ZdqpL-V_F7GA8qsTKEa93g.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*ZdqpL-V_F7GA8qsTKEa93g.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*QbB73S1hJj3Buwzqf8wdSw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*QbB73S1hJj3Buwzqf8wdSw.jpeg" /></p>

<p>因为怕机场网路不好，所以先在 <a href="https://zhgchg.li/posts/aacd5f5cacd1/#%E4%BA%8B%E5%85%88%E5%95%9F%E7%94%A8-esim-iphone-%E7%82%BA%E4%BE%8B" target="_blank">台湾启用 eSIM</a> 。</p>

<h4 id="1640-飞机起飞">~=16:40 飞机起飞</h4>

<p><img src="/assets/8ace34a1a3d8/1*TnEN0BSfol902HADb8_rNw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*TnEN0BSfol902HADb8_rNw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*_2jmZ8VV-D_8uI43mnnLHQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*_2jmZ8VV-D_8uI43mnnLHQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*mKI4jAmJiEQdoyY8E1VU8g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*mKI4jAmJiEQdoyY8E1VU8g.jpeg" /></p>

<p>小延误 15 分钟起飞，座位蛮小的。</p>

<h4 id="2005-抵达韩国釜山">~=20:05 抵达韩国釜山</h4>

<p><img src="/assets/8ace34a1a3d8/1*GmQ4yzkxgxt9MJgcXwwauA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*GmQ4yzkxgxt9MJgcXwwauA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ZmBqlt5oYtJRpCHdqD1W1g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*ZmBqlt5oYtJRpCHdqD1W1g.jpeg" /></p>

<blockquote>
  <p><em>釜山机场是军民两用机场，禁止拍照。</em></p>
</blockquote>

<h4 id="2030-提领行李完成入境">~=20:30 提领行李＋完成入境</h4>

<p><img src="/assets/8ace34a1a3d8/1*6TN-R2eaqfuh_m2cddvJRA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*6TN-R2eaqfuh_m2cddvJRA.jpeg" /></p>

<p>先去机场的超商买一些小东西补充热量，还有换钱跟休息了一下。</p>

<h4 id="2100-抵达金海轻轨--机场站">~=21:00 抵达金海轻轨 — 机场站</h4>

<p>从机场出来大概走路 5 分钟就到了。</p>

<p><img src="/assets/8ace34a1a3d8/1*9qFJw2RhaG6aaQae1WHrPA.webp" alt="" loading="lazy" decoding="async" width="983" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5ODMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*9qFJw2RhaG6aaQae1WHrPA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*qovf8TmzIHYe6jOPqAyqAw.webp" alt="" loading="lazy" decoding="async" width="990" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5OTAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*qovf8TmzIHYe6jOPqAyqAw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*S4Gkbfsb_0uApwcUSEiTnA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*S4Gkbfsb_0uApwcUSEiTnA.jpeg" /></p>

<p>先陪 Sean 储值交通卡，这边有两台可以储值交通卡的机器 (Self Service Charger)， <strong>只能以韩币 1000 元为倍数加值</strong> 。</p>

<p><img src="/assets/8ace34a1a3d8/1*o-mrmvVu8YonD9G7kFgn0A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*o-mrmvVu8YonD9G7kFgn0A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*5PANgTxqra2B7_S1knjfkA.webp" alt="" loading="lazy" decoding="async" width="1200" height="1023" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwMjMiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*5PANgTxqra2B7_S1knjfkA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*jILCIPwHH4B2sUCZb5glEg.webp" alt="" loading="lazy" decoding="async" width="742" height="1382" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NDIiIGhlaWdodD0iMTM4MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*jILCIPwHH4B2sUCZb5glEg.png" /></p>

<p>刷卡进站后请找前往沙上(Sasang Station)的月台，下一站是「西釜山流通地区」。</p>

<h4 id="2115-抵达沙上转乘绿线">~=21:15 抵达沙上转乘绿线</h4>

<p><img src="/assets/8ace34a1a3d8/1*54uF-nAbXp068jDEvOSRxQ.webp" alt="" loading="lazy" decoding="async" width="732" height="1592" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MzIiIGhlaWdodD0iMTU5MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*54uF-nAbXp068jDEvOSRxQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*SU68g_MSrPTZeJQ7BFQLhg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*SU68g_MSrPTZeJQ7BFQLhg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*WR7xmcLqxByn81lIAdRl6g.webp" alt="" loading="lazy" decoding="async" width="516" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTYiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*WR7xmcLqxByn81lIAdRl6g.png" /></p>

<p>这边只要一路跟著地上的绿色指示就能从轻轨出站转地铁绿线，往「 <strong>苌山</strong> 」方向(另一个方向是往 <strong>梁山</strong> ，不要看错字了)，下一站「甘田」。</p>

<h4 id="2120-抵达绿线沙上站等车">~=21:20 抵达绿线沙上站等车</h4>

<p><img src="/assets/8ace34a1a3d8/1*mhSqB1__ButsItcOkBuTBw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*mhSqB1__ButsItcOkBuTBw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*rpFYA13Lb9nyNy1dAp50PA.webp" alt="" loading="lazy" decoding="async" width="1400" height="584" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjU4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*rpFYA13Lb9nyNy1dAp50PA.png" /></p>

<h4 id="2220-抵达海云台">~=22:20 抵达海云台</h4>

<p>快到海云台站的时候地铁广播会有海鸥的叫声。</p>

<p><img src="/assets/8ace34a1a3d8/1*FCNMmVBqS2AKfNQjh5cVmg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*FCNMmVBqS2AKfNQjh5cVmg.jpeg" /></p>

<h4 id="2230-抵达饭店">~=22:30 抵达饭店</h4>

<p><img src="/assets/8ace34a1a3d8/1*LOXnjLsRW91_eVYck5kGeQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*LOXnjLsRW91_eVYck5kGeQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*30mP_dahFonL0ve1n_vEig.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*30mP_dahFonL0ve1n_vEig.jpeg" /></p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/YbU4uG3pLjI" title="海云台高丽良宵酒店" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<h4 id="2250-出门海云台大街觅食">~=22:50 出门海云台大街觅食</h4>

<p><img src="/assets/8ace34a1a3d8/1*yKUlVFqVaS2D6M7j16mfoQ.webp" alt="" loading="lazy" decoding="async" width="1228" height="1518" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjI4IiBoZWlnaHQ9IjE1MTgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*yKUlVFqVaS2D6M7j16mfoQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*64lyMg61i9rRbmJcwxjjgQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*64lyMg61i9rRbmJcwxjjgQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*HjfYqKBHDe5_c0iF7QaHuw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*HjfYqKBHDe5_c0iF7QaHuw.jpeg" /></p>

<p>住的位子会先经过海云台传统市场有卖很多吃的。</p>

<h4 id="2330-回饭店开吃">~=23:30 回饭店开吃</h4>

<p><img src="/assets/8ace34a1a3d8/1*vQBulLYRFkoUQC_Os4hPFw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*vQBulLYRFkoUQC_Os4hPFw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*SyBfYDcG8uh5ArLioXV9vg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*SyBfYDcG8uh5ArLioXV9vg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*My3vIyTLBNbTSDtfh4FtkA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*My3vIyTLBNbTSDtfh4FtkA.jpeg" /></p>

<p>最后买了 BBQ 炸鸡 两种口味跟传统市场的辣年糕还有超商的酒。</p>

<blockquote>
  <p><em>炸鸡一份就够两个人吃了，两份太多了(感觉是台湾的四份)，实刷 NT $1,210。</em></p>
</blockquote>

<blockquote>
  <p><em>这款芒果酒(</em> Iced tea highball with mango cubes <em>)好喝(5%) 里面有芒果罐头果肉，后来发现台湾全家超商也有进。</em></p>
</blockquote>

<h3 id="day-2-0730-三-skyline-luge-滑坡车海东龙宫寺海岸列车胶囊列车釜山-busan-x-the-sky味赞王烤肉">Day 2 07/30 (三) Skyline Luge 滑坡车、海东龙宫寺、海岸列车、胶囊列车、釜山 BUSAN X the SKY、味赞王烤肉</h3>

<h4 id="0930-出门--超级好天气">09:30 出门 — 超级好天气</h4>

<p><img src="/assets/8ace34a1a3d8/1*zShkz0mzeWJhZKml3P1D2A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*zShkz0mzeWJhZKml3P1D2A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*Yf9ZxEjhX1K-YMwhTaDgFw.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Yf9ZxEjhX1K-YMwhTaDgFw.jpeg" /></p>

<p>饭店门口就有公车直达 Skyline Luge。</p>

<h4 id="1025-skyline-luge-">10:25 Skyline Luge 👍👍👍</h4>

<p><img src="/assets/8ace34a1a3d8/1*Yv8wNXoEqXLZZJII4DQsxg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Yv8wNXoEqXLZZJII4DQsxg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*QXuBBjbiGpENtziQS-sagg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*QXuBBjbiGpENtziQS-sagg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*s71ofWNtvFfoIBqnf-0VJw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*s71ofWNtvFfoIBqnf-0VJw.jpeg" /></p>

<p>大约 10:30 开始排换票 (釜山 Pass 需要换票后才能使用)，人蛮多的，大约排了 20 分钟拿到门票；釜山 Pass 可以选择玩两次滑坡车或是玩一次滑坡车跟一次高空滑索，大家几乎都选玩两次滑坡车。</p>

<blockquote>
  <p><a href="https://www.kkday.com/zh-tw/product/152412-gijang-skyline-luge-ticket-busan-south-korea?cid=19365" target="*blank"><em>如果没有买 Pass 也能先在 KKday 购票。</em></a> _<strong>(比现场买便宜，但也要换票才能进)</strong>*</p>
</blockquote>

<p><img src="/assets/8ace34a1a3d8/1*cLgWZh4YrAkhLDfIkUICpw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*cLgWZh4YrAkhLDfIkUICpw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*_V9oQVANR9ncErO9tWEsCw.webp" alt="" loading="lazy" decoding="async" width="1228" height="1506" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjI4IiBoZWlnaHQ9IjE1MDYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*_V9oQVANR9ncErO9tWEsCw.png" /></p>

<p>换好票之后直接去旁边选好符合 Size 的安全帽，戴好安全帽就能搭缆车上去啰。</p>

<h4 id="1100-搭上缆车">~=11:00 搭上缆车</h4>

<p><img src="/assets/8ace34a1a3d8/1*PT-mGar4So6od4dD3A6F5g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*PT-mGar4So6od4dD3A6F5g.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*YzED-cEVaw7wrylcSUjuKw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*YzED-cEVaw7wrylcSUjuKw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*YHu8QYJ2Cx1grupJ55ZmsQ.webp" alt="" loading="lazy" decoding="async" width="930" height="1588" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzAiIGhlaWdodD0iMTU4OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*YHu8QYJ2Cx1grupJ55ZmsQ.png" /></p>

<p>人都集中站换票、买票柜台，后面搭缆车跟滑坡车都不用怎么排队，缆车上去的途中可以看到下面的赛道，大约 5 分钟就抵达出发点。</p>

<p><img src="/assets/8ace34a1a3d8/1*doGVKHy5yunEpR7OFaa6rw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*doGVKHy5yunEpR7OFaa6rw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*f0KgbnLu921Hiq7QAZg5HQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*f0KgbnLu921Hiq7QAZg5HQ.jpeg" /></p>

<p>如果很怕开放式缆车的，这次去有看到旁边另一条箱型式缆车感觉也快开通了(?)。</p>

<h4 id="1105-准备出发">11:05 准备出发</h4>

<p><img src="/assets/8ace34a1a3d8/1*QmbycT8d2Gh5wimLP18CPQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*QmbycT8d2Gh5wimLP18CPQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*SA-bWwl8EuFsllB6_O5IrA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*SA-bWwl8EuFsllB6_O5IrA.jpeg" /></p>

<p>上面可以眺望隔壁的乐天乐园。</p>

<p>第一次请排「首次搭乘入场」会盖手章跟有工作人员做简单教学。</p>

<p><img src="/assets/8ace34a1a3d8/1*UCPhQh3lnSwMiO9UBqoHDQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*UCPhQh3lnSwMiO9UBqoHDQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*loe9DLrp_dtUFnpYrwxAOw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*loe9DLrp_dtUFnpYrwxAOw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*i9BnnhpabwgnxuBDw_7dbA.webp" alt="" loading="lazy" decoding="async" width="917" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTciIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*i9BnnhpabwgnxuBDw_7dbA.png" /></p>

<p>操作方式总之就是：</p>

<ul>
  <li>
    <p><strong>脚打直</strong></p>
  </li>
  <li>
    <p><strong>往后前进、往前放煞车</strong></p>
  </li>
  <li>
    <p>中途不能停、中途不能停、中途不能停，完全停下来就很难继续滑动了</p>
  </li>
  <li>
    <p>适时转弯前减速不然会翻车</p>
  </li>
  <li>
    <p>小心超车</p>
  </li>
  <li>
    <p><strong>双手操控不可手持手机，中途有摄影机会拍照可以去纪念品店购买</strong></p>
  </li>
  <li>
    <p>个人物品要小心不要掉了</p>
  </li>
</ul>

<p><img src="/assets/8ace34a1a3d8/1*GGsBBz5201M0fOrH4T1sqQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1006" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMDYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*GGsBBz5201M0fOrH4T1sqQ.png" /></p>

<p>从上滑到下大约 6 分钟而已。</p>

<p>下来就是纪念品中心跟可以买中途拍的照片。</p>

<p><img src="/assets/8ace34a1a3d8/1*17zdVTPo_LP48TizhwValw.webp" alt="" loading="lazy" decoding="async" width="941" height="1185" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDEiIGhlaWdodD0iMTE4NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*17zdVTPo_LP48TizhwValw.png" /></p>

<p>穿过纪念品中心回到入口，再排一次缆车上去。</p>

<p><img src="/assets/8ace34a1a3d8/1*I0y7aZ0bpynBInkP18lcUQ.webp" alt="" loading="lazy" decoding="async" width="694" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2OTQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*I0y7aZ0bpynBInkP18lcUQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*2Y0iQTWf9pE0fAZJEK7JDg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*2Y0iQTWf9pE0fAZJEK7JDg.jpeg" /></p>

<p>这次排再入场通道（可以直接玩，不会有工作人员教学）。</p>

<p><img src="/assets/8ace34a1a3d8/1*1aOU7IAPVNd6bSLNTaXRsw.webp" alt="" loading="lazy" decoding="async" width="1200" height="865" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*1aOU7IAPVNd6bSLNTaXRsw.png" /></p>

<p>ㄏ胜。</p>

<h4 id="1145-离开前往海东龙宫寺">11:45 离开，前往海东龙宫寺</h4>

<p>出 Skyline Luge 后对面直直走就是海东龙宫寺了，大约需步行 10 分钟、上坡路。</p>

<p><img src="/assets/8ace34a1a3d8/1*W8pHXqKZ-gEPUqqLQV7cSA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*W8pHXqKZ-gEPUqqLQV7cSA.jpeg" /></p>

<h4 id="1155-海东龙宫寺">11:55 海东龙宫寺</h4>

<p>因为 <a href="/posts/z-度旅行遊記/九州自由行攻略-釜山新山茶花号邮轮入境日本博多-深入由布院-大分-福冈等地-cb65fd5ab770/"><strong>去年有来过了</strong></a> ，所以这次只走马看花。</p>

<p><img src="/assets/8ace34a1a3d8/1*QO6ie1PN4o8liIjIs2Y0qQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="861" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*QO6ie1PN4o8liIjIs2Y0qQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*5RNxsL0nD0TQ3I_UvwZQPg.webp" alt="" loading="lazy" decoding="async" width="935" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzUiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*5RNxsL0nD0TQ3I_UvwZQPg.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*NllO9Hy73kJQzWNGoW0ABA.webp" alt="" loading="lazy" decoding="async" width="948" height="1240" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDgiIGhlaWdodD0iMTI0MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*NllO9Hy73kJQzWNGoW0ABA.png" /></p>

<p>大约 11:55 就到海东龙宫寺摊贩入口。</p>

<p><img src="/assets/8ace34a1a3d8/1*m-tact5LRxGmwTBeDj7D2w.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*m-tact5LRxGmwTBeDj7D2w.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*K2ByL3USjy1fUlipsZLv1g.webp" alt="" loading="lazy" decoding="async" width="1200" height="843" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*K2ByL3USjy1fUlipsZLv1g.png" /></p>

<p>这次才发现海东龙宫寺匾牌入口右边也可以走，是缓下坡可以直达本殿；走匾牌入口这边是很陡的楼梯，不好走。</p>

<p><img src="/assets/8ace34a1a3d8/1*dyci1YPm-ApaeV2MDLsW2Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*dyci1YPm-ApaeV2MDLsW2Q.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*wpe6ymEfLMASAEivSVyyJQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*wpe6ymEfLMASAEivSVyyJQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*AvKx5_BLU1cAJSkrvY8u7A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*AvKx5_BLU1cAJSkrvY8u7A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*8RX8RXzZJ_4mW8hxss7hTw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*8RX8RXzZJ_4mW8hxss7hTw.jpeg" /></p>

<h4 id="1245-等公车去松亭站">12:45 等公车去松亭站</h4>

<p><img src="/assets/8ace34a1a3d8/1*hnGZPnjF3eIAeAp7nu-Seg.webp" alt="" loading="lazy" decoding="async" width="942" height="1196" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDIiIGhlaWdodD0iMTE5NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*hnGZPnjF3eIAeAp7nu-Seg.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*05IR75W3B-T4g2QkInLjHg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*05IR75W3B-T4g2QkInLjHg.jpeg" /></p>

<p>釜山的避暑措施做得蛮好的，路上等红绿灯有阳伞、公车站几乎都有风扇，可以按一下启动。</p>

<h4 id="路线计划如下图">路线计划如下图：</h4>

<p><img src="/assets/8ace34a1a3d8/1*wbyHE15DgoW3_pkit_OR_A.webp" alt="" loading="lazy" decoding="async" width="1400" height="947" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk0NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*wbyHE15DgoW3_pkit_OR_A.png" /></p>

<p>从 Skyline Luge 搭公车+走路到海岸列车松亭站，搭海岸列车到青沙浦站，转搭胶囊列车回海云台。</p>

<h4 id="1315-抵达松亭车站">~=13:15 抵达松亭车站</h4>

<p><img src="/assets/8ace34a1a3d8/1*1W63YJR27-niR0rPFiNkdw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*1W63YJR27-niR0rPFiNkdw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*qKTgaE6w7QYNnHU41kgdRg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*qKTgaE6w7QYNnHU41kgdRg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*E1rZoLfWgHKUxb3qRAXhkg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*E1rZoLfWgHKUxb3qRAXhkg.jpeg" /></p>

<p>从公车站走过来还要约 10 分钟，很热很晒。</p>

<p><img src="/assets/8ace34a1a3d8/1*uQegRUm5OVql_OGz5L4TQg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*uQegRUm5OVql_OGz5L4TQg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*PvM5nguf_-Fv6NfoWztP-w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*PvM5nguf_-Fv6NfoWztP-w.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*J76MOVL-li-Tg6c__KNMKg.webp" alt="ref" loading="lazy" decoding="async" width="927" height="322" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjciIGhlaWdodD0iMzIyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*J76MOVL-li-Tg6c__KNMKg.png" /></p>

<p><a href="https://www.kkday.com/zh-tw/product/123012-haeundae-blueline-park-sky-capsule-beach-train-ticket?cid=19365" target="_blank">ref</a></p>

<p>13:30 的人满了，划位划 14:00 的。( <a href="http://m.site.naver.com/0URl8" target="_blank">时刻表</a> )</p>

<blockquote>
  <p><em>小插曲：这站站务员不给用釜山 Pass PDF 档，要我们一定要从 KKday App 开凭证给他。</em></p>
</blockquote>

<blockquote>
  <p><em>釜山 Pass 换的车票可当日、每个车站上车一次，所以其实可以沿途停靠各个景点。</em></p>
</blockquote>

<p><img src="/assets/8ace34a1a3d8/1*mCtniHyCFiDVmGqsr8fFfw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*mCtniHyCFiDVmGqsr8fFfw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*LBR8tx9HfigYr51-ih8dag.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*LBR8tx9HfigYr51-ih8dag.jpeg" /></p>

<p>时间还很早，先去便利超商果腹；松亭站出来就是松亭海水浴场(感觉人比较少)，这边有一家超商。</p>

<h4 id="1340-开始候车">~=13:40 开始候车</h4>

<p>记得提早去排队候车，不然只能站在最后一排。</p>

<p><img src="/assets/8ace34a1a3d8/1*wMw1Bmz47wE2_ivQ4LtQAw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*wMw1Bmz47wE2_ivQ4LtQAw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*_jexN3EvstbOgkts27zQhg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*_jexN3EvstbOgkts27zQhg.jpeg" /></p>

<p>穿过车站出来一路走到月台，在月台验票入场就能开始候车了。</p>

<p>大约 13:50 车就会到，人群开始骚动排队。</p>

<h4 id="1400-出发">~=14:00 出发</h4>

<p><img src="/assets/8ace34a1a3d8/1*HT17e69lak7tbTqoXCpVUg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*HT17e69lak7tbTqoXCpVUg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*QBfTvy19T_Jl6zvxVNDqfQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*QBfTvy19T_Jl6zvxVNDqfQ.jpeg" /></p>

<p>坐到第二排的位子，风景还不错。</p>

<h4 id="1415-抵达青沙浦">~=14:15 抵达青沙浦</h4>

<p><img src="/assets/8ace34a1a3d8/1*xeOjrCl9pQx_u28XnJXELA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*xeOjrCl9pQx_u28XnJXELA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*6JA5jGLBfsMl2GJMmehhtw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*6JA5jGLBfsMl2GJMmehhtw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*H0sBRecqIdECSploIAYVpw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*H0sBRecqIdECSploIAYVpw.jpeg" /></p>

<p>下车后在月台看到往 2 楼的楼梯就是胶囊列车的乘车处了。</p>

<p><img src="/assets/8ace34a1a3d8/1*Y4jeQwk6jnpsbAklaKZI6g.webp" alt="" loading="lazy" decoding="async" width="945" height="1193" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDUiIGhlaWdodD0iMTE5MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Y4jeQwk6jnpsbAklaKZI6g.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*XDAIgiQb3qdEDSr546kNzg.webp" alt="" loading="lazy" decoding="async" width="572" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NzIiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*XDAIgiQb3qdEDSr546kNzg.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*hrnYxziizbB6PrFv97Qiow.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*hrnYxziizbB6PrFv97Qiow.jpeg" /></p>

<p>打开 <a href="https://www.kkday.com/zh-tw/product/123012-haeundae-blueline-park-sky-capsule-beach-train-ticket?cid=19365" target="_blank">KKday 订单凭证中有一个连结</a> ，会出现车票凭证；上二楼后给亭子的工作人员看凭证(我们预约的是 14:30–15:00 的梯次)，他会发一张号码牌给你，时间到会开始叫号，如果已经开始叫号那就只能等叫号完了。</p>

<p><img src="/assets/8ace34a1a3d8/1*KCbwTzka0L2cWDvX2O37iQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*KCbwTzka0L2cWDvX2O37iQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*FjPJSkqC67-UAhlwm9RRzA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*FjPJSkqC67-UAhlwm9RRzA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*5Tx02qf1e3U_IKWJaWjp8g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*5Tx02qf1e3U_IKWJaWjp8g.jpeg" /></p>

<p>等待期间去隔壁纪念品店买了一只扇子。</p>

<blockquote>
  <p><em>胶囊列车也有免费的扇子可以拿(最右张图)。</em></p>
</blockquote>

<h4 id="1430-胶囊列车叫号排队">~=14:30 胶囊列车叫号排队</h4>

<p>时间到工作人员会开始依序叫号排队。</p>

<p><img src="/assets/8ace34a1a3d8/1*ZPQgbN2k7kRG2KI-3YEfEA.webp" alt="" loading="lazy" decoding="async" width="934" height="1229" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzQiIGhlaWdodD0iMTIyOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*ZPQgbN2k7kRG2KI-3YEfEA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*7S7dQYAf2Zqj_dxMjl_pDw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*7S7dQYAf2Zqj_dxMjl_pDw.jpeg" /></p>

<p>排队区域上方有冷气，上车前才会核销凭证(记得先开好)，上车后工作人员会拍一张合照，再看下车后要不要跟他们购买。</p>

<h4 id="1440-胶囊列车青沙浦---尾浦海云台-出发-">~=14:40 胶囊列车青沙浦 -&gt; 尾浦(海云台) 出发! 👍👍👍</h4>

<p><img src="/assets/8ace34a1a3d8/1*fLpUWvXcdl3Ryc1ary_arQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*fLpUWvXcdl3Ryc1ary_arQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*nMQDysR6bNzOxVTLLU7rPQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*nMQDysR6bNzOxVTLLU7rPQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*l1JWUq3qAKEyDoyLJyzSPQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*l1JWUq3qAKEyDoyLJyzSPQ.jpeg" /></p>

<p>看起来很刺激，实际走得很慢；车厢内没冷气但有通风扇跟扩音箱可以插手机放音乐。</p>

<p><img src="/assets/8ace34a1a3d8/1*w4zPWlwQcqHhF4WCokBVyQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*w4zPWlwQcqHhF4WCokBVyQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*L4f0Ebz-fi6SeW7ZZJeTRQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*L4f0Ebz-fi6SeW7ZZJeTRQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*67tHAjdjNoZLmHdg0bLZFw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*67tHAjdjNoZLmHdg0bLZFw.jpeg" /></p>

<p>一路看看风景拍拍网美照(?)</p>

<h4 id="1510-抵达尾浦海云台">~=15:10 抵达尾浦(海云台)</h4>

<p><img src="/assets/8ace34a1a3d8/1*hTEuxliIs2s_098pdVaOsg.webp" alt="" loading="lazy" decoding="async" width="944" height="1203" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDQiIGhlaWdodD0iMTIwMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*hTEuxliIs2s_098pdVaOsg.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*mrsat28nAJ7e1PWJcb-KMQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="986" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*mrsat28nAJ7e1PWJcb-KMQ.png" /></p>

<p>朝著海云台方向(高楼)走出来到路口，对面右边就是有名好吃的 <a href="https://naver.me/x9zcuKNm" target="_blank">盐面包 — Jayeondo saltbread</a> (等下会回来买)左边一路往下走到面海的入口就是 釜山 Sky 入场处。</p>

<p><img src="/assets/8ace34a1a3d8/1*mxRI19obHDJEYWgaWpLC4g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*mxRI19obHDJEYWgaWpLC4g.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*kG7OMT38Kq5n4inz0Zi1VQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*kG7OMT38Kq5n4inz0Zi1VQ.jpeg" /></p>

<h4 id="1535-釜山-busan-x-the-sky">~=15:35 釜山 BUSAN X the SKY</h4>

<p><img src="/assets/8ace34a1a3d8/1*wLhiiMFHth1q0M0I52w0BQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*wLhiiMFHth1q0M0I52w0BQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*4GZH5tai41pbv0WbydQBzQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*4GZH5tai41pbv0WbydQBzQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*MZtM_pbelaE_9DSkReik6Q.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*MZtM_pbelaE_9DSkReik6Q.jpeg" /></p>

<p>海云台沙滩方向的玻璃是有围栏阻隔的，没办法贴著拍照。</p>

<p><img src="/assets/8ace34a1a3d8/1*LphemYMPN0KncWvpEvv-5w.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*LphemYMPN0KncWvpEvv-5w.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*59D8d2G9l56zMvbn3yw55Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*59D8d2G9l56zMvbn3yw55Q.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*Naj3fWNQzQthcPQJvr3onA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Naj3fWNQzQthcPQJvr3onA.jpeg" /></p>

<p>有一个透明玻璃地板桥，不过玻璃磨损严重效果普普；还有可以透明玻璃厕所。</p>

<p><img src="/assets/8ace34a1a3d8/1*-H0j9zTeDr4mJ6Cqk3wWfA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*-H0j9zTeDr4mJ6Cqk3wWfA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*8kH5BBvg3v0xYPxl-NknSw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*8kH5BBvg3v0xYPxl-NknSw.jpeg" /></p>

<p>往下走到咖啡厅、纪念品店可以回望刚刚胶囊列车来的路线。</p>

<p><img src="/assets/8ace34a1a3d8/1*89JfpBVVoL3GcEbkqqMNyQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*89JfpBVVoL3GcEbkqqMNyQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*3MGWqKezW4zdue_uNECOWw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*3MGWqKezW4zdue_uNECOWw.jpeg" /></p>

<p>吃了一根鱼板香肠补充热量(味道普普)。</p>

<p><img src="/assets/8ace34a1a3d8/1*--lNPiay_O4al6tfX5spwg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*--lNPiay_O4al6tfX5spwg.jpeg" /></p>

<p>除了咖啡厅、纪念品店，这层也有免费的展览。</p>

<h4 id="1600-离开走回去买-盐面包--jayeondo-saltbread-">~=16:00 离开，走回去买 <a href="https://naver.me/x9zcuKNm" target="_blank">盐面包 — Jayeondo saltbread</a> 👍👍👍</h4>

<p><img src="/assets/8ace34a1a3d8/1*w9_aMzKXaNfaz_haZN-XIw.webp" alt="" loading="lazy" decoding="async" width="1400" height="995" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*w9_aMzKXaNfaz_haZN-XIw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*XF58GQnLL6PnuqbvlxDNEQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*XF58GQnLL6PnuqbvlxDNEQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*O8DuQ0ywuuN5fxZXc_0_JQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*O8DuQ0ywuuN5fxZXc_0_JQ.jpeg" /></p>

<p>一份就是 6 个，买一份回饭店分著吃，香+脆+微微的盐粒提味，我觉得很好吃。</p>

<p><img src="/assets/8ace34a1a3d8/1*2oV0hKVku4_AgQI7cf_cag.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*2oV0hKVku4_AgQI7cf_cag.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*8-6mY9FWINdMJiYxpfPZEQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*8-6mY9FWINdMJiYxpfPZEQ.jpeg" /></p>

<p>海云台这边有很多大兴土木改造工程，看起来在为 2030 争取办世博做准备(不过已经失败)。</p>

<blockquote>
  <p><em>回饭店休息一下，晚上再去吃味赞王。</em></p>
</blockquote>

<h4 id="1750-抵达-味赞王海云台店--matchandeul-salted-grill-haeundae-branch">17:50 抵达 <a href="https://naver.me/5sG3vEe5" target="_blank">味赞王海云台店 — Matchandeul Salted Grill Haeundae Branch</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*AsOMjouHVz3BRue3olauuw.webp" alt="" loading="lazy" decoding="async" width="943" height="1198" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDMiIGhlaWdodD0iMTE5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*AsOMjouHVz3BRue3olauuw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*O39pGmtLGJIa-bXxK-Nnig.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*O39pGmtLGJIa-bXxK-Nnig.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*52iHV2Dv0vDDxNuqJxYmhg.webp" alt="" loading="lazy" decoding="async" width="484" height="811" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0ODQiIGhlaWdodD0iODExIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*52iHV2Dv0vDDxNuqJxYmhg.png" /></p>

<p>门口有一台机器可以候位，输入信箱会收到通知，17:50 来就开始小排队了。</p>

<p><img src="/assets/8ace34a1a3d8/1*PQL9i8rdeGLZD0rNLEaLxw.webp" alt="" loading="lazy" decoding="async" width="515" height="682" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTUiIGhlaWdodD0iNjgyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*PQL9i8rdeGLZD0rNLEaLxw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*NNmf9vfpx9sX-EPv-6-MCQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*NNmf9vfpx9sX-EPv-6-MCQ.jpeg" /></p>

<p>点按钮可以查看当前号码，时间到也会收到可入场通知信，很方便； <strong>另外，对面、隔壁大楼都在施工要小心。</strong></p>

<h4 id="1825-入场用餐">18:25 入场用餐</h4>

<p>大约等了 30 多分钟才入场。</p>

<p><img src="/assets/8ace34a1a3d8/1*7MgY9p6aZMbGejj56iU11A.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*7MgY9p6aZMbGejj56iU11A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*1dn6e5L69VTVnrcEfhMvDw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*1dn6e5L69VTVnrcEfhMvDw.jpeg" /></p>

<p>我们直接点双人套餐(内容是肉各一+大酱汤+釜饭)然后再一瓶 Cass 啤酒，实刷约 NT$1,500。</p>

<blockquote>
  <p><em>会烤好给你吃，评价是肉好吃但份量不多&amp;要排队等候。</em></p>
</blockquote>

<h4 id="2030-吃饱回海云台大街">~=20:30 吃饱回海云台大街</h4>

<p><img src="/assets/8ace34a1a3d8/1*O2UXV7D8gKQ0hImc8iDnMA.webp" alt="" loading="lazy" decoding="async" width="948" height="1199" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDgiIGhlaWdodD0iMTE5OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*O2UXV7D8gKQ0hImc8iDnMA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*YINokSS0bT-ebB5VXJhW_w.webp" alt="" loading="lazy" decoding="async" width="918" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTgiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*YINokSS0bT-ebB5VXJhW_w.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*PjSGfzXsbc9bYFb1sK18Tw.webp" alt="" loading="lazy" decoding="async" width="918" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTgiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*PjSGfzXsbc9bYFb1sK18Tw.png" /></p>

<p>海云台大街走走消化一下，买了一家抹茶专卖店的冰淇淋当甜点解腻。</p>

<p><img src="/assets/8ace34a1a3d8/1*eEqklwquew6rGg4-Il6FUw.webp" alt="" loading="lazy" decoding="async" width="937" height="1186" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzciIGhlaWdodD0iMTE4NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*eEqklwquew6rGg4-Il6FUw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*XIW1F6tF8P0ExjjlixWKxQ.webp" alt="" loading="lazy" decoding="async" width="1146" height="961" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTQ2IiBoZWlnaHQ9Ijk2MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*XIW1F6tF8P0ExjjlixWKxQ.png" /></p>

<p>隔壁就是 Olive Young 新开的 Delight Project 专卖店，搜刮了一波；很多买二送一并且满15,000 韩元可以直接现场退税。</p>

<p><img src="/assets/8ace34a1a3d8/1*9eNytaAkCGcIgbOzagwTiQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="972" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk3MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*9eNytaAkCGcIgbOzagwTiQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*hW_N_93CpyyzWCGZ-OtJ4Q.webp" alt="" loading="lazy" decoding="async" width="943" height="1214" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDMiIGhlaWdodD0iMTIxNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*hW_N_93CpyyzWCGZ-OtJ4Q.png" /></p>

<p>再去海云台海滩晃了一下才回饭店休息。</p>

<h3 id="day-3-0731-四-青沙浦-spa-land海岸列车釜山游艇之旅">Day 3 07/31 (四) 青沙浦、 Spa Land、海岸列车、釜山游艇之旅</h3>

<p>因为昨天只在青沙浦转乘没特别逛，今天又来。</p>

<h4 id="1100-上公车出发前往青沙浦">11:00 上公车出发前往青沙浦</h4>

<p><img src="/assets/8ace34a1a3d8/1*rbpv52Shw77IaUdT2d7-8w.webp" alt="" loading="lazy" decoding="async" width="954" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*rbpv52Shw77IaUdT2d7-8w.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*DJj6wZCG0KRomyT94xO1lA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*DJj6wZCG0KRomyT94xO1lA.jpeg" /></p>

<p>从海云台直达青沙浦的公车是小巴，沿途会经过釜山山庄之类的社区路比较小也很陡。</p>

<h4 id="1130-抵达青沙浦">11:30 抵达青沙浦</h4>

<p><img src="/assets/8ace34a1a3d8/1*fRTe_hokNNcPNgX97qZcQw.webp" alt="" loading="lazy" decoding="async" width="1200" height="846" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*fRTe_hokNNcPNgX97qZcQw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*77MdQpIY5lupV8oQ3chyDw.webp" alt="" loading="lazy" decoding="async" width="1200" height="990" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk5MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*77MdQpIY5lupV8oQ3chyDw.png" /></p>

<p>附近先随便找了一家有吃的店吃午餐 ( <a href="https://naver.me/GlGmYxyY" target="_blank">Gohyang katsu</a> )，我点猪排三明治，肉很厚很嫩而且价格实惠。</p>

<h4 id="1230-diart-coffee-蜂蜜奶油吐司">~=12:30 <a href="https://naver.me/GkUJQI6r" target="_blank">DIART COFFEE 蜂蜜奶油吐司</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*Su_kwIRgZb18zoMS0Tv0sw.webp" alt="" loading="lazy" decoding="async" width="948" height="1196" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDgiIGhlaWdodD0iMTE5NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Su_kwIRgZb18zoMS0Tv0sw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*smtxM51j_tPmnW-RQql09g.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*smtxM51j_tPmnW-RQql09g.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*8XzQQm3AZ0JR7Gr_TfaYxA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*8XzQQm3AZ0JR7Gr_TfaYxA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*6kxh55_key4KL-Tj5V5WNQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*6kxh55_key4KL-Tj5V5WNQ.jpeg" /></p>

<p>吃完午餐走出来就是大家激推的釜山蜂蜜奶油吐司 <a href="https://naver.me/GkUJQI6r" target="_blank">DIART COFFEE</a> ，点了一份($10,000 韩元)跟咖啡($5,500 韩元)休息一下。</p>

<p>食用方式可参考 <a href="https://m.site.naver.com/1Abyy" target="_blank">小卡</a> ，总之就是先把面包一块一块切好，然后均匀涂抹奶油跟蜂蜜食用。</p>

<blockquote>
  <p><em>蜂蜜不会太甜加上奶油的奶香配上香脆的面包，好吃又不腻。</em></p>
</blockquote>

<h4 id="1330-回青沙浦准备搭海岸列车回尾浦海云台">~=13:30 回青沙浦准备搭海岸列车回尾浦(海云台)</h4>

<p><img src="/assets/8ace34a1a3d8/1*W-yaVbvzi87W8xZk_cza4g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*W-yaVbvzi87W8xZk_cza4g.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*VKTdBhWwiPmOoE4eX7pwVw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*VKTdBhWwiPmOoE4eX7pwVw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*dICe7b0tdWsGppYFDADrhQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*dICe7b0tdWsGppYFDADrhQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*fWJrPrMNalY2YbTFk9ct0Q.webp" alt="" loading="lazy" decoding="async" width="950" height="1214" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTAiIGhlaWdodD0iMTIxNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*fWJrPrMNalY2YbTFk9ct0Q.png" /></p>

<p>昨日的已无法使用，又再用釜山 Pass 换了一张海岸列车车票；这边是中途站上车只能站在最后一排了。</p>

<p><img src="/assets/8ace34a1a3d8/1*_a9Gqyx5xSatuoqZVvDwPQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*_a9Gqyx5xSatuoqZVvDwPQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*6ypVO-ZjcG0zkZAuJKC7Mg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*6ypVO-ZjcG0zkZAuJKC7Mg.jpeg" /></p>

<p>中途会经过几个观景平台，因为太热就没下去了。</p>

<h4 id="1355-抵达尾浦海云台">~=13:55 抵达尾浦(海云台)</h4>

<p><img src="/assets/8ace34a1a3d8/1*viDnwtL1r7EWe3K1FtDKiA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*viDnwtL1r7EWe3K1FtDKiA.jpeg" /></p>

<p>回到海云台后就走路＋搭公车前往新世界 Spa Land 了。</p>

<h4 id="1430-抵达-新世界shinsegae百货">~=14:30 抵达 <a href="https://naver.me/xfYRYAfu" target="_blank">新世界(SHINSEGAE)百货</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*ZqGLAD3UKpURs3HKbviTwQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="848" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*ZqGLAD3UKpURs3HKbviTwQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*WneX4dSsqbfvEps927Zqjw.webp" alt="" loading="lazy" decoding="async" width="925" height="1176" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjUiIGhlaWdodD0iMTE3NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*WneX4dSsqbfvEps927Zqjw.png" /></p>

<p>没有逛，直冲一楼 Spa Land。</p>

<h4 id="1440-spa-land">14:40 Spa Land</h4>

<p>用釜山 Pass 兑换 Spa Land 使用。</p>

<blockquote>
  <p><a href="https://www.kkday.com/zh-tw/product/12213-busan-spa-land-centum-city-ticket?cid=19365" target="_blank"><em>没买 Pass 也能在 Kkday 先购买。</em></a></p>
</blockquote>

<p>进去会发一个感应手环，用手环寄放鞋子、衣物，在场内换汗蒸幕专用衣服，也可以先去三温暖(需全裸)再去汗蒸幕，汗蒸幕入口在女生更衣室那个方向。</p>

<p><img src="/assets/8ace34a1a3d8/1*2UvncJZg2YqeC9pmzSstww.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*2UvncJZg2YqeC9pmzSstww.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*rgOo09p9c0DJFD9h_UH7fQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*rgOo09p9c0DJFD9h_UH7fQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*9oMyMc4jYnkhHcJKydzXJw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*9oMyMc4jYnkhHcJKydzXJw.jpeg" /></p>

<p>一楼有日光浴区、美甲、小吃摊、各种功能的汗蒸幕(暑假人太多了每一间几乎都满满的人)，三楼有餐厅(可以去吃烤蛋、泡面)、按摩、按摩椅跟瑜伽室。</p>

<p>去完三温暖就去日光浴区躺著晒太阳了，点了一杯饮料(超甜)。</p>

<blockquote>
  <p><em>场内所有消费都是凭手环感应，最后出场再结帐。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>老实说这次来根本没体验到汗蒸幕，人多到爆炸，下次再说了。</em></strong></p>
</blockquote>

<h4 id="1700-准备前往游艇码头集合">17:00 准备前往游艇码头集合</h4>

<p>预约 18:30 的场次，需提前去集合点名。</p>

<p><img src="/assets/8ace34a1a3d8/1*I05lgEC-kLYtbw1s_OWJ6Q.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*I05lgEC-kLYtbw1s_OWJ6Q.jpeg" /></p>

<p>出发前先在新世界百货 B1 买了吃了一些东西果腹。</p>

<h4 id="坐地铁前往冬柏站-dongbaek">坐地铁前往冬柏站 (Dongbaek)</h4>

<p><img src="/assets/8ace34a1a3d8/1*nLZyTcQcoS4NBTV_EozYFA.webp" alt="" loading="lazy" decoding="async" width="721" height="514" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MjEiIGhlaWdodD0iNTE0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*nLZyTcQcoS4NBTV_EozYFA.png" /></p>

<p>出站要再走约 15 分钟才会到码头。</p>

<blockquote>
  <p><em>码头这边只有贩卖机跟厕所比较脏、人多要排队； <strong>建议在市区买好需要的东西、上好厕所再来。</strong></em></p>
</blockquote>

<h4 id="1800-抵达游艇码头">~=18:00 抵达游艇码头</h4>

<p><img src="/assets/8ace34a1a3d8/1*2IAvf0t9-X64N-VhcqU3Hw.webp" alt="" loading="lazy" decoding="async" width="944" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*2IAvf0t9-X64N-VhcqU3Hw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*gzCg-qoszdj6FPTDnl6OxA.webp" alt="" loading="lazy" decoding="async" width="1400" height="996" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*gzCg-qoszdj6FPTDnl6OxA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*SEdvFIL6AktezC9W238zDA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*SEdvFIL6AktezC9W238zDA.jpeg" /></p>

<p>穿过游客中心后就能来到码头集合处，各个船家有不同的码头集合处。</p>

<p><img src="/assets/8ace34a1a3d8/1*XWHxS8z33CPpiugdE2ddVw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*XWHxS8z33CPpiugdE2ddVw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*uGw5fIqLJIJoxtzTpzNm3g.webp" alt="" loading="lazy" decoding="async" width="947" height="1182" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDciIGhlaWdodD0iMTE4MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*uGw5fIqLJIJoxtzTpzNm3g.png" /></p>

<p>等到大约 18:15 船家才出现开始整队点名，现场收夜间加价的费用(一人 $5,000 韩元)。</p>

<h4 id="1830-海上游艇出发-">18:30 海上游艇出发 👍👍</h4>

<p><img src="/assets/8ace34a1a3d8/1*UdLDGZfqHM_HneNjqh6qlA.webp" alt="" loading="lazy" decoding="async" width="951" height="1209" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTEiIGhlaWdodD0iMTIwOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*UdLDGZfqHM_HneNjqh6qlA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*Z52u6yd6i_bwsvmdKECD1A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Z52u6yd6i_bwsvmdKECD1A.jpeg" /></p>

<p>上船要穿救生衣，坐到第二层最前面的位子。</p>

<p><img src="/assets/8ace34a1a3d8/1*SEVJsECS6H4ngAof9V0nQQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*SEVJsECS6H4ngAof9V0nQQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*fLsO9aiXUtVx3vm_etmEaA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*fLsO9aiXUtVx3vm_etmEaA.jpeg" /></p>

<p>开得很慢、不会太晃，一路前往穿过广安大桥。</p>

<blockquote>
  <p><strong><em>不过怕晕船的还是建议要吃晕船药。</em></strong></p>
</blockquote>

<h4 id="大致的路线图">大致的路线图：</h4>

<p><img src="/assets/8ace34a1a3d8/1*J0YqfliMZuX7rnrgzKItkA.webp" alt="" loading="lazy" decoding="async" width="1200" height="798" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*J0YqfliMZuX7rnrgzKItkA.png" /></p>

<h4 id="1850-抵达广安里海滩前">~=18:50 抵达广安里海滩前</h4>

<p><img src="/assets/8ace34a1a3d8/1*pDMeZQ252T2zQHU4fnsdmg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*pDMeZQ252T2zQHU4fnsdmg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*0xgRuRCfH8hUew63a7fqqg.webp" alt="" loading="lazy" decoding="async" width="1182" height="665" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTgyIiBoZWlnaHQ9IjY2NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*0xgRuRCfH8hUew63a7fqqg.jpeg" /></p>

<p>大约 20 分钟后就会到达广安里海滩前的海域，可以看到很多玩 SUP 的游客；会在这停留跟放烟火；烟火就是这时段出航的各个游艇的船家工作人员一起手持燃放，不过天还很亮所以看不太到。</p>

<p><img src="/assets/8ace34a1a3d8/1*aPIQ_aNeOjF3F0vc_ghnEA.webp" alt="" loading="lazy" decoding="async" width="1200" height="858" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*aPIQ_aNeOjF3F0vc_ghnEA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*xlY1CbhaJm_y2MH2H2x6FA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*xlY1CbhaJm_y2MH2H2x6FA.jpeg" /></p>

<p>沿途工作人会也会很热情的帮忙拍照。</p>

<h4 id="1900-回程">~=19:00 回程</h4>

<p><img src="/assets/8ace34a1a3d8/1*YFAwnj0StqttQX1mpGD93Q.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*YFAwnj0StqttQX1mpGD93Q.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*XfSCLtKiHYCFpboyNPiWcg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*XfSCLtKiHYCFpboyNPiWcg.jpeg" /></p>

<p>刚好看到晚霞。</p>

<h4 id="1920-回到陆地">~=19:20 回到陆地</h4>

<p>回陆地后就搭公车回海云台了。</p>

<h4 id="1935-回到海云台">~=19:35 回到海云台</h4>

<p><img src="/assets/8ace34a1a3d8/1*5fS1FH22njGy1ppRJNvRhQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*5fS1FH22njGy1ppRJNvRhQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*hS21eQGZ-VvsLKqQINEiEw.webp" alt="" loading="lazy" decoding="async" width="932" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzIiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*hS21eQGZ-VvsLKqQINEiEw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*nEMJPKds-CrjF2BDsR3ZcA.webp" alt="" loading="lazy" decoding="async" width="1400" height="856" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijg1NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*nEMJPKds-CrjF2BDsR3ZcA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*K8XU7m63X0bGVYcaMOwgGQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*K8XU7m63X0bGVYcaMOwgGQ.jpeg" /></p>

<p>海云台沙滩有市集、餐车。</p>

<h4 id="1955-去吃海云台-烤鳗鱼--pungcheonman-">~=19:55 去吃海云台 <a href="https://naver.me/GEiuqenG" target="_blank">烤鳗鱼 — PUNGCHEONMAN</a> 👍👍</h4>

<p><img src="/assets/8ace34a1a3d8/1*--tFcHDWgpPDD__zrK8Jlg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*--tFcHDWgpPDD__zrK8Jlg.jpeg" /></p>

<p>店内位子很多不用排队，直接进来了。</p>

<p><img src="/assets/8ace34a1a3d8/1*R-kS0zI7e106d0e2SAaMKg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*R-kS0zI7e106d0e2SAaMKg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*CHuWZKV3-zp9Z5vDy3h2kQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*CHuWZKV3-zp9Z5vDy3h2kQ.jpeg" /></p>

<p>我们点烤鳗鱼+烤牛肉片+冷面*2+烧啤，实刷 NT$2,387。</p>

<p><img src="/assets/8ace34a1a3d8/1*eebei6lY1kzg2ZkEunW1Gw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*eebei6lY1kzg2ZkEunW1Gw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*3v8CcPgaFWmH4190p4q1og.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*3v8CcPgaFWmH4190p4q1og.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*qku3gySyCW3u98SQ7qXA7g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*qku3gySyCW3u98SQ7qXA7g.jpeg" /></p>

<p>烤鳗鱼脆脆软嫩多汁，很好吃，完全没有任何腥味；烤牛肉片也不错但是普通；荞麦冷面很像什么黑糖ㄘㄨㄚˋ冰，实则是酱油味、有碎冰的，很清爽好吃。</p>

<p><img src="/assets/8ace34a1a3d8/1*IakblW3IGN6wxf1NkX29Ww.webp" alt="" loading="lazy" decoding="async" width="947" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDciIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*IakblW3IGN6wxf1NkX29Ww.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*NUtsqQvPLceti09GjSi1Ew.webp" alt="" loading="lazy" decoding="async" width="947" height="1182" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDciIGhlaWdodD0iMTE4MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*NUtsqQvPLceti09GjSi1Ew.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*NqVaJBSjpavz5Pqaee01Zg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*NqVaJBSjpavz5Pqaee01Zg.jpeg" /></p>

<p>吃完又去海云台大街走走、海云台传统市场(忘了吃海鲜煎饼，可恶！)跟买伴手礼；明天就要离开海云台了。</p>

<h3 id="day-4-0801-五-南浦洞松岛海上缆车龙宫云桥甘川洞文化村釜山塔">Day 4 08/01 (五) 南浦洞、松岛海上缆车、龙宫云桥、甘川洞文化村、釜山塔</h3>

<h4 id="0915-出门前往南浦洞">09:15 出门前往南浦洞</h4>

<p><img src="/assets/8ace34a1a3d8/1*amKvoodXorVlvXyKiBALLg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*amKvoodXorVlvXyKiBALLg.jpeg" /></p>

<p>一早准备离开海云台前往南浦洞。</p>

<h4 id="1030-抵达札嘎其站-hotel-noah-饭店">~=10:30 抵达札嘎其站， <a href="https://www.agoda.com/zh-cn/hotel-noah_3/hotel/busan-kr.html" target="_blank">Hotel Noah</a> 饭店</h4>

<p><img src="/assets/8ace34a1a3d8/1*Kq_QYpAk4Kr-F09JJ_FRWQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*Kq_QYpAk4Kr-F09JJ_FRWQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*sMUSi1v4EluBNNT5emHqOg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*sMUSi1v4EluBNNT5emHqOg.jpeg" /></p>

<p>寄放行李。</p>

<h4 id="biff-广场">BIFF 广场</h4>

<p><img src="/assets/8ace34a1a3d8/1*cQXerZP_VIvP5ToSBrLgEw.webp" alt="" loading="lazy" decoding="async" width="945" height="1194" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDUiIGhlaWdodD0iMTE5NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*cQXerZP_VIvP5ToSBrLgEw.png" /></p>

<p>饭店出来对面就是 BIFF 广场，很热闹、方便。</p>

<h4 id="1100-吃午餐--hongkong-0410-nampo-1st-branch">~=11:00 吃午餐 — <a href="https://naver.me/G28VhTtY" target="_blank">Hongkong 0410 Nampo 1st Branch</a></h4>

<p>接近中午先在 BIFF 内随意找了家餐厅吃午餐，这家是韩式中华料理。</p>

<p><img src="/assets/8ace34a1a3d8/1*PFYie7L_VFf4E70JCoCjAw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*PFYie7L_VFf4E70JCoCjAw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*YNNdD826iQ8fqvZnDgJQFA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*YNNdD826iQ8fqvZnDgJQFA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ERESHYR_kpkJluI7uTd3CQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*ERESHYR_kpkJluI7uTd3CQ.jpeg" /></p>

<p>点了炸水饺、糖醋肉(中，感觉可以点小的)、韩式炸酱面。</p>

<p>炸水饺有点腻，糖醋肉不错。</p>

<h4 id="1215-搭公车走路抵达松岛缆车站">12:15 搭公车+走路，抵达松岛缆车站</h4>

<p><img src="/assets/8ace34a1a3d8/1*O-7uqMkqeEY_hnPImCZ4nA.webp" alt="" loading="lazy" decoding="async" width="604" height="729" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDQiIGhlaWdodD0iNzI5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*O-7uqMkqeEY_hnPImCZ4nA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*e07O9sxOWghCiDG4t57fTQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*e07O9sxOWghCiDG4t57fTQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*G55PQci1BikM7kS7jRyBUg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*G55PQci1BikM7kS7jRyBUg.jpeg" /></p>

<p>下公车大约还要走 10 分钟，太热了，先去超商调一杯自制咖啡拿铁消暑。</p>

<p><img src="/assets/8ace34a1a3d8/1*ntKH7dp9EHgiSQfDiETb1w.webp" alt="" loading="lazy" decoding="async" width="929" height="1189" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjkiIGhlaWdodD0iMTE4OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*ntKH7dp9EHgiSQfDiETb1w.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*gMrRyaT7YG7QVkW6vs4aYw.webp" alt="" loading="lazy" decoding="async" width="928" height="1186" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjgiIGhlaWdodD0iMTE4NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*gMrRyaT7YG7QVkW6vs4aYw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*9hyji_BcmpmX8mnbQ_8sYg.webp" alt="" loading="lazy" decoding="async" width="938" height="1196" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzgiIGhlaWdodD0iMTE5NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*9hyji_BcmpmX8mnbQ_8sYg.png" /></p>

<p>进来之后排柜台兑换釜山 Pass 缆车车票(Pass 是水晶车厢、 <strong>来回，所以票要收好</strong> )。</p>

<p>领完票就直接搭手扶梯上楼排队等缆车。(有发棒棒糖但我没拿)</p>

<h4 id="1225-上车">12:25 上车</h4>

<p><img src="/assets/8ace34a1a3d8/1*2rQjr9yJHeMqKNL2WsdftQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*2rQjr9yJHeMqKNL2WsdftQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*zzQbyUo9b66wPcze_M5CTw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*zzQbyUo9b66wPcze_M5CTw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*OL7mGet2prUpedl96EX1PA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*OL7mGet2prUpedl96EX1PA.jpeg" /></p>

<p>5–6 人一台。</p>

<h4 id="1235-抵达松岛">~=12:35 抵达松岛</h4>

<p><img src="/assets/8ace34a1a3d8/1*qPfpLan9npUSJvb3WCumNA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*qPfpLan9npUSJvb3WCumNA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*iMGGxqNqL_cW6nGUL700ag.webp" alt="" loading="lazy" decoding="async" width="940" height="1176" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDAiIGhlaWdodD0iMTE3NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*iMGGxqNqL_cW6nGUL700ag.png" /></p>

<p>出来直接右转往下走。</p>

<p><img src="/assets/8ace34a1a3d8/1*OTbo_MgGmzY5e3BUofU85A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*OTbo_MgGmzY5e3BUofU85A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*jeVCIVeLt_fhFSTgRBKjow.webp" alt="" loading="lazy" decoding="async" width="955" height="1194" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTUiIGhlaWdodD0iMTE5NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*jeVCIVeLt_fhFSTgRBKjow.png" /></p>

<p>走楼梯往下右转到底就是「松岛龙宫吊桥」了。</p>

<h4 id="1240-抵达松岛龙宫吊桥">~=12:40 抵达松岛龙宫吊桥</h4>

<p><img src="/assets/8ace34a1a3d8/1*witcQsiZpHm_OvIQKoGY3g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*witcQsiZpHm_OvIQKoGY3g.jpeg" /></p>

<p>旁边售票处使用釜山 Pass 换票进场。</p>

<p><img src="/assets/8ace34a1a3d8/1*0vBkG9nJIvyD7hrhYj-xnw.webp" alt="" loading="lazy" decoding="async" width="945" height="1203" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDUiIGhlaWdodD0iMTIwMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*0vBkG9nJIvyD7hrhYj-xnw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*PhNqmy6wBPgUbjY3zRT82w.webp" alt="" loading="lazy" decoding="async" width="360" height="480" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNjAiIGhlaWdodD0iNDgwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*PhNqmy6wBPgUbjY3zRT82w.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*hjmWsaA7pNfx77EXr5M7aQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="858" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*hjmWsaA7pNfx77EXr5M7aQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*-KX5b9yL0bniAwPYFgXcgw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*-KX5b9yL0bniAwPYFgXcgw.jpeg" /></p>

<p>这边完全没遮荫，大太阳下很晒，可以鸟瞰整个松岛缆车。</p>

<h4 id="1300-回到松岛缆车排缆车回去">~=13:00 回到松岛缆车，排缆车回去</h4>

<p><img src="/assets/8ace34a1a3d8/1*Og_17fLIQsrceTBxCRxZow.webp" alt="" loading="lazy" decoding="async" width="960" height="1192" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjAiIGhlaWdodD0iMTE5MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Og_17fLIQsrceTBxCRxZow.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*OHD1o7Nau7E8xTUOb1yjeQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*OHD1o7Nau7E8xTUOb1yjeQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*zkbCoM-RhqaU33418vE2aQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*zkbCoM-RhqaU33418vE2aQ.jpeg" /></p>

<h4 id="1325-离开松岛走回去搭公车">~=13:25 离开松岛走回去搭公车</h4>

<p><img src="/assets/8ace34a1a3d8/1*RCy2E4mmH3saWnKRoc7xWg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*RCy2E4mmH3saWnKRoc7xWg.jpeg" /></p>

<p>缆车这边也有一个观景平台，太热就没去了。</p>

<p>走回公车站回到市区再转乘小巴到甘川洞文化村。</p>

<p><img src="/assets/8ace34a1a3d8/1*zTVKv3tTtOdHSoOj81jtTQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*zTVKv3tTtOdHSoOj81jtTQ.jpeg" /></p>

<h4 id="1420-甘川洞文化村">~=14:20 甘川洞文化村</h4>

<p><img src="/assets/8ace34a1a3d8/1*rn4LG3Z1ckz_GMiNQe-8FA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*rn4LG3Z1ckz_GMiNQe-8FA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*iJV9jBpSfiIbdpOf6t02Kw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*iJV9jBpSfiIbdpOf6t02Kw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*EDPA83YXOSXbRqmWTUzirg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*EDPA83YXOSXbRqmWTUzirg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*Dhi69ZSRcSJyvFgv_Oz5Cw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Dhi69ZSRcSJyvFgv_Oz5Cw.jpeg" /></p>

<p>我们没要拍照，纯踩点；感觉就是个彩虹社区跟一些咖啡厅，一路走马看花往下走，到另一个公车站就搭公车回饭店了。</p>

<blockquote>
  <p><em>这边公车是小巴，有点像上阳明山的小巴，司机也开得很凶、人也很多很挤。</em></p>
</blockquote>

<h4 id="1500-回到-noah-hotel-饭店休息">~=15:00 回到 Noah Hotel 饭店休息</h4>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/ESP5SgZ4MMA" title="Hotel Noah" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p><img src="/assets/8ace34a1a3d8/1*c7JIBKmacB_0FpkD1VSV3A.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*c7JIBKmacB_0FpkD1VSV3A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*fAl0cr7HLrPVGIc76JM94Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*fAl0cr7HLrPVGIc76JM94Q.jpeg" /></p>

<ul>
  <li>
    <p>房间窗户外景色</p>
  </li>
  <li>
    <p>本来以为没有投币洗衣机，结果在三楼厕所有附设免费的洗衣机可以使用。</p>
  </li>
</ul>

<h4 id="1740-出发去吃晚餐">~=17:40 出发去吃晚餐</h4>

<p><img src="/assets/8ace34a1a3d8/1*IX5LmJYb0y7bIOE2FWW1DQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*IX5LmJYb0y7bIOE2FWW1DQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*4qK7MSMMHkG60tIe-3yoDQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*4qK7MSMMHkG60tIe-3yoDQ.jpeg" /></p>

<p>从饭店走过去大约 10 分钟。</p>

<h4 id="1750-喉咙锅盖烤肉--moggumung-nampo-branch-">~=17:50 <a href="https://naver.me/xHmnku7F" target="_blank">喉咙锅盖烤肉 — Moggumung Nampo Branch</a> 👍👍👍</h4>

<p><img src="/assets/8ace34a1a3d8/1*4nvoaUKeXZOVIb1IOCYYXQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*4nvoaUKeXZOVIb1IOCYYXQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*2KHw99GTRvBgKhL2jVZxBw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*2KHw99GTRvBgKhL2jVZxBw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*DZdWxcnw-93O_23CzoNHGg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*DZdWxcnw-93O_23CzoNHGg.jpeg" /></p>

<ul>
  <li>
    <p>特色是烤盘是锅盖</p>
  </li>
  <li>
    <p>小菜会有一颗维他命C (查了一下吃烧烤前或后补充维他命 C 可以减少自由基产生降低致癌风险)</p>
  </li>
  <li>
    <p>最低要点三份肉，一样都有店员烤好给你吃</p>
  </li>
  <li>
    <p>点了两份猪+一份牛+两碗泡面+Cass 啤酒，肉一份都是 $18,000 韩元， <strong>实刷 NT$1,060 相当划算，而且肉也很好吃！！大推</strong></p>
  </li>
</ul>

<h4 id="-1830-走路前往釜山塔">~= 18:30 走路前往釜山塔</h4>

<p>吃饱后再一路走到釜山塔，消化一下，大约 20 分钟。</p>

<p><img src="/assets/8ace34a1a3d8/1*sLs757OOzNAkMKeiRv3lPQ.webp" alt="" loading="lazy" decoding="async" width="698" height="539" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2OTgiIGhlaWdodD0iNTM5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*sLs757OOzNAkMKeiRv3lPQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*wrz7_9izA0-r02hyNB38sg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*wrz7_9izA0-r02hyNB38sg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*k3Z6gYsAotOt5OVIdFIKgw.webp" alt="" loading="lazy" decoding="async" width="933" height="1170" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzMiIGhlaWdodD0iMTE3MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*k3Z6gYsAotOt5OVIdFIKgw.png" /></p>

<p>一路上很热闹、很多吃的餐厅。</p>

<p><img src="/assets/8ace34a1a3d8/1*U8r_Qon2rFimBcnEdWpmyw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*U8r_Qon2rFimBcnEdWpmyw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*Ovz-36q_zBh3L-jFrMdUZQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="833" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgzMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Ovz-36q_zBh3L-jFrMdUZQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*DL3TyNS4bk-sKRx3rNkFqw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*DL3TyNS4bk-sKRx3rNkFqw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*mrV2TAQELoqtWkPK1uj22g.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*mrV2TAQELoqtWkPK1uj22g.jpeg" /></p>

<blockquote>
  <p><strong><em>导航其实应该要设定 — <a href="https://naver.me/GDL5X5TV" target="_blank">龙头山纪念公园入口 Yongdusan Media Park Entrance</a></em></strong> <em>，那边有电扶梯往上；从这边走要小爬一下山 (约 5 分钟)。</em></p>
</blockquote>

<h4 id="1900-抵达釜山塔下等日落之后再上去看夜景">19:00 抵达釜山塔下，等日落之后再上去看夜景</h4>

<p><img src="/assets/8ace34a1a3d8/1*q4kM-CGN-dIC7w5NU32a0A.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*q4kM-CGN-dIC7w5NU32a0A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*JcfGi8vcQtevAvPWGNnuMg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*JcfGi8vcQtevAvPWGNnuMg.jpeg" /></p>

<p>期间先去纪念品店逛逛。</p>

<h4 id="1930-上釜山塔">19:30 上釜山塔</h4>

<p>在一楼柜台出示釜山 Pass 换门票进入。</p>

<p><img src="/assets/8ace34a1a3d8/1*xA5Zg72P8NEN_tUVyPZMkA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*xA5Zg72P8NEN_tUVyPZMkA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*SOJbuAh7kPr2jx-dl1x1zw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*SOJbuAh7kPr2jx-dl1x1zw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*YCkHak-FlJ-mnq0yQWx-yQ.webp" alt="" loading="lazy" decoding="async" width="553" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*YCkHak-FlJ-mnq0yQWx-yQ.jpeg" /></p>

<p>釜山塔凭门票扫描 QRCord 可以玩解谜游戏，解出所有密码可以得到一个小奖品。(密码后面我有写)</p>

<p><img src="/assets/8ace34a1a3d8/1*JnjlJkLecp-f0MseLSVbwQ.webp" alt="" loading="lazy" decoding="async" width="949" height="1148" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDkiIGhlaWdodD0iMTE0OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*JnjlJkLecp-f0MseLSVbwQ.png" /></p>

<p>上来已经有很多人在等了。</p>

<p><img src="/assets/8ace34a1a3d8/1*Kmf1d-_Vm4iMYNKmF1sb_g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Kmf1d-_Vm4iMYNKmF1sb_g.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*lIwknEUuQ6jAeggYxZZegA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*lIwknEUuQ6jAeggYxZZegA.jpeg" /></p>

<p>19:45 的釜山晚霞。</p>

<p><img src="/assets/8ace34a1a3d8/1*iYaorZ3UxxKx0uFa5qpe6A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*iYaorZ3UxxKx0uFa5qpe6A.jpeg" /></p>

<p>20:00/20:10…有光雕投影烟火，效果普普。</p>

<h4 id="2000-釜山夜景">20:00 釜山夜景</h4>

<p><img src="/assets/8ace34a1a3d8/1*DH6uu6N5y8MvhoUoJYt-GQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*DH6uu6N5y8MvhoUoJYt-GQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*9WInxaDdY5aNuL-5CcyuKQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*9WInxaDdY5aNuL-5CcyuKQ.jpeg" /></p>

<h4 id="-2010-下塔离场">~= 20:10 下塔离场</h4>

<p><img src="/assets/8ace34a1a3d8/1*SYJBo1VeGTPz0_-ba7Okbw.webp" alt="" loading="lazy" decoding="async" width="938" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzgiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*SYJBo1VeGTPz0_-ba7Okbw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*bpHpZ2j7hlGjfUqN24QkXQ.webp" alt="" loading="lazy" decoding="async" width="918" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTgiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*bpHpZ2j7hlGjfUqN24QkXQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*trPGYy37LVKvPbDFepZS6g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*trPGYy37LVKvPbDFepZS6g.jpeg" /></p>

<p>离场之前还有很多可以拍照的点。</p>

<h4 id="-2015-兑换小纪念品">~= 20:15 兑换小纪念品</h4>

<p><img src="/assets/8ace34a1a3d8/1*GIz7xVJewRWy35RBleksMw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*GIz7xVJewRWy35RBleksMw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*kUe5ECb7bsWp_Qwh2hlEug.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*kUe5ECb7bsWp_Qwh2hlEug.jpeg" /></p>

<p>下山之前记得去外面无人售票处 (Ticket Box) 机台：</p>

<ul>
  <li>
    <p>输入密码 ： <code class="language-plaintext highlighter-rouge">19731121</code> (釜山塔建塔日期)</p>
  </li>
  <li>
    <p>就能持凭证去外面蓝色房子的纪念品中心(不是釜山塔一楼那个)兑换小奖品。</p>
  </li>
</ul>

<h4 id="小纪念品是一张小卡有多种样式可以选我选了一张透明的釜山塔">小纪念品是一张小卡，有多种样式可以选，我选了一张透明的釜山塔：</h4>

<p><img src="/assets/8ace34a1a3d8/1*jPcatm0ieKrZEYkk75hpmA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*jPcatm0ieKrZEYkk75hpmA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*gpu_v-fM13P4wilbaGzEwA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*gpu_v-fM13P4wilbaGzEwA.jpeg" /></p>

<p>一路从龙头山公园下山。</p>

<p><img src="/assets/8ace34a1a3d8/1*oDNlLOobzNrq0E5Hue-GHA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*oDNlLOobzNrq0E5Hue-GHA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*y3olhVcaCU5pYyDz3U8lcQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*y3olhVcaCU5pYyDz3U8lcQ.jpeg" /></p>

<blockquote>
  <p><strong><em>这边有电扶梯啊啊啊啊！！(往上，下山没有、有一段在整修)</em></strong></p>
</blockquote>

<h4 id="2030-回到--龙头山纪念公园入口-yongdusan-media-park-entrance">20:30 回到 — <a href="https://naver.me/GDL5X5TV" target="_blank">龙头山纪念公园入口 Yongdusan Media Park Entrance</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*G_jAYR7TS8ESc3ddWf-CpA.webp" alt="" loading="lazy" decoding="async" width="961" height="1195" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjEiIGhlaWdodD0iMTE5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*G_jAYR7TS8ESc3ddWf-CpA.png" /></p>

<p>记得从这里去釜山塔比较近。</p>

<p><img src="/assets/8ace34a1a3d8/1*gavdcweW2vtAfov9NgR9_w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*gavdcweW2vtAfov9NgR9_w.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*QXT1p_8zTY09QXle3f8JTA.webp" alt="" loading="lazy" decoding="async" width="947" height="1197" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDciIGhlaWdodD0iMTE5NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*QXT1p_8zTY09QXle3f8JTA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*QdwuA16DAl-Abv2AqrjJEw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*QdwuA16DAl-Abv2AqrjJEw.jpeg" /></p>

<p>在商店街逛了逛，这里有一家 HBAF 杏仁果专卖店，应该是口味最齐全的地方；买了 Yellow 组合包(里面是小包的)跟一些其他特殊(跳跳糖，真的会跳、辣炒年糕)、热门口味(蜂蜜、Oreo、玉米)回家当伴手礼。</p>

<h4 id="2045-回到-biff-广场买宵夜">20:45 回到 —BIFF 广场买宵夜</h4>

<p><img src="/assets/8ace34a1a3d8/1*hGy9kfVNX80z2gYTpXsO1A.webp" alt="" loading="lazy" decoding="async" width="958" height="1196" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTgiIGhlaWdodD0iMTE5NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*hGy9kfVNX80z2gYTpXsO1A.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*I2_vOk86JV7s2IcRV4nwAw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*I2_vOk86JV7s2IcRV4nwAw.jpeg" /></p>

<p>这边有很多摊贩、地板有明星的手印。</p>

<h4 id="玛格利酒-bhc-炸鸡--bhc-chicken-busan-nampo-branch-就在-biff-广场-">玛格利酒、 <a href="https://naver.me/xww9nJx2" target="_blank">BHC 炸鸡 — BHC Chicken Busan Nampo Branch</a> (就在 BIFF 广场) 👍👍</h4>

<p><img src="/assets/8ace34a1a3d8/1*ps1VVbDmZzRPf5CZTrzdtQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*ps1VVbDmZzRPf5CZTrzdtQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*qf2-1dMVz6KrPmTQRXO0Pw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*qf2-1dMVz6KrPmTQRXO0Pw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*oEo33HTYo8UdkOZ60P3Gxw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*oEo33HTYo8UdkOZ60P3Gxw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*C1NraGTlXNjmzfeCg7-5RA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*C1NraGTlXNjmzfeCg7-5RA.jpeg" /></p>

<p>最后买回去吃了：</p>

<ul>
  <li>
    <p>玛格利酒：类似小米酒、酒酿，很赞。</p>
  </li>
  <li>
    <p>BHC 无骨炸鸡：调味跟鸡肉都很嫩、很好吃。</p>
  </li>
</ul>

<h4 id="0000-晚安南浦">00:00 晚安南浦</h4>

<p><img src="/assets/8ace34a1a3d8/1*Hh1Rxl4e47yN-iFuGxer9g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Hh1Rxl4e47yN-iFuGxer9g.jpeg" /></p>

<p>大约 00:00 后摊贩就都清空了。</p>

<h4 id="day-5-0802-六-乐天百货影岛大桥开桥只有周六有">Day 5 08/02 (六) 乐天百货、影岛大桥开桥(只有周六有)</h4>

<h4 id="1045-乐天百货光复店乐天超市--lotte-dept-store-gwangbok-branch-aqua-mall">10:45 <a href="https://naver.me/xWziztAc" target="_blank">乐天百货光复店、乐天超市 — Lotte Dept. Store Gwangbok Branch Aqua Mall</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*cCougQTjZSMEe_nhgbQF2w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*cCougQTjZSMEe_nhgbQF2w.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*CsRLupeh763WBqVnJ8pQDA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*CsRLupeh763WBqVnJ8pQDA.jpeg" /></p>

<p>大约 10:XX 出门，乐天百货 10:30 开始营业，慢慢走去。</p>

<p><img src="/assets/8ace34a1a3d8/1*9fHXV2Og6JodL5Pjad3JDg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*9fHXV2Og6JodL5Pjad3JDg.jpeg" /></p>

<p>先去 B1 美食街咖啡厅随便吃个东西当早餐。(普普，咖啡是 Lungo)</p>

<h4 id="1130-开始百货公司乱逛">11:30 开始百货公司乱逛</h4>

<p><img src="/assets/8ace34a1a3d8/1*A75a3-GEjeoMSxnuqlFt-w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*A75a3-GEjeoMSxnuqlFt-w.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*Nk9RtTQ2z7ruxWDgKhhIrg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Nk9RtTQ2z7ruxWDgKhhIrg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*-usgnffatzz53RtQHbC6PA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*-usgnffatzz53RtQHbC6PA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*J957_He9MA3RC16vdzSjbA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*J957_He9MA3RC16vdzSjbA.jpeg" /></p>

<ul>
  <li>
    <p>去 Kodak 店买了几件衣服(平均比台湾代购便宜 NT$300–$500)
当店直接退税。</p>
  </li>
  <li>
    <p>买了支手持风扇
凭收据去 B1 美食街找退税机列印退税单，最后再去机场退现金。(大概能退 NT$60)</p>
  </li>
</ul>

<p><img src="/assets/8ace34a1a3d8/1*QxFRNLVX2vM0ISZf3vM2-g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*QxFRNLVX2vM0ISZf3vM2-g.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*TxOTSeqke8P2TE0MWWgiPA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*TxOTSeqke8P2TE0MWWgiPA.jpeg" /></p>

<ul>
  <li>百货这边 11 点开始每小时都有水舞秀，蛮精彩的</li>
</ul>

<h4 id="1230-b1-downtown-汉堡">12:30 B1 Downtown 汉堡</h4>

<p><img src="/assets/8ace34a1a3d8/1*i3upBh9hp-ZjdfMxeskBnQ.webp" alt="" loading="lazy" decoding="async" width="553" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*i3upBh9hp-ZjdfMxeskBnQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*oK7jL0JkiRD69PAlv-fO5Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*oK7jL0JkiRD69PAlv-fO5Q.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*1BHaKNhjT3BIOkW4-qnE4g.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*1BHaKNhjT3BIOkW4-qnE4g.jpeg" /></p>

<p>逛累了，中午时分就去 B1 吃 Downtown 汉堡；道理我都懂，但是美式汉堡也有提供泡菜啊！</p>

<p><img src="/assets/8ace34a1a3d8/1*TvleF3CnUri6-JtSSah9mg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*TvleF3CnUri6-JtSSah9mg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*czdiuWsarXuyo7IfATd7hg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*czdiuWsarXuyo7IfATd7hg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*SCYBfHs65_54TAWjMMssnQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*SCYBfHs65_54TAWjMMssnQ.jpeg" /></p>

<p>吃饱到百货公司顶楼观景台晃晃，(超晒、超热)。</p>

<h4 id="1330-走出百货到外面影岛大桥等开桥">~=13:30 走出百货到外面影岛大桥等开桥</h4>

<p><img src="/assets/8ace34a1a3d8/1*SY6E9kWJ4lQ4WfXaX9Lvww.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*SY6E9kWJ4lQ4WfXaX9Lvww.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*PB-U5oD_Iw1PaNIj9vu1Rw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*PB-U5oD_Iw1PaNIj9vu1Rw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ml5meRbBGO-wiXskpKv7FQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*ml5meRbBGO-wiXskpKv7FQ.jpeg" /></p>

<p>外面很晒，越接近 14:00 聚集的人越来越多；此时 <strong>有一个阿珠嬷走过来跟我们说 8/2–30 因为太热改晚上 20:00！！震惊！！</strong> 然后大家就开始人传人说改到 20:00，大家开始慢慢散场。</p>

<p><img src="/assets/8ace34a1a3d8/1*GQondkcuwv5QwfzkKZ7QPw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*GQondkcuwv5QwfzkKZ7QPw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*Lyms5xvH6lwxp0hPFF2DuA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Lyms5xvH6lwxp0hPFF2DuA.jpeg" /></p>

<p>后来才在栏杆上看到公告布条。(左边看板是例行时间)</p>

<h4 id="1350-回乐天百货乐天-mart-继续乱逛">13:50 回乐天百货、乐天 Mart 继续乱逛</h4>

<p><img src="/assets/8ace34a1a3d8/1*O6oXHk-CkB8vJ-vxvVIfSQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*O6oXHk-CkB8vJ-vxvVIfSQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*0fkOrRbJw84kNZ_Eu_zuZA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*0fkOrRbJw84kNZ_Eu_zuZA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*e2LIsRj5B6KtM1tS_Pvldw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*e2LIsRj5B6KtM1tS_Pvldw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ndyL7-V4wbHHLtu5uYqxlQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*ndyL7-V4wbHHLtu5uYqxlQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*Vi3D5-dWbMN0XVogyhAYBA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Vi3D5-dWbMN0XVogyhAYBA.jpeg" /></p>

<p>乐天超市也有卖一些伴手礼跟保养品(就是家乐福)。</p>

<h4 id="b1-退税机台">B1 退税机台</h4>

<p><img src="/assets/8ace34a1a3d8/1*VJW26Pss8GIKP_EdOKhPbQ.webp" alt="" loading="lazy" decoding="async" width="930" height="1147" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzAiIGhlaWdodD0iMTE0NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*VJW26Pss8GIKP_EdOKhPbQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*QpYPLAIoTGVwYHZoYljzGQ.webp" alt="" loading="lazy" decoding="async" width="948" height="1199" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDgiIGhlaWdodD0iMTE5OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*QpYPLAIoTGVwYHZoYljzGQ.png" /></p>

<p>找了好久才找到退税机台，在鼎泰丰旁的小路。</p>

<ul>
  <li>如果不是立即退税的就要到这边刷单据条码换退税单，最后到机场再退钱。(有点麻烦)</li>
</ul>

<blockquote>
  <p><strong><em>才知道韩国是有分不同退税机构的 Global Blue、GLOBAL TAX FREE、Easy Tax Refund、CubeRefund、eTAX FREE，只能使用对应的退税机台</em></strong> <em>；因为我在 Olive Young 有看到能退现金的机台但是是 GLOBAL TAX FREE 的，我的单字是 CubeRefund，还是只能去机场退。</em></p>
</blockquote>

<h4 id="1635-回饭店休息">16:35 回饭店休息</h4>

<p><img src="/assets/8ace34a1a3d8/1*ngRJ5SY55QsOVeEuesGIXg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*ngRJ5SY55QsOVeEuesGIXg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*IoTCxYVKEGU4JpUwsCMEUQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*IoTCxYVKEGU4JpUwsCMEUQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*hA48uOURihuc-sbE-Qrn3Q.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*hA48uOURihuc-sbE-Qrn3Q.jpeg" /></p>

<p>逛累了就去 B1 买了韩国的红豆和桃果子跟老配方自己调的超商手摇(冰杯+香蕉牛奶+无糖黑咖啡)，走地下街回去饭店休息。</p>

<h4 id="1900-出饭店去-biff-olive-young-逛逛">19:00 出饭店去 BIFF Olive Young 逛逛</h4>

<p><img src="/assets/8ace34a1a3d8/1*LVHpdVT1I-X7_BStMRVfnQ.webp" alt="" loading="lazy" decoding="async" width="932" height="1192" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzIiIGhlaWdodD0iMTE5MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*LVHpdVT1I-X7_BStMRVfnQ.png" /></p>

<p>在海云台都没逛 OY，刚好有时间先来看看，这家店很大店员很多也都很亲切。</p>

<p><img src="/assets/8ace34a1a3d8/1*urwdAXWOvdtMGRzUZ2cMWw.webp" alt="战利品" loading="lazy" decoding="async" width="1400" height="1049" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNDkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*urwdAXWOvdtMGRzUZ2cMWw.png" /></p>

<p>战利品</p>

<h4 id="1940-到达影岛大桥等开桥">19:40 到达影岛大桥，等开桥</h4>

<p><img src="/assets/8ace34a1a3d8/1*JG_o0tkChN-UKCtRdkx8Mw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1017" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMTciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*JG_o0tkChN-UKCtRdkx8Mw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ZOT3YuHUnfvKjglbTllFRQ.webp" alt="" loading="lazy" decoding="async" width="912" height="1222" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTIiIGhlaWdodD0iMTIyMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*ZOT3YuHUnfvKjglbTllFRQ.png" /></p>

<p>桥下这边有纪念照合成的摊位。</p>

<p>大约 19:50 就会开始交通管制。</p>

<h4 id="2000-开桥">20:00 开桥</h4>

<p><img src="/assets/8ace34a1a3d8/1*Zpgsucjjm5BNpq_D4zfh1A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*Zpgsucjjm5BNpq_D4zfh1A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*NTI7_uUkEmOE2SLCN3fclQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*NTI7_uUkEmOE2SLCN3fclQ.jpeg" /></p>

<p>先在桥下看，大约 20:05 开的差不多在移动上去。</p>

<p><img src="/assets/8ace34a1a3d8/1*h8neY7OqYx6WG5QVgxAEGQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*h8neY7OqYx6WG5QVgxAEGQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*n_oF3q1EJ4xy7iF-_mNIYA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*n_oF3q1EJ4xy7iF-_mNIYA.jpeg" /></p>

<p>有投影介绍影岛大桥历史，不过可能是第一天投影机角度有问题，看不太清楚。</p>

<h4 id="2015-桥重新下降恢复通车">20:15 桥重新下降，恢复通车</h4>

<p><img src="/assets/8ace34a1a3d8/1*CsyWpHHwp2x8lLZfbvXvvA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*CsyWpHHwp2x8lLZfbvXvvA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*gV_RKoppNxGGwl8BMErUkw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*gV_RKoppNxGGwl8BMErUkw.jpeg" /></p>

<h4 id="2030-吃晚餐--ton-black--tempura-nine">20:30 吃晚餐 — <a href="https://naver.me/Fm3VOYcH" target="_blank">Ton Black &amp; Tempura Nine</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*VEY9B-esGVFWEHU-1y5OoA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*VEY9B-esGVFWEHU-1y5OoA.jpeg" /></p>

<ul>
  <li>
    <p>晚上走回饭店的路上随意找了家猪排饭店吃吃 (猪排一样很嫩，好吃)</p>
  </li>
  <li>
    <p>一份实刷 NT$366</p>
  </li>
</ul>

<h4 id="2150-回饭店休息">~=21:50 回饭店休息</h4>

<p><img src="/assets/8ace34a1a3d8/1*fd1YC6o2Gytnh_shoUXxdg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*fd1YC6o2Gytnh_shoUXxdg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*O-5YaMfjKPHJ3oCMVfn1UQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*O-5YaMfjKPHJ3oCMVfn1UQ.jpeg" /></p>

<h3 id="day-6-0803-日-乐天百货富平罐头市场白浅湾文化村福泉寺夜景">Day 6 08/03 (日) 乐天百货、富平罐头市场、白浅湾文化村、福泉寺夜景</h3>

<blockquote>
  <p><strong><em>今天都在乱走消磨时间，内容不建议参考，纯纪录。</em></strong></p>
</blockquote>

<h4 id="1000-出门先去吃--egg-drop">10:00 出门先去吃 — <a href="https://naver.me/5gYr3qdc" target="_blank">Egg Drop</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*Kh1xpKnZV-MMtVanIicSyA.webp" alt="" loading="lazy" decoding="async" width="946" height="1205" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDYiIGhlaWdodD0iMTIwNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Kh1xpKnZV-MMtVanIicSyA.png" /></p>

<ul>
  <li>位置在乐天百货对面的商店街。</li>
</ul>

<p><img src="/assets/8ace34a1a3d8/1*aRSQiMUWKNfjDtDVZ8V3oQ.webp" alt="" loading="lazy" decoding="async" width="945" height="1196" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDUiIGhlaWdodD0iMTE5NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*aRSQiMUWKNfjDtDVZ8V3oQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*MnFVcEjz135UauqnyR5H3Q.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*MnFVcEjz135UauqnyR5H3Q.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*BD26TaxsDjAO3wb9rbeFwQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*BD26TaxsDjAO3wb9rbeFwQ.jpeg" /></p>

<ul>
  <li>
    <p>一楼机台点完餐拿号码牌上二楼找位子 (应该要先上去看有没有位子)</p>
  </li>
  <li>
    <p>大约等了 20 分钟</p>
  </li>
  <li>
    <p>点了一份火腿起司欧姆蛋吐司＋薯饼＋冰咖啡：$8,400 韩元</p>
  </li>
</ul>

<blockquote>
  <p><em>是不错，但我觉得台湾有些早午餐比这更好吃。</em></p>
</blockquote>

<h4 id="1100-吃饱再出发">11:00 吃饱再出发</h4>

<p><img src="/assets/8ace34a1a3d8/1*p3YDCVRrvV7QQgx6UomwYA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*p3YDCVRrvV7QQgx6UomwYA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*MQgkZeRyQFfcU5Zti1s4eA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*MQgkZeRyQFfcU5Zti1s4eA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*zl6x8Pt3pxiIR94C8KwkIg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*zl6x8Pt3pxiIR94C8KwkIg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*zB10iTHzqS8mD4T678Lgnw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*zB10iTHzqS8mD4T678Lgnw.jpeg" /></p>

<p>往乐天百货的路上有一家「Big Shop」釜山纪念品店专卖店，有很多 Boogi 跟釜山形象周边商品。</p>

<h4 id="乐天百货光复店乐天超市--lotte-dept-store-gwangbok-branch-aqua-mall"><a href="https://naver.me/xWziztAc" target="_blank">乐天百货光复店、乐天超市 — Lotte Dept. Store Gwangbok Branch Aqua Mall</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*IlBfn7L4in16Sqh0S9u89A.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*IlBfn7L4in16Sqh0S9u89A.jpeg" /></p>

<p>无聊继续逛乐天百货。</p>

<h4 id="1145-b1-无国食卓-蒸食料理-lotte-dept-store-gwangbok-branch">11:45 B1 <a href="https://naver.me/5YSwvcB0" target="_blank">无国食卓 蒸食料理 Lotte Dept. Store Gwangbok Branch</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*OebNrqD4ge6viEehCRbprA.webp" alt="" loading="lazy" decoding="async" width="1200" height="851" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*OebNrqD4ge6viEehCRbprA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*TYSdoPRJBzjaNXE9MImmng.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*TYSdoPRJBzjaNXE9MImmng.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*M1rt5vPWP34qVzr4Rwq8OQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*M1rt5vPWP34qVzr4Rwq8OQ.jpeg" /></p>

<p>吃了好几天重口味食物，午餐想吃清淡一点。</p>

<ul>
  <li>
    <p>饭要另外加点。</p>
  </li>
  <li>
    <p>本身没什么味道。</p>
  </li>
</ul>

<p>吃饱后又逛了一下。</p>

<h4 id="1250-离开乐天百货前往-天空之眼展望台--yeongju-haneul-nun-observatory">12:50 离开乐天百货，前往 <a href="https://naver.me/xYvTULtB" target="_blank">天空之眼展望台 — Yeongju Haneul Nun Observatory</a></h4>

<p>没事附近随便晃晃，查到一个 <a href="/posts/z-度旅行遊記/九州自由行攻略-釜山新山茶花号邮轮入境日本博多-深入由布院-大分-福冈等地-cb65fd5ab770/">去年没去到的展望台</a> ，有公车直达(21 分钟)于是就去了。</p>

<p><img src="/assets/8ace34a1a3d8/1*vzM0d49ldD5u40myXdTgug.webp" alt="" loading="lazy" decoding="async" width="382" height="721" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzODIiIGhlaWdodD0iNzIxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*vzM0d49ldD5u40myXdTgug.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*T8YCaXpAOoHzt08VBNO2zQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*T8YCaXpAOoHzt08VBNO2zQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*zlS5hxZG5BXyZNASUNzXMA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*zlS5hxZG5BXyZNASUNzXMA.jpeg" /></p>

<ul>
  <li>
    <p>釜山的公车几乎都是全新的电车、冷气很凉</p>
  </li>
  <li>
    <p>途经 <a href="/posts/z-度旅行遊記/九州自由行攻略-釜山新山茶花号邮轮入境日本博多-深入由布院-大分-福冈等地-cb65fd5ab770/">去年路过的点：釜山站</a></p>
  </li>
</ul>

<h4 id="1300-天空之眼展望台--yeongju-haneul-nun-observatory">13:00 <a href="https://naver.me/xYvTULtB" target="_blank">天空之眼展望台 — Yeongju Haneul Nun Observatory</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*clTNOo-ZktYUKpKKh75heg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*clTNOo-ZktYUKpKKh75heg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*EQMOhh1KhjP0i9bwys0YuQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*EQMOhh1KhjP0i9bwys0YuQ.jpeg" /></p>

<p>公车站下车后走到对面往下就能看到了。</p>

<p><img src="/assets/8ace34a1a3d8/1*YDfNJ4--5A0Kt0fiScCvVQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*YDfNJ4--5A0Kt0fiScCvVQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*fzBzk65b4cALhHQ3_Ej2ow.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*fzBzk65b4cALhHQ3_Ej2ow.jpeg" /></p>

<p>这边的景色很好，可以眺望整个釜山南浦。</p>

<h4 id="下山去富平罐头市场--先去买同事推荐的-the-liter-手摇杯">下山去富平罐头市场 — <a href="https://naver.me/FMT6cQrZ" target="_blank">先去买同事推荐的 The Liter 手摇杯</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*-B44RvmQkP8ROxbo_ycOpA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*-B44RvmQkP8ROxbo_ycOpA.jpeg" /></p>

<ul>
  <li>只推荐：蓝莓优格冰沙(Yogurt Smoothie — Blueberry)，有 600ML or 1,000ML 两种大小；好喝解暑，也不会太甜觉得越喝越渴，价格约 $4,300 韩元。</li>
</ul>

<h4 id="富平罐头市场"><a href="https://naver.me/Goi5D3F6" target="_blank">富平罐头市场</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*V2RiLAAeaBdJUF4RVKtZCg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*V2RiLAAeaBdJUF4RVKtZCg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*o9T02VtSuMwlGadw7Mq1Jg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*o9T02VtSuMwlGadw7Mq1Jg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*9Zbj66ueqAwQvyD6OTvZqQ.webp" alt="" loading="lazy" decoding="async" width="940" height="1196" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDAiIGhlaWdodD0iMTE5NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*9Zbj66ueqAwQvyD6OTvZqQ.png" /></p>

<p>罐头市场内有很多干粮、杂货、海鲜摊贩(像菜市场)，范围很大。</p>

<h4 id="富平罐头市场--milgot-红豆奶油艾草糯米糕-">富平罐头市场 — <a href="https://naver.me/GEiuXPsf" target="_blank">Milgot</a> 红豆奶油艾草糯米糕 👍</h4>

<p><img src="/assets/8ace34a1a3d8/1*Wj_6WUHzrJCVCSyo-gsGSw.webp" alt="" loading="lazy" decoding="async" width="951" height="1180" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTEiIGhlaWdodD0iMTE4MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Wj_6WUHzrJCVCSyo-gsGSw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*2Nj6AKmSZkzlQ5SO013W7w.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*2Nj6AKmSZkzlQ5SO013W7w.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*R14q-E0U_yWC9iXarLhRZg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*R14q-E0U_yWC9iXarLhRZg.jpeg" /></p>

<p>应该是罐头市场最有名的店，特色是 — 红豆奶油艾草糯米糕。</p>

<ul>
  <li>
    <p>因为不会韩文所以直接拍照只给店员看就要这个</p>
  </li>
  <li>
    <p>店员说回去要冰，吃之前退冰半小时到一小时最好吃</p>
  </li>
  <li>
    <p>另外还买了一个咸的面包，也不错！</p>
  </li>
</ul>

<p><img src="/assets/8ace34a1a3d8/1*qm0Wh7MPbrWfst0Y_4eF-A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*qm0Wh7MPbrWfst0Y_4eF-A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*GJ8R6Is85xYOA8HOlA_bQg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*GJ8R6Is85xYOA8HOlA_bQg.jpeg" /></p>

<p>后来带回饭店吃，艾草糕糯糯的口感配上黄豆粉跟红豆奶油内馅，我觉得蛮特别的，稍微有一点甜；如果有路过可以试试！</p>

<p><img src="/assets/8ace34a1a3d8/1*XQYb4xKnzk0rEMbMJWlglQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*XQYb4xKnzk0rEMbMJWlglQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*cwJikydjyNJW3SDbudKmOA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*cwJikydjyNJW3SDbudKmOA.jpeg" /></p>

<p>另外又再买了一盒 <a href="https://naver.me/xww9nJx2" target="_blank">BHC 炸鸡</a> 回去当晚餐吃。</p>

<h4 id="1830-重新出发">18:30 重新出发</h4>

<p>傍晚休息完又再出门，主要是要去福泉寺拍夜景，先去白浅湾文化村看看。</p>

<h4 id="1845-白浅湾文化村">18:45 <a href="https://naver.me/FgTvHYSL" target="_blank">白浅湾文化村</a></h4>

<blockquote>
  <p><em>这边最有名的景点是 — <a href="https://naver.me/52chRHd4" target="_blank">边看风景边喝咖啡边泡足浴 — VIEW, FOOT BATH CAFE</a> 足浴咖啡厅。</em></p>
</blockquote>

<p><img src="/assets/8ace34a1a3d8/1*wFYAic5cJEcssp2DziS85Q.webp" alt="" loading="lazy" decoding="async" width="945" height="1234" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDUiIGhlaWdodD0iMTIzNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*wFYAic5cJEcssp2DziS85Q.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*9xd7-RARtJnwkQUwLqoz2w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*9xd7-RARtJnwkQUwLqoz2w.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*_bg1OXnenjgxXpfoX3xwog.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*_bg1OXnenjgxXpfoX3xwog.jpeg" /></p>

<p>但是因为时间晚了，所以只走马看花；靠海岸这边有很多咖啡厅跟小店，但不知道是不是因为时间晚了没什么人，下方海岸线步道在维修无法下去走；今天天气阴阴景色不佳。</p>

<h4 id="1900-前往-福泉寺--bokcheonsa-temple">19:00 前往 <a href="https://naver.me/5L7oHSSB" target="_blank">福泉寺 — Bokcheonsa Temple</a></h4>

<p>离开白浅湾后就要往上前往福泉寺。</p>

<p><img src="/assets/8ace34a1a3d8/1*kCU_DP31_Q8oVxfZPA7hOw.webp" alt="" loading="lazy" decoding="async" width="1136" height="908" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTM2IiBoZWlnaHQ9IjkwOCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*kCU_DP31_Q8oVxfZPA7hOw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*7BgsQXSUyo7X3sQnbDpgCQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*7BgsQXSUyo7X3sQnbDpgCQ.jpeg" /></p>

<p>原本看 Map 说公车只搭一站，想说用走的就好，走几步之后就放弃了；地图写公车 1 站(1 分钟)；实际走应该要 20 分钟 (全是很抖的山坡路)。</p>

<ul>
  <li>Yeongdogu 1 或 5 都可</li>
</ul>

<p><strong>只搭一站到下一站 <a href="https://naver.me/xzlLlZhM" target="_blank">Sinseon Elementary School</a> ，剩下只能用走的：</strong></p>

<p><img src="/assets/8ace34a1a3d8/1*O0Q9eorhHVOa5e9W69pK2A.webp" alt="" loading="lazy" decoding="async" width="688" height="310" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2ODgiIGhlaWdodD0iMzEwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*O0Q9eorhHVOa5e9W69pK2A.png" /></p>

<p>下车后傻了，依然是很抖的山坡路，从这边一路往上走：</p>

<p><img src="/assets/8ace34a1a3d8/1*KF-K6yfIdIQ_oxTPMFu6TA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*KF-K6yfIdIQ_oxTPMFu6TA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*A232HHlbcIoIpCEE770RhA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*A232HHlbcIoIpCEE770RhA.jpeg" /></p>

<p>经过国小之后再往上就能看到福泉寺入口：</p>

<p><img src="/assets/8ace34a1a3d8/1*8ISDSkUNQK1J6SJokF48Zg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*8ISDSkUNQK1J6SJokF48Zg.jpeg" /></p>

<p>这里才是开始，要再一路爬很抖的山坡路往上到底才是福泉寺：</p>

<p><img src="/assets/8ace34a1a3d8/1*f7K27vuhRDimn9H-2KB6Hw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*f7K27vuhRDimn9H-2KB6Hw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*DIL09kj3M9GtyrJSHP9G0A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*DIL09kj3M9GtyrJSHP9G0A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*JBWBSHF6GYn6fIuWPd4Dsw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*JBWBSHF6GYn6fIuWPd4Dsw.jpeg" /></p>

<blockquote>
  <p><strong><em>这里会有车通行，要注意安全 ⚠️</em></strong></p>
</blockquote>

<h4 id="1925-抵达福泉寺">19:25 抵达福泉寺</h4>

<p><img src="/assets/8ace34a1a3d8/1*a9Rw-kNrof1PF3jtwV5Y1A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*a9Rw-kNrof1PF3jtwV5Y1A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ojagYvbJbUhKBz1JOVOlwA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*ojagYvbJbUhKBz1JOVOlwA.jpeg" /></p>

<blockquote>
  <p><em>大约 19:25 才走到福泉寺（差点累死），Map 写 10 分钟，实际全是上坡路走+休息大概花了 25 分钟。</em></p>
</blockquote>

<p>但更悲剧的事是 — 他关门了！他关门了！他关门了！</p>

<p>没错，福泉寺不太算公开的观光景点，他是宁静的寺院，时间到门就关了；听同事说大约 18:00 后就只进不出了，不会特别赶人，但是超过时间关门就不给进去了。</p>

<p><img src="/assets/8ace34a1a3d8/1*DgPxNoCjrJWvL1uURfNIJA.webp" alt="" loading="lazy" decoding="async" width="944" height="1248" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDQiIGhlaWdodD0iMTI0OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*DgPxNoCjrJWvL1uURfNIJA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*VsLe3FUcx9XaJ8WTVWjlIg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*VsLe3FUcx9XaJ8WTVWjlIg.jpeg" /></p>

<p>悲剧，只能在站外面阁楼看景，后来也有一些慕名而来的人也是都站在这。</p>

<blockquote>
  <p><strong><em>不过住持看我们大粒汗小粒汗，就从里面丢了两罐冰水给我们，太感谢了。</em></strong></p>
</blockquote>

<p><img src="/assets/8ace34a1a3d8/1*5lpfrhdVVFrsN-O0qrTmQw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*5lpfrhdVVFrsN-O0qrTmQw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*lEg8_dHkPXgVIPbMLGpAVQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*lEg8_dHkPXgVIPbMLGpAVQ.jpeg" /></p>

<p>从这边看市区的景色视角。</p>

<p><img src="/assets/8ace34a1a3d8/1*fFLE2v0oSj9z5snHg_KINQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*fFLE2v0oSj9z5snHg_KINQ.jpeg" /></p>

<p>最后随手拍了张夜景就走下山了，当初是看其他部落客拍的图才想来的：</p>

<p><img src="/assets/8ace34a1a3d8/1*gcXOAkYiOkfJZLVpHVqQnw.webp" alt="真的进去拍应该长这样" loading="lazy" decoding="async" width="789" height="743" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3ODkiIGhlaWdodD0iNzQzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*gcXOAkYiOkfJZLVpHVqQnw.png" /></p>

<p><a href="https://judyer.com/bstp/" target="_blank">真的进去拍应该长这样</a></p>

<p>下山一路下坡，一片黑：</p>

<p><img src="/assets/8ace34a1a3d8/1*uYq1hyMs27u89dlhoSsz7A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*uYq1hyMs27u89dlhoSsz7A.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*qAWrK94KUe0KxtQDv0kAsQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*qAWrK94KUe0KxtQDv0kAsQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*KQ_lF81lFAdeVBQ5FiexTQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*KQ_lF81lFAdeVBQ5FiexTQ.jpeg" /></p>

<p>是个很安静的村庄，走下来就搭公车回札嘎其站了。</p>

<p><img src="/assets/8ace34a1a3d8/1*X0odkWacFr5MXbc1iBV-tg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*X0odkWacFr5MXbc1iBV-tg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*2wUeYbwRYkMnLrNhrTMWLg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*2wUeYbwRYkMnLrNhrTMWLg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*3nwYcNLllFSmQ8zjmiKxjA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*3nwYcNLllFSmQ8zjmiKxjA.jpeg" /></p>

<p>回饭店前买了 BIFF 广场蛮多人排的 <a href="https://naver.me/5eZTZe4y" target="_blank">种子糖饼</a> ，我觉得很油很甜不怎么样。</p>

<p><img src="/assets/8ace34a1a3d8/1*dPAGNfr1hlXfTu3CnFl7ng.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*dPAGNfr1hlXfTu3CnFl7ng.jpeg" /></p>

<p>大约 22:00 釜山开始下雨！还好我们旅程快结束了。</p>

<h3 id="day-7-0804-一-釜山西面新世界百货韩牛">Day 7 08/04 (一) 釜山西面、新世界百货、韩牛</h3>

<p>早上出门移动到西面站。</p>

<h4 id="1045-抵达西面站">10:45 抵达西面站</h4>

<p><img src="/assets/8ace34a1a3d8/1*o5yuGlxr94cLNs65fiuL5A.webp" alt="" loading="lazy" decoding="async" width="1400" height="984" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*o5yuGlxr94cLNs65fiuL5A.png" /></p>

<p>到了之后想说直接在地铁站寄物，其他地方：乐天百货也能寄放行李。</p>

<blockquote>
  <p><strong><em>这边寄放行李很贵：早上 10:45 寄放，晚上 20:10 取回。</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>被收了 $6,000 + $7,000 韩元 (约 NT$280)。</em></strong></p>
</blockquote>

<p><img src="/assets/8ace34a1a3d8/1*Wc20JDECq1yHn3CgB1qXFA.webp" alt="" loading="lazy" decoding="async" width="1400" height="998" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Wc20JDECq1yHn3CgB1qXFA.png" /></p>

<p>这站地下街也有一家 Olive Young，再去补货了一波。</p>

<h4 id="1100-午餐-韩式-刀削面--gijang-sonkalguksu">11:00 午餐 韩式 <a href="https://naver.me/Fr0l0gR5" target="_blank">刀削面 — Gijang Sonkalguksu</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*sd_qEyJXkxRxFOBwd40Tvg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*sd_qEyJXkxRxFOBwd40Tvg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*GUBEh-TqX2boCuU2I78HKA.webp" alt="" loading="lazy" decoding="async" width="1400" height="987" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*GUBEh-TqX2boCuU2I78HKA.png" /></p>

<p>逛完接近中午，到附近的市场吃刀韩式削面。</p>

<p><img src="/assets/8ace34a1a3d8/1*eELPbEa7ehdgUH6X47-C9A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*eELPbEa7ehdgUH6X47-C9A.jpeg" /></p>

<p>菜单选择很单纯，就只有刀削面跟海苔卷。</p>

<p><img src="/assets/8ace34a1a3d8/1*EsG2Zr3hz1BvZ6ZYMtfplA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1005" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMDUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*EsG2Zr3hz1BvZ6ZYMtfplA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*B3iHfLVRtZ7zTuzh5pmOag.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*B3iHfLVRtZ7zTuzh5pmOag.jpeg" /></p>

<blockquote>
  <p><em>点了海苔卷分著吃跟我点了刀削冷面，面的口感很劲道，冰凉爽口；缺点是没什么配料(肉)，纯碳水吃起来很单调。</em></p>
</blockquote>

<p>吃完之后走回乐天百货。</p>

<h4 id="the-liter-seo-myeon-medical-street-branch"><a href="https://naver.me/FytxtsbC" target="_blank">The Liter Seo-myeon Medical Street Branch</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*2yLbWMPpyCtAruEp2Cz46g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*2yLbWMPpyCtAruEp2Cz46g.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*i4mbPG5JVPgWfVZvr40MJg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*i4mbPG5JVPgWfVZvr40MJg.jpeg" /></p>

<p>再去买了一杯 Liter 蓝莓冰沙优格解腻。</p>

<ul>
  <li>这家的阿珠妈很热情</li>
</ul>

<h4 id="乐天百货--釜山总店-lotte-dept-store-busan-main-branch"><a href="https://naver.me/GA868sJB" target="_blank">乐天百货 — 釜山总店 Lotte Dept. Store Busan Main Branch</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*VmJEjJZMfCoxu_HLUxnTIA.webp" alt="" loading="lazy" decoding="async" width="952" height="1186" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTIiIGhlaWdodD0iMTE4NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*VmJEjJZMfCoxu_HLUxnTIA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*JnKRh6VL4zQAj5DN0QjOPw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*JnKRh6VL4zQAj5DN0QjOPw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*lBdiaq_smyUqUNRW1ZTLYg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*lBdiaq_smyUqUNRW1ZTLYg.jpeg" /></p>

<p>我觉得很难逛，或是说比昨天的乐天百货-光复店还难逛，楼层少商家少； <strong>唯一优点是楼上有很大的公共休息区，可以充电休息。</strong></p>

<p><img src="/assets/8ace34a1a3d8/1*FIKndhK0XDcFCTNeGi9myA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*FIKndhK0XDcFCTNeGi9myA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*HrvD0lkdT605U-UVMyqdnw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*HrvD0lkdT605U-UVMyqdnw.jpeg" /></p>

<p>这里也有一家釜山纪念品店，但是东西比南浦的少很多。</p>

<p><img src="/assets/8ace34a1a3d8/1*hSXu5dj5gWdLB99e5TaHXA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*hSXu5dj5gWdLB99e5TaHXA.jpeg" /></p>

<p>逛完乐高店，不知道要去哪就改坐公车去逛新世界百货了。</p>

<blockquote>
  <p><em>西面另一家 NC百货已歇业， <strong>其他要逛可能可以去 田浦咖啡街 那边有很多小店(类似东区的感觉)，但是对男生来说兴趣普普。</strong></em></p>
</blockquote>

<h4 id="busan-is-good">Busan is good!</h4>

<p><img src="/assets/8ace34a1a3d8/1*FtpmNOEbpZm_wqMEE0XZXA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*FtpmNOEbpZm_wqMEE0XZXA.jpeg" /></p>

<blockquote>
  <p><em>在釜山到处可以看到「Busan is good」的标语，确实旅游体验下来真的不错，公车超级多、交通方便、公车很新很凉、物价便宜东西好吃。</em></p>
</blockquote>

<h4 id="新世界shinsegae百货--shinsegae-centum-city-"><a href="https://naver.me/xfYRYAfu" target="_blank">新世界(SHINSEGAE)百货 — Shinsegae Centum City</a> 👍👍👍</h4>

<p>前几天来只去了 Spa Land 没有逛到，这次来补逛。</p>

<p><img src="/assets/8ace34a1a3d8/1*_Z3co8etvvt8uJ6IW2WBZg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*_Z3co8etvvt8uJ6IW2WBZg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*U0WsMct8QALuKAQXMVp-fQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*U0WsMct8QALuKAQXMVp-fQ.jpeg" /></p>

<blockquote>
  <p><strong><em>新世界百货超级大(金氏世界纪录第一大)</em></strong> <em>，有很多东西可以逛。</em></p>
</blockquote>

<blockquote>
  <p><em>逛不够隔壁也有 <a href="https://naver.me/5b0d0jtI" target="_blank">乐天百货 — Lotte Dept. Store Centum City Branch</a> 。</em></p>
</blockquote>

<p><img src="/assets/8ace34a1a3d8/1*QGugJUaJZPoHgPEOElZ4uA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*QGugJUaJZPoHgPEOElZ4uA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*wFK6WxUwNb_DeaQyLu_dtA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*wFK6WxUwNb_DeaQyLu_dtA.jpeg" /></p>

<p>由两栋建筑组成，每一栋都有好几层，每一层的面积也都很大；顺手纪录了一下釜山 La Lebo(在一楼) 的价格。</p>

<p><img src="/assets/8ace34a1a3d8/1*yCeQQeere4hq9i_JBXxVug.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*yCeQQeere4hq9i_JBXxVug.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*HCpT3BycowwHj4YH7T3kZg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*HCpT3BycowwHj4YH7T3kZg.jpeg" /></p>

<p>本栋楼顶有 ZOORAJI 免费的恐龙公园可以遛小孩。</p>

<p><img src="/assets/8ace34a1a3d8/1*oFC6DVRe9pA7T-R5TUG0HA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*oFC6DVRe9pA7T-R5TUG0HA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ZRWtwouGGpGv9F2cvFCz_A.webp" alt="" loading="lazy" decoding="async" width="924" height="1202" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjQiIGhlaWdodD0iMTIwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*ZRWtwouGGpGv9F2cvFCz_A.png" /></p>

<p>随意逛了逛，基本上所有品牌、所有类型的柜位都有。</p>

<p><strong>走到另一栋的 1 楼发现有 Shake Shack 那我还不吃爆：</strong></p>

<h4 id="shake-shack-busan-centum"><a href="https://naver.me/GCgugmaP" target="_blank">SHAKE SHACK BUSAN CENTUM</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*kuCM6Mh79ZFYGXtuk2qv7Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="841" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*kuCM6Mh79ZFYGXtuk2qv7Q.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*w8wX3ItxckiitSpt-SPH9Q.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*w8wX3ItxckiitSpt-SPH9Q.jpeg" /></p>

<p>点了这个有脆脆的鸡肉套餐，Shake Shack 除了招牌我觉得鸡肉鲜嫩多汁也很好吃。</p>

<p><img src="/assets/8ace34a1a3d8/1*aVPzCfKsq8FJ5xpyl0Wleg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*aVPzCfKsq8FJ5xpyl0Wleg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*3WaFG6qy3Eg9mm9BvXbLxg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*3WaFG6qy3Eg9mm9BvXbLxg.jpeg" /></p>

<p>呼叫器好像有点问题，其实早做好了只是没响。</p>

<blockquote>
  <p><em>怀念的好滋味。</em></p>
</blockquote>

<blockquote>
  <p><em>游记: <a href="https://zhgchg.li/posts/aacd5f5cacd1/#1200-shake-shack" target="_blank">大阪 Shack Shake</a> / <a href="https://zhgchg.li/posts/b7e7c0938985/#central-world" target="_blank">曼谷 Shake Shack</a></em></p>
</blockquote>

<h4 id="1700-离开新世界百货">~=17:00 离开新世界百货</h4>

<h4 id="1745-回到田浦站西面">~=17:45 回到田浦站(西面)</h4>

<p>准备晚上吃韩牛。</p>

<p><img src="/assets/8ace34a1a3d8/1*A18rMP1xmxzXPrQ9RPTkDQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*A18rMP1xmxzXPrQ9RPTkDQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ytbdvCf_b5ARZf_PyPolmQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*ytbdvCf_b5ARZf_PyPolmQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*vS3dZ4vmhuLZLOkifzpZ4Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*vS3dZ4vmhuLZLOkifzpZ4Q.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*6cr53hsYgiwQJNrgtETIPQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*6cr53hsYgiwQJNrgtETIPQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*3Sg_E9SpDVQi2sIZs5HR7w.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*3Sg_E9SpDVQi2sIZs5HR7w.jpeg" /></p>

<p>田浦站出来就能看到往田浦咖啡街的指示牌，出来这边有一家独栋的 Olive Young。</p>

<p>田浦这块有很多咖啡店、小店，有点像东区的感觉。</p>

<h4 id="花肉店-田浦店--flowerbeefhouse"><a href="https://naver.me/Gj7G7BxZ" target="_blank">花肉店 田浦店 — flowerbeefhouse</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*C7814gYWbA1ajdvCX24HBA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*C7814gYWbA1ajdvCX24HBA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*6lXBVu2a8ooPredaeD98YA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*6lXBVu2a8ooPredaeD98YA.jpeg" /></p>

<p>有点东区网美店的感觉，还好有在 <a href="https://www.catchtable.net/zh-TW/shop/busan_kosaljip?operationType=REMOTE_WAITING_GLOBAL" target="_blank">CatchTable 提前预约</a> 不然现场没位子。</p>

<p><img src="/assets/8ace34a1a3d8/1*0MfOvlWLctZiRYYM9YI2Ow.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*0MfOvlWLctZiRYYM9YI2Ow.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*dODWMoS7WzgH-siJ6pjpbA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*dODWMoS7WzgH-siJ6pjpbA.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*IknycW3IPMrRvAW5jl0aZw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*IknycW3IPMrRvAW5jl0aZw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*nXobUwdMajACPXrjnt4M8w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*nXobUwdMajACPXrjnt4M8w.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*MoSNzb94xyAqw7GFRHdxYA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*MoSNzb94xyAqw7GFRHdxYA.jpeg" /></p>

<blockquote>
  <p><em>点了一份韩牛 Set+炸酱面+Cass 啤酒，韩牛嫩但没什么牛味，我觉得普普；加上 <strong>价格实刷 NT$2,458 C/P 值不太高</strong> ，不如前几天吃的喉咙锅盖烤肉。</em></p>
</blockquote>

<blockquote>
  <p><em>优点大概是拍照漂亮、店员亲切还会中文。</em></p>
</blockquote>

<h4 id="1915-吃饱走回西面站">19:15 吃饱走回西面站</h4>

<p><img src="/assets/8ace34a1a3d8/1*6p05-utFJo4ZG1eFY6yNdQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*6p05-utFJo4ZG1eFY6yNdQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*OJJd1Cu8EacCLHW4NqKJzQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="986" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*OJJd1Cu8EacCLHW4NqKJzQ.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*b-EarSDTdr74ICykPiQrKw.webp" alt="" loading="lazy" decoding="async" width="1200" height="837" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgzNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*b-EarSDTdr74ICykPiQrKw.png" /></p>

<p>田浦到西面这边真的有很多小店、咖啡店、还有看到 ZARA。</p>

<h4 id="回西面站后去乐天百货-b1-美食街买吃的准备去机场饭店">回西面站后去乐天百货 B1 美食街买吃的，准备去机场饭店</h4>

<p><img src="/assets/8ace34a1a3d8/1*w_NQLTD-KKle0HD3xlyngw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*w_NQLTD-KKle0HD3xlyngw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*Rifq7iofXWw4XwV4irb2kQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1021" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMjEiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*Rifq7iofXWw4XwV4irb2kQ.png" /></p>

<p>这里也有超市，最后买了这个章鱼烧回饭店吃，选了最右边的韩式口味。</p>

<h4 id="2030-前往机场饭店">~=20:30 前往机场饭店</h4>

<p><img src="/assets/8ace34a1a3d8/1*rAoS5socLEE80cN-joYtPg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*rAoS5socLEE80cN-joYtPg.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*D0WhmbgOA3EgJVJvW0S_TQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*D0WhmbgOA3EgJVJvW0S_TQ.jpeg" /></p>

<blockquote>
  <p><em>这次是反方向往伽倻大学，同样是周二，仿佛看到上周二刚到釜山的自己。</em></p>
</blockquote>

<h4 id="2100-抵达-air-sky-hotel">~=21:00 抵达 <a href="https://naver.me/FnViVS4g" target="_blank">AIR SKY HOTEL</a></h4>

<p><img src="/assets/8ace34a1a3d8/1*Uv0KMnohG6_icObDYCwnoQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Uv0KMnohG6_icObDYCwnoQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*A1HoGDP-gPzEhYhr7jBa-Q.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*A1HoGDP-gPzEhYhr7jBa-Q.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*ZO4RT_vb0kK09_OwDQCfow.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*ZO4RT_vb0kK09_OwDQCfow.jpeg" /></p>

<p>饭店在机场的上一站 — 西釜山流通地区站，对街有 CU/GS25 超商。</p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/KCmYPL1Joko" title="AIR SKY HOTEL (Busan)" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p><img src="/assets/8ace34a1a3d8/1*MmEJgGoFwwQ58ZeA01MznQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*MmEJgGoFwwQ58ZeA01MznQ.jpeg" /></p>

<blockquote>
  <p><em>这间房间跟浴室都是三天最大、设施最齐全的，不过我们也只是住一天的过客。</em></p>
</blockquote>

<p>房间窗户外可以直接看到飞机起降。</p>

<p><img src="/assets/8ace34a1a3d8/1*1o095_AJ41otB1aOuQrdiw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*1o095_AJ41otB1aOuQrdiw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*DqayI4Jguehj-4uKyeUkEw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*DqayI4Jguehj-4uKyeUkEw.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*s7ieNDtJQZQ8SdCa8FnYEg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*s7ieNDtJQZQ8SdCa8FnYEg.jpeg" /></p>

<p>去超商买了水蜜桃酒配刚刚买的章鱼烧，我觉得这个章鱼烧很赞，虽然带回来已经软掉，但是他是黑色墨鱼浆为基底、台湾章鱼烧的脆感配上韩式的辣酱，很好吃。😋</p>

<h4 id="day-8-0805-二-釜山金海国际机场回程">Day 8 08/05 (二) 釜山金海国际机场、回程</h4>

<p>时光匆匆，很快的八天的釜山行要画下句点了，最后一天就只有去机场一个行程。</p>

<p>从饭店出来搭一站就到达机场 (约 10 分钟)。</p>

<p><img src="/assets/8ace34a1a3d8/1*Dww8cdw_xtLtDoh2R13GNA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Dww8cdw_xtLtDoh2R13GNA.jpeg" /></p>

<p>到机场后直接上二楼国际线出发。</p>

<blockquote>
  <p><em>早上还在困，忘了顺便去 <a href="https://www.instagram.com/reel/C8MojavSlZ2/" target="_blank">申请 SES</a> 加速下次入境通关。</em></p>
</blockquote>

<h4 id="退税">退税</h4>

<p>如果有退税单要退税，记得 <a href="https://www.funliday.com/posts/2024-korea-tax-refund/" target="_blank">照这篇文章</a> 去办理。
我的退税单弄不见了…</p>

<p><img src="/assets/8ace34a1a3d8/1*teDaGZTayKhkL2N84UJ25A.webp" alt="" loading="lazy" decoding="async" width="1400" height="988" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*teDaGZTayKhkL2N84UJ25A.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*pW5hYSUPeitfaOU9aYqklQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*pW5hYSUPeitfaOU9aYqklQ.jpeg" /></p>

<p>二楼边边有很多自助报到机，直接在这边按一按报到、划位；可以看到三楼也很多吃的跟商店。</p>

<p><img src="/assets/8ace34a1a3d8/1*8qabU_7i8fR_lKUelRAukw.webp" alt="" loading="lazy" decoding="async" width="1200" height="791" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc5MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*8qabU_7i8fR_lKUelRAukw.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*CqJalfOGffMcPy86EiF2NQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="804" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjgwNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*CqJalfOGffMcPy86EiF2NQ.png" /></p>

<p>柜台被分配到 D 在最边边。</p>

<p><img src="/assets/8ace34a1a3d8/1*Fe08xzMZ2pZa1ZLJz0i5qQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*Fe08xzMZ2pZa1ZLJz0i5qQ.jpeg" /></p>

<ul>
  <li>
    <p>釜山航空免费额度只有：15 KG</p>
  </li>
  <li>
    <p>会检查随身携带的行动电源有没有装在夹链袋</p>
  </li>
  <li>
    <p><strong>挂完行李务必在那一区域等待 5 分钟，看有没有问题</strong>
那天有人一直被广播找不到人…</p>
  </li>
</ul>

<h4 id="-0930-出境候机">~= 09:30 出境候机</h4>

<p><img src="/assets/8ace34a1a3d8/1*zp0SV0ILqoWylQLYr0S-uA.webp" alt="" loading="lazy" decoding="async" width="1400" height="958" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk1OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*zp0SV0ILqoWylQLYr0S-uA.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*5xLQvy-TjwOBT2RAmlzq6g.webp" alt="" loading="lazy" decoding="async" width="1400" height="984" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*5xLQvy-TjwOBT2RAmlzq6g.png" /></p>

<p><img src="/assets/8ace34a1a3d8/1*6GHIaGkDU8ajLtBZFc5KdA.webp" alt="" loading="lazy" decoding="async" width="1200" height="1185" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjExODUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*6GHIaGkDU8ajLtBZFc5KdA.png" /></p>

<blockquote>
  <p><em>出境大厅不大，就一排而已；有几家免税店跟一家超商跟咖啡厅，卖少许吃的。(如果很饿记得在外面吃完再出境)</em></p>
</blockquote>

<blockquote>
  <p><strong><em>因为是军民两用机场所以不能拍外面飞机。</em></strong></p>
</blockquote>

<p><img src="/assets/8ace34a1a3d8/1*jeZ-QLfYxlbkCFR3s9_6IQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*jeZ-QLfYxlbkCFR3s9_6IQ.jpeg" /></p>

<p><img src="/assets/8ace34a1a3d8/1*oKbFo2YD2LVe80YMI5odeQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*oKbFo2YD2LVe80YMI5odeQ.jpeg" /></p>

<p>不知道要买什么，去超商买了两罐 GD 酒带回台湾。</p>

<h4 id="delay-1107-起飞提早-1158-抵达">Delay 11:07 起飞，提早 11:58 抵达</h4>

<p><img src="/assets/8ace34a1a3d8/1*PEiW_t5NUyQw-EGRq-SyZg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/8ace34a1a3d8/1*PEiW_t5NUyQw-EGRq-SyZg.jpeg" /></p>

<h4 id="釜山行大成功">釜山行大成功！</h4>

<p><img src="/assets/8ace34a1a3d8/1*Oz4R-jMiTOqh0Qa-rh6cHg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/8ace34a1a3d8/1*Oz4R-jMiTOqh0Qa-rh6cHg.jpeg" /></p>

<h4 id="战利品">战利品</h4>

<p><img src="/assets/8ace34a1a3d8/1*mANxdMpisGZuM1PYkslrxg.webp" alt="" loading="lazy" decoding="async" width="968" height="812" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjgiIGhlaWdodD0iODEyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/8ace34a1a3d8/1*mANxdMpisGZuM1PYkslrxg.jpeg" /></p>

<p>没买什么呢。</p>

<h4 id="感谢阅读">感谢阅读</h4>

<blockquote>
  <p>如果您喜欢我的游记欢迎透过我的推广连结购买 <a href="https://www.kkday.com/zh-tw/product/138477-visit-busan-pass-discount-free-attractions?cid=19365" target="_blank">韩国釜山通行证 VISIT BUSAN PASS</a> 我将获得部分分润收益，谢谢。</p>
</blockquote>

<h3 id="更多游记">更多游记</h3>

<ul>
  <li>
    <p><a href="/posts/z-度旅行遊記/九州自由行攻略-釜山新山茶花号邮轮入境日本博多-深入由布院-大分-福冈等地-cb65fd5ab770/"><strong>[游记] 2024 二访九州 9 日自由行，经釜山→博多邮轮入境</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/山阴关西自由行攻略-岛根出云松江鸟取姬路大阪神户7日独旅全记录-aacd5f5cacd1/">[游记] 2024 山阴广域地区 岛根 出云 松江 鸟取 姬路 大阪 神户 7 日独旅自由行</a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/九州自由行攻略-福冈-长崎-熊本10日独旅全纪录与交通住宿实战经验-d78e0b15a08a/">[游记] 2023 九州 10 日自由行独旅</a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/山阳地区广岛冈山自由行攻略-6日行程-交通-住宿全解析-31b9b3a63abc/">[游记] 2023 广岛冈山 6 日自由行</a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/名古屋一日快闪自由行-乐桃航空红眼班机省钱攻略与行程规划-7b8a0563c157/">[游记] 9/11 名古屋一日快闪</a></p>
  </li>
  <li>
    <p>[游记] <a href="/posts/z-度旅行遊記/东京自由行攻略-5-天食住行全记录与必访景点推荐-9da2c51fa4f2/">2023 东京 5 日自由行</a></p>
  </li>
  <li>
    <p>[游记] <a href="/posts/z-度旅行遊記/京阪神自由行攻略-京都大阪神户8日游全纪录与实用交通住宿指南-76d66c2e34af/">2023 京阪神 8 日自由行</a></p>
  </li>
</ul>]]></content>
  </entry><entry>
    <title type="html">Google Offerwall 广告｜内容创作者快速转换流量为收益的奖励墙方案</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/google-offerwall-%E5%B9%BF%E5%91%8A-%E5%86%85%E5%AE%B9%E5%88%9B%E4%BD%9C%E8%80%85%E5%BF%AB%E9%80%9F%E8%BD%AC%E6%8D%A2%E6%B5%81%E9%87%8F%E4%B8%BA%E6%94%B6%E7%9B%8A%E7%9A%84%E5%A5%96%E5%8A%B1%E5%A2%99%E6%96%B9%E6%A1%88-ba132457e6a5/" rel="alternate" type="text/html" title="Google Offerwall 广告｜内容创作者快速转换流量为收益的奖励墙方案" />
    <published>2025-07-24T16:15:09+08:00</published>
    <updated>2025-07-24T16:26:29+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/ba132457e6a5</id><summary type="html">内容创作者透过 Google Offerwall 广告，轻松设定任务解锁内容，无需自行开发系统，快速将流量转换为稳定收益，适合中小型网站与个人部落格，提升变现效率并扩展多元获利模式。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="simplified-chinese" /><category term="ios-app-development" /><category term="google-ads" /><category term="offerwall" /><category term="google-adsense" /><category term="jekyll" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/ba132457e6a5/1*fBIJDsQ994Wn0JNyPDJt8Q.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/google-offerwall-%E5%B9%BF%E5%91%8A-%E5%86%85%E5%AE%B9%E5%88%9B%E4%BD%9C%E8%80%85%E5%BF%AB%E9%80%9F%E8%BD%AC%E6%8D%A2%E6%B5%81%E9%87%8F%E4%B8%BA%E6%94%B6%E7%9B%8A%E7%9A%84%E5%A5%96%E5%8A%B1%E5%A2%99%E6%96%B9%E6%A1%88-ba132457e6a5/"><![CDATA[<h3 id="google-offerwall-广告--内容创作者的全新收益选择">Google Offerwall 广告 — 内容创作者的全新收益选择</h3>

<p>Google Offerwall 广告的浅谈与试用，可快速将既有流量内容转换成限制小额支持或观看广告后才能存取。</p>

<h3 id="live-demo"><a href="/posts/zrealm-dev/google-offerwall-广告-内容创作者快速转换流量为收益的奖励墙方案-ba132457e6a5/">Live Demo</a></h3>

<p><img src="/assets/ba132457e6a5/1*V4LD8JJoor7SusoHX01_eQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="994" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*V4LD8JJoor7SusoHX01_eQ.png" /></p>

<p><img src="/assets/ba132457e6a5/1*fBIJDsQ994Wn0JNyPDJt8Q.webp" alt="https://zhgchg.li/posts/ba132457e6a5/" loading="lazy" decoding="async" width="1400" height="973" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk3MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*fBIJDsQ994Wn0JNyPDJt8Q.png" /></p>

<p><a href="/posts/zrealm-dev/google-offerwall-广告-内容创作者快速转换流量为收益的奖励墙方案-ba132457e6a5/">https://zhgchg.li/posts/ba132457e6a5/</a></p>

<blockquote>
  <p><strong><em>Live Demo -&gt; <a href="/posts/zrealm-dev/google-offerwall-广告-内容创作者快速转换流量为收益的奖励墙方案-ba132457e6a5/">https://zhgchg.li/posts/ba132457e6a5/</a></em></strong></p>
</blockquote>

<h3 id="google-offerwall-广告">Google Offerwall 广告</h3>

<p><img src="/assets/ba132457e6a5/1*DNW0ylu9LHLs4ztWVzw3UQ.webp" alt="&lt;https://support.google.com/admanager/answer/13860694?hl=zh-Hant&gt;" loading="lazy" decoding="async" width="1400" height="976" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk3NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*DNW0ylu9LHLs4ztWVzw3UQ.png" /></p>

<p><a href="https://support.google.com/admanager/answer/13860694?hl=zh-Hant" target="_blank">https://support.google.com/admanager/answer/13860694?hl=zh-Hant</a></p>

<p>「 <a href="https://support.google.com/admanager/answer/13860694?hl=zh-Hant" target="_blank">Google Offerwall</a> 」，个人觉得是「 <strong>奖励型的 Offerwall 奖励墙广告</strong> 」结合奖励型广告的特性，开发者可以很轻易的 <strong>指定网站内容页面需要完成任务才能存取</strong> ， <strong>任务则为 Offerwall 奖励墙任务</strong> ，可以设定使用者须先完成兴趣调查、看广告、小额支付、订阅电子报…或 <a href="https://support.google.com/admanager/answer/13566866?hl=zh-Hant&amp;ref_topic=13821812&amp;sjid=14925592883586634734-NC" target="_blank">串接自家系统的任务</a> ，奖励内容则为存取权限可以是几小时或几天的无限制数量存取、也可以是数量限制；而这一切都只需要嵌入 Google Adsense 动态广告程式码就能达成，不需要自行开发系统。</p>

<h4 id="-优点">✅ 优点</h4>

<ul>
  <li>
    <p><strong>实现容易</strong> ：只要网站 <a href="https://support.google.com/adsense/answer/9189560?hl=zh-Hant" target="_blank">嵌入动态广告程式码</a> 即可，一次设定终身使用。</p>
  </li>
  <li>
    <p><strong>直接获利</strong> ：同 Google Adesnse 好处，不需要自己建置复杂的广告系统、数据追踪系统；也不需要自己找广告商投放广告，一切都由平台代为管理操作。</p>
  </li>
  <li>
    <p><strong>弹性多元</strong> ：提供更弹性多元的内容、流量变现方式。</p>
  </li>
  <li>
    <p><strong>跨平台</strong> ：支援手机、电脑版。</p>
  </li>
</ul>

<h4 id="-缺点">❌ 缺点</h4>

<ul>
  <li>
    <p><strong>出价低</strong> ：这也是 Google Adesnse 的通病，广告出价低。</p>
  </li>
  <li>
    <p><strong>容易阻挡</strong> ：因为 Google Offerwall 是纯前端遮蔽广告，所以可以很轻易的被挡广告外挂组饶或使用者使用开发工具可以直接绕过； <strong>因此不建议将其实现在敏感重要有价值的内容之上。</strong></p>
  </li>
</ul>

<h4 id="-技术要求">📝 技术要求</h4>

<ul>
  <li>
    <p>需要先申请通过 <a href="https://adsense.google.com/" target="_blank">Google Adsense</a>
<strong>现在门槛比较低了，只要有网站网址，内容有5–10 篇文章基本上就能申请通过。</strong></p>
  </li>
  <li>
    <p>网站需要能在 HTML Head 中 <a href="https://support.google.com/adsense/answer/9189560?hl=zh-Hant" target="_blank">嵌入动态广告程式码</a></p>
  </li>
</ul>

<h4 id="️-适合场景">❤️ 适合场景</h4>

<ul>
  <li>
    <p><strong>For 广告</strong> ：同 Google Adsense 适合无自售广告版位的中小型内容网站或个人部落格，例如使用 <a href="https://wordpress.com/zh-tw/" target="_blank">Wordpress</a> 、 <a href="https://pages.github.com/" target="_blank">GitHub Pages</a> 托管的网站；除原本的广告版位显示，还能对有价值的内容文章设定 Offerwall 奖励墙广告。
<strong>本篇文章会以 For 广告为案例，目前除广告外都还在 Beta。</strong></p>
  </li>
  <li>
    <p><strong>For 问券、小额支付、订阅电子报</strong> ：任何网站都能使用此机制快速建立Pop-up 广告。</p>
  </li>
</ul>

<h3 id="安装启用步骤">安装启用步骤</h3>

<h4 id="嵌入动态广告程式码">嵌入动态广告程式码</h4>

<p>首先要确认网站有嵌入 Google Adsense 广告程式码，如果之前就有使用动态广告则可忽略此步骤。</p>

<p><strong>前往 <a href="https://adsense.google.com/" target="_blank">Google Adsense</a> -&gt; 广告 -&gt; 按网站 -&gt; 取得程式码：</strong></p>

<p><img src="/assets/ba132457e6a5/1*CYX4r932I3qkkOgKRVYTSg.webp" alt="" loading="lazy" decoding="async" width="1400" height="742" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijc0MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*CYX4r932I3qkkOgKRVYTSg.png" /></p>

<p><img src="/assets/ba132457e6a5/1*JAEN6wEMLaSgu5wpUkRTnw.webp" alt="" loading="lazy" decoding="async" width="1200" height="522" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjUyMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*JAEN6wEMLaSgu5wpUkRTnw.png" /></p>

<p>将程式码内容贴到网站的 <code class="language-plaintext highlighter-rouge">&lt;head&gt;&lt;/head&gt;</code> 区块之间：</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;head&gt;</span>
  //...
  <span class="nt">&lt;script</span> <span class="err">async</span> <span class="na">src=</span><span class="s">"https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3184248473087645"</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;/head&gt;</span>
</code></pre></div></div>

<h4 id="建立-offerwall-广告">建立 Offerwall 广告</h4>

<p><strong>前往 <a href="https://adsense.google.com/" target="_blank">Google Adsense</a> -&gt; 隐私权与讯息 -&gt; 管理 -&gt; 建立讯息：</strong></p>

<p><img src="/assets/ba132457e6a5/1*aQ3svqP3lo16CGH8R-28yw.webp" alt="" loading="lazy" decoding="async" width="1200" height="1171" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjExNzEiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/ba132457e6a5/1*aQ3svqP3lo16CGH8R-28yw.png" /></p>

<p><img src="/assets/ba132457e6a5/1*ziurWzmp3N6S5-P4O9GO7w.webp" alt="" loading="lazy" decoding="async" width="1380" height="998" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzgwIiBoZWlnaHQ9Ijk5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*ziurWzmp3N6S5-P4O9GO7w.png" /></p>

<blockquote>
  <p><em>也可以在这个页面查看广告收益。</em></p>
</blockquote>

<p><strong>设定 Offerwall 广告：</strong></p>

<p><img src="/assets/ba132457e6a5/1*QfG2HVUy728iSMOdKb7rLw.webp" alt="" loading="lazy" decoding="async" width="1200" height="637" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjYzNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*QfG2HVUy728iSMOdKb7rLw.png" /></p>

<p><img src="/assets/ba132457e6a5/1*E0Pkk8T4e9YVBxJ8xnv1ow.webp" alt="" loading="lazy" decoding="async" width="826" height="960" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MjYiIGhlaWdodD0iOTYwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/ba132457e6a5/1*E0Pkk8T4e9YVBxJ8xnv1ow.png" /></p>

<p><img src="/assets/ba132457e6a5/1*J6wnirCtE8Qp5VsnsTAn_w.webp" alt="" loading="lazy" decoding="async" width="980" height="778" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5ODAiIGhlaWdodD0iNzc4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/ba132457e6a5/1*J6wnirCtE8Qp5VsnsTAn_w.png" /></p>

<p><img src="/assets/ba132457e6a5/1*akZZ5_K3BS1FVSomf8AvvA.webp" alt="3, 5, 6" loading="lazy" decoding="async" width="1200" height="723" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjcyMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*akZZ5_K3BS1FVSomf8AvvA.png" /></p>

<p>3, 5, 6</p>

<p><img src="/assets/ba132457e6a5/1*g_PkT5TqCEFYajdT4ugPCQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="982" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*g_PkT5TqCEFYajdT4ugPCQ.png" /></p>

<p><img src="/assets/ba132457e6a5/1*wnbt-BkLE-0Bk3KGr9ED7Q.webp" alt="4, 8" loading="lazy" decoding="async" width="1400" height="747" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijc0NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*wnbt-BkLE-0Bk3KGr9ED7Q.png" /></p>

<p>4, 8</p>

<ol>
  <li>
    <p><strong>广告名称</strong></p>
  </li>
  <li>
    <p><strong>您的网站</strong> ：设定要套用的网站</p>
  </li>
  <li>
    <p><strong>网页纳入项目和排除项目</strong> ：可设定要涵盖的页面网址或是排除的网址
<em>这边我是设定 <code class="language-plaintext highlighter-rouge">https://zhgchg.li/posts/</code> 路径下的网址才会触发。</em></p>
  </li>
  <li>
    <p><strong>预设语言</strong> ：设定预设语言与支援的其他语言，可在左上方切换语言编辑不同语言的文案。</p>
  </li>
  <li>
    <p><strong>计量</strong> ：可设定使用者浏览第几个(次)网页后才触发
<em>这边我设 0 代表第一次就触发。</em></p>
  </li>
  <li>
    <p><strong>奖励广告</strong> ：可设定完成任务的内容解锁奖励，可以是时间内无限次数浏览或是有限次数网页浏览，奖励到期后需要重新完成任务。
<em>这边我设完成一次任务 24 小时可无限浏览。</em></p>
  </li>
  <li>
    <p><strong>文案设定：</strong> 指定文案内容、记得至少要上传个 Logo 增加品牌力</p>
  </li>
  <li>
    <p><strong>样式设定：</strong> 点击 7 文案后还可以从这边设定文字样式、颜色
可以参考 <a href="https://support.google.com/admanager/answer/13860694?hl=zh-Hant#zippy=%2C%E5%A6%82%E4%BD%95%E6%B8%AC%E8%A9%A6-offerwall" target="_blank">测试方式</a> 在页面网址加上 <code class="language-plaintext highlighter-rouge">?fc=alwaysshow&amp;fctype=monetization</code> 预览结果。</p>
  </li>
  <li>
    <p><strong>发布变更</strong> ：都设定好之后记得按发布</p>
  </li>
</ol>

<p><img src="/assets/ba132457e6a5/1*fRqD1tZ-513FjKsTTwDYkw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1047" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNDciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/ba132457e6a5/1*fRqD1tZ-513FjKsTTwDYkw.png" /></p>

<p>奖励完成后讯息，目前不能更改。</p>

<p><img src="/assets/ba132457e6a5/1*fjfArCVeVNus7J48rEHcaQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="781" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc4MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*fjfArCVeVNus7J48rEHcaQ.png" /></p>

<p>确认广告是已发布状态。</p>

<h4 id="测试-offerwall-广告">测试 Offerwall 广告</h4>

<p>使用无痕浏览器、确认没有启用挡广告、反追踪套件，后前往规则内的网页：</p>

<p><img src="/assets/ba132457e6a5/1*OSEzFBhd-wXSAdm-41aLjQ.webp" alt="https://zhgchg.li/posts/c008a9e8ceca/" loading="lazy" decoding="async" width="1400" height="1349" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEzNDkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/ba132457e6a5/1*OSEzFBhd-wXSAdm-41aLjQ.png" /></p>

<p><a href="/posts/zrealm-dev/ci-cd-是什么-打造高效稳定开发团队的关键流程与工具选择-c008a9e8ceca/">https://zhgchg.li/posts/c008a9e8ceca/</a></p>

<blockquote>
  <p>成功🙌🙌🙌</p>
</blockquote>

<p>尽量使用 Chrome 无痕进行测试，Safari 要关闭挡广告、反追踪会比较麻烦。</p>

<h4 id="收益方面">收益方面</h4>

<p>因为我的浏览量不高，所以单次点击出价也都不太高，大约点击一次广告在 USD $0.01 ~ 0.07 之间而已。</p>

<h3 id="medium-to-github-pages-x-google-offerwall">Medium To Github Pages x Google Offerwall</h3>

<p>可参考我之前的文章「 <a href="/posts/zrealm-dev/无痛转移-medium-文章到自架-jekyll-静态网站-快速部署与自动同步教学-a0c08d579ab1/">无痛转移 Medium 到自架网站</a> 」先将 Medium 文章无痛镜像到 GitHub Pages 托管的静态网站，然后在网站上再加入 Google Offerwall 即可将内容变现收益。</p>

<p>或直接参考「 <a href="/posts/zrealm-life/medium-partner-program-全球开放-台湾创作者轻松加入赚取文章收益-cefdf4d41746/">Medium Partner Program 终于对全球(包含台湾)写作者开放啦！</a> 」将 Medium 文章加入付费墙获得收益。</p>

<blockquote>
  <p><em>因为 Medium 付费墙机制要求读者必须花月费加入 Medium 才能阅读文章，我觉得对资讯传播不太友善，因此我的文章都没有加入付费墙计划；有了 Google Offerwall 正好补足了这块中间地带，使用者可以简单地看广告支持内容创作者，不用强绑月费付费，创作者也能获得收益，一举两得！</em></p>
</blockquote>

<h3 id="补充-offerwall-奖励墙广告与奖励型广告类型说明"><strong><em>[补充] Offerwall 奖励墙广告与奖励型广告类型说明</em></strong></h3>

<h4 id="offerwall--奖励墙广告是什么">Offerwall — 奖励墙广告是什么？</h4>

<p>相比传统的固定版位广告，奖励墙广告更强调与使用者之间的互动与目的性。它整合了内容展示、奖励激励以及使用者行为，使得使用者除了可以选择主动付费解锁加值项目外，还能以更有趣、参与性更高的方式获得额外资源。而创作者则能从中获得额外收益，实现双赢效果。</p>

<p><strong>Example — Line Points 奖励墙</strong></p>

<p><img src="/assets/ba132457e6a5/1*SWF8K0p5asGiDoPMhZRAWQ.webp" alt="" loading="lazy" decoding="async" width="554" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*SWF8K0p5asGiDoPMhZRAWQ.jpeg" /></p>

<p>经典的日常生活中的案例就是 — Line Points，使用者除了直接加值购买 Line Points 之外也能从 Offwall 奖励墙当中挑选喜欢的任务(加好友、注册帐号、填问券、看广告…等等)完成后获得对应奖励。</p>

<h4 id="rewarded-ads--奖励型广告">Rewarded Ads — <strong>奖励型广告</strong></h4>

<p>奖励型广告是一种常见于游戏与行动应用中的广告形式，使用者只需自愿完成特定行为，例如 <strong>观看一段影片、点击互动内容，或试用特定功能</strong> ，就能获得虚拟货币、额外生命、游戏道具等奖励。</p>

<p><strong>Example — Candy Crush</strong></p>

<p><img src="/assets/ba132457e6a5/1*D9PdoZg-mlCbtO19roltdQ.webp" alt="" loading="lazy" decoding="async" width="600" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/ba132457e6a5/1*D9PdoZg-mlCbtO19roltdQ.png" /></p>

<p>经典案例就是游戏中死亡继续游玩的广告，这类广告不仅提升使用者的参与度与满意度，也让开发者在不影响用户体验的前提下创造收益，同样实现双赢效果。</p>]]></content>
  </entry><entry>
    <title type="html">CI/CD 打包工具平台｜使用 Google Apps Script Web App 串接 GitHub Actions 提升跨团队效率</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/ci-cd-%E6%89%93%E5%8C%85%E5%B7%A5%E5%85%B7%E5%B9%B3%E5%8F%B0-%E4%BD%BF%E7%94%A8-google-apps-script-web-app-%E4%B8%B2%E6%8E%A5-github-actions-%E6%8F%90%E5%8D%87%E8%B7%A8%E5%9B%A2%E9%98%9F%E6%95%88%E7%8E%87-4273e57e7148/" rel="alternate" type="text/html" title="CI/CD 打包工具平台｜使用 Google Apps Script Web App 串接 GitHub Actions 提升跨团队效率" />
    <published>2025-07-10T20:30:51+08:00</published>
    <updated>2025-11-19T23:59:42+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/4273e57e7148</id><summary type="html">打造免费且易用的打包工具平台，解决非工程人员操作 GitHub Actions 的复杂性与权限控管问题，透过 Google Apps Script Web App 整合 GitHub、Slack、Firebase 等 API，实现跨团队任务单打包与即时进度通知，提升开发与验证效率。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="ios-app-development" /><category term="cicd" /><category term="google-apps-script" /><category term="web-development" /><category term="tools" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/4273e57e7148/1*kJhD4PCaIphZ9G1BG_dtNw.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/ci-cd-%E6%89%93%E5%8C%85%E5%B7%A5%E5%85%B7%E5%B9%B3%E5%8F%B0-%E4%BD%BF%E7%94%A8-google-apps-script-web-app-%E4%B8%B2%E6%8E%A5-github-actions-%E6%8F%90%E5%8D%87%E8%B7%A8%E5%9B%A2%E9%98%9F%E6%95%88%E7%8E%87-4273e57e7148/"><![CDATA[<h3 id="cicd-实战指南四使用-google-apps-script-web-app-串接-github-actions-建置免费易用的打包工具平台">CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</h3>

<p>GAS Web App 串接 GitHub, Slack, Firebase 或 Asana/Jira API，建置中继站，提供跨团队共用的打包工具平台</p>

<p><img src="/assets/4273e57e7148/1*kJhD4PCaIphZ9G1BG_dtNw.webp" alt="Photo by Lee Campbell" loading="lazy" decoding="async" width="1400" height="935" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjkzNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4273e57e7148/1*kJhD4PCaIphZ9G1BG_dtNw.jpeg" /></p>

<p>Photo by <a href="https://unsplash.com/@leecampbell?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank">Lee Campbell</a></p>

<h3 id="前言">前言</h3>

<p>前篇「 <a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/"><strong>CI/CD 实战指南（三）：使用 GitHub Actions 实作 App iOS CI 与 CD 工作流程</strong></a> 」我们已经完成了 App iOS 专案的 CI/CD 底层功能建设，现在已经可以 CI 自动测试验证跟 CD 打包部署；然而在实务产品开发流程上， <strong>打包部署工作多半是为了后续交付给其他职能伙伴</strong> 进 行 QA(Quality Assurance) 功能验证，这时候 CD 场景就不在只局限在工程端了，可能跨足 QA、PM、设计(Design QA) 甚至是老板想先玩看看。</p>

<p>GitHub Actions <code class="language-plaintext highlighter-rouge">workflow_dispatch</code> 手动表单触发事件，虽然能提供简易的表单让使用者操作打包，但如果操作的对象是非工程人员就相对很不友善，他们不懂：什么是分支？栏位要不要填？怎么知道打包好了？好了怎么下载？…etc
另外还有权限控管问题，如果要让其他职能伙伴直接使用 GitHub Actions 打包，就需要把他的帐号加到 Repo 当中， <strong>资安控管上很不安全也不合理</strong> ，只是要操作打包表单却要开整个 Source Code 给他。</p>

<p>不同于 Jenkins 有独立的 Web 工具平台，GitHub Actions 就只有这个功能。</p>

<p><img src="/assets/4273e57e7148/1*qDD8HAAHxDxPEU3vJPEhjA.webp" alt="`workflow_dispatch 的表单样式`" loading="lazy" decoding="async" width="342" height="445" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNDIiIGhlaWdodD0iNDQ1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*qDD8HAAHxDxPEU3vJPEhjA.png" /></p>

<p><code class="language-plaintext highlighter-rouge">workflow_dispatch 的表单样式</code></p>

<p>因此 <strong>我们需要一个中继站打包平台，用来服务其他职能使用者</strong> ，整合 Asana/Jira 的任务单，让使用的人可以直接用任务单打包 App，并且直接在上面查看进度、下载打包结果。</p>

<p><img src="/assets/4273e57e7148/1*bHYawmSnhqwB4TzIJVfGow.webp" alt="GAS Web App 中继站" loading="lazy" decoding="async" width="1400" height="1037" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMzciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/4273e57e7148/1*bHYawmSnhqwB4TzIJVfGow.png" /></p>

<p>GAS Web App 中继站</p>

<p><a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/">上一篇</a> 关注的是右边核心 GitHub Actions CI/CD 工作流程开发；本文关注的是左半部 to End-User 打包工具平台、增加使用者体验的部分。</p>

<h4 id="google-apps-script--web-app-打包工具平台-成果图">Google Apps Script — Web App 打包工具平台 成果图</h4>

<p><img src="/assets/4273e57e7148/1*yXMeaOELhqdvMCxIJ5ElBw.gif" alt="" loading="lazy" decoding="async" width="1048" height="822" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDQ4IiBoZWlnaHQ9IjgyMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<p><img src="/assets/4273e57e7148/1*EM0goWpuDeHGVkZoybLm8g.webp" alt="" loading="lazy" decoding="async" width="980" height="899" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5ODAiIGhlaWdodD0iODk5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*EM0goWpuDeHGVkZoybLm8g.png" /></p>

<p><img src="/assets/4273e57e7148/1*haoGMvAUroz7rUMDEez9gA.webp" alt="" loading="lazy" decoding="async" width="984" height="826" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5ODQiIGhlaWdodD0iODI2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*haoGMvAUroz7rUMDEez9gA.png" /></p>

<p><img src="/assets/4273e57e7148/1*afCwKITlerG1g6swB_2wZA.webp" alt="" loading="lazy" decoding="async" width="955" height="758" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTUiIGhlaWdodD0iNzU4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*afCwKITlerG1g6swB_2wZA.png" /></p>

<p><img src="/assets/4273e57e7148/1*mvwpHBdrC73_PjL8H32nkw.webp" alt="" loading="lazy" decoding="async" width="554" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4273e57e7148/1*mvwpHBdrC73_PjL8H32nkw.jpeg" /></p>

<p><img src="/assets/4273e57e7148/1*BbbEd_thhUOdbAQqsCt-Tw.webp" alt="" loading="lazy" decoding="async" width="1046" height="585" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDQ2IiBoZWlnaHQ9IjU4NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4273e57e7148/1*BbbEd_thhUOdbAQqsCt-Tw.png" /></p>

<p><img src="/assets/4273e57e7148/1*HXjfMpUPssaw3sJgH6KKJQ.webp" alt="" loading="lazy" decoding="async" width="312" height="292" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMTIiIGhlaWdodD0iMjkyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*HXjfMpUPssaw3sJgH6KKJQ.png" /></p>

<ul>
  <li>
    <p><strong>打包表单：</strong> 整合专案管理工具捞取单号、整合 GitHub 捞取开启中的 Pull Request</p>
  </li>
  <li>
    <p><strong>把包纪录：</strong> 显示打包历史纪录、正在打包的任务进度状态、点击取得下载连结捞取 Firebase App Distribution 下载连结、资讯</p>
  </li>
  <li>
    <p><strong>Runner 状态：</strong> 显示 Self-hosted Runner 状态。</p>
  </li>
  <li>
    <p><strong>Slack 打包进度通知。</strong></p>
  </li>
  <li>
    <p>支援手机版</p>
  </li>
  <li>
    <p>支援限制组织团队内帐号使用</p>
  </li>
</ul>

<p><strong>主要职责</strong></p>

<p>0 状态、0 资料库， <strong>单纯为中继交换站</strong> ，整合显示各个 API 资料 (e.g. Asana/Jira/GitHub)、转发表单请求到 GitHub Actions。</p>

<p><strong>操作要求：</strong> 支援手机与电脑。</p>

<p><strong>权限要求：</strong> 能限制只有团队组织成员能存取。</p>

<h4 id="online-demo-web-app"><a href="https://script.google.com/macros/s/AKfycbwNW6N5ozKbIz_E1HK6yFEUtA8KQrUciS-jcPsQptvIKlARmKgLxbQzNu8ksVeg-BmEfg/exec" target="_blank">Online Demo Web App</a></h4>

<ul>
  <li>初次使用请参考下图授权(Only For Demo App)：</li>
</ul>

<p><img src="/assets/4273e57e7148/0*7pJ876yQbcakQvdO.webp" alt="" loading="lazy" decoding="async" width="700" height="607" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDAiIGhlaWdodD0iNjA3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/0*7pJ876yQbcakQvdO.png" /></p>

<p>专案原始码： <a href="https://script.google.com/home/projects/1CBB39OMedqP9Ro1WSlvgDnMBin4-ksyhgly2h_KrbOuFiPHTalNgwHOp/edit" target="_blank">https://script.google.com/home/projects/1CBB39OMedqP9Ro1WSlvgDnMBin4-ksyhgly2h_KrbOuFiPHTalNgwHOp/edit</a></p>

<h3 id="技术选择">技术选择</h3>

<p><a href="/posts/zrealm-dev/ci-cd-是什么-打造高效稳定开发团队的关键流程与工具选择-c008a9e8ceca/">第一篇文章</a> 有提到过，这边再详细整理一次。</p>

<h4 id="整合进-slack">整合进 Slack</h4>

<p>我们尝试过让 Slack 担任打包平台，自行开发后端服务并架设在 GCP 上，与 Slack API、Asana API 进行串接整合，再将 Slack 送来的表单转手发送给 GitHub API 触发后续 GitHub Actions；体验上非常爽而且统一在团队的协作工具上，可以无痛使用； <strong>缺点是开发及后续维护成本很高</strong> ，因为是自己用 Ktor 开发的后端服务，需要 App 工程师同时兼做后端、处理 Google 服务 OAuth 整合问题、部分功能可能在这做掉(例如：送审)…功能复杂；如果后来的新人没衔接好这整块几乎没办法维护下去了，另外每个月还要花 $15 USD GCP 伺服器费用。</p>

<p>初期也尝试过用 FaaS 服务串接 Slack API，例如 Cloud Funtions，但是 Slack API 要求串接的服务要能在 3 秒内回应请求，否则视为失败；FaaS 会有 <a href="https://www.cloudflare.com/zh-tw/learning/serverless/what-is-serverless/" target="_blank">冷启动问题</a> ，当服务一段时间没呼叫就会进入休眠，再次呼叫时会需要较长时间才能响应 (≥ 5秒)，会造成 Slack 打包表单很不稳定，时常出现 Timeout Error。</p>

<h4 id="整合进内部系统">整合进内部系统</h4>

<p>这当然是最优解，如果团队有 Web、后端人力，直接与现有系统整合是最好也最安全的。</p>

<blockquote>
  <p><em>本文的前提是：没有，App 自立自强。</em></p>
</blockquote>

<h4 id="google-apps-script--web-app">Google Apps Script — Web App</h4>

<p>Google Apps Script 是我们的老伙伴，之前做过很多 RPA 专案都是用他去做排程触发执行任务，例如：「 <a href="/posts/zrealm-dev/crashlytics与google-analytics自动查询app-crash-free-users-rate-google-apps-script整合实作-793cb8f89b72/">Crashlytics + Google Analytics 自动查询 App Crash-Free Users Rate</a> 」、「 <a href="/posts/zrealm-robotic-process-automation/google-apps-script-打造每日数据报表自动化-rpa-快速串接-google-analytics-与-google-sheet-f6713ba3fee3/">使用 Google Apps Script 实现每日数据报表 RPA 自动化</a> 」，这时候我又想起了它；GAS 有一个功能是部署成 Web (App) 直接当网页服务。</p>

<p><strong>Google Apps Script 优点：</strong></p>

<ul>
  <li>
    <p>✅ 免费、 <a href="https://developers.google.com/apps-script/guides/services/quotas?hl=zh-tw" target="_blank">正常使用下几乎摸不到上限</a></p>
  </li>
  <li>
    <p>✅ Functions as a Service 方法即服务，不需自行架设维护伺服器</p>
  </li>
  <li>
    <p>✅ 权限控管同 Google Workspace，可设定仅限组织内 Google 帐号使用</p>
  </li>
  <li>
    <p>✅ 无痛整合 Google 生态系相关服务(e.g. Firebase, GA…etc)与资料 (不用自己做 OAuth)</p>
  </li>
  <li>
    <p>✅ 程式语言使用 JavaScript 易上手 (V8 Runtime 支援 ES6+ )</p>
  </li>
  <li>
    <p>✅ 快速撰写、快速上线、快速使用</p>
  </li>
  <li>
    <p>✅ 服务稳定、长久 (已推出超过 16 年)</p>
  </li>
  <li>
    <p><strong>✅ AI Can Help! 实测使用 ChatGPT 辅助开发，准确率可达 95%</strong></p>
  </li>
</ul>

<p><strong>Google Apps Script 缺点：</strong></p>

<ul>
  <li>
    <p>❌ 内建的版本管控一言难尽</p>
  </li>
  <li>
    <p>❌ 内建不支援档案、资料储存、金钥/凭证管理</p>
  </li>
  <li>
    <p>❌ Web App 无法做到 100% 体验的 RWD</p>
  </li>
  <li>
    <p>❌ 专案只能绑在个人帐号而不是组织</p>
  </li>
  <li>
    <p>❌ 虽然 Google 有持续在开发维护，但整体功能更新缓慢</p>
  </li>
  <li>
    <p>❌ 网路请求 <code class="language-plaintext highlighter-rouge">UrlFetchApp</code> 不支援设定 User-Agent</p>
  </li>
  <li>
    <p>❌ Web App <code class="language-plaintext highlighter-rouge">doGet</code> / <code class="language-plaintext highlighter-rouge">doPost</code> 不支援取得 Headers 资讯</p>
  </li>
  <li>
    <p>❌ FaaS <a href="https://www.cloudflare.com/zh-tw/learning/serverless/what-is-serverless/" target="_blank">冷启动问题</a></p>
  </li>
  <li>
    <p>❌ <strong>不支援多人同时开发</strong>
但在 Web App 影响不大，顶多要多等几秒才进入网页。</p>
  </li>
</ul>

<p>以上是 GAS 本身服务的优缺点，对做打包工具 Web 影响不大；选择使用此方案对比 Slack 方案，更快速、轻量跟容易交接上手， <strong>缺点是团队需要多知道这个工具的网址在哪跟怎么用、还有因 GAS 程式库功能有限</strong> (e.g. 无内建加密演算法库) 基本上只能做纯中继平台，例如送审，那也只能转发送审请求请 GitHub Actions 做。</p>

<blockquote>
  <p><strong><em>另外也仅适用是 Google Workspace 工作环境的团队；</em></strong> <em>权衡了资源与需求，因此采用 Google Apps Script — Web App 来实现打包工具平台。</em></p>
</blockquote>

<h4 id="ui-framework">UI Framework</h4>

<p><a href="https://getbootstrap.com/" target="_blank"><img src="https://getbootstrap.com/docs/5.3/assets/brand/bootstrap-social.png" alt="" /></a></p>

<p>我们直接使用 Bootstrap CDN，不然要自己弄 CSS 样式太麻烦了，Bootstrap 问 AI 怎么组合使用也更准确方便。</p>

<h3 id="动手做">动手做</h3>

<p>这边已经把整个平台架构开源了，大家可以依照自己团队的需求基于这个版本再客制化即可。</p>

<h4 id="开源范例专案">开源范例专案</h4>

<p>在 GAS 上直接检视专案：</p>

<p><a href="https://script.google.com/home/projects/1CBB39OMedqP9Ro1WSlvgDnMBin4-ksyhgly2h_KrbOuFiPHTalNgwHOp/edit" target="_blank"><img src="https://www.gstatic.com/devrel-devsite/prod/v210625d4186b230b6e4f2892d2ebde056c890c9488f9b443a741ca79ae70171d/developers/images/opengraph/white.png" alt="" /></a></p>

<p><img src="/assets/4273e57e7148/1*Xzh2eBpVR92uZq-8POPegw.webp" alt="" loading="lazy" decoding="async" width="760" height="860" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjAiIGhlaWdodD0iODYwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*Xzh2eBpVR92uZq-8POPegw.png" /></p>

<p>GitHub Repo 备份：</p>

<p><a href="https://github.com/ZhgChgLi/google-apps-script-cd-web-app-demo" target="_blank"><img src="https://opengraph.githubassets.com/3d7c517cd747bc49656701ef275357816667a72ebe2b7744c22e8a34c82b4a26/ZhgChgLi/google-apps-script-cd-web-app-demo" alt="" /></a></p>

<h4 id="档案架构">档案架构</h4>

<p><img src="/assets/4273e57e7148/1*ohVakhlaflRXCI_3j2-cOA.webp" alt="" loading="lazy" decoding="async" width="227" height="716" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMjciIGhlaWdodD0iNzE2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*ohVakhlaflRXCI_3j2-cOA.png" /></p>

<p><img src="/assets/4273e57e7148/1*AyIEF0wqEFdMDBuRzQXDEQ.webp" alt="" loading="lazy" decoding="async" width="1177" height="991" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTc3IiBoZWlnaHQ9Ijk5MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4273e57e7148/1*AyIEF0wqEFdMDBuRzQXDEQ.png" /></p>

<p>写了一个很阳春的 类-MVC 架构，如要调整或不知道功能问 AI 都能得到准确答案。</p>

<p><strong>系统</strong></p>

<ul>
  <li>
    <p>appsscript.json: GAS 系统的 Metadata 设定档案
<strong>重点是「oauthScopes」变数，宣告这个 Script 会用到的外部权限。</strong></p>
  </li>
  <li>
    <p>Entrypoint.gs: 定义 doGet( ) 进入点</p>
  </li>
</ul>

<p><strong>Controller</strong></p>

<ul>
  <li>Controller_iOS.gs: iOS 打包工具页面 Controller，负责捞数据给 View 显示</li>
</ul>

<p><strong>View</strong></p>

<ul>
  <li>
    <p>View_index.html: 整个打包工具骨架、首页</p>
  </li>
  <li>
    <p>View_iOS.html: iOS 打包工具页面骨架</p>
  </li>
  <li>
    <p>View_iOS_Runs.html: iOS 打包工具 — 打包纪录内容页面</p>
  </li>
  <li>
    <p>View_iOS_Form.html: iOS 打包工具 —打包表单页面</p>
  </li>
  <li>
    <p>View_iOS_Runners.html: iOS 打包工具 — Self-hosted Runner 状态页面</p>
  </li>
</ul>

<p><strong>Model(Lib)</strong></p>

<ul>
  <li>
    <p>Credentials.gs: 定义金钥内容
(⚠️️️请注意️，GAS 如果要走 GCP IAM 会蛮复杂的因此我们直接定义金钥在此， <strong>所以这个 GAS 专案会包含机密资讯，请不要随意共享专案检视编辑权限</strong> )</p>
  </li>
  <li>
    <p>StubData.gs: Online Demo 用的 Stub 方法、资料。</p>
  </li>
  <li>
    <p>Settings.gs: 一些常用设定，跟 lib init。</p>
  </li>
  <li>
    <p>GitHub.gs: GitHub API 操作封装。</p>
  </li>
  <li>
    <p>Slack.gs: Slack API 操作封装。</p>
  </li>
  <li>
    <p>Firebase.gs: Firebase — App Distribution API 操作封装。</p>
  </li>
</ul>

<h4 id="建立自己的打包平台">建立自己的打包平台</h4>

<p>1.建立一个 <a href="https://script.google.com/home" target="_blank">Google Apps Script 专案</a> 、命名</p>

<p><img src="/assets/4273e57e7148/1*_uVqy6cDNvFSEL0feOS-pw.webp" alt="" loading="lazy" decoding="async" width="919" height="369" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTkiIGhlaWdodD0iMzY5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*_uVqy6cDNvFSEL0feOS-pw.png" /></p>

<p>到专案设定 → 勾选「在编辑器中显示「appsscript.json」资讯清单档案」才会出现「appsscript.json」Metadata 档案。</p>

<p><img src="/assets/4273e57e7148/1*tvXsQufQs5-5UzV0bg5WLA.webp" alt="" loading="lazy" decoding="async" width="736" height="466" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MzYiIGhlaWdodD0iNDY2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*tvXsQufQs5-5UzV0bg5WLA.png" /></p>

<p>2.参考我的 <a href="https://script.google.com/home/projects/1CBB39OMedqP9Ro1WSlvgDnMBin4-ksyhgly2h_KrbOuFiPHTalNgwHOp/edit" target="_blank">开源专案档案</a> ，把所有档案按照范例建立好跟把内容无脑复制过来</p>

<p><img src="/assets/4273e57e7148/1*PxZvHNeW6PFaaqmZqifFfg.webp" alt="" loading="lazy" decoding="async" width="572" height="272" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NzIiIGhlaWdodD0iMjcyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*PxZvHNeW6PFaaqmZqifFfg.png" /></p>

<blockquote>
  <p><strong><em>很蠢，但没办法。</em></strong></p>
</blockquote>

<blockquote>
  <p><em>StubData.gs 先一起复制过来，第一次部署测试可以使用。</em></p>
</blockquote>

<blockquote>
  <p><em>另一个方法是用 <a href="https://developers.google.com/apps-script/guides/clasp?hl=zh-tw" target="_blank">clasp (Google Apps Script CLI)</a> git clone demo project 后把 Code 推上去。</em></p>
</blockquote>

<p><img src="/assets/4273e57e7148/1*FLM2SGIhAI7Z7OWIJpeT9A.webp" alt="" loading="lazy" decoding="async" width="1150" height="852" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTUwIiBoZWlnaHQ9Ijg1MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4273e57e7148/1*FLM2SGIhAI7Z7OWIJpeT9A.png" /></p>

<p>复制完长得会跟范例专案一模一样。</p>

<ol>
  <li>首次部署「网页应用程式」查看结果</li>
</ol>

<p><img src="/assets/4273e57e7148/1*KbWpaEinVZh6M8o8bCCl6A.webp" alt="" loading="lazy" decoding="async" width="833" height="239" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MzMiIGhlaWdodD0iMjM5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*KbWpaEinVZh6M8o8bCCl6A.png" /></p>

<p><img src="/assets/4273e57e7148/1*2RrwNxZVidodX6Kq037Yvw.webp" alt="" loading="lazy" decoding="async" width="761" height="601" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjEiIGhlaWdodD0iNjAxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*2RrwNxZVidodX6Kq037Yvw.png" /></p>

<p><img src="/assets/4273e57e7148/1*CZSIfASW4hmQeXwTS3x7Fg.webp" alt="" loading="lazy" decoding="async" width="761" height="602" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjEiIGhlaWdodD0iNjAyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*CZSIfASW4hmQeXwTS3x7Fg.png" /></p>

<p>专案右上角「部署」 → 「新增部署作业」 → 类型「网页应用程式」:</p>

<p><strong>执行身份：</strong></p>

<ul>
  <li>
    <p>我 <code class="language-plaintext highlighter-rouge">统一都用你的帐号身分执行脚本。</code></p>
  </li>
  <li>
    <p>存取网页程式的使用者 <code class="language-plaintext highlighter-rouge">会以当前登入的 Google 帐号使用者身份执行脚本。</code></p>
  </li>
</ul>

<p><strong>谁可以存取：</strong></p>

<ul>
  <li>
    <p>只有我自己</p>
  </li>
  <li>
    <p><strong>XXX 同个组织中的所有使用者</strong> <code class="language-plaintext highlighter-rouge">只有同组织＋已登入的 Google 帐号使用者可以存取。</code></p>
  </li>
  <li>
    <p>所有已登入 Google 帐号的使用者 <code class="language-plaintext highlighter-rouge">已登入的 Google 帐号使用者都可以存取。</code></p>
  </li>
  <li>
    <p>所有人 <code class="language-plaintext highlighter-rouge">不需要登入 Google 帐号、所有人都可以公开存取。</code></p>
  </li>
</ul>

<blockquote>
  <p><em>如果是内部工具：可以选择「 <strong>谁可以存取：XXX 同个组织中的所有使用者」+「执行身份：存取网页程式的使用者」进行安全控管。</strong></em></p>
</blockquote>

<p>完成部署后的「网页应用程式」网址，就是你的 Web App 打包工具网址，可以分享给团队成员使用。(网址很丑，可以自己用短网址服务包装一下、 <strong>更新部署内容不会异动网址</strong> )</p>

<h4 id="使用者首次使用需要同意授权">使用者首次使用需要同意授权</h4>

<p>首次点击 Web App 网址，需要先同意授权。</p>

<p><img src="/assets/4273e57e7148/1*lckRkGtc7EVqz9aTZaBIOw.webp" alt="" loading="lazy" decoding="async" width="519" height="491" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTkiIGhlaWdodD0iNDkxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*lckRkGtc7EVqz9aTZaBIOw.png" /></p>

<p><img src="/assets/4273e57e7148/1*l1t290T_4xs1ly-RjjZXtg.webp" alt="" loading="lazy" decoding="async" width="766" height="674" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjYiIGhlaWdodD0iNjc0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*l1t290T_4xs1ly-RjjZXtg.png" /></p>

<p><img src="/assets/4273e57e7148/1*O9ItCSBNoBcuqepd-6ygCA.webp" alt="" loading="lazy" decoding="async" width="722" height="630" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MjIiIGhlaWdodD0iNjMwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*O9ItCSBNoBcuqepd-6ygCA.png" /></p>

<ul>
  <li>
    <p>Review Permission → 选择要使用此 Web App 的帐户身份</p>
  </li>
  <li>
    <p>未验证警告视窗，点击「进阶」展开 → 点击 前往「XXX」(不安全)</p>
  </li>
</ul>

<p><img src="/assets/4273e57e7148/1*cYloLsBROLbZDPIciYUm5g.webp" alt="" loading="lazy" decoding="async" width="1054" height="876" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDU0IiBoZWlnaHQ9Ijg3NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4273e57e7148/1*cYloLsBROLbZDPIciYUm5g.png" /></p>

<ul>
  <li>点击「允许」</li>
</ul>

<blockquote>
  <p><em>尔后如果脚本权限没更动不用重新授权。</em></p>
</blockquote>

<p><strong>完成授权同意后就会进入打包工具首页：</strong></p>

<p><img src="/assets/4273e57e7148/1*vG5SsVFHPPDukc4ej0hqLA.webp" alt="" loading="lazy" decoding="async" width="1149" height="1113" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTQ5IiBoZWlnaHQ9IjExMTMiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/4273e57e7148/1*vG5SsVFHPPDukc4ej0hqLA.png" /></p>

<blockquote>
  <p>Demo 打包工具部署成功 🎉🎉🎉</p>
</blockquote>

<p>注:「这个应用程式是由 Google Apps Script 的使用者建立」这个提示无法自动隐欌。</p>

<h4 id="更新部署">更新部署</h4>

<blockquote>
  <p>⚠️所有程式码的变动都需要更新部署才会生效。</p>
</blockquote>

<blockquote>
  <p>️️⚠️所有程式码的变动都需要更新部署才会生效。</p>
</blockquote>

<blockquote>
  <p>⚠️所有程式码的变动都需要更新部署才会生效。</p>
</blockquote>

<p>这边要注意程式码变动储存完不会直接变动到 Web App 上，所以发现重整没效果就是这个原因； <strong>需要到「部署」 → 「管理部署作业」→「编辑」→ 版本「建立新版本」 → 点击「部署」 → 「完成」</strong> 。</p>

<p><img src="/assets/4273e57e7148/1*VsfCEfwnPlx9RbQ8DtXpnA.webp" alt="" loading="lazy" decoding="async" width="298" height="229" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOTgiIGhlaWdodD0iMjI5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*VsfCEfwnPlx9RbQ8DtXpnA.png" /></p>

<p><img src="/assets/4273e57e7148/1*n62MVd6o8W3hUtQpfn9Q0w.webp" alt="" loading="lazy" decoding="async" width="761" height="603" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjEiIGhlaWdodD0iNjAzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*n62MVd6o8W3hUtQpfn9Q0w.png" /></p>

<blockquote>
  <p><em>更新部署完再重整网页就能看到改动生效。</em></p>
</blockquote>

<h4 id="新增测试部署方便开发">新增测试部署方便开发</h4>

<p><img src="/assets/4273e57e7148/1*4fLoW6jf8z1AIXvULW-AOA.webp" alt="" loading="lazy" decoding="async" width="413" height="235" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MTMiIGhlaWdodD0iMjM1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*4fLoW6jf8z1AIXvULW-AOA.png" /></p>

<p><img src="/assets/4273e57e7148/1*yvTxeaImQ4Mr7FwESsuf5A.webp" alt="" loading="lazy" decoding="async" width="761" height="599" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjEiIGhlaWdodD0iNTk5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*yvTxeaImQ4Mr7FwESsuf5A.png" /></p>

<p>如同前述，所有改动要生效都要更新部署；这在开发阶段非常麻烦，因此在开发阶段我们可以用「测试部署」来快速验证改动是否正确。</p>

<p><strong>到「部署」 → 「测试部署作业」 → 取得测试用「网页应用程式」网址。</strong></p>

<p><img src="/assets/4273e57e7148/1*Rt0XEw9uAev58isLEnsoPA.webp" alt="" loading="lazy" decoding="async" width="762" height="603" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjIiIGhlaWdodD0iNjAzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*Rt0XEw9uAev58isLEnsoPA.png" /></p>

<p>在开发阶段我们直接使用此网址就能储存，档案更改储存完，回到这个开发用网址重整网页就能看到成果！</p>

<blockquote>
  <p><strong><em>都开发好之后再照前文说的更新部署，释出给使用者使用。</em></strong></p>
</blockquote>

<h3 id="修改-demo-范例专案串接真实资料">修改 Demo 范例专案串接真实资料</h3>

<p>再来才是重点，串接真实资料，GitHub Actions Workflow 参考的是 <a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/"><strong>上一篇文章中建立好的 CI/CD 流程</strong></a> ，你也可依照实际的 Actions Workflow 调整参数。</p>

<h4 id="️修改前请注意">⚠️修改前请注意</h4>

<p>Google Apps Script 平台并不能很好的支援多人或甚至多开视窗开发，我自己踩过的雷是不小心开了两个编辑视窗，在 A 编辑完，后来在 B 编辑，所以修改都被 B 的旧版覆盖掉了；因此 <strong>建议同时间只有一个人一个视窗在编辑 Script</strong> 。</p>

<h4 id="github-串接">GitHub 串接</h4>

<p><strong>带入 GitHub API Token:</strong></p>

<p>GitHub -&gt; 帐号 -&gt; Settings -&gt; Developer Settings -&gt; Fine-grained personal access tokens or Personal access tokens (classic)。</p>

<p>建议使用 Fine-grained personal access tokens 比较安全(但有期限)。</p>

<p><strong>Fine-grained personal access tokens 需要的权限如下：</strong></p>

<p><img src="/assets/4273e57e7148/1*lCNQHwC4EMU4gNXYC-zs2A.webp" alt="" loading="lazy" decoding="async" width="821" height="579" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MjEiIGhlaWdodD0iNTc5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*lCNQHwC4EMU4gNXYC-zs2A.png" /></p>

<ul>
  <li>
    <p>Repo: 记得选要操作的 Repo</p>
  </li>
  <li>
    <p>Permissions: <code class="language-plaintext highlighter-rouge">Actions (read/write)</code> 、 <code class="language-plaintext highlighter-rouge">Administration (read only)</code></p>
  </li>
</ul>

<blockquote>
  <p><em>如果不想依赖在某人的帐号上建议建立一支干净的团队 GitHub 帐号，使用它的 Token。</em></p>
</blockquote>

<p>到 GAS 专案 → <code class="language-plaintext highlighter-rouge">Credentials.gs</code> → 将 Token 带入到 <code class="language-plaintext highlighter-rouge">githubToken</code> 变数中。</p>

<p><strong>替换 GithubStub 成 GitHub:</strong></p>

<p>到 GAS 专案 → <code class="language-plaintext highlighter-rouge">Settings.gs</code> → 将：</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">iOSGitHub</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">GitHubStub</span><span class="p">(</span><span class="nx">githubToken</span><span class="p">,</span> <span class="nx">iOSRepoPath</span><span class="p">);</span>
</code></pre></div></div>

<p><strong>改成</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">iOSGitHub</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">GitHub</span><span class="p">(</span><span class="nx">githubToken</span><span class="p">,</span> <span class="nx">iOSRepoPath</span><span class="p">);</span>
</code></pre></div></div>

<p>储存档案。</p>

<p><strong>重新整理测试用「网页应用程式」网址查看改动是否正确:</strong></p>

<p><img src="/assets/4273e57e7148/1*30k1iDALT9WdupmuBiG2uQ.webp" alt="" loading="lazy" decoding="async" width="958" height="859" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTgiIGhlaWdodD0iODU5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*30k1iDALT9WdupmuBiG2uQ.png" /></p>

<blockquote>
  <p><em>能正确显示资料代表： <strong>GitHub 改串真实资料成功</strong> 🎉🎉🎉</em></p>
</blockquote>

<p>也能顺手切到「Runner 状态」查看 Self-hosted Runner 状态捞取正不正常：</p>

<p><img src="/assets/4273e57e7148/1*K3yzISn5J7o1e1F5zhIQpg.webp" alt="" loading="lazy" decoding="async" width="972" height="394" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NzIiIGhlaWdodD0iMzk0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*K3yzISn5J7o1e1F5zhIQpg.png" /></p>

<p>注：我 Runner 没开…所以是离线中。</p>

<h4 id="slack-串接">Slack 串接</h4>

<p>为了串接 Slack 通知，我们首先要回到 Repo → GitHub Actions 新增一个包裹打包 Action Workflow 的通知容器 Action。</p>

<p><strong>CD-Deploy-Form.yml:</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Workflow(Action) 名称</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">CD-Deploy-Form</span>

<span class="c1"># Actions Log 的标题名称</span>
<span class="na">run-name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">[CD-Deploy-Form]</span><span class="nv"> </span><span class="s">${{</span><span class="nv"> </span><span class="s">github.ref</span><span class="nv"> </span><span class="s">}}"</span>

<span class="c1"># 同个 Concurrency Group 如果有新的 Job 会取消正在跑的</span>
<span class="c1"># 例如 重复触发相同分支的打包任务，会取消前一个任务</span>
<span class="na">concurrency</span><span class="pi">:</span>
  <span class="na">group</span><span class="pi">:</span> <span class="s">${{ github.workflow }}-${{ github.ref }}</span>
  <span class="na">cancel-in-progress</span><span class="pi">:</span> <span class="kc">true</span>

<span class="c1"># 触发事件</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># 手动表单触发</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>
    <span class="c1"># 表单 Inputs 栏位</span>
    <span class="na">inputs</span><span class="pi">:</span>
      <span class="c1"># App 版本号</span>
      <span class="na">VERSION_NUMBER</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Version</span><span class="nv"> </span><span class="s">Number</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">app</span><span class="nv"> </span><span class="s">(e.g.,</span><span class="nv"> </span><span class="s">1.0.0).</span><span class="nv"> </span><span class="s">Auto-detect</span><span class="nv"> </span><span class="s">from</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">Xcode</span><span class="nv"> </span><span class="s">project</span><span class="nv"> </span><span class="s">if</span><span class="nv"> </span><span class="s">left</span><span class="nv"> </span><span class="s">blank.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="c1"># App Build Number</span>
      <span class="na">BUILD_NUMBER</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Build</span><span class="nv"> </span><span class="s">number</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">app</span><span class="nv"> </span><span class="s">(e.g.,</span><span class="nv"> </span><span class="s">1).</span><span class="nv"> </span><span class="s">Will</span><span class="nv"> </span><span class="s">use</span><span class="nv"> </span><span class="s">a</span><span class="nv"> </span><span class="s">timestamp</span><span class="nv"> </span><span class="s">if</span><span class="nv"> </span><span class="s">left</span><span class="nv"> </span><span class="s">blank.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="c1"># App Release Note</span>
      <span class="na">RELEASE_NOTE</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Release</span><span class="nv"> </span><span class="s">notes</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">deployment.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="c1"># 触发者的 Slack User ID</span>
      <span class="na">SLACK_USER_ID</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Slack</span><span class="nv"> </span><span class="s">user</span><span class="nv"> </span><span class="s">id.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">true</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="c1"># 触发者的 Email</span>
      <span class="na">AUTHOR</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Trigger</span><span class="nv"> </span><span class="s">author</span><span class="nv"> </span><span class="s">email.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">true</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
        
<span class="c1"># Job 工作项目</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="c1"># 开始打包时传送 Slack 讯息</span>
  <span class="c1"># Job ID</span>
  <span class="na">start-message</span><span class="pi">:</span>
    <span class="c1"># 小工作直接用 GitHub Hosted Runner 跑，用量不大</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    
    <span class="c1"># 设定最长 Timeout 时间，防止异常情况发生时无止尽的等待</span>
    <span class="c1"># 正常情况不可能跑超过 5 分钟</span>
    <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">5</span>

    <span class="c1"># 工作步骤</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Post a Start Slack Message</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">slack</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">slackapi/slack-github-action@v2.0.0</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">method</span><span class="pi">:</span> <span class="s">chat.postMessage</span>
          <span class="na">token</span><span class="pi">:</span> <span class="s">${{ secrets.SLACK_BOT_TOKEN }}</span>
          <span class="na">payload</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">channel</span><span class="err">:</span> <span class="s">${{ inputs.SLACK_USER_ID }}</span>
            <span class="s">text</span><span class="err">:</span> <span class="s2">"</span><span class="s">已收到打包请求。</span><span class="se">\n</span><span class="s">ID:</span><span class="nv"> </span><span class="s">&lt;${{</span><span class="nv"> </span><span class="s">github.server_url</span><span class="nv"> </span><span class="s">}}/${{</span><span class="nv"> </span><span class="s">github.repository</span><span class="nv"> </span><span class="s">}}/actions/runs/${{</span><span class="nv"> </span><span class="s">github.run_id</span><span class="nv"> </span><span class="s">}}</span><span class="se">\\</span><span class="s">|${{</span><span class="nv"> </span><span class="s">github.run_id</span><span class="nv"> </span><span class="s">}}&gt;</span><span class="se">\n</span><span class="s">Branch:</span><span class="nv"> </span><span class="s">${{</span><span class="nv"> </span><span class="s">github.ref_name</span><span class="nv"> </span><span class="s">}}</span><span class="se">\n</span><span class="s">cc'ed</span><span class="nv"> </span><span class="s">&lt;@${{</span><span class="nv"> </span><span class="s">inputs.SLACK_USER_ID</span><span class="nv"> </span><span class="s">}}&gt;"</span>
    <span class="c1"># Job Output 给后续 Job 使用</span>
    <span class="c1"># ts = Slack 讯息 ID，后续通知才可以 Reply 在同个 Threads</span>
    <span class="na">outputs</span><span class="pi">:</span>
      <span class="na">ts</span><span class="pi">:</span> <span class="s">${{ steps.slack.outputs.ts }}</span>

  <span class="na">deploy</span><span class="pi">:</span>
    <span class="c1"># Job 预设是并发执行，用 needs 限制需等待 start-message 完成才执行</span>
    <span class="c1"># 执行打包部署任务</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="s">start-message</span>
    <span class="na">uses</span><span class="pi">:</span> <span class="s">./.github/workflows/CD-Deploy.yml</span>
    <span class="na">secrets</span><span class="pi">:</span> <span class="s">inherit</span>
    <span class="na">with</span><span class="pi">:</span>
      <span class="na">VERSION_NUMBER</span><span class="pi">:</span> <span class="s">${{ inputs.VERSION_NUMBER }}</span>
      <span class="na">BUILD_NUMBER</span><span class="pi">:</span> <span class="s">${{ inputs.BUILD_NUMBER }}</span>
      <span class="na">RELEASE_NOTE</span><span class="pi">:</span> <span class="s">${{ inputs.RELEASE_NOTE }}</span>
      <span class="na">AUTHOR</span><span class="pi">:</span> <span class="s">${{ inputs.AUTHOR }}</span>

  <span class="c1"># 打包部署任务成功讯息</span>
  <span class="na">end-message-success</span><span class="pi">:</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">start-message</span><span class="pi">,</span> <span class="nv">deploy</span><span class="pi">]</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">${{ needs.deploy.result == 'success' }}</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">5</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Post a Success Slack Message</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">slackapi/slack-github-action@v2.0.0</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">method</span><span class="pi">:</span> <span class="s">chat.postMessage</span>
          <span class="na">token</span><span class="pi">:</span> <span class="s">${{ secrets.SLACK_BOT_TOKEN }}</span>
          <span class="na">payload</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">channel</span><span class="err">:</span> <span class="s">${{ inputs.SLACK_USER_ID }}</span>
            <span class="s">thread_ts</span><span class="err">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">needs.start-message.outputs.ts</span><span class="nv"> </span><span class="s">}}"</span>
            <span class="na">text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">✅</span><span class="nv"> </span><span class="s">打包部署成功。</span><span class="se">\n\n</span><span class="s">cc'ed</span><span class="nv"> </span><span class="s">&lt;@${{</span><span class="nv"> </span><span class="s">inputs.SLACK_USER_ID</span><span class="nv"> </span><span class="s">}}&gt;"</span>
  
  <span class="c1"># 打包部署任务失败讯息</span>
  <span class="na">end-message-failure</span><span class="pi">:</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">deploy</span><span class="pi">,</span> <span class="nv">start-message</span><span class="pi">]</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">${{ needs.deploy.result == 'failure' }}</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">5</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Post a Failure Slack Message</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">slackapi/slack-github-action@v2.0.0</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">method</span><span class="pi">:</span> <span class="s">chat.postMessage</span>
          <span class="na">token</span><span class="pi">:</span> <span class="s">${{ secrets.SLACK_BOT_TOKEN }}</span>
          <span class="na">payload</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">channel</span><span class="err">:</span> <span class="s">${{ inputs.SLACK_USER_ID }}</span>
            <span class="s">thread_ts</span><span class="err">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">needs.start-message.outputs.ts</span><span class="nv"> </span><span class="s">}}"</span>
            <span class="na">text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">❌</span><span class="nv"> </span><span class="s">打包部署失败，请检查执行状况结果或稍后再试。</span><span class="se">\n\n</span><span class="s">cc'ed</span><span class="nv"> </span><span class="s">&lt;@${{</span><span class="nv"> </span><span class="s">inputs.SLACK_USER_ID</span><span class="nv"> </span><span class="s">}}&gt;"</span>

  <span class="c1"># 打包部署任务取消讯息</span>
  <span class="na">end-message-cancelled</span><span class="pi">:</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">deploy</span><span class="pi">,</span> <span class="nv">start-message</span><span class="pi">]</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">${{ needs.deploy.result == 'cancelled' }}</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">5</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Post a Cancelled Slack Message</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">slackapi/slack-github-action@v2.0.0</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">method</span><span class="pi">:</span> <span class="s">chat.postMessage</span>
          <span class="na">token</span><span class="pi">:</span> <span class="s">${{ secrets.SLACK_BOT_TOKEN }}</span>
          <span class="na">payload</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">channel</span><span class="err">:</span> <span class="s">${{ inputs.SLACK_USER_ID }}</span>
            <span class="s">thread_ts</span><span class="err">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">needs.start-message.outputs.ts</span><span class="nv"> </span><span class="s">}}"</span>
            <span class="na">text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">:black_square_for_stop:</span><span class="nv"> </span><span class="s">打包部署已取消。</span><span class="se">\n\n</span><span class="s">cc'ed</span><span class="nv"> </span><span class="s">&lt;@${{</span><span class="nv"> </span><span class="s">inputs.SLACK_USER_ID</span><span class="nv"> </span><span class="s">}}&gt;"</span>
</code></pre></div></div>

<p><strong>完整程式码：</strong> <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/CD-Deploy-Form.yml" target="_blank">CD-Deploy-Form.yml</a></p>

<p><img src="/assets/4273e57e7148/1*NatyC_Oid4BrKYk4nehuKA.webp" alt="" loading="lazy" decoding="async" width="952" height="287" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTIiIGhlaWdodD0iMjg3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*NatyC_Oid4BrKYk4nehuKA.png" /></p>

<p>这个 Action 只是个容器，串接 Slack 通知，实际是复用 <a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/">上一篇文章</a> 中写好的 <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/CD-Deploy.yml" target="_blank">CD-Deploy.yml</a> Action。</p>

<ul>
  <li>
    <p>Slack Bot App 建立、发讯息权限设定可参考我 <a href="/posts/zrealm-dev/slack-app-整合-chatgpt-利用-openai-api-与-google-cloud-functions-自建智能助理-bd94cc88f9c9/">之前的文章</a></p>
  </li>
  <li>
    <p>记得到 Repo → Secrets 新增对应的 <code class="language-plaintext highlighter-rouge">SLACK_BOT_TOKEN</code> 跟带入 Slack Bot App Token 值</p>
  </li>
</ul>

<p>回到 GAS 专案 → <code class="language-plaintext highlighter-rouge">Credentials.gs</code> → 将 Token 带入到 <code class="language-plaintext highlighter-rouge">slackBotToken</code> 变数中。</p>

<p>再到 GAS 专案 → <code class="language-plaintext highlighter-rouge">Settings.gs</code> → 将：</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">slack</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SlackStub</span><span class="p">(</span><span class="nx">slackBotToken</span><span class="p">);</span>
</code></pre></div></div>

<p><strong>改成</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">slack</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Slack</span><span class="p">(</span><span class="nx">slackBotToken</span><span class="p">);</span>
</code></pre></div></div>

<p>储存档案。</p>

<blockquote>
  <p><em>如果你没有现成的 Slack Bot App 可发通知也懒得建立，可以忽略这里的所有步骤，并删除 GAS 专案中有关 slack 的使用。</em></p>
</blockquote>

<h4 id="github-串接--打包表单">GitHub 串接 — 打包表单</h4>

<p>到 GAS 专案 → <code class="language-plaintext highlighter-rouge">Controller_iOS.gs</code> → 调整 <code class="language-plaintext highlighter-rouge">View_iOS_Form.html</code> 内容:
移除假 Asana Tasks 串接方法：</p>

<pre><code class="language-php-template">      &lt;? tasks.forEach(function(task) { ?&gt;
      &lt;option value="&lt;?=task.githubBranch?&gt;"&gt;[&lt;?=task.id?&gt;] &lt;?=task.title?&gt;&lt;/option&gt;
      &lt;? }) ?&gt;
</code></pre>

<p>也可以在这边自己调整预设分支(这边是 <code class="language-plaintext highlighter-rouge">main</code> )。</p>

<p>—</p>

<p>到 GAS 专案 → <code class="language-plaintext highlighter-rouge">Controller_iOS.gs</code> → 调整 <code class="language-plaintext highlighter-rouge">iOSLoadForm()</code> 内容:</p>

<ul>
  <li>
    <p>移除 <code class="language-plaintext highlighter-rouge">template.tasks = Stubable.fetchStubAsanaTasks();</code> 这行假串接 Asana 的方法。
如果要串 Asana/Jira 可以直接问 ChatGPT 请他帮忙产串接方法。</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">template.prs = iOSGitHub.fetchOpenPRs();</code> 是真的串 GitHub API 拿 Opened PR List，可依需求保留。</p>
  </li>
</ul>

<p><strong>送出后的处理</strong> 在 <code class="language-plaintext highlighter-rouge">iOSSubmitForm()</code> 内容:</p>

<p>可依照实际 GitHub Actions Workflow 档案名称、 <code class="language-plaintext highlighter-rouge">workflow_dispatch</code> inputs 栏位参数进行调整：</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nx">iOSGitHub</span><span class="p">.</span><span class="nf">dispatchWorkflow</span><span class="p">(</span><span class="dl">"</span><span class="s2">CD-Deploy-Form.yml</span><span class="dl">"</span><span class="p">,</span> <span class="nx">branch</span><span class="p">,</span> <span class="p">{</span>
    <span class="dl">"</span><span class="s2">BUILD_NUMBER</span><span class="dl">"</span><span class="p">:</span> <span class="nx">buildNumber</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">VERSION_NUMBER</span><span class="dl">"</span><span class="p">:</span> <span class="nx">versionNumber</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">VERSION_NUMBER</span><span class="dl">"</span><span class="p">:</span> <span class="nx">versionNumber</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">RELEASE_NOTE</span><span class="dl">"</span><span class="p">:</span> <span class="nx">releaseNote</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">AUTHOR</span><span class="dl">"</span><span class="p">:</span> <span class="nx">email</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">SLACK_USER_ID</span><span class="dl">"</span><span class="p">:</span> <span class="nx">slack</span><span class="p">.</span><span class="nf">fetchUserID</span><span class="p">(</span><span class="nx">email</span><span class="p">)</span>
  <span class="p">});</span>
</code></pre></div></div>

<p>也可以加入自己的必填条件验证，这边只验证一定要填分支，不然会跳错误讯息。</p>

<p>如果认为这样不够安全可以自己再加入密码验证或只有特殊帐号可以使用。</p>

<blockquote>
  <p><em>最后一行 <strong>Slack 通知功能需要设定好 Slack</strong> ，如果没有 Slack Bot App 或懒得串接 Slack，在 <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/actions" target="_blank">Demo Actions Repo</a> 中可以直接改用 <code class="language-plaintext highlighter-rouge">iOSGitHub.dispatchWorkflow("CD-Deploy.yml")</code> 然后移除掉 <code class="language-plaintext highlighter-rouge">SLACK_USER_ID</code> 参数即可。</em></p>
</blockquote>

<p><strong>重新整理测试用「网页应用程式」网址查看改动是否正确：</strong></p>

<p><img src="/assets/4273e57e7148/1*OkJJrssZBcJPss_cMW-Qew.webp" alt="" loading="lazy" decoding="async" width="754" height="711" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NTQiIGhlaWdodD0iNzExIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*OkJJrssZBcJPss_cMW-Qew.png" /></p>

<p>可以看到打包表单就只剩 Opened PR List 了。</p>

<p><strong>填好资料按「送出请求」测试看看打包表单：</strong></p>

<p><img src="/assets/4273e57e7148/1*dl-g3j6GH0AnYL8dqvSyYA.webp" alt="" loading="lazy" decoding="async" width="523" height="252" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MjMiIGhlaWdodD0iMjUyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*dl-g3j6GH0AnYL8dqvSyYA.png" /></p>

<p><strong>提示送出成功代表没问题，回到打包纪录也能看到任务开始执行了 <em>🎉</em></strong> ：</p>

<p><img src="/assets/4273e57e7148/1*cByPF6T8WdXKionifRj1Ew.webp" alt="" loading="lazy" decoding="async" width="959" height="383" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTkiIGhlaWdodD0iMzgzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*cByPF6T8WdXKionifRj1Ew.png" /></p>

<blockquote>
  <p><em>重复点打包纪录能更新进度。</em></p>
</blockquote>

<p><strong>常见送出错误：</strong></p>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">Required input ‘SLACK_USER_ID’ not provided</code> <em>: GitHub Actions 这个SLACK_USER_ID 栏位为必填，但没有带，可能是 Slack 设定失败、当前 User Email 找不到对应的 Slack UID。</em></p>
</blockquote>

<blockquote>
  <p><em><code class="language-plaintext highlighter-rouge">Workflow does not have ‘workflow_dispatch’ trigger</code> 、 <code class="language-plaintext highlighter-rouge">分支过旧，请更新 xxx 分支</code> : 选择的分支找不到对应的 Action Workflow 档案(iOSGitHub.dispatchWorkflow 指定的档案)。</em></p>
</blockquote>

<blockquote>
  <p><em><code class="language-plaintext highlighter-rouge">No ref found for</code> 、 <code class="language-plaintext highlighter-rouge">找不到分支</code> : 找不到此分支。</em></p>
</blockquote>

<h3 id="firebase-app-distribution--取得下载连结串接">Firebase App Distribution — 取得下载连结串接</h3>

<p>最后一个小功能是串接 Firebase App Distribution 直接取得下载资讯跟连结，方便在手机上开启打包平台工具点击直接下载安装。</p>

<blockquote>
  <p><em>之前介绍过「 <a href="/posts/zrealm-robotic-process-automation/google-apps-script-快速串接-firebase-app-distribution-api-教学与进阶设定-71400d408dc8/">Google Apps Script x Google APIs 快速串接整合方式</a> 」GAS 能快速无痛整合 Firebase。</em></p>
</blockquote>

<h4 id="串接原理"><strong>串接原理</strong></h4>

<blockquote>
  <p><strong><em>在串接之前先讲一下这个「Tricky」的串接原理。</em></strong></p>
</blockquote>

<p>我们的打包平台是没有资料库的，纯做 API 中继站；所以实际上是我们在 <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/actions/workflows/CD-Deploy.yml" target="_blank"><strong>GitHub Acitons CD-Deploy.yml</strong></a> 打包作业时，把 Job Run ID 带入到 Release Note (当然也可以带到 Build Number)：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">ID</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="p">{ github.run_id </span><span class="k">}</span><span class="s2">}"</span> // Job Run ID
<span class="nv">COMMIT_SHA</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="p">{ github.sha </span><span class="k">}</span><span class="s2">}"</span>
<span class="nv">BRANCH_NAME</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="p">{ github.ref_name </span><span class="k">}</span><span class="s2">}"</span>
<span class="nv">AUTHOR</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="p">{ env.AUTHOR </span><span class="k">}</span><span class="s2">}"</span>

<span class="c"># 组合 Release Note</span>
<span class="nv">RELEASE_NOTE</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="p">{ env.RELEASE_NOTE </span><span class="k">}</span><span class="s2">}
ID: </span><span class="k">${</span><span class="nv">ID</span><span class="k">}</span><span class="s2">
Commit SHA: </span><span class="k">${</span><span class="nv">COMMIT_SHA</span><span class="k">}</span><span class="s2">
Branch: </span><span class="k">${</span><span class="nv">BRANCH_NAME</span><span class="k">}</span><span class="s2">
Author: </span><span class="k">${</span><span class="nv">AUTHOR</span><span class="k">}</span><span class="s2">
"</span>

<span class="c"># 执行 Fastlane 打包＆部署 Lane</span>
bundle <span class="nb">exec </span>fastlane beta release_notes:<span class="s2">"</span><span class="k">${</span><span class="nv">RELEASE_NOTE</span><span class="k">}</span><span class="s2">"</span> version_number:<span class="s2">"</span><span class="k">${</span><span class="nv">VERSION_NUMBER</span><span class="k">}</span><span class="s2">"</span> build_number:<span class="s2">"</span><span class="k">${</span><span class="nv">BUILD_NUMBER</span><span class="k">}</span><span class="s2">"</span>
</code></pre></div></div>

<p>这样 Firebase App Distribution Release Notes 就会有 Job Run ID。</p>

<p>GAS Web App 打包工具平台会串 GitHub API 取得 GitHub Actions 执行纪录我们直接用 API 给的 Job Run ID 带到 Firebase App Distribution API 查询 Release Notes 中有包含 <code class="language-plaintext highlighter-rouge">*ID: XXX*</code> 的版本，就能找到对应的打包纪录了。</p>

<p><strong>不用任何资料库也能做到两个工具平台的对应。</strong></p>

<p><img src="/assets/4273e57e7148/1*AJRMWv_rqu64H0ZrY4q6QA.webp" alt="" loading="lazy" decoding="async" width="559" height="347" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTkiIGhlaWdodD0iMzQ3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*AJRMWv_rqu64H0ZrY4q6QA.png" /></p>

<p><img src="/assets/4273e57e7148/1*Sdzt1MDXh7TNnMDkpc5uJg.webp" alt="" loading="lazy" decoding="async" width="1055" height="702" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDU1IiBoZWlnaHQ9IjcwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4273e57e7148/1*Sdzt1MDXh7TNnMDkpc5uJg.png" /></p>

<h4 id="串接专案设定">串接专案设定</h4>

<p>到 GAS → 专案设定 → Google Cloud Platform (GCP) 专案 → 变更专案：</p>

<p><img src="/assets/4273e57e7148/1*klclBbiBQXNBzbzzj1jH0Q.webp" alt="" loading="lazy" decoding="async" width="1140" height="1115" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTQwIiBoZWlnaHQ9IjExMTUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/4273e57e7148/1*klclBbiBQXNBzbzzj1jH0Q.png" /></p>

<p><img src="/assets/4273e57e7148/1*gv8m_v5O_yyUrq8uQoverQ.webp" alt="" loading="lazy" decoding="async" width="1086" height="632" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDg2IiBoZWlnaHQ9IjYzMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4273e57e7148/1*gv8m_v5O_yyUrq8uQoverQ.png" /></p>

<p>输入想串接的 Firebase 专案编号。</p>

<p><img src="/assets/4273e57e7148/1*OEaxA6SZWYbiVstOK60hQg.webp" alt="" loading="lazy" decoding="async" width="760" height="444" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjAiIGhlaWdodD0iNDQ0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*OEaxA6SZWYbiVstOK60hQg.png" /></p>

<blockquote>
  <p><strong><em>初次设定可能会跳错误</em></strong> <em>「如要变更专案，请设定 OAuth 同意画面。设定 OAuth 同意画面详细资料。」没有的话可跳过以下步骤。</em></p>
</blockquote>

<p><strong>点击「OAuth 同意画面详细资料」连结 → 点击「设定同意画面」：</strong></p>

<p><img src="/assets/4273e57e7148/1*oiZeO5mEqH-D3tHrJsnE1A.webp" alt="" loading="lazy" decoding="async" width="1149" height="676" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTQ5IiBoZWlnaHQ9IjY3NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4273e57e7148/1*oiZeO5mEqH-D3tHrJsnE1A.png" /></p>

<p><strong>点击「开始」:</strong></p>

<p><img src="/assets/4273e57e7148/1*NK9RG0kaXoxJB5X-B8vhww.webp" alt="" loading="lazy" decoding="async" width="762" height="550" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjIiIGhlaWdodD0iNTUwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*NK9RG0kaXoxJB5X-B8vhww.png" /></p>

<p><strong>应用程式资讯:</strong></p>

<ul>
  <li>
    <p>应用程式名称: <code class="language-plaintext highlighter-rouge">输入你的工具名称</code></p>
  </li>
  <li>
    <p>使用者支援电子邮件: <code class="language-plaintext highlighter-rouge">选择电子邮件</code></p>
  </li>
</ul>

<p><strong>目标对象:</strong></p>

<ul>
  <li>
    <p>内部：仅限组织内部伙伴使用</p>
  </li>
  <li>
    <p>外部：所有 Google 帐户使用者都能同意授权后使用</p>
  </li>
</ul>

<p><strong>联络资讯:</strong></p>

<ul>
  <li>输入接收通知用电子邮件</li>
</ul>

<p><strong>勾选同意《 <a href="https://developers.google.com/terms/api-services-user-data-policy?hl=zh_TW" target="_blank">Google API 服务：使用者资料政策</a> 》。</strong></p>

<p>最后点击「 <strong>建立</strong> 」。</p>

<p>—</p>

<p>回到 GAS → 专案设定 → Google Cloud Platform (GCP) 专案 → 变更专案：</p>

<p>再次输入 Firebase 专案编号点击「变更专案」。</p>

<p><img src="/assets/4273e57e7148/1*g-Lo04WjhaDjtXeXthNtDg.webp" alt="" loading="lazy" decoding="async" width="779" height="272" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NzkiIGhlaWdodD0iMjcyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*g-Lo04WjhaDjtXeXthNtDg.png" /></p>

<p><strong>没出现错误就是完成绑定了。</strong></p>

<p>—</p>

<p><strong>如果选择的是「外部」可能还需要完成以下设定：</strong></p>

<p>点击「专案编号」 → 展开左侧栏 → 「API 和服务」→ 「OAuth 同意画面」</p>

<p><img src="/assets/4273e57e7148/1*RJNQv8v3KZoTcVwUbsXSHQ.webp" alt="" loading="lazy" decoding="async" width="808" height="719" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MDgiIGhlaWdodD0iNzE5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*RJNQv8v3KZoTcVwUbsXSHQ.png" /></p>

<p>选择「目标对象」 → 测试 点击「发布应用程式」→ 完成。</p>

<p><img src="/assets/4273e57e7148/1*8vqrxhchsILPy4eSdvXfNg.webp" alt="" loading="lazy" decoding="async" width="626" height="445" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MjYiIGhlaWdodD0iNDQ1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*8vqrxhchsILPy4eSdvXfNg.png" /></p>

<blockquote>
  <p><em>使用者就能照前文的「 <strong>使用者首次使用需要同意授权</strong> 」步骤完成授权就能使用了！</em></p>
</blockquote>

<p><strong>如果上述步骤没设定，使用者会遇到以下错误：</strong></p>

<p><img src="/assets/4273e57e7148/1*2omUPFoubsrXVLHBPFkPbg.webp" alt="已封锁存取权「XXX」未完成 Google 验证程序" loading="lazy" decoding="async" width="766" height="673" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjYiIGhlaWdodD0iNjczIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*2omUPFoubsrXVLHBPFkPbg.png" /></p>

<p>已封锁存取权「XXX」未完成 Google 验证程序</p>

<p>— — —</p>

<h4 id="串接专案">串接专案</h4>

<p>回到串接上，Firebase 是直接用 <code class="language-plaintext highlighter-rouge">ScriptApp.getOAuthToken()</code> 依照执行身份动态取得 Token 使用，因此不需要设定 Token。</p>

<p>只需要到 GAS 专案 → <code class="language-plaintext highlighter-rouge">Settings.gs</code> → 将：</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">iOSFirebase</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">FirebaseStub</span><span class="p">(</span><span class="nx">iOSFirebaseProject</span><span class="p">);</span>
</code></pre></div></div>

<p><strong>改成</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">iOSFirebase</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Firebase</span><span class="p">(</span><span class="nx">iOSFirebaseProject</span><span class="p">);</span>
</code></pre></div></div>

<p>即可。</p>

<p><strong>重新整理测试用「网页应用程式」网址到打包纪录 → 找一笔纪录点击「取得下载连结」：</strong></p>

<p><img src="/assets/4273e57e7148/1*9z-KsIAL5jyEzQvJv3YLgg.webp" alt="" loading="lazy" decoding="async" width="913" height="452" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTMiIGhlaWdodD0iNDUyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*9z-KsIAL5jyEzQvJv3YLgg.png" /></p>

<p><img src="/assets/4273e57e7148/1*q0HUYN2W3UonQLzwxZKXdQ.webp" alt="" loading="lazy" decoding="async" width="554" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4273e57e7148/1*q0HUYN2W3UonQLzwxZKXdQ.png" /></p>

<p>如果有在 Firebase App Distribution Release Notes 找到对应的 Job Run Id 打包，就会直接显示下载资讯跟点下载能直接导到下载页。</p>

<blockquote>
  <p>完成！🎉🎉🎉</p>
</blockquote>

<h3 id="成果">成果</h3>

<p><img src="/assets/4273e57e7148/1*znvPmqsaivk3KhsE26sFwA.webp" alt="Demo Web App" loading="lazy" decoding="async" width="1010" height="766" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDEwIiBoZWlnaHQ9Ijc2NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4273e57e7148/1*znvPmqsaivk3KhsE26sFwA.png" /></p>

<p><a href="https://script.google.com/macros/s/AKfycbwNW6N5ozKbIz_E1HK6yFEUtA8KQrUciS-jcPsQptvIKlARmKgLxbQzNu8ksVeg-BmEfg/exec" target="_blank">Demo Web App</a></p>

<p>至此你已经把范例都改成您的实际可用的打包工具，剩下的客制化功能、更多第三方 API 串接、更多表单可以自行延伸 (跟 ChatGPT 讨论)。</p>

<blockquote>
  <p><em>最后不要忘记都开发好测试完毕要上线，需要照前文步骤 — <strong>更新部署作业才会生效喔！</strong></em></p>
</blockquote>

<h3 id="串接延伸">串接延伸</h3>

<p>延续我们「中继站」角色的精神，这边提供几个快速串接的 CheatSheet：</p>

<p><a href="https://developers.asana.com/reference/gettasksforproject" target="_blank"><strong>Asana API — 取得 Tasks:</strong></a></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kd">function</span> <span class="nf">asanaAPI</span><span class="p">(</span><span class="nx">endPoint</span><span class="p">,</span> <span class="nx">method</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">GET</span><span class="dl">"</span><span class="p">,</span> <span class="nx">data</span> <span class="o">=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
      <span class="dl">"</span><span class="s2">method</span><span class="dl">"</span> <span class="p">:</span> <span class="nx">method</span><span class="p">,</span>
      <span class="dl">"</span><span class="s2">headers</span><span class="dl">"</span><span class="p">:</span> <span class="p">{</span>
          <span class="dl">"</span><span class="s2">Authorization</span><span class="dl">"</span><span class="p">:</span>  <span class="dl">"</span><span class="s2">Bearer </span><span class="dl">"</span><span class="o">+</span><span class="nx">asanaToken</span>
      <span class="p">},</span>
      <span class="dl">"</span><span class="s2">payload</span><span class="dl">"</span> <span class="p">:</span> <span class="nx">data</span>
    <span class="p">};</span>

    <span class="kd">var</span> <span class="nx">url</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">https://app.asana.com/api/1.0</span><span class="dl">"</span><span class="o">+</span><span class="nx">endPoint</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">res</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">res</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>
    <span class="k">return</span> <span class="nx">data</span><span class="p">;</span>
<span class="p">}</span>

<span class="nf">asanaAPI</span><span class="p">(</span><span class="dl">"</span><span class="s2">/projects/{project_gid}/tasks</span><span class="dl">"</span><span class="p">)</span>
</code></pre></div></div>

<p><a href="https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/#about" target="_blank"><strong>Jira API — 取得 Tickets (JQL):</strong></a></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// jql = 筛选条件</span>
<span class="kd">function</span> <span class="nf">jiraTickets</span><span class="p">(</span><span class="nx">jql</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="s2">`https://xxx.atlassian.net/rest/api/3/search`</span><span class="p">;</span>
  <span class="kd">const</span> <span class="nx">maxResults</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span>

  <span class="kd">let</span> <span class="nx">allIssues</span> <span class="o">=</span> <span class="p">[];</span>
  <span class="kd">let</span> <span class="nx">startAt</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="kd">let</span> <span class="nx">total</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

  <span class="k">do</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">queryParams</span> <span class="o">=</span> <span class="p">{</span>
      <span class="na">jql</span><span class="p">:</span> <span class="nx">jql</span><span class="p">,</span>
      <span class="na">startAt</span><span class="p">:</span> <span class="nx">startAt</span><span class="p">,</span>
      <span class="na">maxResults</span><span class="p">:</span> <span class="nx">maxResults</span><span class="p">,</span>
      <span class="na">fields</span><span class="p">:</span> <span class="dl">"</span><span class="s2">assignee,summary,status</span><span class="dl">"</span>
    <span class="p">};</span>

    <span class="kd">const</span> <span class="nx">queryString</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nf">keys</span><span class="p">(</span><span class="nx">queryParams</span><span class="p">)</span>
      <span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">key</span> <span class="o">=&gt;</span> <span class="s2">`</span><span class="p">${</span><span class="nf">encodeURIComponent</span><span class="p">(</span><span class="nx">key</span><span class="p">)}</span><span class="s2">=</span><span class="p">${</span><span class="nf">encodeURIComponent</span><span class="p">(</span><span class="nx">queryParams</span><span class="p">[</span><span class="nx">key</span><span class="p">])}</span><span class="s2">`</span><span class="p">)</span>
      <span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="dl">"</span><span class="s2">&amp;</span><span class="dl">"</span><span class="p">);</span>

    <span class="kd">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
      <span class="na">method</span><span class="p">:</span> <span class="dl">"</span><span class="s2">get</span><span class="dl">"</span><span class="p">,</span>
      <span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
        <span class="na">Authorization</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Basic </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">jiraToken</span><span class="p">,</span>
        <span class="dl">"</span><span class="s2">Content-Type</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/json</span><span class="dl">"</span><span class="p">,</span>
      <span class="p">},</span>
      <span class="na">muteHttpExceptions</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
    <span class="p">};</span>

    <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">url</span><span class="p">}</span><span class="s2">?</span><span class="p">${</span><span class="nx">queryString</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
    <span class="kd">const</span> <span class="nx">json</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getResponseCode</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">200</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Failed to fetch Jira issues.</span><span class="dl">"</span><span class="p">);</span> 
    <span class="p">}</span>

    <span class="k">if </span><span class="p">(</span><span class="nx">json</span><span class="p">.</span><span class="nx">issues</span> <span class="o">&amp;&amp;</span> <span class="nx">json</span><span class="p">.</span><span class="nx">issues</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">allIssues</span> <span class="o">=</span> <span class="nx">allIssues</span><span class="p">.</span><span class="nf">concat</span><span class="p">(</span><span class="nx">json</span><span class="p">.</span><span class="nx">issues</span><span class="p">);</span>
      <span class="nx">total</span> <span class="o">=</span> <span class="nx">json</span><span class="p">.</span><span class="nx">total</span><span class="p">;</span>
      <span class="nx">startAt</span> <span class="o">+=</span> <span class="nx">json</span><span class="p">.</span><span class="nx">issues</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span> <span class="k">while </span><span class="p">(</span><span class="nx">startAt</span> <span class="o">&lt;</span> <span class="nx">total</span><span class="p">);</span>

  <span class="kd">var</span> <span class="nx">groupIssues</span> <span class="o">=</span> <span class="p">{};</span>
  <span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">allIssues</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">issue</span> <span class="o">=</span> <span class="nx">allIssues</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">groupIssues</span><span class="p">[</span><span class="nx">issue</span><span class="p">.</span><span class="nx">fields</span><span class="p">.</span><span class="nx">status</span><span class="p">.</span><span class="nx">name</span><span class="p">]</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">groupIssues</span><span class="p">[</span><span class="nx">issue</span><span class="p">.</span><span class="nx">fields</span><span class="p">.</span><span class="nx">status</span><span class="p">.</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="p">[];</span>
    <span class="p">}</span>
    <span class="nx">groupIssues</span><span class="p">[</span><span class="nx">issue</span><span class="p">.</span><span class="nx">fields</span><span class="p">.</span><span class="nx">status</span><span class="p">.</span><span class="nx">name</span><span class="p">].</span><span class="nf">push</span><span class="p">(</span><span class="nx">issue</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="k">return</span> <span class="nx">groupIssues</span><span class="p">;</span>
<span class="p">}</span>

<span class="nf">jiraTickets</span><span class="p">(</span><span class="s2">`project IN(App)`</span><span class="p">);</span>
</code></pre></div></div>

<p><strong>如果真的需要资料库，可以使用 Google Sheet 代替：</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Saveable</span> <span class="p">{</span>
  <span class="nf">constructor</span><span class="p">(</span><span class="nx">type</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// https://docs.google.com/spreadsheets/d/Sheet-ID/edit</span>
    <span class="kd">const</span> <span class="nx">spreadsheet</span> <span class="o">=</span> <span class="nx">SpreadsheetApp</span><span class="p">.</span><span class="nf">openById</span><span class="p">(</span><span class="dl">"</span><span class="s2">Sheet-ID</span><span class="dl">"</span><span class="p">);</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">sheet</span> <span class="o">=</span> <span class="nx">spreadsheet</span><span class="p">.</span><span class="nf">getSheetByName</span><span class="p">(</span><span class="dl">"</span><span class="s2">Data</span><span class="dl">"</span><span class="p">);</span> <span class="c1">// Sheet Name</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">type</span> <span class="o">=</span> <span class="nx">type</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="nf">write</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">sheet</span><span class="p">.</span><span class="nf">appendRow</span><span class="p">([</span>
      <span class="k">this</span><span class="p">.</span><span class="nx">type</span><span class="p">,</span>
      <span class="nx">key</span><span class="p">,</span>
      <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span>
    <span class="p">]);</span>
  <span class="p">}</span>

  <span class="nf">read</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">sheet</span><span class="p">.</span><span class="nf">getDataRange</span><span class="p">().</span><span class="nf">getValues</span><span class="p">();</span>
    <span class="kd">const</span> <span class="nx">row</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="nx">r</span> <span class="o">=&gt;</span> <span class="nx">r</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">===</span> <span class="k">this</span><span class="p">.</span><span class="nx">type</span> <span class="o">&amp;&amp;</span> <span class="nx">r</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">===</span> <span class="nx">key</span><span class="p">);</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">row</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="kd">let</span> <span class="nx">saveable</span> <span class="o">=</span> <span class="nc">Saveable</span><span class="p">(</span><span class="dl">"</span><span class="s2">user</span><span class="dl">"</span><span class="p">);</span>
<span class="c1">// Write</span>
<span class="nx">saveable</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">birthday_zhgchgli</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">0718</span><span class="dl">"</span><span class="p">);</span>
<span class="c1">// Read</span>
<span class="nx">saveable</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="dl">"</span><span class="s2">birthday_zhgchgli</span><span class="dl">"</span><span class="p">);</span> <span class="c1">// -&gt; 0718</span>
</code></pre></div></div>

<p><a href="https://api.slack.com/methods/chat.postMessage" target="_blank"><strong>Slack API &amp; 发送讯息方法：</strong></a></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">slackSendMessage</span><span class="p">(</span><span class="nx">channel</span><span class="p">,</span> <span class="nx">text</span> <span class="o">=</span> <span class="dl">""</span><span class="p">,</span> <span class="nx">blocks</span> <span class="o">=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">channel</span><span class="p">:</span> <span class="nx">channel</span><span class="p">,</span>
    <span class="na">unfurl_links</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
    <span class="na">unfurl_media</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
    <span class="na">text</span><span class="p">:</span> <span class="nx">text</span><span class="p">,</span>
    <span class="na">blocks</span><span class="p">:</span> <span class="nx">blocks</span>
  <span class="p">};</span>

  <span class="k">try</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nf">slackRequest</span><span class="p">(</span><span class="dl">"</span><span class="s2">chat.postMessage</span><span class="dl">"</span><span class="p">,</span> <span class="nx">content</span><span class="p">);</span>
    <span class="k">return</span> <span class="nx">response</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="s2">`Failed to send Slack message: </span><span class="p">${</span><span class="nx">error</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">slackRequest</span><span class="p">(</span><span class="nx">path</span><span class="p">,</span> <span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">method</span><span class="p">:</span> <span class="dl">"</span><span class="s2">post</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">contentType</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/json</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">Authorization</span><span class="p">:</span> <span class="s2">`Bearer </span><span class="p">${</span><span class="nx">slackBotToken</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span>
      <span class="dl">'</span><span class="s1">X-Slack-No-Retry</span><span class="dl">'</span><span class="p">:</span> <span class="mi">1</span>
    <span class="p">},</span>
    <span class="na">payload</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span>
  <span class="p">};</span>

  <span class="k">try</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="dl">"</span><span class="s2">https://slack.com/api/</span><span class="dl">"</span><span class="o">+</span><span class="nx">path</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
    <span class="kd">const</span> <span class="nx">responseData</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">responseData</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="nx">responseData</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="s2">`Slack: </span><span class="p">${</span><span class="nx">responseData</span><span class="p">.</span><span class="nx">error</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">throw</span> <span class="nx">error</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="更多-google-apps-script-案例">更多 Google Apps Script 案例：</h4>

<ul>
  <li>
    <p><a href="/posts/zrealm-robotic-process-automation/google-apps-script-快速串接-firebase-app-distribution-api-教学与进阶设定-71400d408dc8/">Google Apps Script x Google APIs 快速串接整合方式</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-robotic-process-automation/ga4-自动数据通知机器人-3-步骤用-google-apps-script-串接-telegram-bot-1e85b8df2348/">简单 3 步骤 — 打造免费 GA4 自动数据通知机器人</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-robotic-process-automation/google-apps-script-打造每日数据报表自动化-rpa-快速串接-google-analytics-与-google-sheet-f6713ba3fee3/">使用 Google Apps Script 实现每日数据报表 RPA 自动化</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/slack-app-整合-chatgpt-利用-openai-api-与-google-cloud-functions-自建智能助理-bd94cc88f9c9/">Slack &amp; ChatGPT Integration</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/google-apps-script-三步骤打造免费-github-repo-star-通知器-实时获取-star-动态-382218e15697/">使用 Google Apps Script 三步骤免费建立 Github Repo Star Notifier</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/crashlytics与google-analytics自动查询app-crash-free-users-rate-google-apps-script整合实作-793cb8f89b72/">Crashlytics + Google Analytics 自动查询 App Crash-Free Users Rate</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/crashlytics-big-query-串接教学-自动查询并转发-ios-app-闪退报告到-slack-e77b80cc6f89/">Crashlytics + Big Query 打造更即时便利的 Crash 追踪工具</a></p>
  </li>
</ul>

<h3 id="总结">总结</h3>

<p>感谢您的耐心阅读与参与，CI/CD 从 0 到 1 系列文章到此告一段落；希望能实际帮助到您与您的团队建置完善的 CI/CD 工作流程，提升效率与产品稳定性；有任何实作问题欢迎留言讨论，这四篇文章大约花了 14+ 天撰写， <strong>如果您觉得不错欢迎 Follow 我的 Medium 和与朋友同事分享</strong> 。</p>

<blockquote>
  <p>谢谢。</p>
</blockquote>

<h4 id="-buy-me-a-beer-on-paypal"><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank">🍺 Buy me a beer on PayPal</a></h4>

<blockquote>
  <p><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank"><strong><em>本系列文章花费了大量的时间精力撰写，如果内容对您有帮助、对您的团队有实质提升工作效率与产品品质；欢迎请我喝杯咖啡，感谢支持！</em></strong></a></p>
</blockquote>

<p><img src="/assets/4273e57e7148/1*QJj54G9gOjtQS-rbHVT1SQ.webp" alt="Buy me a coffee" loading="lazy" decoding="async" width="700" height="700" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDAiIGhlaWdodD0iNzAwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4273e57e7148/1*QJj54G9gOjtQS-rbHVT1SQ.png" /></p>

<p><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank">🍺 Buy me a beer on PayPal</a></p>

<h4 id="系列文章">系列文章：</h4>

<ul>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-是什么-打造高效稳定开发团队的关键流程与工具选择-c008a9e8ceca/"><strong>CI/CD 实战指南（一）：CI/CD 是什么？如何透过 CI/CD 打造稳定高效的开发团队？工具选择？</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-self-hosted-runner-详解与实战案例-ci-cd-自动化工作流程建置-404bd5c70040/"><strong>CI/CD 实战指南（二）：GitHub Actions 与 self-hosted Runner 使用与建置大全</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/"><strong>CI/CD 实战指南（三）：使用 GitHub Actions 实作 App 专案的 CI 与 CD 工作流程</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/"><strong>CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</strong></a></p>
  </li>
</ul>]]></content>
  </entry><entry>
    <title type="html">GitHub Actions iOS CI/CD｜完整实作自动化建置、测试与部署流程教学</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/github-actions-ios-ci-cd-%E5%AE%8C%E6%95%B4%E5%AE%9E%E4%BD%9C%E8%87%AA%E5%8A%A8%E5%8C%96%E5%BB%BA%E7%BD%AE-%E6%B5%8B%E8%AF%95%E4%B8%8E%E9%83%A8%E7%BD%B2%E6%B5%81%E7%A8%8B%E6%95%99%E5%AD%A6-4b001d2e8440/" rel="alternate" type="text/html" title="GitHub Actions iOS CI/CD｜完整实作自动化建置、测试与部署流程教学" />
    <published>2025-07-07T23:02:24+08:00</published>
    <updated>2026-01-04T11:38:01+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/4b001d2e8440</id><summary type="html">针对iOS开发者打造的GitHub Actions CI/CD流程，解决手动建置与测试繁琐问题，结合Fastlane与Firebase实现自动化打包与部署，提升团队开发效率与产品品质。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="ios-app-development" /><category term="cicd" /><category term="github-actions" /><category term="firebase" /><category term="cicd-pipeline" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/4b001d2e8440/1*0LK6m6CTImL6rcsrliiOQA.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/github-actions-ios-ci-cd-%E5%AE%8C%E6%95%B4%E5%AE%9E%E4%BD%9C%E8%87%AA%E5%8A%A8%E5%8C%96%E5%BB%BA%E7%BD%AE-%E6%B5%8B%E8%AF%95%E4%B8%8E%E9%83%A8%E7%BD%B2%E6%B5%81%E7%A8%8B%E6%95%99%E5%AD%A6-4b001d2e8440/"><![CDATA[<h3 id="cicd-实战指南三使用-github-actions-实作-app-ios-ci-与-cd-工作流程">CI/CD 实战指南（三）：使用 GitHub Actions 实作 App iOS CI 与 CD 工作流程</h3>

<p>iOS App 自动化建置、测试、部署的 GitHub Actions 实作步骤完整教学</p>

<p><img src="/assets/4b001d2e8440/1*0LK6m6CTImL6rcsrliiOQA.webp" alt="Photo by Robs" loading="lazy" decoding="async" width="1400" height="934" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjkzNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*0LK6m6CTImL6rcsrliiOQA.jpeg" /></p>

<p>Photo by <a href="https://unsplash.com/@robinne?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank">Robs</a></p>

<h4 id="前言">前言</h4>

<p>前篇「 <a href="/posts/zrealm-dev/github-actions-self-hosted-runner-详解与实战案例-ci-cd-自动化工作流程建置-404bd5c70040/"><strong>CI/CD 实战指南（二）：GitHub Actions 与 Self-hosted Runner 使用与建置大全</strong></a> 」我们介绍了 GitHub Actions 的基础知识与运作流程还有如何使用自己的机器当成 Runner、带大家实现了三个简单的自动化 Actions； <strong>本篇将深入著重在现实使用 GitHub Actions 建置 App (iOS) CI/CD 工作流程上</strong> ，一样手把手带大家一步一步完成并一边补足 GitHub Actions 相关知识。</p>

<h3 id="app-cicd-流程关系图">App CI/CD 流程关系图</h3>

<p><img src="/assets/4b001d2e8440/1*VRygfRAkBRNEDAC4RyGzRA.webp" alt="" loading="lazy" decoding="async" width="1400" height="669" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjY2OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*VRygfRAkBRNEDAC4RyGzRA.png" /></p>

<p>本篇将关注在 GitHub Actions 建置 CI/CD 的区块，下一篇「 <a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/">CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</a> 」才会介绍右半部分的使用 Google Apps Script Web App 建置跨团队协作打包平台。</p>

<h4 id="运作流程">运作流程：</h4>

<ol>
  <li>
    <p>GitHub Actions 开 Pull Request 触发 or 表单触发 or 定时触发</p>
  </li>
  <li>
    <p>执行对应 Workflow Jobs/Steps</p>
  </li>
  <li>
    <p>Step 执行对应 Fastlane (iOS) or (Android Gradle) 脚本</p>
  </li>
  <li>
    <p>Fastlane 执行对应 xcodebuild (iOS) 指令</p>
  </li>
  <li>
    <p>取得执行结果</p>
  </li>
  <li>
    <p>后续 Workflow Jobs/Steps 处理结果</p>
  </li>
  <li>
    <p>完成</p>
  </li>
</ol>

<h4 id="github-actions-成果图">GitHub Actions 成果图</h4>

<p>先上最终成果给大家一点实作动力！</p>

<p><img src="/assets/4b001d2e8440/1*5gnQYdVAOtGR-bMK4ZrOhA.webp" alt="CI Testing" loading="lazy" decoding="async" width="911" height="566" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTEiIGhlaWdodD0iNTY2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*5gnQYdVAOtGR-bMK4ZrOhA.png" /></p>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/pull/11" target="_blank">CI Testing</a></p>

<p><img src="/assets/4b001d2e8440/1*u6A77KwkXS2SY5-DPPPR9A.webp" alt="" loading="lazy" decoding="async" width="1200" height="802" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*u6A77KwkXS2SY5-DPPPR9A.png" /></p>

<p><img src="/assets/4b001d2e8440/1*t9PrQfcTANyvG7gfXXC-bw.webp" alt="CI Nightly Build, CD Deploy" loading="lazy" decoding="async" width="1179" height="2556" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTc5IiBoZWlnaHQ9IjI1NTYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/4b001d2e8440/1*t9PrQfcTANyvG7gfXXC-bw.jpeg" /></p>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/actions/runs/16119750747" target="_blank">CI Nightly Build, CD Deploy</a></p>

<h3 id="github-actions-x-self-hosted-runner-基础知识">GitHub Actions x Self-hosted Runner 基础知识</h3>

<p>如果你对 GitHub Actions 与架设 Self-hosted Runner 还不熟悉强烈建议先看过上篇「 <a href="/posts/zrealm-dev/github-actions-self-hosted-runner-详解与实战案例-ci-cd-自动化工作流程建置-404bd5c70040/"><strong>CI/CD 实战指南（二）：GitHub Actions 与 Self-hosted Runner 使用与建置大全</strong></a> 」或是搭配上篇知识一起实作。</p>

<blockquote>
  <p><strong><em>实作开始！</em></strong></p>
</blockquote>

<h3 id="ios-demo-专案的-infra-架构">iOS Demo 专案的 Infra 架构</h3>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo" target="_blank"><img src="https://opengraph.githubassets.com/ac0aa481002311af0e60721a17f7533f54be5d308c641c48ea717e12a1f3d725/ZhgChgLi/github-actions-ci-cd-demo" alt="" /></a></p>

<p><strong>本文用到的 iOS 专案内容包含测试项目都是用 AI 产生的</strong> ，不需在意 iOS 的程式细节，只针对 Infra &amp; CI/CD 部分做讨论。</p>

<blockquote>
  <p><strong><em>以下工具只是凭以往经验，如果是新专案可以考虑使用更新的 <a href="https://github.com/jdx/mise" target="_blank">mise</a> 和 <a href="https://github.com/tuist/tuist" target="_blank">tuist</a> 。</em></strong></p>
</blockquote>

<h4 id="mint">Mint</h4>

<p><a href="https://github.com/yonaskolb/Mint" target="_blank"><img src="https://opengraph.githubassets.com/5b9cf093f4868403ac9212a468eda99979267fe5e14c7dd1ce13c3b42b875f5f/yonaskolb/Mint" alt="" /></a></p>

<p>Mint 工具可以帮我们统一管理依赖工具的版本(Gemfile 只能管理 Ruby Gems)，例如 XCodeGen、XCodeGen、SwiftFormat、SwiftLint、Periphery</p>

<p>…etc</p>

<p><strong>Mintfile:</strong></p>

<div class="language-graphql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">yonaskolb/Mint@0.17.5</span><span class="w">
</span><span class="err">yonaskolb/XcodeGen@2.35.0</span><span class="w">
</span><span class="err">nicklockwood/SwiftFormat@0.51.13</span><span class="w">
</span></code></pre></div></div>

<p>这边我们只用到三个。</p>

<blockquote>
  <p><strong><em>觉得太复杂不使用也可以，直接在 Action Workflow Step 中用 brew install 安装需要的工具即可。</em></strong></p>
</blockquote>

<h4 id="bundle">Bundle</h4>

<p><strong>Gemfile:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">source</span> <span class="s1">'https://rubygems.org'</span>
gem <span class="s1">'cocoapods'</span>, <span class="s1">'~&gt;1.16.0'</span>
gem <span class="s1">'fastlane'</span>, <span class="s1">'~&gt;2.228.0'</span>

plugins_path <span class="o">=</span> File.join<span class="o">(</span>File.dirname<span class="o">(</span>__FILE__<span class="o">)</span>, <span class="s1">'Product'</span>, <span class="s1">'fastlane'</span>, <span class="s1">'Pluginfile'</span><span class="o">)</span>
eval_gemfile<span class="o">(</span>plugins_path<span class="o">)</span> <span class="k">if </span>File.exist?<span class="o">(</span>plugins_path<span class="o">)</span>
</code></pre></div></div>

<p>管理 Ruby (Gems) 相关依赖，一般 iOS 专案最常用的就是这两个 <code class="language-plaintext highlighter-rouge">cocoapods</code> 跟 <code class="language-plaintext highlighter-rouge">fastlane</code> 。</p>

<h4 id="cocoapods">Cocoapods</h4>

<p><strong>Product/podfile:</strong></p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">platform</span> <span class="ss">:ios</span><span class="p">,</span> <span class="s1">'13.0'</span>
<span class="n">use_frameworks!</span>

<span class="n">target</span> <span class="s1">'app-ci-cd-github-actions-demo'</span> <span class="k">do</span>
  <span class="n">pod</span> <span class="s1">'SnapKit'</span>
<span class="k">end</span> 
</code></pre></div></div>

<p>虽然已宣告 <a href="https://blog.cocoapods.org/CocoaPods-Specs-Repo/" target="_blank">即将停止维护</a> ，但 Cocoapods 在有年代的 iOS 专案中仍很常见，这边简单加一个 Snapkit 当 Demo。</p>

<h4 id="xcodegen">XCodeGen</h4>

<p>避免多人开发中 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> / <code class="language-plaintext highlighter-rouge">.xcworkspace</code> 异动造成的冲突，统一使用 Project.yaml 定义 XCode Project 内容，然后在本地自己 Gen Project 档案(不上 Git)。</p>

<p><strong>Product/project.yaml:</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">app-ci-cd-github-actions-demo</span>
<span class="na">options</span><span class="pi">:</span>
  <span class="na">bundleIdPrefix</span><span class="pi">:</span> <span class="s">com.example</span>
  <span class="na">deploymentTarget</span><span class="pi">:</span>
    <span class="na">iOS</span><span class="pi">:</span> <span class="s1">'</span><span class="s">13.0'</span>
  <span class="na">usesTabs</span><span class="pi">:</span> <span class="kc">false</span>
  <span class="na">indentWidth</span><span class="pi">:</span> <span class="m">2</span>
  <span class="na">tabWidth</span><span class="pi">:</span> <span class="m">2</span>

<span class="na">configs</span><span class="pi">:</span>
  <span class="na">Debug</span><span class="pi">:</span> <span class="s">debug</span>
  <span class="na">Release</span><span class="pi">:</span> <span class="s">release</span>

<span class="na">targets</span><span class="pi">:</span>
  <span class="na">app-ci-cd-github-actions-demo</span><span class="pi">:</span>
    <span class="na">type</span><span class="pi">:</span> <span class="s">application</span>
    <span class="na">platform</span><span class="pi">:</span> <span class="s">iOS</span>
    <span class="na">sources</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">app-ci-cd-github-actions-demo</span>
    <span class="na">resources</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">app-ci-cd-github-actions-demo/Assets.xcassets</span>
      <span class="pi">-</span> <span class="s">app-ci-cd-github-actions-demo/Base.lproj</span>
    <span class="na">info</span><span class="pi">:</span>
      <span class="na">path</span><span class="pi">:</span> <span class="s">app-ci-cd-github-actions-demo/Info.plist</span>
      <span class="na">properties</span><span class="pi">:</span>
        <span class="na">CFBundleIdentifier</span><span class="pi">:</span> <span class="s">$(PRODUCT_BUNDLE_IDENTIFIER)</span>
    <span class="na">settings</span><span class="pi">:</span>
      <span class="na">base</span><span class="pi">:</span>
        <span class="na">PRODUCT_BUNDLE_IDENTIFIER</span><span class="pi">:</span> <span class="s">com.test.appcicdgithubactionsdemo</span>
    <span class="na">cocoapods</span><span class="pi">:</span> <span class="kc">true</span>

  <span class="na">app-ci-cd-github-actions-demoTests</span><span class="pi">:</span>
    <span class="na">type</span><span class="pi">:</span> <span class="s">bundle.unit-test</span>
    <span class="na">platform</span><span class="pi">:</span> <span class="s">iOS</span>
    <span class="na">sources</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">app-ci-cd-github-actions-demoTests</span>
    <span class="na">dependencies</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">target</span><span class="pi">:</span> <span class="s">app-ci-cd-github-actions-demo</span>
    <span class="na">info</span><span class="pi">:</span>
      <span class="na">path</span><span class="pi">:</span> <span class="s">app-ci-cd-github-actions-demoTests/Info.plist</span>
    <span class="na">settings</span><span class="pi">:</span>
      <span class="na">base</span><span class="pi">:</span>
        <span class="na">PRODUCT_BUNDLE_IDENTIFIER</span><span class="pi">:</span> <span class="s">com.test.appcicdgithubactionsdemo.tests</span>

  <span class="na">app-ci-cd-github-actions-demoUITests</span><span class="pi">:</span>
    <span class="na">type</span><span class="pi">:</span> <span class="s">bundle.ui-testing</span>
    <span class="na">platform</span><span class="pi">:</span> <span class="s">iOS</span>
    <span class="na">sources</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">app-ci-cd-github-actions-demoUITests</span>
    <span class="na">dependencies</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">target</span><span class="pi">:</span> <span class="s">app-ci-cd-github-actions-demo</span>
    <span class="na">info</span><span class="pi">:</span>
      <span class="na">path</span><span class="pi">:</span> <span class="s">app-ci-cd-github-actions-demoUITests/Info.plist</span>
    <span class="na">settings</span><span class="pi">:</span>
      <span class="na">base</span><span class="pi">:</span>
        <span class="na">PRODUCT_BUNDLE_IDENTIFIER</span><span class="pi">:</span> <span class="s">com.test.appcicdgithubactionsdemo.uitests</span>

  <span class="na">app-ci-cd-github-actions-demoSnapshotTests</span><span class="pi">:</span>
    <span class="na">type</span><span class="pi">:</span> <span class="s">bundle.unit-test</span>
    <span class="na">platform</span><span class="pi">:</span> <span class="s">iOS</span>
    <span class="na">sources</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">path</span><span class="pi">:</span> <span class="s">app-ci-cd-github-actions-demoSnapshotTests</span>
        <span class="na">excludes</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="s2">"</span><span class="s">**/__Snapshots__/**"</span>
    <span class="na">dependencies</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">target</span><span class="pi">:</span> <span class="s">app-ci-cd-github-actions-demo</span>
      <span class="pi">-</span> <span class="na">product</span><span class="pi">:</span> <span class="s">SnapshotTesting</span>
        <span class="na">package</span><span class="pi">:</span> <span class="s">SnapshotTesting</span>
    <span class="na">info</span><span class="pi">:</span>
      <span class="na">path</span><span class="pi">:</span> <span class="s">app-ci-cd-github-actions-demoSnapshotTests/Info.plist</span>
      <span class="na">settings</span><span class="pi">:</span>
        <span class="na">base</span><span class="pi">:</span>
          <span class="na">PRODUCT_BUNDLE_IDENTIFIER</span><span class="pi">:</span> <span class="s">com.test.appcicdgithubactionsdemo.snapshottests</span>

<span class="na">packages</span><span class="pi">:</span>
  <span class="na">SnapshotTesting</span><span class="pi">:</span>
    <span class="na">url</span><span class="pi">:</span> <span class="s">https://github.com/pointfreeco/swift-snapshot-testing</span>
    <span class="na">from</span><span class="pi">:</span> <span class="s">1.18.4</span>
</code></pre></div></div>

<p>SnapshotTesting: 使用 Swift Package Manager 管理。</p>

<h4 id="fastlane">Fastlane</h4>

<p>封装 xcodebuild 指令、封装串接 App Store Connect API、Firebase API. .等服务的复杂步骤。</p>

<p><strong>Product/fastlane/Fastfile:</strong></p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="nf">default_platform</span><span class="p">(</span><span class="o">:</span><span class="n">ios</span><span class="p">)</span>

<span class="n">platform</span> <span class="o">:</span><span class="n">ios</span> <span class="k">do</span>
  <span class="n">desc</span> <span class="s2">"Run all tests (Unit Tests + UI Tests)"</span>
  <span class="n">lane</span> <span class="o">:</span><span class="n">run_all_tests</span> <span class="k">do</span> <span class="err">\\</span><span class="o">|</span><span class="n">options</span><span class="err">\\</span><span class="o">|</span>
    <span class="n">device</span> <span class="o">=</span> <span class="n">options</span><span class="p">[</span><span class="o">:</span><span class="n">device</span><span class="p">]</span>
    <span class="nf">scan</span><span class="p">(</span>
      <span class="n">scheme</span><span class="o">:</span> <span class="s2">"app-ci-cd-github-actions-demo"</span><span class="p">,</span>
      <span class="n">device</span><span class="o">:</span> <span class="n">device</span><span class="p">,</span>
      <span class="n">clean</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
      <span class="n">output_directory</span><span class="o">:</span> <span class="s2">"fastlane/test_output"</span><span class="p">,</span>
      <span class="n">output_types</span><span class="o">:</span> <span class="s2">"junit"</span>
    <span class="p">)</span>
  <span class="n">end</span>

  <span class="n">desc</span> <span class="s2">"Run only Unit Tests"</span>
  <span class="n">lane</span> <span class="o">:</span><span class="n">run_unit_tests</span> <span class="k">do</span> <span class="err">\\</span><span class="o">|</span><span class="n">options</span><span class="err">\\</span><span class="o">|</span>
    <span class="n">device</span> <span class="o">=</span> <span class="n">options</span><span class="p">[</span><span class="o">:</span><span class="n">device</span><span class="p">]</span>
    <span class="nf">scan</span><span class="p">(</span>
      <span class="n">scheme</span><span class="o">:</span> <span class="s2">"app-ci-cd-github-actions-demo"</span><span class="p">,</span>
      <span class="n">device</span><span class="o">:</span> <span class="n">device</span><span class="p">,</span>
      <span class="n">clean</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
      <span class="n">only_testing</span><span class="o">:</span> <span class="p">[</span>
        <span class="s2">"app-ci-cd-github-actions-demoTests"</span>
      <span class="p">],</span>
      <span class="n">output_directory</span><span class="o">:</span> <span class="s2">"fastlane/test_output"</span><span class="p">,</span>
      <span class="n">output_types</span><span class="o">:</span> <span class="s2">"junit"</span>
    <span class="p">)</span>
  <span class="n">end</span>

  <span class="n">desc</span> <span class="s2">"Build and upload to Firebase App Distribution"</span>
  <span class="n">lane</span> <span class="o">:</span><span class="n">beta</span> <span class="k">do</span> <span class="err">\\</span><span class="o">|</span><span class="n">options</span><span class="err">\\</span><span class="o">|</span>
    
    <span class="k">if</span> <span class="n">options</span><span class="p">[</span><span class="o">:</span><span class="n">version_number</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">options</span><span class="p">[</span><span class="o">:</span><span class="n">version_number</span><span class="p">]</span><span class="mf">.</span><span class="n">to_s</span><span class="mf">.</span><span class="n">strip</span> <span class="o">!=</span> <span class="s2">""</span>
      <span class="nf">increment_version_number</span><span class="p">(</span><span class="n">version_number</span><span class="o">:</span> <span class="n">options</span><span class="p">[</span><span class="o">:</span><span class="n">version_number</span><span class="p">])</span>
    <span class="n">end</span>

    <span class="k">if</span> <span class="n">options</span><span class="p">[</span><span class="o">:</span><span class="n">build_number</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">options</span><span class="p">[</span><span class="o">:</span><span class="n">build_number</span><span class="p">]</span><span class="mf">.</span><span class="n">to_s</span><span class="mf">.</span><span class="n">strip</span> <span class="o">!=</span> <span class="s2">""</span>
      <span class="nf">increment_build_number</span><span class="p">(</span><span class="n">build_number</span><span class="o">:</span> <span class="n">options</span><span class="p">[</span><span class="o">:</span><span class="n">build_number</span><span class="p">])</span>
    <span class="n">end</span>

    <span class="nf">update_code_signing_settings</span><span class="p">(</span>
      <span class="n">use_automatic_signing</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
      <span class="n">path</span><span class="o">:</span> <span class="s2">"app-ci-cd-github-actions-demo.xcodeproj"</span><span class="p">,</span>
      <span class="n">team_id</span><span class="o">:</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'TEAM_ID'</span><span class="p">],</span>
      <span class="n">code_sign_identity</span><span class="o">:</span> <span class="s2">"iPhone Developer"</span><span class="p">,</span>
      <span class="n">sdk</span><span class="o">:</span> <span class="s2">"iphoneos*"</span><span class="p">,</span>
      <span class="n">profile_name</span><span class="o">:</span> <span class="s2">"cicd"</span>
    <span class="p">)</span>

    <span class="nf">gym</span><span class="p">(</span>
      <span class="n">scheme</span><span class="o">:</span> <span class="s2">"app-ci-cd-github-actions-demo"</span><span class="p">,</span>
      <span class="n">clean</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
      <span class="n">export_method</span><span class="o">:</span> <span class="s2">"development"</span><span class="p">,</span>
      <span class="n">output_directory</span><span class="o">:</span> <span class="s2">"fastlane/build"</span><span class="p">,</span>
      <span class="n">output_name</span><span class="o">:</span> <span class="s2">"app-ci-cd-github-actions-demo.ipa"</span><span class="p">,</span>
      <span class="n">export_options</span><span class="o">:</span> <span class="p">{</span>
          <span class="n">provisioningProfiles</span><span class="o">:</span> <span class="p">{</span>
            <span class="s2">"com.test.appcicdgithubactionsdemo"</span> <span class="o">=&gt;</span> <span class="s2">"cicd"</span><span class="p">,</span>
          <span class="p">},</span>
      <span class="p">}</span>
    <span class="p">)</span>

    <span class="nf">firebase_app_distribution</span><span class="p">(</span>
      <span class="n">app</span><span class="o">:</span> <span class="s2">"1:127683058219:ios:98896929fa131c7a80686e"</span><span class="p">,</span>
      <span class="n">firebase_cli_token</span><span class="o">:</span> <span class="no">ENV</span><span class="p">[</span><span class="s2">"FIREBASE_CLI_TOKEN"</span><span class="p">],</span>
      <span class="n">release_notes</span><span class="o">:</span> <span class="n">options</span><span class="p">[</span><span class="o">:</span><span class="n">release_notes</span><span class="p">]</span> <span class="err">\\</span><span class="o">|</span><span class="err">\\</span><span class="o">|</span> <span class="s2">"New beta build"</span>
    <span class="p">)</span>
  <span class="n">end</span>
<span class="n">end</span>
</code></pre></div></div>

<p>注: provisioningProfiles、profile_name 对应的是 <a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">App Developer 中的 Profiles 凭证名称</a> 。(如果有用 match 则也不需要这些指定。)</p>

<p><img src="/assets/4b001d2e8440/1*WXqqnErto3nn8rnNg6TXgw.webp" alt="" loading="lazy" decoding="async" width="1117" height="616" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTE3IiBoZWlnaHQ9IjYxNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*WXqqnErto3nn8rnNg6TXgw.png" /></p>

<p><strong>Fastlane 是 iOS CI/CD 当中不可或缺的一部分</strong> ，直接使用它封装好的方法就能快速开发 CI/CD 实际执行的步骤；我们只需关注在整体的脚本设计，而不需去处理复杂的 API 串接或指令撰写。</p>

<p>例如：Fastlane 只需要写「scan(xxx)」就能执行测试，如果要写成 xcodebuild 则需要「 <code class="language-plaintext highlighter-rouge">xcodebuild -workspace ./xxx.xcworkspace -scheme xxx -derivedDataPath xxx ‘platform=iOS Simulator,id=xxx’ clean build test</code> 」，打包部署要自己做更是麻烦，要自行串接 App Store Connect/Firebase API，光金钥验证都要写超过 10 行程式了。</p>

<p><strong>Demo 专案我们只有三个 Lane:</strong></p>

<ul>
  <li>
    <p>run_all_tests: 跑所有类型的测试 (Snapshot+Unit)</p>
  </li>
  <li>
    <p>run_unit_tests: 只跑单元测试 (Unit)</p>
  </li>
  <li>
    <p>beta: 打包部署到 Firebase App Distribution</p>
  </li>
</ul>

<h4 id="fastlane--match">Fastlane — Match</h4>

<p>因 Demo 专案限制，这边没用到 Match 管理团队开发、部署凭证，但这边还是要提一下，建议使用 Match 去管理团队的所有开发、部署凭证，方便控管跟统一更新。</p>

<blockquote>
  <p><em>有用 Match 就能在专案 Setup 步骤直接使用 <code class="language-plaintext highlighter-rouge">match all</code> 之类的指令一键安装好所有开发需要的凭证。</em></p>
</blockquote>

<ul>
  <li><strong>Fastlane Match 会使用另一个 Private Repo 管理凭证金钥，在 GitHub Actions 中需要设定好 SSH Agent 才能 Clone 另一个 Private Repo。</strong>
(请参考文末补充)</li>
</ul>

<p><strong>[2026/02 Update] 延伸阅读 — 补充 iOS 凭证、Fastlane Match、CI/CD 使用细节:</strong></p>

<ul>
  <li>「 <a href="/posts/zrealm-dev/ios-certificates-identifiers与profiles详解-fastlane-match统一管理凭证与ci-cd整合实战-823ac523ccc8/">iOS Certificates, Identifiers &amp; Profiles 是什么及 Fastlane Match 统一管理凭证与 CI/CD 的一些笔记</a> 」</li>
</ul>

<p>— — —</p>

<h4 id="makefile">Makefile</h4>

<p><img src="/assets/4b001d2e8440/1*jYACUYFP3MkeHCgeUY7j3w.webp" alt="Makefile" loading="lazy" decoding="async" width="1200" height="423" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQyMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*jYACUYFP3MkeHCgeUY7j3w.png" /></p>

<p>Makefile</p>

<p>让开发端与 CI/CD 统一都使用 Makefile 执行指令，方便我们封装同样的环境、路径与操作行为。</p>

<blockquote>
  <p><em>经典的案例是有的人使用的是本机安装的 <code class="language-plaintext highlighter-rouge">pod install</code> 有的人则使用的是 Bundel 管理的 <code class="language-plaintext highlighter-rouge">bundle exec pod install</code> 如果版本不同就可能产生差异。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>觉得太复杂不使用也可以，那就是在 Action Workflow Step 中直接写要执行的指令即可。</em></strong></p>
</blockquote>

<p><strong>Makefile:</strong></p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!make
</span><span class="nv">PRODUCT_FOLDER</span> <span class="o">=</span> ./Product/
<span class="nv">SHELL</span>         <span class="o">:=</span> /bin/zsh
<span class="nv">.DEFAULT_GOAL</span> <span class="o">:=</span> <span class="nb">install</span>
<span class="nv">MINT_DIRECTORY</span> <span class="o">:=</span> ./mint/

<span class="k">export </span><span class="nv">MINT_PATH</span><span class="o">=</span><span class="p">$(</span>MINT_DIRECTORY<span class="p">)</span>

<span class="c">## 👇 Help function
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">help</span>
<span class="nl">help</span><span class="o">:</span>
 <span class="err">@echo</span> <span class="s2">""</span>
 <span class="nl">@echo "📖 可用指令</span><span class="o">:</span><span class="nf">"</span>
 <span class="nl">@grep -E '^[a-zA-Z_-]+</span><span class="o">:</span><span class="nf">.*?</span><span class="c">##</span><span class="nf"> .*$$' $(MAKEFILE_LIST) </span>\\<span class="nf">| </span>\
<span class="nf">  awk 'BEGIN {FS = ":.*?</span><span class="c">##</span><span class="nf"> "}; {printf "  </span>\0<span class="nf">33[36m%-20s</span>\0<span class="nf">33[0m %s</span>\n<span class="nf">"</span><span class="p">,</span><span class="nf"> $$1</span><span class="p">,</span><span class="nf"> $$2}'</span>
 <span class="err">@echo</span> <span class="s2">""</span>

<span class="c">## Setup
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">setup</span>
<span class="nl">setup</span><span class="o">:</span> <span class="nf">check-mint </span><span class="c">##</span><span class="nf"> 安装 Ruby 和 Mint 依赖</span>
 <span class="err">@echo</span> <span class="s2">"🔨 Installing Ruby dependencies..."</span>
 <span class="err">bundle</span> <span class="err">config</span> <span class="err">set</span> <span class="err">path</span> <span class="s1">'vendor/bundle'</span>
 <span class="err">bundle</span> <span class="err">install</span>
 <span class="err">@echo</span> <span class="s2">"🔨 Installing Mint dependencies..."</span>
 <span class="err">mint</span> <span class="err">bootstrap</span>

<span class="c">## Install
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">install</span>
<span class="nl">install</span><span class="o">:</span> <span class="nf">XcodeGen PodInstall </span><span class="c">##</span><span class="nf"> 执行 XcodeGen 和 CocoaPods 安装</span>

<span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">XcodeGen</span>
<span class="nl">XcodeGen</span><span class="o">:</span> <span class="nf">check-mint </span><span class="c">##</span><span class="nf"> 用 XcodeGen 产生 .xcodeproj</span>
 <span class="err">@echo</span> <span class="s2">"🔨 Execute XcodeGen"</span>
 <span class="err">cd</span> <span class="err">$(PRODUCT_FOLDER)</span> <span class="err">&amp;&amp;</span> <span class="err">\</span>
 <span class="err">mint</span> <span class="err">run</span> <span class="err">yonaskolb/XcodeGen</span> <span class="err">--quiet</span>

<span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">PodInstall</span>
<span class="nl">PodInstall</span><span class="o">:</span> <span class="c">##</span><span class="nf"> 安装 CocoaPods 依赖</span>
 <span class="err">@echo</span> <span class="s2">"📦 Installing CocoaPods dependencies..."</span>
 <span class="err">cd</span> <span class="err">$(PRODUCT_FOLDER)</span> <span class="err">&amp;&amp;</span> <span class="err">\</span>
 <span class="err">bundle</span> <span class="err">exec</span> <span class="err">pod</span> <span class="err">install</span>

<span class="c">### Mint
</span><span class="nl">check-mint</span><span class="o">:</span> <span class="nf">check-brew </span><span class="c">##</span><span class="nf"> 检查 Mint 是否安装，没有就自动安装</span>
 <span class="err">@if</span> <span class="err">!</span> <span class="err">command</span> <span class="err">-v</span> <span class="err">mint</span> <span class="err">&amp;&gt;</span> <span class="err">/dev/null;</span> <span class="err">then</span> <span class="err">\</span>
  <span class="err">echo</span> <span class="s2">"🔨 Installing mint..."</span><span class="err">;</span> <span class="err">\</span>
  <span class="err">brew</span> <span class="err">install</span> <span class="err">mint;</span> <span class="err">\</span>
 <span class="err">fi</span>

<span class="c">### Brew
</span><span class="nl">check-brew</span><span class="o">:</span> <span class="c">##</span><span class="nf"> 检查 Homebrew 是否安装，没有就自动安装</span>
 <span class="err">@if</span> <span class="err">!</span> <span class="err">command</span> <span class="err">-v</span> <span class="err">brew</span> <span class="err">&amp;&gt;</span> <span class="err">/dev/null;</span> <span class="err">then</span> <span class="err">\</span>
  <span class="err">echo</span> <span class="s2">"🔨 Installing Homebrew..."</span><span class="err">;</span> <span class="err">\</span>
  <span class="nl">/bin/bash -c "$$(curl -fsSL https</span><span class="o">:</span><span class="nf">//raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"; </span>\
<span class="nf"> fi</span>

<span class="c">## Format only git swift files
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">format</span>
<span class="nl">format</span><span class="o">:</span> <span class="nf">check-mint </span><span class="c">##</span><span class="nf"> 格式化 Product/ 下所有 Swift 档</span>
 <span class="err">mint</span> <span class="err">run</span> <span class="err">swiftformat</span> <span class="err">$(PRODUCT_FOLDER)</span>
</code></pre></div></div>

<p>为了避免污染整个系统或其他专案，我们尽可能把 Dependency 套件(e.g. mint, bundle…etc)的路径都改指定在专案目录之下 (再搭配 <code class="language-plaintext highlighter-rouge">.gitignore</code> 排除)。</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">├──</span> <span class="nt">mint</span> <span class="o">(</span><span class="nt">Mint</span> <span class="err">依赖</span><span class="o">)</span>
<span class="err">│</span>   <span class="err">└──</span> <span class="nt">packages</span>
<span class="err">├──</span> <span class="nt">Product</span>
<span class="err">│</span>   <span class="err">├──</span> <span class="nt">app-ci-cd-github-actions-demo</span>
<span class="err">│</span>   <span class="err">├──</span> <span class="nt">app-ci-cd-github-actions-demo</span><span class="nc">.xcodeproj</span>
<span class="err">│</span>   <span class="err">├──</span> <span class="nt">app-ci-cd-github-actions-demo</span><span class="nc">.xcworkspace</span>
<span class="err">│</span>   <span class="err">├──</span> <span class="nt">app-ci-cd-github-actions-demoSnapshotTests</span>
<span class="err">│</span>   <span class="err">├──</span> <span class="nt">app-ci-cd-github-actions-demoTests</span>
<span class="err">│</span>   <span class="err">├──</span> <span class="nt">app-ci-cd-github-actions-demoUITests</span>
<span class="err">│</span>   <span class="err">├──</span> <span class="nt">fastlane</span>
<span class="err">│</span>   <span class="err">└──</span> <span class="nt">Pods</span> <span class="o">(</span><span class="nt">Cocoapods</span> <span class="err">依赖</span><span class="o">)</span>
<span class="err">└──</span> <span class="nt">vendor</span> <span class="o">(</span><span class="nt">Bundle</span> <span class="err">依赖</span><span class="o">)</span>
    <span class="err">└──</span> <span class="nt">bundle</span>
</code></pre></div></div>

<p><img src="/assets/4b001d2e8440/1*F1KFntT8bCZzyYm9JahiuA.webp" alt="make help" loading="lazy" decoding="async" width="449" height="142" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NDkiIGhlaWdodD0iMTQyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*F1KFntT8bCZzyYm9JahiuA.png" /></p>

<p>make help</p>

<p><strong>使用 Makefine 的统一专案 Setup 步骤：</strong></p>

<ol>
  <li>
    <p><code class="language-plaintext highlighter-rouge">git clone repo</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">cd ./repo</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">make setup</code>
安装必要的工具依赖 ( <strong>brew</strong> , <strong>mint</strong> , <strong>bundle</strong> , xcodegen, swiftformat,…)</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">make install</code>
产生专案 (执行 pod install, xcodegen)</p>
  </li>
  <li>
    <p>完成</p>
  </li>
  <li>
    <p>打开、执行专案</p>
  </li>
</ol>

<blockquote>
  <p><strong><em>不管是 CI/CD 或新人 onboard 都是照以上步骤把专案建置起来。</em></strong></p>
</blockquote>

<h3 id="本篇-github-actions-cicd-案例">本篇 GitHub Actions CI/CD 案例</h3>

<p>本篇会介绍三个 GitHub Actions CI/CD 工作流程建置案例，大家也可以参考其中的步骤建置符合自己团队工作流程的 CI/CD。</p>

<ol>
  <li>
    <p>CI — 发 Pull Request 执行单元测试</p>
  </li>
  <li>
    <p>CD — 打包+部署到 Firebase App Distribution</p>
  </li>
  <li>
    <p>CI +CD— Nightly Build 执行快照+单元测试+打包+部署到 Firebase App Distribution</p>
  </li>
</ol>

<blockquote>
  <p><em>因 Demo 限制，本文只会串接 打包部署到 Firebase App Distribution，打包到 Testflight 或是 App Store 也是同样步骤只差别在 Fastlane 里的脚本不同，大家可以自行发挥。</em></p>
</blockquote>

<h3 id="ci--发-pull-request-执行单元测试">CI — 发 Pull Request 执行单元测试</h3>

<h4 id="流程">流程</h4>

<p>Develop 分支 <strong>无法直接推送</strong> ，必须发 Pull Request 才能更新；所有 Pull Request <strong>均需 Review 通过加上单元测试通过才能 Merge</strong> 、有新 Commit Push 会重新测试。</p>

<h4 id="ci-testingyml">CI-Testing.yml</h4>

<p>Repo → Actions → New workflow → set up a workflow yourself。</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Workflow(Action) 名称</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">CI-Testing</span>

<span class="c1"># Actions Log 的标题名称</span>
<span class="na">run-name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">[CI-Testing]</span><span class="nv"> </span><span class="s">${{</span><span class="nv"> </span><span class="s">github.event.pull_request.title</span><span class="nv"> </span><span class="se">\\</span><span class="s">|</span><span class="se">\\</span><span class="s">|</span><span class="nv"> </span><span class="s">github.ref</span><span class="nv"> </span><span class="s">}}"</span>

<span class="c1"># 同个 Concurrency Group 如果有新的 Job 会取消正在跑的</span>
<span class="c1"># 例如 Push Commit 触发的任务还没执行就又 Push Commit 时，会取消前一个任务</span>
<span class="na">concurrency</span><span class="pi">:</span>
  <span class="na">group</span><span class="pi">:</span> <span class="s">${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number \\|\\| github.ref }}</span>
  <span class="na">cancel-in-progress</span><span class="pi">:</span> <span class="kc">true</span>

<span class="c1"># 触发事件</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># PR 事件</span>
  <span class="na">pull_request</span><span class="pi">:</span>
    <span class="c1"># PR - 开启、重开、有新 Push Commit 时</span>
    <span class="na">types</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">opened</span><span class="pi">,</span> <span class="nv">synchronize</span><span class="pi">,</span> <span class="nv">reopened</span><span class="pi">]</span>
  <span class="c1"># 手动表单触发</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>
    <span class="c1"># 表单 Inputs 栏位</span>
    <span class="na">inputs</span><span class="pi">:</span>
      <span class="c1"># 执行的 Test Fastlane Lane</span>
      <span class="na">TEST_LANE</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Test</span><span class="nv"> </span><span class="s">Lane'</span>
        <span class="na">default</span><span class="pi">:</span> <span class="s1">'</span><span class="s">run_unit_tests'</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">choice</span>
        <span class="na">options</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="s">run_unit_tests</span>
          <span class="pi">-</span> <span class="s">run_all_tests</span>
  <span class="c1"># 其他 Workflow 呼叫此 Workflow 触发</span>
  <span class="c1"># Nightly Build 会呼叫使用</span>
  <span class="na">workflow_call</span><span class="pi">:</span>
    <span class="c1"># 表单 Inputs 栏位</span>
    <span class="na">inputs</span><span class="pi">:</span>
      <span class="c1"># 执行的 Test Fastlane Lane</span>
      <span class="na">TEST_LANE</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Test</span><span class="nv"> </span><span class="s">Lane'</span>
        <span class="na">default</span><span class="pi">:</span> <span class="s1">'</span><span class="s">run_unit_tests'</span>
        <span class="c1"># workflow_call inputs 不支援 choice</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="na">BRANCH</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Branch'</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
  
<span class="c1"># Job 工作项目</span>
<span class="c1"># Job 会并发执行</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="c1"># Job ID</span>
  <span class="na">testing</span><span class="pi">:</span>
    <span class="c1"># Job 名称 (可省略，有设定在 Log 显示比较好读)</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Testing</span>
    
    <span class="c1"># Runner Label - 使用 GitHub Hosted Runner macos-15 来执行工作</span>
    <span class="c1"># 请注意：因为此专案是 Public Repo 可以无限免费使用</span>
    <span class="c1"># 请注意：因为此专案是 Public Repo 可以无限免费使用</span>
    <span class="c1"># 请注意：因为此专案是 Public Repo 可以无限免费使用</span>
    <span class="c1"># 如果是 Private Repo 需要按计量收费，macOS 机器是最贵的(10倍)，可能跑 10 次就达到 2,000 分钟免费上限</span>
    <span class="c1"># 建议使用 self-hosted Runner</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">macos-15</span>

    <span class="c1"># 设定最长 Timeout 时间，防止异常情况发生时无止尽的等待</span>
    <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">30</span>

    <span class="c1"># use zsh</span>
    <span class="c1"># 可省略，只是我习惯用 zsh，预设是 bash</span>
    <span class="na">defaults</span><span class="pi">:</span>
      <span class="na">run</span><span class="pi">:</span>
        <span class="na">shell</span><span class="pi">:</span> <span class="s">zsh {0}</span>
          
    <span class="c1"># 工作步骤</span>
    <span class="c1"># 工作步骤会照顺序执行  </span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="c1"># git clone 当前专案 &amp; checkout 到执行的分支</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout repository</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="c1"># Git Large File Storage，我们的测试环境用不到</span>
          <span class="c1"># default: false</span>
          <span class="na">lfs</span><span class="pi">:</span> <span class="kc">false</span>
          
          <span class="c1"># 如果有指定则 Checkout 指定分支，没有则使用预设(当前分支)</span>
          <span class="c1"># 因 on: schedule 事件只能在 main 主分支执行，因此想做 Nightly Build 之类的工作就需要指定分支</span>
          <span class="c1"># e.g. on: schedule -&gt; main 分支，Nightly Build master 分支</span>
          <span class="na">ref</span><span class="pi">:</span> <span class="s">${{ github.event.inputs.BRANCH \\|\\| '' }}</span>

      <span class="c1"># ========== Env Setup Steps ==========</span>
      
      <span class="c1"># 读取专案指定的 XCode 版本</span>
      <span class="c1"># 在后续之中，我们自己手动指定使用的 XCode_x.x.x.app</span>
      <span class="c1"># 而不使用 xcversion，因为 xcversion 已经 sunset 不稳定。 </span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Read .xcode-version</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">read_xcode_version</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">XCODE_VERSION=$(cat .xcode-version)</span>
          <span class="s">echo "XCODE_VERSION</span><span class="err">:</span> <span class="s">${XCODE_VERSION}"</span>
          <span class="s">echo "xcode_version=${XCODE_VERSION}" &gt;&gt; $GITHUB_OUTPUT</span>

          <span class="s"># 也可以直接在这指定全域 XCode 版本，这样就不用在后续步骤指定 DEVELOPER_DIR</span>
          <span class="s"># 但此指令需要 sudoer 权限，如果是 self-hosted runner 就要确定 runner 执行环境有 sudo 权限</span>
          <span class="s"># sudo xcode-select -s "/Applications/Xcode_${XCODE_VERSION}.app/Contents/Developer"</span>

      <span class="c1"># 读取专案指定的 Ruby 版本</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Read .ruby-version</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">read_ruby_version</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">RUBY_VERSION=$(cat .ruby-version)</span>
          <span class="s">echo "RUBY_VERSION</span><span class="err">:</span> <span class="s">${RUBY_VERSION}"</span>
          <span class="s">echo "ruby_version=${RUBY_VERSION}" &gt;&gt; $GITHUB_OUTPUT</span>

      <span class="c1"># 安装或设定 Runner Ruby 版本成专案指定版本</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set up Ruby</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">ruby/setup-ruby@v1</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">ruby-version</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">steps.read_ruby_version.outputs.ruby_version</span><span class="nv"> </span><span class="s">}}"</span>

      <span class="c1"># 可设可不设，原因是之前在 self-hosted 起多个 runner 跑 CI/CD 因为 cocoapods repos 是共用目录</span>
      <span class="c1"># 解决的问题是：有很小的机率会出现在同时 pod install 时拉 cocoapods repos 出现冲突(因为预设都是用) $HOME/.cocoapods/</span>
      <span class="c1"># GitHub Hosted Runner 则不需此设定</span>
      <span class="c1"># - name: Change Cocoapods Repos Folder</span>
      <span class="c1">#   if: contains(runner.labels, 'self-hosted')</span>
      <span class="c1">#   run: \\|</span>
      <span class="c1">#     # 每个 Runner 用自己的 .cocoapods 资料夹，防止资源冲突</span>
      <span class="c1">#     mkdir -p "$HOME/.cocoapods-${{ env.RUNNER_NAME }}/"</span>
      <span class="c1">#     export CP_HOME_DIR="$HOME/.cocoapods-${{ env.RUNNER_NAME }}"</span>
      <span class="c1">#     rm -f "$HOME/.cocoapods-${{ env.RUNNER_NAME }}/repos/cocoapods/.git/index.lock"</span>

      <span class="c1"># ========== Cache Setting Steps ==========</span>
      <span class="c1"># 请注意，就算是 self-hosted，Cache 目前也是 Cloud Cache 会计算用量</span>
      <span class="c1"># 规则：7 天未 hit 自动删除、单个 Cache 上限 10 GB、Action 成功才会 Cache</span>
      <span class="c1"># Public Repo: 免费无限制</span>
      <span class="c1"># Private Repo: 5 GB 起</span>
      <span class="c1"># Self-hosted 可以自己用 shell script 撰写 Cache &amp; Restore 策略或使用其他工具协助</span>
      
      <span class="c1"># Bundle Cache (Gemfile)</span>
      <span class="c1"># 对应 Makefile 中我们指定了 Bundle  安装路径 ./vendor 下</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Cache Bundle</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/cache@v3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">./vendor</span>
          <span class="na">key</span><span class="pi">:</span> <span class="s">${{ runner.os }}-bundle-${{ hashFiles('Gemfile.lock') }}</span>
          <span class="na">restore-keys</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">${{ runner.os }}-bundle-</span>

      <span class="c1"># CocoaPods Cache (Podfile)</span>
      <span class="c1"># 默认就是 专案/Pods 下</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Cache CocoaPods</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/cache@v3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">./Product/Pods</span>
          <span class="na">key</span><span class="pi">:</span> <span class="s">${{ runner.os }}-cocoapods-${{ hashFiles('Product/Podfile.lock') }}</span>
          <span class="na">restore-keys</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">${{ runner.os }}-cocoapods-</span>

      <span class="c1"># Mint cache</span>
      <span class="c1"># 对应 Makefile 中我们指定的 Mint 安装路径 ./mint 下</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Cache Mint</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/cache@v3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s">./mint</span>
          <span class="na">key</span><span class="pi">:</span> <span class="s">${{ runner.os }}-mint-${{ hashFiles('Mintfile') }}</span>
          <span class="na">restore-keys</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">${{ runner.os }}-mint-</span>

      <span class="c1"># ====================</span>

      <span class="c1"># 专案 Setup &amp; 依赖安装</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Setup &amp; Install Dependency</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s"># 执行 Makefile 中封装的 Setup 指令，对应成指令大概是：</span>
          <span class="s"># brew install mint</span>
          <span class="s"># bundle config set path 'vendor/bundle'</span>
          <span class="s"># bundle install</span>
          <span class="s"># mint bootstrap</span>
          <span class="s"># ...</span>
          <span class="s"># 等等 setup 指令</span>
          <span class="s">make setup</span>

          <span class="s"># 执行 Makefile 中封装的 Install 指令，对应成指令大概是：</span>
          <span class="s"># mint run yonaskolb/XcodeGen --quiet</span>
          <span class="s"># bundle exec pod install</span>
          <span class="s"># ...</span>
          <span class="s"># 等等 install 指令</span>
          <span class="s">make install</span>

      <span class="c1"># 执行 Fastlane Unit 测试 Lane</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Run Tests</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">testing</span>
        <span class="c1"># 指定工作目录，这样后续指令就不用在特别 cd ./Product/</span>
        <span class="na">working-directory</span><span class="pi">:</span> <span class="s">./Product/</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="c1"># 测试计划，全跑还是只跑单元测试</span>
          <span class="c1"># 如为开 PR 触发则使用 run_unit_tests，否则看 inputs.TEST_LANE 的值，预设值 run_all_tests</span>
          <span class="na">TEST_LANE</span><span class="pi">:</span> <span class="s">${{ github.event_name == 'pull_request' &amp;&amp; 'run_unit_tests' \\|\\| github.event.inputs.TEST_LANE \\|\\| 'run_all_tests' }}</span>
          
          <span class="c1"># 指定这个 Job 要使用 XCode_x.x.x 指定的版本执行</span>
          <span class="na">DEVELOPER_DIR</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/Applications/Xcode_${{</span><span class="nv"> </span><span class="s">steps.read_xcode_version.outputs.xcode_version</span><span class="nv"> </span><span class="s">}}.app/Contents/Developer"</span>
          
          <span class="c1"># Repo -&gt; Settings -&gt; Actions secrets and variables -&gt; variables</span>
          <span class="c1"># 使用的模拟器名称</span>
          <span class="na">SIMULATOR_NAME</span><span class="pi">:</span> <span class="s">${{ vars.SIMULATOR_NAME }}</span>
          <span class="c1"># 模拟器的 iOS 版本</span>
          <span class="na">SIMULATOR_IOS_VERSION</span><span class="pi">:</span> <span class="s">${{ vars.SIMULATOR_IOS_VERSION }}</span>

          <span class="c1"># 当前 Runner 名称</span>
          <span class="na">RUNNER_NAME</span><span class="pi">:</span> <span class="s">${{ runner.name }}</span>
          
          <span class="c1"># 提升 XCodebuild 指令 timeout 时间, retry 次数</span>
          <span class="c1"># 因为机器 Loading 比较大的时候可能 3 次就失败了</span>
          <span class="na">FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT</span><span class="pi">:</span> <span class="m">60</span>
          <span class="na">FASTLANE_XCODEBUILD_SETTINGS_RETRIES</span><span class="pi">:</span> <span class="m">10</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>

          <span class="s"># 如果是 self-hosted 在同一台机器起多个 Runner 会出现抢模拟器的问题 (文章后会讲)</span>
          <span class="s"># 要避免这问题建议将模拟名称命名成 Runner 名称，每个 Runner 都设一个模拟器，这样就不会互抢导致测试失败</span>
          <span class="s"># e.g. bundle exec fastlane run_unit_tests device:"${RUNNER_NAME} (${SIMULATOR_IOS_VERSION})"</span>
          <span class="s"># 这边是用 GitHub Hosted Runner 没这问题，所以直接用 device:"${SIMULATOR_NAME} (${SIMULATOR_IOS_VERSION})"</span>

          <span class="s"># 发生错误不直接退出并将所有输出都写入 temp/testing_output.txt 档案</span>
          <span class="s"># 后续我们会分析档案内容区分出是 Build Failed 还是 Test Failed，Comment 不同讯息到 PR</span>
          <span class="s">set +e</span>
          
          <span class="s"># EXIT_CODE 储存执行结果的 exit code.</span>
          <span class="s"># 0 = OK</span>
          <span class="s"># 1 = exit</span>
          <span class="s">EXIT_CODE=0</span>
          
          <span class="s"># 所有输出都写入档案</span>
          <span class="s">bundle exec fastlane ${TEST_LANE} device:"${SIMULATOR_NAME} (${SIMULATOR_IOS_VERSION})" \\| tee "$RUNNER_TEMP/testing_output.txt"</span>
          <span class="s"># 如果目前 EXIT_CODE 是 0，则将 ${PIPESTATUS[0]} = bundle exec fastlane ${TEST_LANE}.. 结果</span>
          <span class="s">[[ $EXIT_CODE -eq 0 ]] &amp;&amp; EXIT_CODE=${PIPESTATUS[0]}</span>

          <span class="s"># 恢复出错就退出</span>
          <span class="s">set -e</span>

          <span class="s"># 检查 Testing Output</span>
          <span class="s"># 如果 Testing Output 包含 "Error building"，则设 is_build_error=true 给 Actions 环境变数，为 Build 就失败</span>
          <span class="s"># 如果 Testing Output 包含 "Tests have failed"，则设 is_test_error=true 给 Actions 环境变数，为测试失败</span>
          
          <span class="s">if grep -q "Error building" "$RUNNER_TEMP/testing_output.txt"; then</span>
            <span class="s">echo "is_build_error=true" &gt;&gt; $GITHUB_OUTPUT</span>
            <span class="s">echo "❌ Detected Build Error"</span>
          <span class="s">elif grep -q "Tests have failed" "$RUNNER_TEMP/testing_output.txt"; then</span>
            <span class="s">echo "is_test_error=true" &gt;&gt; $GITHUB_OUTPUT</span>
            <span class="s">echo "❌ Detected Test Error"</span>
          <span class="s">fi</span>

          <span class="s"># 恢复 Exit Code Output</span>
          <span class="s">exit $EXIT_CODE</span>
          
      <span class="c1"># ========== Handle Result Steps ==========</span>
      
      <span class="c1"># 解析 *.junit 测试报告，并标记结果、Comment(如果是 PR 的话)</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Publish Test Report</span>
        <span class="c1"># 直接复用别人写好的 .junit Paser Actions: https://github.com/mikepenz/action-junit-report</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">mikepenz/action-junit-report@v5</span>
        <span class="c1"># if:</span>
        <span class="c1"># 上一步(Testing) success or</span>
        <span class="c1"># 上一步(Testing) failed and is_test_error (build failed 不执行这个 step)</span>
        <span class="na">if</span><span class="pi">:</span> <span class="s">${{ (failure() &amp;&amp; steps.testing.outputs.is_test_error == 'true') \\|\\| success() }}</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">check_name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Testing</span><span class="nv"> </span><span class="s">Report"</span>
          <span class="na">comment</span><span class="pi">:</span> <span class="kc">true</span>
          <span class="na">updateComment</span><span class="pi">:</span> <span class="kc">false</span>
          <span class="na">require_tests</span><span class="pi">:</span> <span class="kc">true</span>
          <span class="na">detailed_summary</span><span class="pi">:</span> <span class="kc">true</span>
          <span class="na">report_paths</span><span class="pi">:</span> <span class="s2">"</span><span class="s">./Product/fastlane/test_output/*.junit"</span>

      <span class="c1"># 测试建置失败 Comment</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Build Failure Comment</span>
        <span class="c1"># if:</span>
        <span class="c1"># 上一步(Testing) failed and is_build_error and 有 PR Number</span>
        <span class="c1"># </span>
        <span class="na">if</span><span class="pi">:</span> <span class="s">${{ failure() &amp;&amp; steps.testing.outputs.is_build_error == 'true' &amp;&amp; github.event.pull_request.number }}</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/github-script@v6</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">action_url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">github.server_url</span><span class="nv"> </span><span class="s">}}/${{</span><span class="nv"> </span><span class="s">github.repository</span><span class="nv"> </span><span class="s">}}/actions/runs/${{</span><span class="nv"> </span><span class="s">github.run_id</span><span class="nv"> </span><span class="s">}}/attempts/${{</span><span class="nv"> </span><span class="s">github.run_attempt</span><span class="nv"> </span><span class="s">}}"</span>
        <span class="na">with</span><span class="pi">:</span>
            <span class="na">script</span><span class="pi">:</span> <span class="s">\\|</span>
              <span class="s">const action_url = process.env.action_url</span>
              <span class="s">const pullRequest = context.payload.pull_request \\|\\| {}</span>
              <span class="s">const commitSha = pullRequest.head?.sha \\|\\| context.sha</span>
              <span class="s">const creator = pullRequest.user?.login \\|\\| context.actor</span>
        
              <span class="s">const commentBody = [</span>
                <span class="s">`# 专案或测试建置失败 ❌`,</span>
                <span class="s">`请确认您的 Pull Request 是否可以正确编译与执行测试。`,</span>
                <span class="s">``,</span>
                <span class="s">`🔗 **Action**</span><span class="err">:</span> <span class="pi">[</span><span class="nv">View Workflow Run</span><span class="pi">]</span><span class="s">(${action_url})`,</span>
                <span class="s">`📝 **Commit**</span><span class="err">:</span> <span class="s">${commitSha}`,</span>
                <span class="s">`👤 **Author**</span><span class="err">:</span> <span class="err">@</span><span class="s">${creator}`</span>
              <span class="s">].join('\n')</span>
        
              <span class="s">await github.rest.issues.createComment({</span>
                <span class="s">owner</span><span class="err">:</span> <span class="s">context.repo.owner,</span>
                <span class="s">repo</span><span class="err">:</span> <span class="s">context.repo.repo,</span>
                <span class="s">issue_number</span><span class="err">:</span> <span class="s">context.payload.pull_request.number,</span>
                <span class="s">body</span><span class="err">:</span> <span class="s">commentBody</span>
              <span class="s">})</span>
</code></pre></div></div>

<p><strong>技术重点说明：</strong></p>

<ul>
  <li>
    <p>runs-on: 建议改用 self-hosted Runner， <a href="https://docs.github.com/en/billing/managing-billing-for-your-products/about-billing-for-github-actions#per-minute-rates" target="_blank">GitHub Hosted Runner macOS 很贵的</a> 。</p>
  </li>
  <li>
    <p>手动读取 <code class="language-plaintext highlighter-rouge">.xcode-version</code> 档案取得指定的 XCode 版本并在需要指定 XCode 的 Step 设定 <code class="language-plaintext highlighter-rouge">DEVELOPER_DIR</code> env 可以轻松免 Sudo 切换 XCode</p>
  </li>
  <li>
    <p>Cache: 可以加速依赖安装速度，但需注意就算是 self-hosted Runner 依然会使用 GitHub Cloud Cache，受到收费限制</p>
  </li>
  <li>
    <p>使用 <code class="language-plaintext highlighter-rouge">set +e</code> 使指令执行失败不会马上退出+将 output 都输出到档案+读取档案判断是 Build Failed or Test Failed；如果不这样做讯息统一都会是 Test Failed。
也可以延伸去判断其他错误，例如： <code class="language-plaintext highlighter-rouge">Underlying Error: Unable to boot the Simulator.</code> 模拟器启动失败，请重新尝试。</p>
  </li>
  <li>
    <p>Checkout Code 可接受指定分支：因为 <code class="language-plaintext highlighter-rouge">on: schedule</code> 事件只能在 main (Default Branch) 触发，如果我们希望排程对某个其他分支操作，就需要指定分支。</p>
  </li>
  <li>
    <p>指定 .cocoapods Repo 路径可做可不做，之前是遇过 self-hosted 同一台机器两个 Runner 同时卡在 pod install 就是因为刚好都在针对 .cocoapods Repo 操作造成 git lock。
(但机率很低就是了)</p>
  </li>
  <li>
    <p><strong>如果你有 Private Pods Repo 需要设定 SSH Agent 才有权限 Clone。</strong>
<strong>(请参考文末补充)</strong></p>
  </li>
  <li>
    <p>记得到 Repo -&gt; Settings -&gt; Actions secrets and variables -&gt; variables 新增：
<code class="language-plaintext highlighter-rouge">SIMULATOR_IOS_VERSION</code> 模拟器 iOS 版本
<code class="language-plaintext highlighter-rouge">SIMULATOR_NAME</code> 模拟器名称</p>
  </li>
</ul>

<p><img src="/assets/4b001d2e8440/1*Vj37P9vZ6KL5wWNvU3Cq3Q.webp" alt="" loading="lazy" decoding="async" width="1156" height="549" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTU2IiBoZWlnaHQ9IjU0OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*Vj37P9vZ6KL5wWNvU3Cq3Q.png" /></p>

<p><strong>Commit 档案到 Repo 主分支，手动触发一次验证正不正确：</strong></p>

<p><img src="/assets/4b001d2e8440/1*tA2nKehTJ7aURSGgU7MM0g.webp" alt="" loading="lazy" decoding="async" width="1200" height="413" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQxMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*tA2nKehTJ7aURSGgU7MM0g.png" /></p>

<p><img src="/assets/4b001d2e8440/1*Qap3KmhIJrLov2O7GneV3w.webp" alt="" loading="lazy" decoding="async" width="1031" height="910" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDMxIiBoZWlnaHQ9IjkxMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*Qap3KmhIJrLov2O7GneV3w.png" /></p>

<p>正确后继续设定。</p>

<h4 id="github-流程设定">GitHub 流程设定</h4>

<p>Repo → Settins → Rules → Rulesets。</p>

<p><img src="/assets/4b001d2e8440/1*cf_M6NnakdcbzvC2VHSfpw.webp" alt="" loading="lazy" decoding="async" width="1200" height="962" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk2MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*cf_M6NnakdcbzvC2VHSfpw.png" /></p>

<ul>
  <li>
    <p>Ruleset Name: 规则名称</p>
  </li>
  <li>
    <p>Enforcement status: 启用/停用 此规则限制</p>
  </li>
  <li>
    <p>Target branches: 目标的 Base 分支，设 Default Branch 就是所有想合进到 main or develop 的分支都受到此规则限制</p>
  </li>
  <li>
    <p>Bypass list: 可指定特殊身份、Team 可以不受此限</p>
  </li>
  <li>
    <p>Branch rules:</p>
  </li>
</ul>

<p><img src="/assets/4b001d2e8440/1*Hzd9CCTsu18kyDR1goRWag.webp" alt="" loading="lazy" decoding="async" width="812" height="1231" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MTIiIGhlaWdodD0iMTIzMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*Hzd9CCTsu18kyDR1goRWag.png" /></p>

<ul>
  <li>
    <p>Restrict deletions: 禁止删除分支</p>
  </li>
  <li>
    <p>Require a pull request before mergin: 只能透过 PR Merge
Required approvals: 限制需要几人 Approve</p>
  </li>
  <li>
    <p>Require status checks to pass: 限制哪些 Checks 要 Passed 才能 Merge
点 + Add checks 输入 <code class="language-plaintext highlighter-rouge">Testing</code> 选择有 GitHub Actions 标志的。
<strong>这边有个小问题，如果 Suggestions</strong> <strong>找不到 <code class="language-plaintext highlighter-rouge">Testing</code> 那需要先回到 Actions 触发(开 PR 试试)成功一次，这里才会出现。</strong></p>
  </li>
</ul>

<p><img src="/assets/4b001d2e8440/1*MRPwUEVVbbz8nH0sS2hFfQ.webp" alt="" loading="lazy" decoding="async" width="834" height="394" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MzQiIGhlaWdodD0iMzk0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*MRPwUEVVbbz8nH0sS2hFfQ.png" /></p>

<ul>
  <li>Block force pushes: 禁止 Force push</li>
</ul>

<p>储存、确定 Enforcement status 是 Active 后，规则就会生效了。</p>

<p><strong>都设定好之后，开 PR 测试看看：</strong></p>

<p><img src="/assets/4b001d2e8440/1*iPETBWx6Boq12rY1fHXmuQ.webp" alt="" loading="lazy" decoding="async" width="919" height="546" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTkiIGhlaWdodD0iNTQ2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*iPETBWx6Boq12rY1fHXmuQ.png" /></p>

<ul>
  <li>Checks 有出现 CI-Testing ( <strong>Requried</strong> )、Merging is blocked、At least X approving review is required by reviewers with write access. 代表设置成功了。</li>
</ul>

<p><strong>如果专案建置失败 (Build Failed) 会 Comment：</strong></p>

<p><img src="/assets/4b001d2e8440/1*4E35VRPo--pI8uqrR4UZNA.webp" alt="" loading="lazy" decoding="async" width="915" height="295" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTUiIGhlaWdodD0iMjk1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*4E35VRPo--pI8uqrR4UZNA.png" /></p>

<p><strong>如果专案建置成功但测试案例失败 (Test Failed) 会 Comment：</strong></p>

<p><img src="/assets/4b001d2e8440/1*wYFzsn5a_yvi8CbZxi-QdQ.webp" alt="" loading="lazy" decoding="async" width="921" height="389" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjEiIGhlaWdodD0iMzg5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*wYFzsn5a_yvi8CbZxi-QdQ.png" /></p>

<p><strong>如果专案建置成功测试也成功(Test Success) 会 Comment：</strong></p>

<p><img src="/assets/4b001d2e8440/1*WqPK1629jYdYTEWCWBHWqg.webp" alt="" loading="lazy" decoding="async" width="915" height="321" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTUiIGhlaWdodD0iMzIxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*WqPK1629jYdYTEWCWBHWqg.png" /></p>

<p><strong>完成 Review Approve + Check 测试通过后：</strong></p>

<p><img src="/assets/4b001d2e8440/1*5gnQYdVAOtGR-bMK4ZrOhA.webp" alt="Demo PR" loading="lazy" decoding="async" width="911" height="566" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTEiIGhlaWdodD0iNTY2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*5gnQYdVAOtGR-bMK4ZrOhA.png" /></p>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/pull/11" target="_blank">Demo PR</a></p>

<p>就能 Merge PR。</p>

<ul>
  <li>如果有 Push New Commit 会自动重跑 Checks 测试。</li>
</ul>

<p><strong>完整程式码： <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/CI-Testing.yml" target="_blank">CI-Testing.yml</a></strong></p>

<p><strong>Auto-merge:</strong></p>

<p>另外，也可以打开 Repo Settings → General → Pull Request 中的：</p>

<p><img src="/assets/4b001d2e8440/1*hl6mfqnnv_zAA3YVrI_M0w.webp" alt="" loading="lazy" decoding="async" width="856" height="257" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NTYiIGhlaWdodD0iMjU3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*hl6mfqnnv_zAA3YVrI_M0w.png" /></p>

<ul>
  <li>
    <p>Automatically delete head branches: Merge PR 后自动删除分支</p>
  </li>
  <li>
    <p>Allow Auto-merge: 当 Checks 通过＋符合条件的 Approvals 达成会自动 Merge PR
<strong>只有当有设条件＋当前条件还不能 Merge 时才会出现 Enable auto-merge 按钮。</strong></p>
  </li>
</ul>

<p><img src="/assets/4b001d2e8440/1*gi0LaaMVXit-DGKnsxS1lQ.webp" alt="" loading="lazy" decoding="async" width="927" height="431" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjciIGhlaWdodD0iNDMxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*gi0LaaMVXit-DGKnsxS1lQ.png" /></p>

<h3 id="cd--打包部署到-firebase-app-distribution">CD — 打包+部署到 Firebase App Distribution</h3>

<h4 id="流程-1">流程</h4>

<p>使用 GitHub Actions 表单触发打包工作，可指定版本号、Release Notes，打包完会自动上传到 Firebase App Distribution 供团队下载测试使用。</p>

<h4 id="cd-deployyml">CD-Deploy.yml</h4>

<p>Repo → Actions → New workflow → set up a workflow yourself。</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Workflow(Action) 名称</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">CD-Deploy</span>

<span class="c1"># Actions Log 的标题名称</span>
<span class="na">run-name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">[CD-Deploy]</span><span class="nv"> </span><span class="s">${{</span><span class="nv"> </span><span class="s">github.ref</span><span class="nv"> </span><span class="s">}}"</span>

<span class="c1"># 同个 Concurrency Group 如果有新的 Job 会取消正在跑的</span>
<span class="c1"># 例如 重复触发相同分支的打包任务，会取消前一个任务</span>
<span class="na">concurrency</span><span class="pi">:</span>
  <span class="na">group</span><span class="pi">:</span> <span class="s">${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}</span>
  <span class="na">cancel-in-progress</span><span class="pi">:</span> <span class="kc">true</span>

<span class="c1"># 触发事件</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># 手动表单触发</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>
    <span class="c1"># 表单 Inputs 栏位</span>
    <span class="na">inputs</span><span class="pi">:</span>
      <span class="c1"># App 版本号</span>
      <span class="na">VERSION_NUMBER</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Version</span><span class="nv"> </span><span class="s">Number</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">app</span><span class="nv"> </span><span class="s">(e.g.,</span><span class="nv"> </span><span class="s">1.0.0).</span><span class="nv"> </span><span class="s">Auto-detect</span><span class="nv"> </span><span class="s">from</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">Xcode</span><span class="nv"> </span><span class="s">project</span><span class="nv"> </span><span class="s">if</span><span class="nv"> </span><span class="s">left</span><span class="nv"> </span><span class="s">blank.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="c1"># App Build Number</span>
      <span class="na">BUILD_NUMBER</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Build</span><span class="nv"> </span><span class="s">number</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">app</span><span class="nv"> </span><span class="s">(e.g.,</span><span class="nv"> </span><span class="s">1).</span><span class="nv"> </span><span class="s">Will</span><span class="nv"> </span><span class="s">use</span><span class="nv"> </span><span class="s">a</span><span class="nv"> </span><span class="s">timestamp</span><span class="nv"> </span><span class="s">if</span><span class="nv"> </span><span class="s">left</span><span class="nv"> </span><span class="s">blank.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="c1"># App Release Note</span>
      <span class="na">RELEASE_NOTE</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Release</span><span class="nv"> </span><span class="s">notes</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">deployment.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
  <span class="c1"># 其他 Workflow 呼叫此 Workflow 触发</span>
  <span class="c1"># Nightly Build 会呼叫使用</span>
  <span class="na">workflow_call</span><span class="pi">:</span>
    <span class="na">inputs</span><span class="pi">:</span>
      <span class="c1"># App 版本号</span>
      <span class="na">VERSION_NUMBER</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Version</span><span class="nv"> </span><span class="s">Number</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">app</span><span class="nv"> </span><span class="s">(e.g.,</span><span class="nv"> </span><span class="s">1.0.0).</span><span class="nv"> </span><span class="s">Auto-detect</span><span class="nv"> </span><span class="s">from</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">Xcode</span><span class="nv"> </span><span class="s">project</span><span class="nv"> </span><span class="s">if</span><span class="nv"> </span><span class="s">left</span><span class="nv"> </span><span class="s">blank.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="c1"># App Build Number</span>
      <span class="na">BUILD_NUMBER</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Build</span><span class="nv"> </span><span class="s">number</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">app</span><span class="nv"> </span><span class="s">(e.g.,</span><span class="nv"> </span><span class="s">1).</span><span class="nv"> </span><span class="s">Will</span><span class="nv"> </span><span class="s">use</span><span class="nv"> </span><span class="s">a</span><span class="nv"> </span><span class="s">timestamp</span><span class="nv"> </span><span class="s">if</span><span class="nv"> </span><span class="s">left</span><span class="nv"> </span><span class="s">blank.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="c1"># App Release Note</span>
      <span class="na">RELEASE_NOTE</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Release</span><span class="nv"> </span><span class="s">notes</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">deployment.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="na">BRANCH</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Branch'</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>


<span class="c1"># 定义全域静态变数</span>
<span class="na">env</span><span class="pi">:</span>
  <span class="na">APP_STORE_CONNECT_API_KEY_FILE_NAME</span><span class="pi">:</span> <span class="s2">"</span><span class="s">app_store_connect_api_key.json"</span>

<span class="c1"># Job 工作项目</span>
<span class="c1"># Job 会并发执行</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="c1"># Job ID</span>
  <span class="na">deploy</span><span class="pi">:</span>
    <span class="c1"># Job 名称 (可省略，有设定在 Log 显示比较好读)</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy - Firebase App Distribution</span>
    
    <span class="c1"># Runner Label - 使用 GitHub Hosted Runner macos-15 来执行工作</span>
    <span class="c1"># 请注意：因为此专案是 Public Repo 可以无限免费使用</span>
    <span class="c1"># 请注意：因为此专案是 Public Repo 可以无限免费使用</span>
    <span class="c1"># 请注意：因为此专案是 Public Repo 可以无限免费使用</span>
    <span class="c1"># 如果是 Private Repo 需要按计量收费，macOS 机器是最贵的(10倍)，可能跑 10 次就达到 2,000 分钟免费上限</span>
    <span class="c1"># 建议使用 self-hosted Runner</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">macos-15</span>

    <span class="c1"># 设定最长 Timeout 时间，防止异常情况发生时无止尽的等待</span>
    <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">30</span>

    <span class="c1"># use zsh</span>
    <span class="c1"># 可省略，只是我习惯用 zsh，预设是 bash</span>
    <span class="na">defaults</span><span class="pi">:</span>
      <span class="na">run</span><span class="pi">:</span>
        <span class="na">shell</span><span class="pi">:</span> <span class="s">zsh {0}</span>

    <span class="c1"># 工作步骤</span>
    <span class="c1"># 工作步骤会照顺序执行  </span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="c1"># git clone 当前专案 &amp; checkout 到执行的分支</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout repository</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="c1"># Git Large File Storage，我们的测试环境用不到</span>
          <span class="c1"># default: false</span>
          <span class="na">lfs</span><span class="pi">:</span> <span class="kc">false</span>
          
          <span class="c1"># 如果有指定则 Checkout 指定分支，没有则使用预设(当前分支)</span>
          <span class="c1"># 因 on: schedule 事件只能在 main 主分支执行，因此想做 Nightly Build 之类的工作就需要指定分支</span>
          <span class="c1"># e.g. on: schedule -&gt; main 分支，Nightly Build master 分支</span>
          <span class="na">ref</span><span class="pi">:</span> <span class="s">${{ github.event.inputs.BRANCH \\|\\| '' }}</span>

      <span class="c1"># ========== Certificates Steps ==========</span>
      
      <span class="c1"># 建议是使用 Fastlnae - Match 管理开发凭证并在 Lane 中直接执行 match 安装设定好</span>
      <span class="c1"># Match 会用另一个 Private Repo 管理凭证，但要设定好 SSH Agent 才有权限 git clone private repo</span>
      <span class="c1"># ref: https://stackoverflow.com/questions/57612428/cloning-private-github-repository-within-organisation-in-actions</span>
      <span class="c1">#</span>
      <span class="c1">#</span>
      <span class="c1"># --- 以下是没有使用 Fastlane - Match 的情况下直接下载 &amp; Import 凭证给 Runner 的做法 ---</span>
      <span class="c1"># ref: https://docs.github.com/en/actions/how-tos/use-cases-and-examples/deploying/installing-an-apple-certificate-on-macos-runners-for-xcode-development</span>
      <span class="c1">#</span>
      <span class="c1"># GitHub Actions Secret 无法储存档案，因此所有凭证档案都要先转成 Base64 Encoded 文字格式存在 Secret</span>
      <span class="c1"># 在 GitHub Actions Step 中再动态读出来写入 TEMP 档案并移动到正确位置给系统读取使用</span>
      <span class="c1"># 其他设定细节请参考文章</span>
      <span class="c1">#</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Install the Apple certificate and provisioning profile</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">BUILD_CERTIFICATE_BASE64</span><span class="pi">:</span> <span class="s">${{ secrets.BUILD_CERTIFICATE_BASE64 }}</span>
          <span class="na">P12_PASSWORD</span><span class="pi">:</span> <span class="s">${{ secrets.BUILD_CERTIFICATE_P12_PASSWORD }}</span>
          <span class="na">BUILD_PROVISION_PROFILE_BASE64</span><span class="pi">:</span> <span class="s">${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}</span>
          <span class="c1"># GitHub Hosted Runner 为自定义字串</span>
          <span class="c1"># Self-hosted Runner 为机器登入密码</span>
          <span class="na">KEYCHAIN_PASSWORD</span><span class="pi">:</span> <span class="s">${{ secrets.KEYCHAIN_PASSWORD }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s"># create variables</span>
          <span class="s">CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12</span>
          <span class="s">PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision</span>
          <span class="s">KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db</span>

          <span class="s"># import certificate and provisioning profile from secrets</span>
          <span class="s">echo -n "$BUILD_CERTIFICATE_BASE64" \\| base64 --decode -o $CERTIFICATE_PATH</span>
          <span class="s">echo -n "$BUILD_PROVISION_PROFILE_BASE64" \\| base64 --decode -o $PP_PATH</span>

          <span class="s"># create temporary keychain</span>
          <span class="s">security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH</span>
          <span class="s">security set-keychain-settings -lut 21600 $KEYCHAIN_PATH</span>
          <span class="s">security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH</span>

          <span class="s"># import certificate to keychain</span>
          <span class="s">security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH</span>
          <span class="s">security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH</span>
          <span class="s">security list-keychain -d user -s $KEYCHAIN_PATH</span>

          <span class="s"># apply provisioning profile</span>
          <span class="s">mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles</span>
          <span class="s">cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles</span>

      <span class="c1"># App Store Connect API Fastlane JSON Key</span>
      <span class="c1"># 另一个在打包环境几乎是必须的 App Store Connect API Fastlane JSON Key (.json)</span>
      <span class="c1"># format: .json 内容格式：https://docs.fastlane.tools/app-store-connect-api/</span>
      <span class="c1"># 里面包含 App Store Connect API .p8 Key</span>
      <span class="c1"># 会在后续带给 Fastlane，用于上传到 Testflight、App Store API 使用</span>
      <span class="c1">#</span>
      <span class="c1"># GitHub Actions Secret 无法储存档案，因此所有凭证档案都要先转成 Base64 Encoded 文字格式存在 Secret</span>
      <span class="c1"># 在 GitHub Actions Step 中再动态读出来写入 TEMP 档案供其他步骤引用使用</span>
      <span class="c1"># 其他设定细节请参考文章</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Read and Write Apple Store Connect API Key to Temp</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">APP_STORE_CONNECT_API_KEY_BASE64</span><span class="pi">:</span> <span class="s">${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }}</span>
          <span class="na">APP_STORE_CONNECT_API_KEY_PATH</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">runner.temp</span><span class="nv"> </span><span class="s">}}/${{</span><span class="nv"> </span><span class="s">env.APP_STORE_CONNECT_API_KEY_FILE_NAME</span><span class="nv"> </span><span class="s">}}"</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s"># import certificate and provisioning profile from secrets</span>
          <span class="s">echo -n "$APP_STORE_CONNECT_API_KEY_BASE64" \\| base64 --decode -o $APP_STORE_CONNECT_API_KEY_PATH</span>

      <span class="c1"># ========== Env Setup Steps ==========</span>
      
      <span class="c1"># 读取专案指定的 XCode 版本</span>
      <span class="c1"># 在后续之中，我们自己手动指定使用的 XCode_x.x.x.app</span>
      <span class="c1"># 而不使用 xcversion，因为 xcversion 已经 sunset 不稳定。 </span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Read .xcode-version</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">read_xcode_version</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">XCODE_VERSION=$(cat .xcode-version)</span>
          <span class="s">echo "XCODE_VERSION</span><span class="err">:</span> <span class="s">${XCODE_VERSION}"</span>
          <span class="s">echo "xcode_version=${XCODE_VERSION}" &gt;&gt; $GITHUB_OUTPUT</span>

          <span class="s"># 也可以直接在这指定全域 XCode 版本，这样就不用在后续步骤指定 DEVELOPER_DIR</span>
          <span class="s"># 但此指令需要 sudoer 权限，如果是 self-hosted runner 就要确定 runner 执行环境有 sudo 权限</span>
          <span class="s"># sudo xcode-select -s "/Applications/Xcode_${XCODE_VERSION}.app/Contents/Developer"</span>

      <span class="c1"># 读取专案指定的 Ruby 版本</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Read .ruby-version</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">read_ruby_version</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">RUBY_VERSION=$(cat .ruby-version)</span>
          <span class="s">echo "RUBY_VERSION</span><span class="err">:</span> <span class="s">${RUBY_VERSION}"</span>
          <span class="s">echo "ruby_version=${RUBY_VERSION}" &gt;&gt; $GITHUB_OUTPUT</span>

      <span class="c1"># 安装或设定 Runner Ruby 版本成专案指定版本</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set up Ruby</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">ruby/setup-ruby@v1</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">ruby-version</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">steps.read_ruby_version.outputs.ruby_version</span><span class="nv"> </span><span class="s">}}"</span>

      <span class="c1"># 可设可不设，原因是之前在 self-hosted 起多个 runner 跑 CI/CD 因为 cocoapods repos 是共用目录</span>
      <span class="c1"># 解决的问题是：有很小的机率会出现在同时 pod install 时拉 cocoapods repos 出现冲突(因为预设都是用) $HOME/.cocoapods/</span>
      <span class="c1"># GitHub Hosted Runner 则不需此设定</span>
      <span class="c1"># - name: Change Cocoapods Repos Folder</span>
      <span class="c1">#   if: contains(runner.labels, 'self-hosted')</span>
      <span class="c1">#   run: \\|</span>
      <span class="c1">#     # 每个 Runner 用自己的 .cocoapods 资料夹，防止资源冲突</span>
      <span class="c1">#     mkdir -p "$HOME/.cocoapods-${{ env.RUNNER_NAME }}/"</span>
      <span class="c1">#     export CP_HOME_DIR="$HOME/.cocoapods-${{ env.RUNNER_NAME }}"</span>
      <span class="c1">#     rm -f "$HOME/.cocoapods-${{ env.RUNNER_NAME }}/repos/cocoapods/.git/index.lock"</span>

      <span class="c1"># ========== Cache Setting Steps ==========</span>
      <span class="c1"># 请注意，就算是 self-hosted，Cache 目前也是 Cloud Cache 会计算用量</span>
      <span class="c1"># 规则：7 天未 hit 自动删除、单个 Cache 上限 10 GB、Action 成功才会 Cache</span>
      <span class="c1"># Public Repo: 免费无限制</span>
      <span class="c1"># Private Repo: 5 GB 起</span>
      <span class="c1"># Self-hosted 可以自己用 shell script 撰写 Cache &amp; Restore 策略或使用其他工具协助</span>
      
      <span class="c1"># Bundle Cache (Gemfile)</span>
      <span class="c1"># 对应 Makefile 中我们指定了 Bundle  安装路径 ./vendor 下</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Cache Bundle</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/cache@v3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">./vendor</span>
          <span class="na">key</span><span class="pi">:</span> <span class="s">${{ runner.os }}-bundle-${{ hashFiles('Gemfile.lock') }}</span>
          <span class="na">restore-keys</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">${{ runner.os }}-bundle-</span>

      <span class="c1"># CocoaPods Cache (Podfile)</span>
      <span class="c1"># 默认就是 专案/Pods 下</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Cache CocoaPods</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/cache@v3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">./Product/Pods</span>
          <span class="na">key</span><span class="pi">:</span> <span class="s">${{ runner.os }}-cocoapods-${{ hashFiles('Product/Podfile.lock') }}</span>
          <span class="na">restore-keys</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">${{ runner.os }}-cocoapods-</span>

      <span class="c1"># Mint cache</span>
      <span class="c1"># 对应 Makefile 中我们指定的 Mint 安装路径 ./mint 下</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Cache Mint</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/cache@v3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s">./mint</span>
          <span class="na">key</span><span class="pi">:</span> <span class="s">${{ runner.os }}-mint-${{ hashFiles('Mintfile') }}</span>
          <span class="na">restore-keys</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">${{ runner.os }}-mint-</span>

      <span class="c1"># ====================</span>

      <span class="c1"># 专案 Setup &amp; 依赖安装</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Setup &amp; Install Dependency</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s"># 执行 Makefile 中封装的 Setup 指令，对应成指令大概是：</span>
          <span class="s"># brew install mint</span>
          <span class="s"># bundle config set path 'vendor/bundle'</span>
          <span class="s"># bundle install</span>
          <span class="s"># mint bootstrap</span>
          <span class="s"># ...</span>
          <span class="s"># 等等 setup 指令</span>
          <span class="s">make setup</span>

          <span class="s"># 执行 Makefile 中封装的 Install 指令，对应成指令大概是：</span>
          <span class="s"># mint run yonaskolb/XcodeGen --quiet</span>
          <span class="s"># bundle exec pod install</span>
          <span class="s"># ...</span>
          <span class="s"># 等等 install 指令</span>
          <span class="s">make install</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy Beta</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">deploy</span>
        <span class="c1"># 指定工作目录，这样后续指令就不用在特别 cd ./Product/</span>
        <span class="na">working-directory</span><span class="pi">:</span> <span class="s">./Product/</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="c1"># 打包 Input 参数</span>
          <span class="na">VERSION_NUMBER</span><span class="pi">:</span> <span class="s">${{ inputs.VERSION_NUMBER \\|\\| '' }}</span>
          <span class="na">BUILD_NUMBER</span><span class="pi">:</span> <span class="s">${{ inputs.BUILD_NUMBER \\|\\| '' }}</span>
          <span class="na">RELEASE_NOTE</span><span class="pi">:</span> <span class="s">${{ inputs.RELEASE_NOTE \\|\\| '' }}</span>
          <span class="na">AUTHOR</span><span class="pi">:</span> <span class="s">${{ github.actor }}</span>

          <span class="c1"># Repo -&gt; Settings -&gt; Actions secrets and variables -&gt; secrets</span>
          <span class="c1"># Firebase CLI Token 密钥 (取得方式请参考文章)</span>
          <span class="na">FIREBASE_CLI_TOKEN</span><span class="pi">:</span> <span class="s">${{ secrets.FIREBASE_CLI_TOKEN }}</span>
          <span class="c1"># Apple Developer Program Team ID</span>
          <span class="na">TEAM_ID</span><span class="pi">:</span> <span class="s">${{ secrets.TEAM_ID }}</span>
                    
          <span class="c1"># 指定这个 Job 要使用 XCode_x.x.x 指定的版本执行</span>
          <span class="na">DEVELOPER_DIR</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/Applications/Xcode_${{</span><span class="nv"> </span><span class="s">steps.read_xcode_version.outputs.xcode_version</span><span class="nv"> </span><span class="s">}}.app/Contents/Developer"</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s"># 取得当前 Timestamp</span>
          <span class="s">BUILD_TIMESTAMP=$(date +'%Y%m%d%H%M%S')</span>

          <span class="s"># 如果 BUILD_NUMBER 没有值，用 Timestamp 当 App Build Number</span>
          <span class="s">BUILD_NUMBER="${BUILD_NUMBER:-$BUILD_TIMESTAMP}"</span>
  
          <span class="s">ID="${{ github.run_id }}"</span>
          <span class="s">COMMIT_SHA="${{ github.sha }}"</span>
          <span class="s">BRANCH_NAME="${{ github.ref_name }}"</span>
          <span class="s">AUTHOR="${{ env.AUTHOR }}"</span>

          <span class="s"># 组合 Release Note</span>
          <span class="s">RELEASE_NOTE="${{ env.RELEASE_NOTE }}</span>
          <span class="s">ID</span><span class="err">:</span> <span class="s">${ID}</span>
          <span class="s">Commit SHA</span><span class="err">:</span> <span class="s">${COMMIT_SHA}</span>
          <span class="s">Branch</span><span class="err">:</span> <span class="s">${BRANCH_NAME}</span>
          <span class="s">Author</span><span class="err">:</span> <span class="s">${AUTHOR}</span>
          <span class="s">"</span>

          <span class="s"># 执行 Fastlane 打包＆部署 Lane</span>
          <span class="s">bundle exec fastlane beta release_notes:"${RELEASE_NOTE}" version_number:"${VERSION_NUMBER}" build_number:"${BUILD_NUMBER}"</span>

      <span class="c1"># GitHub Actions 建议的 self-hosted 安全性设定：</span>
      <span class="c1"># ref: https://docs.github.com/en/actions/how-tos/use-cases-and-examples/deploying/installing-an-apple-certificate-on-macos-runners-for-xcode-development#required-clean-up-on-self-hosted-runners</span>
      <span class="c1"># 对应 Step: Install the Apple certificate and provisioning profile</span>
      <span class="c1"># 用途是删除机器上下载下来的金钥凭证</span>
      <span class="c1"># 如果你是用 Match 则需要改写成 Match 的 Clean</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Clean up keychain and provisioning profile</span>
        <span class="na">if</span><span class="pi">:</span> <span class="s">${{ always() &amp;&amp; contains(runner.labels, 'self-hosted') }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">security delete-keychain $RUNNER_TEMP/app-signing.keychain-db</span>
          <span class="s">rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.mobileprovision</span>
</code></pre></div></div>

<ul>
  <li>记得到 Repo -&gt; Settings -&gt; Actions secrets and variables -&gt; secrets 新增一个 <code class="language-plaintext highlighter-rouge">TEAM_ID</code> 变数，内容是 Apple Developer Team ID 字串。</li>
</ul>

<p><img src="/assets/4b001d2e8440/1*dxdmT_N_w_VUd56f6GRLSQ.webp" alt="" loading="lazy" decoding="async" width="1181" height="498" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTgxIiBoZWlnaHQ9IjQ5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*dxdmT_N_w_VUd56f6GRLSQ.png" /></p>

<p><strong>Commit 档案到 Repo 主分支，测试看看打包功能：</strong></p>

<p><img src="/assets/4b001d2e8440/1*Z_UAfWAsJSIoWxeTRMvtDQ.webp" alt="" loading="lazy" decoding="async" width="1072" height="685" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDcyIiBoZWlnaHQ9IjY4NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*Z_UAfWAsJSIoWxeTRMvtDQ.png" /></p>

<blockquote>
  <p><em>请注意若其他分支要使用此 Action 需要先 Merge 主分支的 CD-Deploy.yml 档案。</em></p>
</blockquote>

<p><strong>等待任务跑完：</strong></p>

<p><img src="/assets/4b001d2e8440/1*Q-c2IUlJpssooiqcqcm_Bg.webp" alt="" loading="lazy" decoding="async" width="1200" height="1115" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjExMTUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/4b001d2e8440/1*Q-c2IUlJpssooiqcqcm_Bg.png" /></p>

<p><img src="/assets/4b001d2e8440/1*W8PBkatfsITMDFSlp7xpjg.webp" alt="Demo" loading="lazy" decoding="async" width="1200" height="975" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk3NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*W8PBkatfsITMDFSlp7xpjg.png" /></p>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/actions/runs/16114046420" target="_blank">Demo</a></p>

<blockquote>
  <p><strong><em>打包＋部署成功 ✅</em></strong></p>
</blockquote>

<p><strong>完整程式码： <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/CD-Deploy.yml" target="_blank">CD-Deploy.yml</a></strong></p>

<h4 id="技术细节--firebase-cli-token-取得设定">技术细节 — Firebase CLI Token 取得＆设定</h4>

<p>按照 <a href="https://firebase.google.com/docs/cli?hl=zh-tw#install-cli-mac-linux" target="_blank">Firebase 官方文件步骤</a> ：</p>

<p>先安装好 Firebase CLI 工具：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-sL</span> https://firebase.tools <span class="se">\\</span>| bash
</code></pre></div></div>

<p>执行：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>firebase login:ci
</code></pre></div></div>

<p>完成登入、授权：</p>

<p><img src="/assets/4b001d2e8440/1*Jex5aYzRSs7Trfx6z_e1Aw.webp" alt="" loading="lazy" decoding="async" width="1063" height="701" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDYzIiBoZWlnaHQ9IjcwMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*Jex5aYzRSs7Trfx6z_e1Aw.png" /></p>

<p><img src="/assets/4b001d2e8440/1*S-1ckn9WC6j0DIqZGSdUUg.webp" alt="" loading="lazy" decoding="async" width="427" height="213" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MjciIGhlaWdodD0iMjEzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*S-1ckn9WC6j0DIqZGSdUUg.png" /></p>

<p>回到 Terminal 复制 Firebase CLI Token:</p>

<p><img src="/assets/4b001d2e8440/1*sa_h8L08JbeC2nA0kACQtQ.webp" alt="" loading="lazy" decoding="async" width="682" height="483" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2ODIiIGhlaWdodD0iNDgzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*sa_h8L08JbeC2nA0kACQtQ.png" /></p>

<p>到 Repo → Settings → Secrets and variables → Actions → 新增一个 Secret: <code class="language-plaintext highlighter-rouge">FIREBASE_CLI_TOKEN</code> 并贴上 Firebase CLI Token。</p>

<p><img src="/assets/4b001d2e8440/1*Lc6yGPu7L_0z6u1HH2PB5A.webp" alt="" loading="lazy" decoding="async" width="1171" height="515" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTcxIiBoZWlnaHQ9IjUxNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*Lc6yGPu7L_0z6u1HH2PB5A.png" /></p>

<blockquote>
  <p><strong><em>这个 Token = 你的登入身份</em></strong> <em>，请妥善保存，如果帐号离职也需要进行更换。</em></p>
</blockquote>

<h4 id="技术细节--install-the-apple-certificate-and-provisioning-profile">技术细节 — Install the Apple certificate and provisioning profile</h4>

<p>补充开发凭证汇入 Runner 的步骤细节。</p>

<p>因 GitHub Actions Secret 无法储存档案，因此所有凭证档案都要先转成 Base64 Encoded 文字格式存在 Secrets，GitHub Actions Step 中再动态读出来写入 TEMP 档案并移动到正确位置给系统读取使用。</p>

<p><strong>打包 Development 需要两把金钥凭证：</strong></p>

<ul>
  <li>
    <p><a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Provision Profile ( .mobileprovision)</a></p>
  </li>
  <li>
    <p><a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Development Certifcate ( .p12)</a></p>
  </li>
</ul>

<p><img src="/assets/4b001d2e8440/1*WXqqnErto3nn8rnNg6TXgw.webp" alt="cicd.mobileprovision" loading="lazy" decoding="async" width="1117" height="616" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTE3IiBoZWlnaHQ9IjYxNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*WXqqnErto3nn8rnNg6TXgw.png" /></p>

<p>cicd.mobileprovision</p>

<p><img src="/assets/4b001d2e8440/1*RkeZ1PkXeY9Nt1kSRJKEQw.webp" alt="development.cer" loading="lazy" decoding="async" width="1078" height="738" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDc4IiBoZWlnaHQ9IjczOCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*RkeZ1PkXeY9Nt1kSRJKEQw.png" /></p>

<p>development.cer</p>

<p>从 <a href="https://developer.apple.com/account/resources/certificates/list" target="_blank">Apple Developer</a> 中下载的 Certificate 是 .cer 格式，而我们需要的是 .p12 格式，可以先把下载下来的 .cer 点两下安装到 Keychain，然后打开 Keychain 选择该凭证右键 Export 汇出。</p>

<p><img src="/assets/4b001d2e8440/1*HJMxwM3IDjxT-UGqnoUtWw.webp" alt="" loading="lazy" decoding="async" width="924" height="526" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjQiIGhlaWdodD0iNTI2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*HJMxwM3IDjxT-UGqnoUtWw.png" /></p>

<p>档案名称：cicd.p12、格式 .p12</p>

<p>P12 金钥密码：输入一组安全的自订义字串 (范例是不好的示范，用 <code class="language-plaintext highlighter-rouge">123456</code> )</p>

<p><img src="/assets/4b001d2e8440/1*tyH0XqDVPGPWFJPL4dxksw.webp" alt="" loading="lazy" decoding="async" width="572" height="356" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NzIiIGhlaWdodD0iMzU2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*tyH0XqDVPGPWFJPL4dxksw.png" /></p>

<p><img src="/assets/4b001d2e8440/1*qKeZWel3w_5wW7meMtHmLA.webp" alt="" loading="lazy" decoding="async" width="556" height="381" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTYiIGhlaWdodD0iMzgxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*qKeZWel3w_5wW7meMtHmLA.png" /></p>

<p><strong>现在两个档案：</strong> cicd.p12、cicd.mobileprovision 都准备好了</p>

<p><strong>转换成 BASE64 格式字串并存到 Repo Secrets：</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">base64</span> <span class="nt">-i</span> cicd.mobileprovision <span class="se">\\</span>| pbcopy
</code></pre></div></div>

<p>到 Repo → Settings → Secrets and variables → Actions → 新增一个 Secret: <code class="language-plaintext highlighter-rouge">BUILD_PROVISION_PROFILE_BASE64</code> 并贴上以上内容。</p>

<p>-</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">base64</span> <span class="nt">-i</span> cicd.p12 <span class="se">\\</span>| pbcopy
</code></pre></div></div>

<p>到 Repo → Settings → Secrets and variables → Actions → 新增一个 Secret: <code class="language-plaintext highlighter-rouge">BUILD_CERTIFICATE_BASE64</code> 并贴上以上内容。</p>

<p>-</p>

<p>到 Repo → Settings → Secrets and variables → Actions → 新增一个 Secret: <code class="language-plaintext highlighter-rouge">P12_PASSWORD</code> 内容是刚汇出 P12 金钥设定的密码。</p>

<p>-
到 Repo → Settings → Secrets and variables → Actions → 新增一个 Secret: <code class="language-plaintext highlighter-rouge">KEYCHAIN_PASSWORD</code> ：
如果是 GitHub Hosted Runner 则随便输入一个任意字串， <strong>如果是 Self-hosted Runner 则为 macOS Runner 使用者的登入密码</strong> 。</p>

<p><img src="/assets/4b001d2e8440/1*JZCkFUJCQsggqYtW8acjTw.webp" alt="" loading="lazy" decoding="async" width="1088" height="493" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDg4IiBoZWlnaHQ9IjQ5MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*JZCkFUJCQsggqYtW8acjTw.png" /></p>

<h4 id="技术细节-app-store-connect-api-key">技术细节 —App Store Connect API Key</h4>

<p>Fastlane 打包部署到 App Store, Testflight <a href="https://docs.fastlane.tools/app-store-connect-api/" target="_blank">必须提供的 .json 金钥</a> ，同样受限 GitHub Actions Secrets 只能存字串不能存档案，所以我们也要把金钥内容转成 Base64 字串，GitHub Actions Step 中再动态读出来写入 TEMP 档案并把档案路径给 Fastlane 引用使用。</p>

<p><strong>首先到 <a href="/posts/zrealm-dev/app-store-connect-api-快速读取与管理-customer-reviews-提升-ios-app-评价整合效率-f1365e51902c/">App Store Connect 建立&amp;下载好 App Store Connect API Key</a> ( .p8) ：</strong></p>

<pre><code class="language-vbnet">-----BEGIN PRIVATE KEY-----
sss
axzzvcxz
zxzvzcxv
vzxcvzxvczxcvz
-----END PRIVATE KEY-----
</code></pre>

<p>新增一个 <code class="language-plaintext highlighter-rouge">app_store_connect_api.json</code> 档案( <a href="https://docs.fastlane.tools/app-store-connect-api/" target="_blank">内容参考</a> )：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">{</span>
  <span class="s2">"key_id"</span>: <span class="s2">"App Store Connect 上写的 Key ID"</span>,
  <span class="s2">"issuer_id"</span>: <span class="s2">"App Store Connect 上写的 Issuer ID"</span>,
  <span class="s2">"key"</span>: <span class="s2">"-----BEGIN PRIVATE KEY-----记得把换行改成</span><span class="se">\n</span><span class="s2">-----END PRIVATE KEY-----"</span>,
  <span class="s2">"duration"</span>: 1200, <span class="c"># optional (maximum 1200)</span>
  <span class="s2">"in_house"</span>: <span class="nb">false</span> <span class="c"># optional but may be required if using match/sigh</span>
<span class="o">}</span>
</code></pre></div></div>

<p>储存档案后执行：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">base64</span> <span class="nt">-i</span> app_store_connect_api.json <span class="se">\\</span>| pbcopy
</code></pre></div></div>

<p>将字串内容贴到 Repo → Settings → Secrets and variables → Actions → 新增一个 Secret: <code class="language-plaintext highlighter-rouge">APP_STORE_CONNECT_API_KEY_BASE64</code> 并贴上以上内容。</p>

<p><img src="/assets/4b001d2e8440/1*QxRuxEPEfWbJ383hhnxGkA.webp" alt="" loading="lazy" decoding="async" width="1159" height="549" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTU5IiBoZWlnaHQ9IjU0OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*QxRuxEPEfWbJ383hhnxGkA.png" /></p>

<p><code class="language-plaintext highlighter-rouge">Read and Write Apple Store Connect API Key to Temp</code> Step 完成之后在后续的 Step 只要传入 env <code class="language-plaintext highlighter-rouge">APP_STORE_CONNECT_API_KEY_PATH</code> :</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy</span>
  <span class="na">env</span><span class="pi">:</span>
    <span class="na">APP_STORE_CONNECT_API_KEY_PATH</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">runner.temp</span><span class="nv"> </span><span class="s">}}/${{</span><span class="nv"> </span><span class="s">env.APP_STORE_CONNECT_API_KEY_FILE_NAME</span><span class="nv"> </span><span class="s">}}"</span>
  <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
    <span class="s">....</span>
</code></pre></div></div>

<p>Fastlane 就能自动取得使用。</p>

<h4 id="技术延伸--reuse-action-workflow-拆分打包和部署动作">技术延伸 — Reuse Action Workflow 拆分打包和部署动作</h4>

<p>在这个案例中我们直接使用 Fastlane <code class="language-plaintext highlighter-rouge">beta</code> Lane 执行打包＋部署两个动作。</p>

<p>在实际案例中我们可能需要将同一包打包结果分别部署到不同平台上(Firebase, Testflight…etc) 因此比较好的做法是打包是一个 Action、部署是一个 Action，不然会重复跑两次打包；而且也更符合 CI/CD 的权责划分。</p>

<blockquote>
  <p><strong><em>以下为范例介绍：</em></strong></p>
</blockquote>

<p><strong>CI-Build.yml:</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Build</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">main</span>
  <span class="na">workflow_call</span><span class="pi">:</span>
     <span class="na">inputs</span><span class="pi">:</span>
        <span class="na">RELEASE_NOTE</span><span class="pi">:</span>
          <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Release</span><span class="nv"> </span><span class="s">notes</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">deployment.'</span>
          <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
          <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">build</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">macos-latest</span>

    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout Code</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Install Dependencies</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">make steup</span>
          <span class="s">make instal</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Build Project</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">bundle exec fastlane build</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Upload Build Artifact</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/upload-artifact@v4</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">name</span><span class="pi">:</span> <span class="s">build-artifact</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s">./fastlane/build/</span>
</code></pre></div></div>

<p><strong>CD-Deploy-Firebase.yml:</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Deploy Firebase</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># 当 Build Action 完成时自动触发执行</span>
  <span class="na">workflow_run</span><span class="pi">:</span>
    <span class="na">workflows</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">Build"</span><span class="pi">]</span>
    <span class="na">types</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">completed</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">deploy</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="c1"># 完成＋执行成功才执行部署</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">${{ github.event.workflow_run.conclusion == 'success' }}</span>

    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout Code</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Install Dependencies</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">make steup</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Download Build Artifact</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/download-artifact@v4</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">name</span><span class="pi">:</span> <span class="s">build-artifact</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s">./fastlane/build/</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy to Production</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">bundle exec fastlane deploy-firebase</span>
</code></pre></div></div>

<p><strong>CD-Deploy-Testflight.yml:</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Deploy Testflight</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># 当 Build Action 完成时自动触发执行</span>
  <span class="na">workflow_run</span><span class="pi">:</span>
    <span class="na">workflows</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">Build"</span><span class="pi">]</span>
    <span class="na">types</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">completed</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">deploy</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="c1"># 完成＋执行成功才执行部署</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">${{ github.event.workflow_run.conclusion == 'success' }}</span>

    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout Code</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Install Dependencies</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">make steup</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Download Build Artifact</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/download-artifact@v4</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">name</span><span class="pi">:</span> <span class="s">build-artifact</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s">./fastlane/build/</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy to Production</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">bundle exec fastlane deploy-testflight</span>
</code></pre></div></div>

<p><strong>另外也可以用 <a href="https://docs.github.com/en/actions/how-tos/sharing-automations/reusing-workflows" target="_blank">Reusing Workflow</a> :</strong></p>

<p><strong>CD-Deploy-Firebase.yml:</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Deploy Firebase</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># 任意的触发条件，这里以手动表单触发为例</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>
    <span class="na">inputs</span><span class="pi">:</span>
      <span class="na">RELEASE_NOTE</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Release</span><span class="nv"> </span><span class="s">notes</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">deployment.'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">build</span><span class="pi">:</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="s">Build</span>
    <span class="na">uses</span><span class="pi">:</span> <span class="s">./.github/workflows/CD-Build.yml</span>
    <span class="na">secrets</span><span class="pi">:</span> <span class="s">inherit</span>
    <span class="na">with</span><span class="pi">:</span>
      <span class="na">RELEASE_NOTE</span><span class="pi">:</span> <span class="s">${{ inputs.RELEASE_NOTE }}</span>

  <span class="na">deploy</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="c1"># Job 预设是并发执行，用 needs 限制需等待 build 完成才执行</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">build</span><span class="pi">]</span>
    <span class="c1"># 执行成功，才部署</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">${{ always() &amp;&amp; needs.deploy.result == 'success' }}</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout Code</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Install Dependencies</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">make steup</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Download Build Artifact</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/download-artifact@v4</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">name</span><span class="pi">:</span> <span class="s">build-artifact</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s">./fastlane/build/</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy to Production</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">bundle exec fastlane deploy-firebase</span>
</code></pre></div></div>

<h4 id="github-actions--artifact">GitHub Actions — Artifact</h4>

<p>同 Cache，目前 <strong>就算是 Self-hosted Runner Artifcact 功能依然会走 GitHub Cloud</strong> 受到使用量限制 ( <a href="https://docs.github.com/en/billing/managing-billing-for-your-products/about-billing-for-github-actions#included-storage-and-minutes" target="_blank">免费帐号 500MB 起</a> )。</p>

<blockquote>
  <p><em>Self-hosted Runner 要达到类似的效果可以自行建立共享主机目录或找其他工具替代。</em></p>
</blockquote>

<p>因此目前 Artifact 实际我只用来存放小资料，例如 Snapshot Tests 的错误结果、测试报告…等等</p>

<h3 id="ci-nightly-build-执行快照单元测试打包cd-部署到-firebase-app-distribution">CI— Nightly Build 执行快照+单元测试+打包+CD 部署到 Firebase App Distribution</h3>

<h4 id="流程-2">流程</h4>

<p>每天凌晨 3 点自动针对 main(develop or master) 分支跑全部测试(unit+snapshot tests)，如果失败则传送失败通知到 Slack 工作群组；如果成功则打包+部署一个版本到 Firebase App Disturbution，打包成功/失败都会传送 Slack 通知。</p>

<h4 id="ci-nightly-build-and-deployyml">CI-Nightly-Build-And-Deploy.yml</h4>

<p>Repo → Actions → New workflow → set up a workflow yourself。</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Workflow(Action) 名称</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">CI-Nightly Build And Deploy</span>

<span class="c1"># Actions Log 的标题名称</span>
<span class="na">run-name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">[CI-Nightly</span><span class="nv"> </span><span class="s">Build</span><span class="nv"> </span><span class="s">And</span><span class="nv"> </span><span class="s">Deploy]</span><span class="nv"> </span><span class="s">${{</span><span class="nv"> </span><span class="s">github.ref</span><span class="nv"> </span><span class="s">}}"</span>

<span class="c1"># 触发事件</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># 排程定时自动执行</span>
  <span class="c1"># https://crontab.guru/</span>
  <span class="c1"># UTC 时间</span>
  <span class="na">schedule</span><span class="pi">:</span>
    <span class="c1"># UTC 的 19:00 = 每天 UTC+8 的 03:00</span>
    <span class="pi">-</span> <span class="na">cron</span><span class="pi">:</span> <span class="s1">'</span><span class="s">0</span><span class="nv"> </span><span class="s">19</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*'</span>
  <span class="c1"># 手动触发</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>

<span class="c1"># Job 工作项目</span>
<span class="c1"># Job 会并发执行</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="c1"># 测试工作</span>
  <span class="na">testing</span><span class="pi">:</span>
    <span class="c1"># Reuse Workflow (workflow_call)</span>
    <span class="na">uses</span><span class="pi">:</span> <span class="s">./.github/workflows/CI-Testing.yml</span>
    <span class="c1"># 传递所有 Secrets 给 CD-Testing.yml</span>
    <span class="na">secrets</span><span class="pi">:</span> <span class="s">inherit</span>
    <span class="na">with</span><span class="pi">:</span>
      <span class="c1"># 执行全部测试</span>
      <span class="na">TEST_LANE</span><span class="pi">:</span> <span class="s2">"</span><span class="s">run_all_tests"</span>
      <span class="c1"># 目标分支：main, develop or master...etc</span>
      <span class="na">BRANCH</span><span class="pi">:</span> <span class="s2">"</span><span class="s">main"</span>

  <span class="na">deploy-env</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">outputs</span><span class="pi">:</span>
      <span class="na">DATE_STRING</span><span class="pi">:</span> <span class="s">${{ steps.get_date.outputs.DATE_STRING }}</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Get Date String</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">get_date</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">VERSION_DATE=$(date -u '+%Y%m%d')</span>
          <span class="s">echo "${VERSION_DATE}"</span>
          <span class="s">echo "DATE_STRING=${VERSION_DATE}" &gt;&gt; $GITHUB_ENV</span>
          <span class="s">echo "DATE_STRING=${VERSION_DATE}" &gt;&gt; $GITHUB_OUTPUT</span>
    
  <span class="na">deploy</span><span class="pi">:</span>
    <span class="c1"># Job 预设是并发执行，用 needs 限制需等待 testing 和 deploy-env 完成才执行</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">testing</span><span class="pi">,</span> <span class="nv">deploy-env</span><span class="pi">]</span>
    <span class="c1"># 如果测试成功才执行</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">${{ needs.testing.result == 'success' }}</span>
    <span class="c1"># Reuse Workflow (workflow_call)</span>
    <span class="na">uses</span><span class="pi">:</span> <span class="s">./.github/workflows/CD-Deploy.yml</span>
    <span class="c1"># 传递所有 Secrets 给 CD-Deploy.yml</span>
    <span class="na">secrets</span><span class="pi">:</span> <span class="s">inherit</span>
    <span class="na">with</span><span class="pi">:</span>
      <span class="na">VERSION_NUMBER</span><span class="pi">:</span> <span class="s">NightlyBuild-${{ needs.deploy-env.outputs.DATE_STRING }}</span>
      <span class="na">RELEASE_NOTE</span><span class="pi">:</span> <span class="s">NightlyBuild-${{ needs.deploy-env.outputs.DATE_STRING }}</span>
      <span class="c1"># 目标分支：main, develop or master...etc</span>
      <span class="na">BRANCH</span><span class="pi">:</span> <span class="s2">"</span><span class="s">main"</span>

<span class="c1"># ----- Slack Notify -----</span>
  <span class="na">testing-failed-slack-notify</span><span class="pi">:</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">testing</span><span class="pi">]</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">${{ needs.testing.result == 'failure' }}</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Post text to a Slack channel</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">slackapi/slack-github-action@v2.1.0</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">method</span><span class="pi">:</span> <span class="s">chat.postMessage</span>
          <span class="na">token</span><span class="pi">:</span> <span class="s">${{ secrets.SLACK_BOT_TOKEN }}</span>
          <span class="na">payload</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">channel</span><span class="err">:</span> <span class="s">${{ vars.SLACK_TEAM_CHANNEL_ID }}</span>
            <span class="s">text</span><span class="err">:</span> <span class="s2">"</span><span class="s">:x:</span><span class="nv"> </span><span class="s">Nightly</span><span class="nv"> </span><span class="s">Build</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">Testing</span><span class="nv"> </span><span class="s">失败</span><span class="se">\n</span><span class="s">Workflow:</span><span class="nv"> </span><span class="s">&lt;${{</span><span class="nv"> </span><span class="s">github.server_url</span><span class="nv"> </span><span class="s">}}/${{</span><span class="nv"> </span><span class="s">github.repository</span><span class="nv"> </span><span class="s">}}/actions/runs/${{</span><span class="nv"> </span><span class="s">github.run_id</span><span class="nv"> </span><span class="s">}}</span><span class="se">\\</span><span class="s">|View</span><span class="nv"> </span><span class="s">Run&gt;"</span>

  <span class="na">deploy-failed-slack-notify</span><span class="pi">:</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">deploy</span><span class="pi">]</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">${{ needs.deploy.result == 'failure' }}</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Post text to a Slack channel</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">slackapi/slack-github-action@v2.1.0</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">method</span><span class="pi">:</span> <span class="s">chat.postMessage</span>
          <span class="na">token</span><span class="pi">:</span> <span class="s">${{ secrets.SLACK_BOT_TOKEN }}</span>
          <span class="na">payload</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">channel</span><span class="err">:</span> <span class="s">${{ vars.SLACK_TEAM_CHANNEL_ID }}</span>
            <span class="s">text</span><span class="err">:</span> <span class="s2">"</span><span class="s">:x:</span><span class="nv"> </span><span class="s">Nightly</span><span class="nv"> </span><span class="s">Build</span><span class="nv"> </span><span class="s">Deploy</span><span class="nv"> </span><span class="s">失败</span><span class="se">\n</span><span class="s">Workflow:</span><span class="nv"> </span><span class="s">&lt;${{</span><span class="nv"> </span><span class="s">github.server_url</span><span class="nv"> </span><span class="s">}}/${{</span><span class="nv"> </span><span class="s">github.repository</span><span class="nv"> </span><span class="s">}}/actions/runs/${{</span><span class="nv"> </span><span class="s">github.run_id</span><span class="nv"> </span><span class="s">}}</span><span class="se">\\</span><span class="s">|View</span><span class="nv"> </span><span class="s">Run&gt;"</span>

  <span class="na">deploy-success-slack-notify</span><span class="pi">:</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">deploy</span><span class="pi">]</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">${{ needs.deploy.result == 'success' }}</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Post text to a Slack channel</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">slackapi/slack-github-action@v2.1.0</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">method</span><span class="pi">:</span> <span class="s">chat.postMessage</span>
          <span class="na">token</span><span class="pi">:</span> <span class="s">${{ secrets.SLACK_BOT_TOKEN }}</span>
          <span class="na">payload</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">channel</span><span class="err">:</span> <span class="s">${{ vars.SLACK_TEAM_CHANNEL_ID }}</span>
            <span class="s">text</span><span class="err">:</span> <span class="s2">"</span><span class="s">:white_check_mark:</span><span class="nv"> </span><span class="s">Nightly</span><span class="nv"> </span><span class="s">Build</span><span class="nv"> </span><span class="s">Deploy</span><span class="nv"> </span><span class="s">成功</span><span class="se">\n</span><span class="s">Workflow:</span><span class="nv"> </span><span class="s">&lt;${{</span><span class="nv"> </span><span class="s">github.server_url</span><span class="nv"> </span><span class="s">}}/${{</span><span class="nv"> </span><span class="s">github.repository</span><span class="nv"> </span><span class="s">}}/actions/runs/${{</span><span class="nv"> </span><span class="s">github.run_id</span><span class="nv"> </span><span class="s">}}</span><span class="se">\\</span><span class="s">|View</span><span class="nv"> </span><span class="s">Run&gt;"</span>
</code></pre></div></div>

<p><strong>Commit 档案到 Repo 主分支，手动触发测试、打包功能看看结果：</strong></p>

<p><img src="/assets/4b001d2e8440/1*l71fL8oLoeAv-JX_FgkqzQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="483" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQ4MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*l71fL8oLoeAv-JX_FgkqzQ.png" /></p>

<blockquote>
  <p><em>日后会每日自动触发。</em></p>
</blockquote>

<p><img src="/assets/4b001d2e8440/1*u6A77KwkXS2SY5-DPPPR9A.webp" alt="Demo" loading="lazy" decoding="async" width="1200" height="802" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*u6A77KwkXS2SY5-DPPPR9A.png" /></p>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/actions/runs/16119750747" target="_blank">Demo</a></p>

<p><img src="/assets/4b001d2e8440/1*6DQL_v4eahSqSuVJZRPrEA.webp" alt="" loading="lazy" decoding="async" width="310" height="92" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMTAiIGhlaWdodD0iOTIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/4b001d2e8440/1*6DQL_v4eahSqSuVJZRPrEA.png" /></p>

<p>等待测试任务、打包部署任务、通知任务都完成后，查看结果。</p>

<p><img src="/assets/4b001d2e8440/1*4UVgyCQljqZQgzxHpXPB4g.webp" alt="" loading="lazy" decoding="async" width="903" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDMiIGhlaWdodD0iOTAwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*4UVgyCQljqZQgzxHpXPB4g.png" /></p>

<p><img src="/assets/4b001d2e8440/1*t9PrQfcTANyvG7gfXXC-bw.webp" alt="" loading="lazy" decoding="async" width="1179" height="2556" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTc5IiBoZWlnaHQ9IjI1NTYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/4b001d2e8440/1*t9PrQfcTANyvG7gfXXC-bw.jpeg" /></p>

<p>我们就能直接在手机上安装 Nightly Build 版本来进行抢先体验测试。</p>

<h4 id="技术细节">技术细节</h4>

<p>这个 Action 我们直接复用前面设计的 CI-Testing 和 CD-Deploy，组合成我们的 Nightly Build，非常弹性好用！</p>

<p><strong>完整程式码： <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/actions/workflows/CI-Nightly-Build-And-Deploy.yml" target="_blank">CI-Nightly-Build-And-Deploy.yml</a></strong></p>

<h3 id="self-hosted-runner-注意事项">Self-hosted Runner 注意事项</h3>

<p>本文是 Public Repo 因此直接使用 GitHub Hosted 的 macOS Runner，但在实际工作上我们的 Repo 一定是 Private，直接使用 GitHub Hosted Runner 超贵不划算(约一个月就能买一台 Mac Mini 放在公司吃到饱爽爽跑)，每一台依照效能可以起多个 Runner 同时并发接任务来做。</p>

<blockquote>
  <p><strong><em>细节可参考 <a href="/posts/zrealm-dev/github-actions-self-hosted-runner-详解与实战案例-ci-cd-自动化工作流程建置-404bd5c70040/">上一篇</a> 「 <a href="/posts/zrealm-dev/github-actions-self-hosted-runner-详解与实战案例-ci-cd-自动化工作流程建置-404bd5c70040/">Self-hosted Runner 建置与改用</a> 」部分</em></strong> <em>，在本地电脑安装好 XCode 跟基本环境后注册、启用 Runner、Action Worflow YAML 中把 <code class="language-plaintext highlighter-rouge">runs-on</code> 改成 <code class="language-plaintext highlighter-rouge">[self-hosted]</code> 即可。</em></p>
</blockquote>

<p>多个 Runner 在同一台电脑的问题，我们多半已在上面的 Actions 里解决了，例如把所有依赖的共用目录都改成本地目录，还有一个测试会遇到的问题要解决，就是抢模拟器问题：「 <strong>当两个测试 Job 被两个 Runner 在同一台机器上同时检来做，如果指定同个模拟器就会互相干扰导致测试失败。」</strong></p>

<p>解决方法也很容易，就是为个别 Runner 都设定一台模拟器。</p>

<h4 id="多个-runner-在同台机器的模拟器设定">多个 Runner 在同台机器的模拟器设定</h4>

<p>假设我 <strong>同一台电脑上有两个 Runner</strong> 在并行接收任务：</p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">ZhgChgLideMacBook-Pro-Runner-A</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">ZhgChgLideMacBook-Pro-Runner-B</code></p>
  </li>
</ul>

<p><img src="/assets/4b001d2e8440/1*3ptg9Tl5fBbEIYB4kgh0kw.webp" alt="" loading="lazy" decoding="async" width="819" height="333" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MTkiIGhlaWdodD0iMzMzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*3ptg9Tl5fBbEIYB4kgh0kw.png" /></p>

<p>在 XCode 模拟器设定我们就需要新增两个模拟器：</p>

<p><img src="/assets/4b001d2e8440/1*k9bR2C12Wk11HAKKiYJ2zg.webp" alt="" loading="lazy" decoding="async" width="1037" height="695" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDM3IiBoZWlnaHQ9IjY5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*k9bR2C12Wk11HAKKiYJ2zg.png" /></p>

<p><img src="/assets/4b001d2e8440/1*iigArewZEW0063Q6xwZn7g.webp" alt="" loading="lazy" decoding="async" width="322" height="281" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMjIiIGhlaWdodD0iMjgxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*iigArewZEW0063Q6xwZn7g.png" /></p>

<ul>
  <li>型号、iOS 版本同测试环境</li>
</ul>

<p><strong>CI-Testing.yml 中测试步骤改成：</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 执行 Fastlane Unit 测试 Lane</span>
      - name: Run Tests
        <span class="nb">id</span>: testing
        <span class="c"># 指定工作目录，这样后续指令就不用在特别 cd ./Product/</span>
        working-directory: ./Product/
        <span class="nb">env</span>:
          <span class="c"># ...</span>
          <span class="c"># Repo -&gt; Settings -&gt; Actions secrets and variables -&gt; variables</span>
          <span class="c"># 模拟器的 iOS 版本</span>
          SIMULATOR_IOS_VERSION: <span class="k">${</span><span class="p">{ vars.SIMULATOR_IOS_VERSION </span><span class="k">}</span><span class="o">}</span>

          <span class="c"># 当前 Runner 名称</span>
          RUNNER_NAME: <span class="k">${</span><span class="p">{ runner.name </span><span class="k">}</span><span class="o">}</span>
          
          <span class="c"># ...</span>
        run: <span class="se">\\</span>|

          <span class="c"># ...</span>
          bundle <span class="nb">exec </span>fastlane <span class="k">${</span><span class="nv">TEST_LANE</span><span class="k">}</span> device:<span class="s2">"</span><span class="k">${</span><span class="nv">RUNNER_NAME</span><span class="k">}</span><span class="s2"> (</span><span class="k">${</span><span class="nv">SIMULATOR_IOS_VERSION</span><span class="k">}</span><span class="s2">)"</span> <span class="se">\\</span>| <span class="nb">tee</span> <span class="s2">"</span><span class="nv">$RUNNER_TEMP</span><span class="s2">/testing_output.txt"</span>
          <span class="c"># ...</span>
</code></pre></div></div>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">device</code> <strong>改成</strong> <code class="language-plaintext highlighter-rouge">${RUNNER_NAME} (${SIMULATOR_IOS_VERSION})</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">SIMULATOR_IOS_VERSION</code> 还是统一看 Repo variables 变数</p>
  </li>
</ul>

<p><strong>组合结果就会是(以 18.4 为例)：</strong></p>

<ul>
  <li>
    <p>Runner: <code class="language-plaintext highlighter-rouge">ZhgChgLideMacBook-Pro-Runner-A</code>
模拟器: <strong>ZhgChgLideMacBook-Pro-Runner-A(18.4)</strong></p>
  </li>
  <li>
    <p>Runner: <code class="language-plaintext highlighter-rouge">ZhgChgLideMacBook-Pro-Runner-B</code>
模拟器: <strong>ZhgChgLideMacBook-Pro-Runner-B(18.4)</strong></p>
  </li>
</ul>

<p>这样两个 Runner 同时在执行测试时就会起两个模拟器自己跑自己的了。</p>

<h4 id="完整专案-repo">完整专案 Repo</h4>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo" target="_blank"><img src="https://opengraph.githubassets.com/ac0aa481002311af0e60721a17f7533f54be5d308c641c48ea717e12a1f3d725/ZhgChgLi/github-actions-ci-cd-demo" alt="" /></a></p>

<h3 id="补充-ssh-agent-设定--for-fastlane-match-or-private-cocoapods-repo">补充 SSH Agent 设定 — For Fastlane Match or Private CocoaPods Repo</h3>

<p>在使用 Fastlane Match 或 Private CocoaPods Repo，因为是在另一个 Private Repo 当中，当前 Repo/Action 环境无法直接 git clone，需要使用 ssh agent 设定好环境，在 Action 执行时才有权限操作。</p>

<h4 id="step-1-产生-ssh-key">Step 1. 产生 SSH Key</h4>

<p><img src="/assets/4b001d2e8440/1*kPWl9hombBgQ15i-n2sY2A.webp" alt="" loading="lazy" decoding="async" width="682" height="483" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2ODIiIGhlaWdodD0iNDgzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*kPWl9hombBgQ15i-n2sY2A.png" /></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-C</span> <span class="s2">"zhgchgli@gmail.com"</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Enter file in which to save the key (/Users/zhgchgli/.ssh/id_ed25519):</code> /Users/zhgchgli/Downloads/zhgchgli</p>

<ul>
  <li>输入到下载路径方便我们拷贝内容</li>
</ul>

<p><code class="language-plaintext highlighter-rouge">Enter passphrase for “/Users/zhgchgli/Downloads/zhgchgli” (empty for no passphrase):</code></p>

<ul>
  <li>
    <p><strong>留空：</strong> CI/CD 使用，无法在 CLI 交互下输入 Passphrase， <strong>因此请留空</strong></p>
  </li>
  <li>
    <p>产生完毕 ( .pub/private_key)</p>
  </li>
</ul>

<p><img src="/assets/4b001d2e8440/1*aF5P6EK9Hfv-CI3MRZ8MCA.webp" alt="" loading="lazy" decoding="async" width="220" height="51" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMjAiIGhlaWdodD0iNTEiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/4b001d2e8440/1*aF5P6EK9Hfv-CI3MRZ8MCA.png" /></p>

<h4 id="step-2-到-private-repo-设定-deploy-key">Step 2. 到 Private Repo 设定 Deploy Key</h4>

<p><img src="/assets/4b001d2e8440/1*3K6JvCHa23QfvWoNq2xdBQ.webp" alt="github-actions-ci-cd-demo-certificates Repo" loading="lazy" decoding="async" width="1172" height="781" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTcyIiBoZWlnaHQ9Ijc4MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*3K6JvCHa23QfvWoNq2xdBQ.jpeg" /></p>

<p>github-actions-ci-cd-demo-certificates Repo</p>

<p>Settings → Security → Deploy keys → Add deploy key。</p>

<ul>
  <li>
    <p>Title: 输入 Key 名称</p>
  </li>
  <li>
    <p>Key: <code class="language-plaintext highlighter-rouge">贴上 .pub Key 内容</code></p>
  </li>
</ul>

<p>完成。</p>

<p><img src="/assets/4b001d2e8440/1*Xo_g-AchEk0j4SGXOmBuxg.webp" alt="" loading="lazy" decoding="async" width="1168" height="814" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTY4IiBoZWlnaHQ9IjgxNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*Xo_g-AchEk0j4SGXOmBuxg.jpeg" /></p>

<h4 id="step-3-回-action-的-repo-设定-ssh-private-key-to-secrets">Step 3. 回 Action 的 Repo 设定 SSH Private Key to Secrets</h4>

<p><img src="/assets/4b001d2e8440/1*Jm92pQHMOImQzZtmmvd1ng.webp" alt="github-actions-ci-cd-demo Repo" loading="lazy" decoding="async" width="1174" height="899" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTc0IiBoZWlnaHQ9Ijg5OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*Jm92pQHMOImQzZtmmvd1ng.jpeg" /></p>

<p>github-actions-ci-cd-demo Repo</p>

<p>Settings → Secrets and variables → Actions → New repository secret。</p>

<ul>
  <li>
    <p>Name: 输入密钥变数名称 <code class="language-plaintext highlighter-rouge">SSH_PRIVATE_KEY</code></p>
  </li>
  <li>
    <p>Secret: <code class="language-plaintext highlighter-rouge">贴上 private_key 内容</code></p>
  </li>
</ul>

<p>完成。</p>

<h4 id="step-4-ssh-agent-设定完成来验证一下-git-clone-private-repo-的权限">Step 4. SSH Agent 设定完成，来验证一下 Git Clone Private Repo 的权限</h4>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/actions/workflows/Demo-Git-Clone-Private-Repo.yml" target="_blank"><strong>Demo-Git-Clone-Private-Repo.yml</strong></a> <strong>:</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Demo Git Clone Private Repo</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">clone-private-repo</span><span class="pi">:</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Git Clone Private Repo</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">30</span>

    <span class="na">steps</span><span class="pi">:</span>
      <span class="c1"># 🔐 启用 SSH Agent 并加入私钥</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Setup SSH Agent</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">webfactory/ssh-agent@v0.9.0</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">ssh-private-key</span><span class="pi">:</span> <span class="s">${{ secrets.SSH_PRIVATE_KEY }}</span>

      <span class="c1"># 🛡️ 将 github.com 加入 known_hosts 以避免 host verification 错误</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Add GitHub to known_hosts</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">mkdir -p ~/.ssh</span>
          <span class="s">ssh-keyscan github.com &gt;&gt; ~/.ssh/known_hosts</span>
      <span class="c1"># 📦 使用 SSH clone private repo 并验证</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Clone and Verify Private Repo</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">git clone git@github.com:ZhgChgLi/github-actions-ci-cd-demo-certificates.git ./fakeMatch/</span>
          <span class="s">if [ -d "./fakeMatch/.git" ]; then</span>
            <span class="s">echo "✅ Repo cloned successfully into ./fakeMatch/"</span>
            <span class="s">cd ./fakeMatch</span>
            <span class="s">echo "📌 Current commit</span><span class="err">:</span> <span class="s">$(git rev-parse --short HEAD)"</span>
          <span class="s">else</span>
            <span class="s">echo "❌ Clone failed. SSH Agent may not be configured properly."</span>
            <span class="s">exit </span><span class="m">1</span>
          <span class="s">fi</span>
</code></pre></div></div>

<p>可以用以上 Action 验证一下是否设定成功。</p>

<p><img src="/assets/4b001d2e8440/1*YLbr7l0FBSOYx_fQT-tiCA.webp" alt="" loading="lazy" decoding="async" width="1200" height="690" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY5MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4b001d2e8440/1*YLbr7l0FBSOYx_fQT-tiCA.png" /></p>

<p>成功，后续 <code class="language-plaintext highlighter-rouge">fastlane match</code> or <code class="language-plaintext highlighter-rouge">pod install</code> private pods 应该就能正确执行。</p>

<h3 id="总结">总结</h3>

<p>这篇文章详细纪录了使用 GitHub Actions 开发完整的 iOS CI/CD 流程，下一篇将优化使用者端(工程师/PM/设计师)体验， <strong>完善 Slack 通知及使用 Google Apps Script Web App 串接 GitHub Actions 打造免费易用的跨团队打包平台工具。</strong></p>

<h3 id="系列文章">系列文章：</h3>

<ul>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-是什么-打造高效稳定开发团队的关键流程与工具选择-c008a9e8ceca/"><strong>CI/CD 实战指南（一）：CI/CD 是什么？如何透过 CI/CD 打造稳定高效的开发团队？工具选择？</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-self-hosted-runner-详解与实战案例-ci-cd-自动化工作流程建置-404bd5c70040/"><strong>CI/CD 实战指南（二）：GitHub Actions 与 self-hosted Runner 使用与建置大全</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/"><strong>CI/CD 实战指南（三）：使用 GitHub Actions 实作 App 专案的 CI 与 CD 工作流程</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/"><strong>CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</strong></a></p>
  </li>
</ul>

<h4 id="-buy-me-a-beer-on-paypal"><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank">🍺 Buy me a beer on PayPal</a></h4>

<blockquote>
  <p><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank"><strong><em>本系列文章花费了大量的时间精力撰写，如果内容对您有帮助、对您的团队有实质提升工作效率与产品品质；欢迎请我喝杯咖啡，感谢支持！</em></strong></a></p>
</blockquote>

<p><img src="/assets/4b001d2e8440/1*QJj54G9gOjtQS-rbHVT1SQ.webp" alt="Buy me a coffee" loading="lazy" decoding="async" width="700" height="700" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDAiIGhlaWdodD0iNzAwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4b001d2e8440/1*QJj54G9gOjtQS-rbHVT1SQ.png" /></p>

<p><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank">🍺 Buy me a beer on PayPal</a></p>]]></content>
  </entry><entry>
    <title type="html">GitHub Actions｜Self-hosted Runner 详解与实战案例｜CI/CD 自动化工作流程建置</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/github-actions-self-hosted-runner-%E8%AF%A6%E8%A7%A3%E4%B8%8E%E5%AE%9E%E6%88%98%E6%A1%88%E4%BE%8B-ci-cd-%E8%87%AA%E5%8A%A8%E5%8C%96%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B%E5%BB%BA%E7%BD%AE-404bd5c70040/" rel="alternate" type="text/html" title="GitHub Actions｜Self-hosted Runner 详解与实战案例｜CI/CD 自动化工作流程建置" />
    <published>2025-07-02T20:22:32+08:00</published>
    <updated>2025-07-12T22:49:01+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/404bd5c70040</id><summary type="html">针对开发团队自动化需求，解析 GitHub Actions 与 Self-hosted Runner 架构与设定，并透过三大实战案例教你快速建立自动标记 PR、指派负责人及每日 PR 统计通知，提升 CI/CD 执行效率与成本优化。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="simplified-chinese" /><category term="ios-app-development" /><category term="cicd" /><category term="github-actions" /><category term="github" /><category term="self-hosted" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/404bd5c70040/1*_vGYh_XSI3ZDbdeT8xCihA.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/github-actions-self-hosted-runner-%E8%AF%A6%E8%A7%A3%E4%B8%8E%E5%AE%9E%E6%88%98%E6%A1%88%E4%BE%8B-ci-cd-%E8%87%AA%E5%8A%A8%E5%8C%96%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B%E5%BB%BA%E7%BD%AE-404bd5c70040/"><![CDATA[<h3 id="cicd-实战指南二github-actions-与-self-hosted-runner-使用与建置大全">CI/CD 实战指南（二）：GitHub Actions 与 Self-hosted Runner 使用与建置大全</h3>

<p>带您从头了解 GitHub Actions/Self-hosted Runner 运作方式与手把手使用教学。</p>

<p><img src="/assets/404bd5c70040/1*_vGYh_XSI3ZDbdeT8xCihA.webp" alt="Photo by Dan Taylor" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*_vGYh_XSI3ZDbdeT8xCihA.jpeg" /></p>

<p>Photo by <a href="https://unsplash.com/@theoneandonlydantaylor?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank">Dan Taylor</a></p>

<h4 id="前言">前言</h4>

<p>前篇「 <a href="/posts/zrealm-dev/ci-cd-是什么-打造高效稳定开发团队的关键流程与工具选择-c008a9e8ceca/"><strong>CI/CD 实战指南（一）：CI/CD 是什么？如何透过 CI/CD 打造稳定高效的开发团队？工具选择？</strong></a> 」我们介绍了 CI/CD 是什么？能带来哪些效益与工具的选择， <strong>这篇将著重在 GitHub Actions, Self-hosted Runner 的架构与使用介绍</strong> ，并手把手一起建立几个有趣的自动化工作流程，带您慢慢上手。</p>

<h3 id="github-actions-架构流程图">GitHub Actions 架构流程图</h3>

<p>在开始之前我们先来确定一下 GitHub Actions 的运作架构流程关系与职责。</p>

<p><img src="/assets/404bd5c70040/1*iacfyTX_b3YTSzMcn2ldjw.webp" alt="" loading="lazy" decoding="async" width="1200" height="803" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*iacfyTX_b3YTSzMcn2ldjw.png" /></p>

<h4 id="github-repo"><strong>GitHub Repo</strong></h4>

<ul>
  <li>在 GitHub Actions 的世界里，所有 Actions (Workflow YAML 档案) 都要存放在某个 Git Repo 之中 ( <code class="language-plaintext highlighter-rouge">REPO/.github/workflows/</code> )</li>
</ul>

<h4 id="github-repo-actions-secrets">GitHub Repo —Actions Secrets</h4>

<p>Repo → Settings → Secrets and variables → Actions → Secrets。</p>

<ul>
  <li>
    <p>存放 Actions 步骤中会用到的 Secret Key, Token
e.g. Slack Bot Token、Apple Store Connect API .p8 Key</p>
  </li>
  <li>
    <p><strong>Secrets 内容无法在 Action Log 中查看，会自动用 * * * * 隐蔽</strong></p>
  </li>
  <li>
    <p>Secrets 内容无法查看、编辑，只能覆盖</p>
  </li>
  <li>Secrets <strong>目前只支援纯文字内容，无法上传档案</strong>
<strong>-</strong> 如果是二进制的金要请参考 <a href="https://docs.github.com/en/actions/how-tos/security-for-github-actions/security-guides/using-secrets-in-github-actions#storing-base64-binary-blobs-as-secrets" target="_blank">官方步骤使用 Base64 编码转换后储存</a> 。
    <ul>
      <li>iOS 开发凭证储存方式可参考官方教学： <a href="https://docs.github.com/en/actions/how-tos/use-cases-and-examples/deploying/installing-an-apple-certificate-on-macos-runners-for-xcode-development" target="_blank">Installing an Apple certificate on macOS runners for Xcode development</a></li>
    </ul>
  </li>
  <li>可以储存组织层级的 Secrets，跨 Repo 共享</li>
</ul>

<h4 id="github-repo--actions-variables">GitHub Repo — Actions Variables</h4>

<p>Repo → Settings → Secrets and variables → Actions → Variables。</p>

<ul>
  <li>
    <p>存放 Actions 步骤中常用到的变数
e.g. 模拟器 iOS 版本、工作目录</p>
  </li>
  <li>
    <p>Variables 内容可以查看、编辑</p>
  </li>
  <li>
    <p>Variables 内容可以输出在 Action Log 中</p>
  </li>
  <li>
    <p>Variables 只支援纯文字，也可存放 json 字串然后自己解析使用</p>
  </li>
  <li>
    <p>可以储存组织层级的 Variables，跨 Repo 共享</p>
  </li>
</ul>

<h4 id="github-actions--trigger">GitHub Actions — Trigger</h4>

<ul>
  <li>
    <p><strong>Github Action 中最重要的起始点 — 触发事件(条件)</strong></p>
  </li>
  <li>
    <p>符合触发事件的 GitHub Actions 才会触发执行</p>
  </li>
  <li>
    <p>完整事件列表可 <a href="https://docs.github.com/en/actions/reference/events-that-trigger-workflows" target="_blank">参考官方文件</a></p>
  </li>
  <li>
    <p>基本上涵盖了所有 CI/CD、自动化会遇到的事件场景。
但 <strong>如果有特殊场景没有事件，那就只能用其他事件+在 Job 中判断组合或是用 Schedule 排程手动检查了</strong> 。
e.g. 例如没有 PR Merged 事件，就只能用 <code class="language-plaintext highlighter-rouge">pull_request: closed</code> + Job <code class="language-plaintext highlighter-rouge">if: github.event.pull_request.merged == true</code> 达成</p>
  </li>
</ul>

<p><strong>常用事件：</strong></p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">schedule</code> (cron)：排程定时执行(同 crontab)
可以用来做自动化：定时检查 PR、定时打包、定时执行自动化脚本
<strong>统一都在 main / develop (Default Branch) 执行。</strong></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">pull_request:</code> ：PR 相关事件
当 PR 开启时、PR Assign 时、加 Label 时、有新 Push Commit 时…等等</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">issues</code> 、 <code class="language-plaintext highlighter-rouge">issue_comment</code> ：Issue 相关事件
当 Issue 开启时、有新留言时…等等</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">workflow_dispatch</code> ：手动触发；可以设定需要提供的栏位，GitHub Actions 提供简易的表单让使用者可以填写资讯。
e.g.:</p>
  </li>
</ul>

<p><img src="/assets/404bd5c70040/1*XogIJsCbrNPerWBto_PG8w.webp" alt="" loading="lazy" decoding="async" width="332" height="432" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMzIiIGhlaWdodD0iNDMyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*XogIJsCbrNPerWBto_PG8w.png" /></p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">workflow_call</code> ：触发另一个 Action(Workflow) 执行任务。</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">workflow_run</code> ：当别的 Action(Workflow) 执行任务，触发执行此任务。</p>
  </li>
</ul>

<blockquote>
  <p><em>更多事件类型、设定细节请 <a href="https://docs.github.com/en/actions/reference/events-that-trigger-workflows" target="_blank">参考官方文件</a> 。</em></p>
</blockquote>

<h4 id="github-actions--workflow"><strong>GitHub Actions — Workflow</strong></h4>

<ul>
  <li>
    <p>a.k.a Action</p>
  </li>
  <li>
    <p>使用 YAML 撰写 .yaml 档案，档案统一放置在 <code class="language-plaintext highlighter-rouge">REPO/.github/workflows/</code> 之下</p>
  </li>
  <li>
    <p><strong>以主分支内的 Workflow YAML 档案为主</strong>
如果在其他分支看不到正在开发的 Action 或执行上有误，可以先 Merge 回主分支看看。</p>
  </li>
  <li>
    <p>GitHub Actions 中的最基础单位，每个 Workflow 就代表一项 CI/CD 或自动化操作</p>
  </li>
  <li>
    <p>Workflow 可以呼叫别的 Workflow 执行任务
(可以利用这个特性拆出核心 Workflow 和呼叫的 Workflow)</p>
  </li>
  <li>
    <p>当中会定义任务名称、执行策略、触发事件、任务工作…等等所有 Action 相关设定</p>
  </li>
  <li>
    <p>目前档案结构不支援子目录</p>
  </li>
  <li>
    <p>Action 完全免费 (Public and Private Repo)</p>
  </li>
</ul>

<h4 id="github-actions--workflow--job">GitHub Actions — Workflow — Job</h4>

<ul>
  <li>
    <p>GitHub Actions 中的执行单位</p>
  </li>
  <li>
    <p>定义 Workflow 中的任务工作有哪些</p>
  </li>
  <li>
    <p>每个 Workflow 可以有多个 Jobs</p>
  </li>
  <li>
    <p>每个 Job 需要指定使用哪个 Runner Label，执行的时候会使用对应的 Runner 机器来执行任务</p>
  </li>
  <li>
    <p><strong>多个 Jobs 是并发执行</strong> (如有顺序可以用 <code class="language-plaintext highlighter-rouge">needs</code> 约束)</p>
  </li>
  <li>
    <p><strong>每个 Job 应该视为独立执行个体(每个都要当成是 Sandbox)</strong> ，Job 结束后如果有产出资源档案要给后续其他 Job/Workflow 使用，需要 Upload Artifacts 或在 self-hosted 移动到共用产出目录。</p>
  </li>
  <li>
    <p>Job 做完可以 Output 字串给其他 Job 参考使用。
(例如执行结果 true or false)</p>
  </li>
  <li>
    <p>没特别设流程条件的话，多个 Job 如果其中有 Job 发生错误， <strong>其他 Job 依然会继续执行</strong></p>
  </li>
</ul>

<h4 id="github-actions--reuse-workflowjob">GitHub Actions — Reuse Workflow/Job</h4>

<ul>
  <li>
    <p>Workflow 定义 <code class="language-plaintext highlighter-rouge">on: workflow_call</code> 就能封装给其他 Workflow 当成 Job 复用</p>
  </li>
  <li>
    <p>同个组织下可以跨 Repo 分享使用</p>
  </li>
  <li>
    <p>因此可以把跨 Repo 共用的 CI/CD 工作放到共享的 Repo 一起使用</p>
  </li>
</ul>

<h4 id="github-actions--workflow--job--step">GitHub Actions — Workflow — Job — Step</h4>

<ul>
  <li>
    <p>GitHub Actions 中的最小执行项目</p>
  </li>
  <li>
    <p>Job 中实际执行任务的程式</p>
  </li>
  <li>
    <p>每个 Job 可以有多个 Steps</p>
  </li>
  <li>
    <p><strong>多个 Steps 是照顺序执行</strong></p>
  </li>
  <li>
    <p>Step 做完可以 Output 字串给后续 Steps 参考使用。</p>
  </li>
  <li>
    <p><strong>Step 可以直接撰写 shell script 程式</strong>
可以引用 <a href="https://cli.github.com/manual/gh" target="_blank">gh cli</a> 、当前环境变数(例如取得 PR 编号)，直接做想做的事</p>
  </li>
  <li>
    <p>没特别设流程条件的话，Step 如果发生错误， <strong>会直接中断</strong> ，后续的 Steps 不会执行</p>
  </li>
</ul>

<h4 id="github-actions--workflow--job--reuse-action-step">GitHub Actions — Workflow — Job — Reuse Action Step</h4>

<ul>
  <li>
    <p><strong>可以直接复用 <a href="https://github.com/marketplace?type=actions" target="_blank">Marketplace</a> 上各路大神包好的现有工作步骤。</strong>
例如： <a href="https://github.com/marketplace/actions/comment-pull-request" target="_blank">Comment 内容到 PR</a> 。</p>
  </li>
  <li>
    <p>也可以将自己一系列的工作任务 Step 打包成一个 Action GitHub Repo 让其他工作直接复用</p>
  </li>
  <li>
    <p>Public Repo 的 Action 可以上架到 Marketplace</p>
  </li>
</ul>

<p><strong>打包 Action 支援使用：</strong></p>

<ul>
  <li>
    <p><strong>Docker Action</strong> — 代表 GitHub Actions 会把环境变数传到 Docker 容器中，再看你要怎么处理，可以是 shell script、Java、PHP…etc.</p>
  </li>
  <li>
    <p><strong>JavaScript/TypeScript Action</strong> — 直接使用 node.js 撰写 GitHub Actions 处理逻辑，同样的会把环境变数都传给你参考使用。
e.g. <a href="https://github.com/pozil/auto-assign-issue/blob/v2/action.yml" target="_blank">pozil/auto-assign-issue</a></p>
  </li>
  <li>
    <p><strong>Composite (YAML) —</strong> 纯 YAML 描述任务步骤 (同 GitHub Actions — Workflow — Job — Step) 可以宣告有哪写步骤要做或直接在上面写 shell script。
e.g. <a href="https://github.com/ZhgChgLi/ZReviewTender/blob/main/action.yml" target="_blank">ZhgChgLi/ZReviewTender</a></p>
  </li>
</ul>

<blockquote>
  <p><em>碍于篇幅，本篇文章不会介绍如何打包 Github Actions Action，有兴趣可以参考官方文件： <a href="https://docs.github.com/en/actions/tutorials/creating-a-composite-action" target="_blank">tutorials/creating-a-composite-action</a> 。</em></p>
</blockquote>

<h4 id="github-runner">GitHub Runner</h4>

<ul>
  <li>
    <p>GitHub 会根据 Runner Label 派发对应的 Job 给 Runner 执行</p>
  </li>
  <li>
    <p>Runner 只做为监听者，轮询监听 GitHub 派发任务</p>
  </li>
  <li>
    <p>只关心 Job 不关心是哪个 Action(Workflow)
因此会出现 Action A 的 Job-1 执行完，下一个换 Action B 的 Job-1，而不是 Action A 的 Jobs 都执行完才换 Action B。</p>
  </li>
  <li>
    <p>Runner 可以使用 GitHub Hosted Runner 或 Self-hosted Runner。</p>
  </li>
</ul>

<h4 id="github-hosted-runner"><strong>GitHub Hosted Runner</strong></h4>

<ul>
  <li>GitHub 提供的 Runner，可参考官方 Repo 列表：</li>
</ul>

<p><a href="https://github.com/actions/runner-images" target="_blank"><img src="https://opengraph.githubassets.com/b479f2537a0d7620cc8bed955bf9331e739ee02383a1715546a26bc35390a494/actions/runner-images" alt="" /></a></p>

<p><img src="/assets/404bd5c70040/1*KtQV4kDCWscEeaZ8jQI8Dg.webp" alt="2025/06 的 Images 列表" loading="lazy" decoding="async" width="1200" height="1154" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjExNTQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/404bd5c70040/1*KtQV4kDCWscEeaZ8jQI8Dg.png" /></p>

<p><a href="https://github.com/actions/runner-images" target="_blank">2025/06 的 Images 列表</a></p>

<ul>
  <li>Runner 预先安装了什么可以点进去查看：
e.g. <a href="https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md" target="_blank">macos-14-arm64</a></li>
</ul>

<p><img src="/assets/404bd5c70040/1*svXtXH78-TvK1C_XXCyYLA.webp" alt="macos-14-arm64" loading="lazy" decoding="async" width="1400" height="780" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijc4MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*svXtXH78-TvK1C_XXCyYLA.png" /></p>

<p><a href="https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md" target="_blank">macos-14-arm64</a></p>

<ul>
  <li>
    <p>iOS 开发优先使用 -arm64 (M系列) 处理器的 Runner，跑起来比较快</p>
  </li>
  <li>
    <p>只要在 Job <code class="language-plaintext highlighter-rouge">run-on</code> 贴上表格上的 YAML Label，就能使用该 Runner 执行任务</p>
  </li>
  <li>
    <p><strong>Public Repo 收费方式: 完全免费无限使用</strong></p>
  </li>
  <li>
    <p><strong>️</strong> Private Repo 免费额度:
免费额度(依照帐号不同额度不同，以 GitHub Free 为例)：
用量：每月免费 2,000 分钟
储存：500 MB</p>
  </li>
  <li>
    <p><strong>⚠️️Private Repo 计费方式:</strong>
<strong>超过免费额度之后开始用用量计费(可设上限跟通知)，依照 Runner 所属的机器作业系统、核心不同，价格也不同：</strong></p>
  </li>
</ul>

<p><img src="/assets/404bd5c70040/1*rkhRJN4ZRas_lDOJh-pjkQ.webp" alt="about-billing-for-github-actions" loading="lazy" decoding="async" width="1064" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDY0IiBoZWlnaHQ9IjEyMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/404bd5c70040/1*rkhRJN4ZRas_lDOJh-pjkQ.png" /></p>

<p><a href="https://docs.github.com/en/billing/managing-billing-for-your-products/about-billing-for-github-actions" target="_blank">about-billing-for-github-actions</a></p>

<p>可以看到 macOS 的价格因为设备成本很高所以贵。</p>

<ul>
  <li>最多并发任务数限制：</li>
</ul>

<p><img src="/assets/404bd5c70040/1*LU3zGSBe57NBVMfDwl0wdQ.webp" alt="usage-limits-billing-and-administration" loading="lazy" decoding="async" width="1200" height="490" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQ5MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*LU3zGSBe57NBVMfDwl0wdQ.png" /></p>

<p><a href="https://docs.github.com/en/actions/concepts/overview/usage-limits-billing-and-administration#usage-limits" target="_blank">usage-limits-billing-and-administration</a></p>

<blockquote>
  <p><em>这边扯太多了，我们的重点是 Self-hosted Runner。</em></p>
</blockquote>

<h4 id="self-hosted-runner-on-in-house-server">Self-hosted Runner on In-house Server</h4>

<ul>
  <li>
    <p>将自己的机器作为 Runner</p>
  </li>
  <li>
    <p><strong>一台实体机器可以起多个 Runner 并发接任务来做</strong></p>
  </li>
  <li>
    <p><strong>免费无限量无限制使用</strong>
只有机器购买成本，花一次使用到饱！
以 32G RAM M4 Mini (=NT$40,900) 计算，如果用 GitHub Hosted Runner 一个月要花 500 USD； <strong>买一台架设好用超过三个月就回本</strong> 了！</p>
  </li>
  <li>
    <p>支援 Windows, macOS, Linux (x64/ARM/ARM64)</p>
  </li>
  <li>
    <p><strong>同个组织可以跨 Repo 共享 Runner</strong></p>
  </li>
  <li>
    <p><strong>⚠️目前：actions/cache, actions/upload-artifact, actions/download-artifact 都只支援 GitHub 云端服务，代表这些内容还是会上传到 GitHub 伺服器并计算储存量收费。</strong>
可以在自己的机器上开共用目录取代。</p>
  </li>
  <li>
    <p>Self-hosted Runner 也支援 <a href="https://docs.github.com/en/actions/concepts/runners/about-actions-runner-controller" target="_blank">Docker, k8s</a> 只是我没研究。</p>
  </li>
</ul>

<blockquote>
  <p><strong><em>架设 Self-hosted Runner 只需几步 (10 分钟内设定好) 就能上线开始接任务执行(本文稍后会介绍)。</em></strong></p>
</blockquote>

<h4 id="github-workflow-x-job-x-step-x-runner-流程关系图">GitHub Workflow x Job x Step x Runner 流程关系图</h4>

<p><img src="/assets/404bd5c70040/1*WHIVfXdVRoEsdXGfJhu2Rw.webp" alt="" loading="lazy" decoding="async" width="1200" height="730" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjczMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*WHIVfXdVRoEsdXGfJhu2Rw.png" /></p>

<p>这边用一张图总结工作流程与关系，假设我们有两个 Workflow、两个 Runner:</p>

<ul>
  <li>
    <p>CI —假设 R有 3 个 Jobs，每个 Job 各有几个 Steps，Runner Label(run-on) — <code class="language-plaintext highlighter-rouge">self-hosted-app</code></p>
  </li>
  <li>
    <p>CD — 有 4 个 Jobs，每个 Job 各有几个 Steps，Runner Label(run-on) — <code class="language-plaintext highlighter-rouge">self-hosted-app</code></p>
  </li>
  <li>
    <p>Runner — 有 2 个，Runner Label 也都是— <code class="language-plaintext highlighter-rouge">self-hosted-app</code></p>
  </li>
</ul>

<p>同前述，Runner 跟 Workflow 是依照 Runnler Label 来派发、接收任务来做，这个案例都是用同个 <code class="language-plaintext highlighter-rouge">self-hosted-app</code> Runner Label，Workflow 的 Jobs 预设是并发执行、Steps 是每个 Job 的实际执行内容，串行照顺序执行，Steps 都执行完等于 Job 执行完毕。</p>

<blockquote>
  <p><strong><em>因此 Workflow 实际执行的时间轴会是在两个 Runner 之间穿梭执行 Job，也会并发执行、当前 Job 执行完下一个也不一定是接著同个 Worflow 的下一个 Job。</em></strong></p>
</blockquote>

<blockquote>
  <p><em>⚠️ 所以才说确保每个 Job 是独立的很重要 (尤其在 Self-hosted Runner 环境之下，Job 结束之后可能不会清除的太干净，我们可能会下意识觉得这个 Job 的产出，下一个 Job 可以接著做事)，不应该这样用。</em></p>
</blockquote>

<h4 id="如果-job-有产出要给后续的-job-使用">如果 Job 有产出要给后续的 Job 使用:</h4>

<ul>
  <li>
    <p><strong>Job Output String</strong> : 输出纯文字到变数给其他 Job 引用</p>
  </li>
  <li>
    <p><strong>Artifact-upload/download:</strong> Job 的 Step 最后一步将执行结果上传到 GitHub Artifact，另一个 Job 的第一个 Step 下载回来继续处理使用。
e.g. 例如 Job — 打包 → 将打包结果 .ipa 传到 <strong>Artifact →</strong> Job — 部署 → 下载回来 .ipa → 上传 App Store 部署
要注意： <strong>目前就算是 Self-hosted 也是会上 GitHub Artifact 云储存。</strong></p>
  </li>
  <li>
    <p><strong>AWS/GCP…云端储存</strong> : 同上，只是是用自己的云端储存服务。</p>
  </li>
  <li>
    <p><strong>[Self-hosted Only] 共用硬碟、目录:</strong> Self-hosted Runner 如果都有挂载一个共用目录，则可用这个目录依照 UUID 建立资料夹存放产出结果，然后后续 Job 去读取前一个 Job Output UUID 去找到对应的储存再拿回来用。
要注意，不同主机的 Runner 也都要挂载同个共用目录。</p>
  </li>
  <li>
    <p>在同个 Job 的 Steps 把所有事情做完。</p>
  </li>
</ul>

<h3 id="做中学-github-actions--案例实作">做中学 GitHub Actions — 案例实作</h3>

<p>「坐而言，不如起而行」以上名词解释跟流程架构介绍相信大家也是看得懵懵懂懂，接下来会直接举三个功能例子，带大家实际动手做，并一边解释碰到的东西，从做当中学习，以了解 GitHub Actions 到底是什么。</p>

<h3 id="案例--1">案例 — 1</h3>

<p>建立 Pull Request 后自动标记 File Changes Size Label 让 Reviewer 方便安排 Review 工作。</p>

<h4 id="成果图">成果图</h4>

<p><img src="/assets/404bd5c70040/1*vjSWeu2zB-hmVpfziMDR5Q.webp" alt="Demo PR" loading="lazy" decoding="async" width="774" height="206" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NzQiIGhlaWdodD0iMjA2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*vjSWeu2zB-hmVpfziMDR5Q.png" /></p>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/pull/11" target="_blank">Demo PR</a></p>

<h4 id="运作流程">运作流程</h4>

<ul>
  <li>
    <p>使用者开 PR、重开 PR、Push 新 Commit 到 PR</p>
  </li>
  <li>
    <p>触发 GitHub Actions Workflow</p>
  </li>
  <li>
    <p>shell script 取的 file changes 数量</p>
  </li>
  <li>
    <p>判断数量对 PR 标记上 Label</p>
  </li>
  <li>
    <p>完成</p>
  </li>
</ul>

<h4 id="动手做">动手做</h4>

<p>Repo → Actions → New workflow → set up a workflow yourself。</p>

<p><strong>档案名称：</strong> <code class="language-plaintext highlighter-rouge">Automation-PullRequest.yml</code></p>

<p>Action Workflow 可以每个任务独立一个档案，也可以依照触发事件、目的，同个目的聚合在同个档案，反正多个 Job 是并发执行的，另外 <strong>因为 GitHub Actions 暂时不支援目录结构，所以档案少一点、使用阶层命名档案会比较好管理</strong> 。</p>

<p>这边把 PR 相关事件的 Actions 都放在同个 Workflow。</p>

<h4 id="automation-pullrequestyml"><code class="language-plaintext highlighter-rouge">Automation-PullRequest.yml</code></h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Workflow(Action) 名称</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Pull Reqeust Automation</span>

<span class="c1"># Actions Log 的标题名称</span>
<span class="na">run-name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">[Pull</span><span class="nv"> </span><span class="s">Reqeust</span><span class="nv"> </span><span class="s">Automation]</span><span class="nv"> </span><span class="s">${{</span><span class="nv"> </span><span class="s">github.event.pull_request.title</span><span class="nv"> </span><span class="se">\\</span><span class="s">|</span><span class="se">\\</span><span class="s">|</span><span class="nv"> </span><span class="s">github.ref</span><span class="nv"> </span><span class="s">}}"</span>

<span class="c1"># 触发事件</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># PR 事件</span>
  <span class="na">pull_request</span><span class="pi">:</span>
    <span class="c1"># PR - 开启、重开、有新 Push Commit 时</span>
    <span class="na">types</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">opened</span><span class="pi">,</span> <span class="nv">synchronize</span><span class="pi">,</span> <span class="nv">reopened</span><span class="pi">]</span>


<span class="c1"># 同个 Concurrency Group 如果有新的 Job 会取消正在跑的</span>
<span class="c1"># 例如 Push Commit 触发的任务还没执行就又 Push Commit 时，会取消前一个任务</span>
<span class="na">concurrency</span><span class="pi">:</span>
  <span class="na">group</span><span class="pi">:</span> <span class="s">${{ github.workflow }}-${{ github.ref_name }}</span>
  <span class="na">cancel-in-progress</span><span class="pi">:</span> <span class="kc">true</span>

<span class="c1"># Job 工作项目</span>
<span class="c1"># Job 会并发执行</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="c1"># Job ID</span>
  <span class="na">label-pr-by-file-count</span><span class="pi">:</span>
    <span class="c1"># Job 名称 (可省略，有设定在 Log 显示比较好读)</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Label PR by changes file count</span>

    <span class="c1"># 如果这个 Job 失败，不影响整个 Workflow，继续其他 Job</span>
    <span class="na">continue-on-error</span><span class="pi">:</span> <span class="kc">true</span>
    
    <span class="c1"># 设定最长 Timeout 时间，防止异常情况发生时无止尽的等待</span>
    <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">10</span>

    <span class="c1"># Runner Label - 使用 GitHub Hosted Runner ubuntu-latest 来执行工作</span>
    <span class="c1"># 如果是 Private Repo 会计算用量，超过可能会产生费用</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>

    <span class="c1"># 工作步骤</span>
    <span class="c1"># 工作步骤会照顺序执行</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="c1"># 步骤名称</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Get changed file count and apply label</span>
        <span class="c1"># 步骤 ID (可省略，后续若没有 Step 要引用 Output 输出则不需设定)</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">get-changed-files-count-by-gh</span>
        <span class="c1"># 注入外部环境参数到执行阶段</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="c1"># secrets.GITHUB_TOKEN 是 GitHub Actions 执行时自动产生的 Token，不需自行在 Secrets 设定，拥有一些 GitHub Repo API Scopes 权限</span>
          <span class="c1"># https://docs.github.com/en/actions/how-tos/security-for-github-actions/security-guides/use-github_token-in-workflows</span>
          <span class="c1"># gh(GitHub) cli 需要注入 GH_TOKEN 到 ENV，gh 才有权限操作  </span>
          <span class="na">GH_TOKEN</span><span class="pi">:</span> <span class="s">${{ secrets.GITHUB_TOKEN }}</span>
        <span class="c1"># Shell script</span>
        <span class="c1"># GitHub Hosted Runner 内建都有安装好 gh cli，不需要安装 Job 就能直接使用</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">#   ${{ github.xxx }} 是 GitHub Actions Context 表达式</span>
          <span class="s">#   不是 Shell 变数，而是 YAML 解析阶段由 GitHub Actions 替换成对应值</span>
          <span class="s">#   其他参数：https://docs.github.com/en/actions/learn-github-actions/contexts#github-context</span>
          
          <span class="s"># 取得 PR 编号</span><span class="err">:</span>
          <span class="s">PR_NUMBER=${{ github.event.pull_request.number }}</span>

          <span class="s"># 取得 Repo</span><span class="err">:</span>
          <span class="s">REPO=${{ github.repository }}</span>

          <span class="s"># 使用 GitHub API (gh cli) 取得 File changed 数量</span>
          <span class="s">FILE_COUNT=$(gh pr view $PR_NUMBER --repo $REPO --json files --jq '.files \\| length')</span>
          
          <span class="s"># Print Log</span>
          <span class="s">echo "Changed file count</span><span class="err">:</span> <span class="s">$FILE_COUNT"</span>

          <span class="s"># Label 逻辑</span>
          <span class="s">if [ "$FILE_COUNT" -lt 5 ]; then</span>
            <span class="s">LABEL="XS"</span>
          <span class="s">elif [ "$FILE_COUNT" -lt 10 ]; then</span>
            <span class="s">LABEL="S"</span>
          <span class="s">elif [ "$FILE_COUNT" -lt 30 ]; then</span>
            <span class="s">LABEL="M"</span>
          <span class="s">elif [ "$FILE_COUNT" -lt 80 ]; then</span>
            <span class="s">LABEL="L"</span>
          <span class="s">elif [ "$FILE_COUNT" -lt 200 ]; then</span>
            <span class="s">LABEL="XL"</span>
          <span class="s">else</span>
            <span class="s">LABEL="XXL"</span>
          <span class="s">fi</span>

          <span class="s"># 使用 GitHub API (gh cli) 移除目前的 Size Label</span>
          <span class="s">EXISTING_LABELS=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json labels --jq '.labels[].name')</span>
          <span class="s">for EXISTING in $EXISTING_LABELS; do</span>
            <span class="s">case "$EXISTING" in</span>
              <span class="s">XS\\|S\\|M\\|L\\|XL\\|XXL)</span>
                <span class="s">echo "🧹 Removing existing label</span><span class="err">:</span> <span class="s">$EXISTING"</span>
                <span class="s">gh pr edit "$PR_NUMBER" --repo "$REPO" --remove-label "$EXISTING"</span>
                <span class="s">;;</span>
            <span class="s">esac</span>
          <span class="s">done</span>

          <span class="s"># (可选)如果 Label 不存在则建立</span>
          <span class="s">if ! gh label list --repo "$REPO" \\| grep -q "^$LABEL"; then</span>
            <span class="s">echo "🆕 Creating missing label</span><span class="err">:</span> <span class="s">$LABEL"</span>
            <span class="s">gh label create "$LABEL" --repo "$REPO" --description "Size label</span><span class="err">:</span> <span class="s">$LABEL" --color "ededed"</span>
          <span class="s">else</span>
            <span class="s">echo "✅ Label '$LABEL' already exists"</span>
          <span class="s">fi</span>
          
          <span class="s"># 使用 GitHub API (gh cli) 标记上 Label</span>
          <span class="s">gh pr edit $PR_NUMBER --repo $REPO --add-label "$LABEL"</span>
</code></pre></div></div>

<p>Commit 档案到 Repo 主分支之后，我们再开新 PR 就会自动触发 GitHub Actions：</p>

<p><img src="/assets/404bd5c70040/1*wdAztL0BgPeSZdqXxqUEXg.webp" alt="" loading="lazy" decoding="async" width="938" height="744" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzgiIGhlaWdodD0iNzQ0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*wdAztL0BgPeSZdqXxqUEXg.png" /></p>

<p>Action 执行状态显示 <strong>Queued</strong> 代表任务正在等待 Runner 接任务回去做。</p>

<h4 id="执行结果">执行结果</h4>

<p><img src="/assets/404bd5c70040/1*-JoD8IQYHVrDqHmLmrXyaQ.webp" alt="Demo PR" loading="lazy" decoding="async" width="1338" height="948" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzM4IiBoZWlnaHQ9Ijk0OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*-JoD8IQYHVrDqHmLmrXyaQ.png" /></p>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/pull/11" target="_blank">Demo PR</a></p>

<p>执行完毕并且成功后 PR 上就会自动标记好对应的 Label 了！纪录会显示由 <code class="language-plaintext highlighter-rouge">github-actions</code> 标记。</p>

<p><strong>完整程式码： <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/Automation-PullRequest.yml" target="_blank">Automation-PullRequest.yml</a></strong></p>

<h4 id="直接使用别人包好的-action-步骤-pascalgnsize-label-action">直接使用别人包好的 Action 步骤： <a href="https://github.com/pascalgn/size-label-action/tree/main" target="_blank">pascalgn/size-label-action</a></h4>

<p>前面有说到可以直接使用别人封装好的 Action，标记 PR Size Label 这任务已经有现成的轮子可以使用，上述只是为了教学目的，实际上不需要自己重造轮子。</p>

<p>只需要在 Action Workflow Job Step 中直接使用就能完成任务：</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Workflow(Action) 名称</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Pull Reqeust Automation</span>

<span class="c1"># 触发事件</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># PR 事件</span>
  <span class="na">pull_request</span><span class="pi">:</span>
    <span class="c1"># PR - 开启、重开、有新 Push Commit 时</span>
    <span class="na">types</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">opened</span><span class="pi">,</span> <span class="nv">synchronize</span><span class="pi">,</span> <span class="nv">reopened</span><span class="pi">]</span>


<span class="c1"># 同个 Concurrency Group 如果有新的 Job 会取消正在跑的</span>
<span class="c1"># 例如 Push Commit 触发的任务还没执行就又 Push Commit 时，会取消前一个任务</span>
<span class="na">concurrency</span><span class="pi">:</span>
  <span class="na">group</span><span class="pi">:</span> <span class="s">${{ github.workflow }}-${{ github.ref_name }}</span>
  <span class="na">cancel-in-progress</span><span class="pi">:</span> <span class="kc">true</span>

<span class="c1"># Job 工作项目</span>
<span class="c1"># Job 会并发执行</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="c1"># Job ID</span>
  <span class="na">label-pr-by-file-count</span><span class="pi">:</span>
    <span class="c1"># Job 名称 (可省略，有设定在 Log 显示比较好读)</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Label PR by changes file count</span>

    <span class="c1"># 如果这个 Job 失败，不影响整个 Workflow，继续其他 Job</span>
    <span class="na">continue-on-error</span><span class="pi">:</span> <span class="kc">true</span>
    
    <span class="c1"># 设定最长 Timeout 时间，防止异常情况发生时无止尽的等待</span>
    <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">10</span>

    <span class="c1"># Runner Label - 使用 GitHub Hosted Runner ubuntu-latest 来执行工作</span>
    <span class="c1"># 如果是 Private Repo 会计算用量，超过可能会产生费用</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>

    <span class="c1"># 工作步骤</span>
    <span class="c1"># 工作步骤会照顺序执行</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="c1"># 步骤名称</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Get changed file count and apply label</span>
        <span class="c1"># 步骤 ID (可省略，后续若没有 Step 要引用 Output 输出则不需设定)</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">get-changed-files-count-by-gh</span>
        <span class="c1"># 直接使用别人封装好的程式</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s2">"</span><span class="s">pascalgn/size-label-action@v0.5.5"</span>
        <span class="c1"># 注入外部环境参数到执行阶段</span>
        <span class="c1"># 参数命名、可用参数要参考说明：https://github.com/pascalgn/size-label-action/tree/main</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="c1"># secrets.GITHUB_TOKEN 是 GitHub Actions 执行时自动产生的 Token (github-actions 身份)，不需自行在 Secrets 设定，拥有一些 GitHub Repo API Scopes 权限</span>
          <span class="c1"># https://docs.github.com/en/actions/how-tos/security-for-github-actions/security-guides/use-github_token-in-workflows</span>
          <span class="na">GITHUB_TOKEN</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">secrets.GITHUB_TOKEN</span><span class="nv"> </span><span class="s">}}"</span>
</code></pre></div></div>

<p><a href="https://github.com/pascalgn/size-label-action/tree/main" target="_blank"><img src="https://opengraph.githubassets.com/1e5c6f52127032dc1a5fea71a498fa9cc585987880889f0306ef705de3990867/pascalgn/size-label-action" alt="" /></a></p>

<p>这个包好的 Action 是 JavaScript Action，实际执行程式码可以参考以下档案： <a href="https://github.com/pascalgn/size-label-action/blob/main/dist/index.js" target="_blank">dist/index.js</a> 。</p>

<h4 id="name-run-name-的补充">name, run-name 的补充：</h4>

<p><img src="/assets/404bd5c70040/1*zBmjm_3AU53NN0UhTrmOBQ.webp" alt="" loading="lazy" decoding="async" width="1012" height="569" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDEyIiBoZWlnaHQ9IjU2OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*zBmjm_3AU53NN0UhTrmOBQ.png" /></p>

<ul>
  <li>
    <p>name: Action Workflow 的名称</p>
  </li>
  <li>
    <p>run-name: 执行纪录的标题名称 (可带入 PR Title or Branch or Author…etc)
如果是 on:pull_request 事件预设是 PR Title。</p>
  </li>
</ul>

<h3 id="案例--2">案例 — 2</h3>

<p>建立 Pull Request 后如果没有 Assignee 则自动 Assign 作者自己并且 Comment 提示。(只有在初次建立时才会执行)</p>

<h4 id="成果图-1">成果图</h4>

<p><img src="/assets/404bd5c70040/1*EL-0nQF7jhP34d6ZoSkJAg.webp" alt="Demo PR" loading="lazy" decoding="async" width="1200" height="682" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY4MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*EL-0nQF7jhP34d6ZoSkJAg.png" /></p>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/pull/11" target="_blank">Demo PR</a></p>

<h4 id="运作流程-1">运作流程</h4>

<ul>
  <li>
    <p>使用者开 PR</p>
  </li>
  <li>
    <p>触发 GitHub Actions Workflow</p>
  </li>
  <li>
    <p>github script 取得 assignee</p>
  </li>
  <li>
    <p>如果没有 asignee 则 assign 开 PR 的作者 &amp; Comment 讯息</p>
  </li>
  <li>
    <p>完成</p>
  </li>
</ul>

<h4 id="动手做-1">动手做</h4>

<p>Repo → Actions → New workflow → set up a workflow yourself。</p>

<p><strong>档案名称：</strong> <code class="language-plaintext highlighter-rouge">Automation-PullRequest.yml</code> (同上)</p>

<h4 id="automation-pullrequestyml-1"><code class="language-plaintext highlighter-rouge">Automation-PullRequest.yml</code></h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Workflow(Action) 名称</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Pull Reqeust Automation</span>

<span class="c1"># Actions Log 的标题名称</span>
<span class="na">run-name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Pull</span><span class="nv"> </span><span class="s">Reqeust</span><span class="nv"> </span><span class="s">Automation</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">Daily</span><span class="nv"> </span><span class="s">Checker"</span>

<span class="c1"># 触发事件</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># PR 事件</span>
  <span class="na">pull_request</span><span class="pi">:</span>
    <span class="c1"># PR - 开启、重开、有新 Push Commit 时</span>
    <span class="na">types</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">opened</span><span class="pi">,</span> <span class="nv">synchronize</span><span class="pi">,</span> <span class="nv">reopened</span><span class="pi">]</span>


<span class="c1"># 同个 Concurrency Group 如果有新的 Job 会取消正在跑的</span>
<span class="c1"># 例如 Push Commit 触发的任务还没执行就又 Push Commit 时，会取消前一个任务</span>
<span class="na">concurrency</span><span class="pi">:</span>
  <span class="na">group</span><span class="pi">:</span> <span class="s">${{ github.workflow }}-${{ github.ref_name }}</span>
  <span class="na">cancel-in-progress</span><span class="pi">:</span> <span class="kc">true</span>

<span class="c1"># Job 工作项目</span>
<span class="c1"># Job 会并发执行</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="c1"># Job ID</span>
  <span class="na">label-pr-by-file-count</span><span class="pi">:</span>
    <span class="c1"># 请参考前文，略....</span>
  <span class="c1"># ---------</span>
  <span class="na">assign-self-if-no-assignee</span><span class="pi">:</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Automatically assign to self if no assignee is specified</span>
    <span class="c1"># 因为是共用触发事件，所以在 Job 上自己判断，当是 Pull Request Opened(首次建立) 时才执行 Job 否则会 Skipped</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">github.event_name == 'pull_request' &amp;&amp; github.event.action == 'opened'</span>

    <span class="c1"># 如果这个 Job 失败，不影响整个 Workflow，继续其他 Job</span>
    <span class="na">continue-on-error</span><span class="pi">:</span> <span class="kc">true</span>
    
    <span class="c1"># 设定最长 Timeout 时间，防止异常情况发生时无止尽的等待</span>
    <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">10</span>
    
    <span class="c1"># Runner Label - 使用 GitHub Hosted Runner ubuntu-latest 来执行工作</span>
    <span class="c1"># 如果是 Private Repo 会计算用量，超过可能会产生费用</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>

    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Assign self if No Assignee</span>
        <span class="c1"># 使用 GitHub Script (JavaScript) 撰写脚本 (Node.js 环境)</span>
        <span class="c1"># 相较上面直接用 Shell Script 写起来更方便漂亮</span>
        <span class="c1"># 也不需要自行注入环境变数、GITHUB_TOKEN</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/github-script@v7</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">script</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">// github-script 中会自动注入到 context 变数供 javascript 直接引用</span>
            <span class="s">// https://docs.github.com/en/actions/learn-github-actions/contexts#github-context</span>

            <span class="s">const issue = context.payload.pull_request; // 如果要连 Issue 一起支援可写成 context.payload.issue \\|\\| context.payload.pull_request</span>
            <span class="s">const assignees = issue.assignees \\|\\| [];</span>
            <span class="s">const me = context.actor;</span>

            <span class="s">if (assignees.length === 0) {</span>
              <span class="s">// Assignee 设成自己</span>
              <span class="s">await github.rest.issues.addAssignees({</span>
                <span class="s">owner</span><span class="err">:</span> <span class="s">context.repo.owner,</span>
                <span class="s">repo</span><span class="err">:</span> <span class="s">context.repo.repo,</span>
                <span class="s">issue_number</span><span class="err">:</span> <span class="s">issue.number,</span>
                <span class="s">assignees</span><span class="err">:</span> <span class="pi">[</span><span class="nv">me</span><span class="pi">]</span>
              <span class="err">}</span><span class="s">);</span>

              <span class="s">// 留言通知</span>
              <span class="s">await github.rest.issues.createComment({</span>
                <span class="s">owner</span><span class="err">:</span> <span class="s">context.repo.owner,</span>
                <span class="s">repo</span><span class="err">:</span> <span class="s">context.repo.repo,</span>
                <span class="s">issue_number</span><span class="err">:</span> <span class="s">issue.number,</span>
                <span class="s">body</span><span class="err">:</span> <span class="err">`</span><span class="s">🔧 No assignee was set, so I have assigned this to myself (@${me}).`</span>
              <span class="s">});</span>
            <span class="s">}</span>
</code></pre></div></div>

<p>这次我们示范改用 GitHub Script (JavaScript) 撰写脚本，程式码语法上更弹性更好撰写。</p>

<p>当然如果你想照我之前说的每个任务一个档案，就可以拔掉 Job If. . 直接在 Action Workflow 触发条件设定：</p>

<p><code class="language-plaintext highlighter-rouge">Automation-PullRequest-Auto-Assign.yml</code> <strong>：</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Workflow(Action) 名称</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Pull Reqeust Automation - Auto Assignee Self</span>

<span class="c1"># 触发事件</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># PR 事件</span>
  <span class="na">pull_request</span><span class="pi">:</span>
    <span class="c1"># PR - 开启时</span>
    <span class="na">types</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">opened</span><span class="pi">]</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">assign-self-if-no-assignee</span><span class="pi">:</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Automatically assign to self if no assignee is specified</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="c1"># 请参考前文，略....</span>
</code></pre></div></div>

<p>Commit 档案到 Repo 主分支之后，我们再开新 PR 就会自动触发 GitHub Actions：</p>

<p><img src="/assets/404bd5c70040/1*Y-A6owUibNEFBoRFHnqIYg.webp" alt="" loading="lazy" decoding="async" width="1271" height="708" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjcxIiBoZWlnaHQ9IjcwOCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*Y-A6owUibNEFBoRFHnqIYg.png" /></p>

<p>现在有两个 Job 要执行了！</p>

<h4 id="执行结果-1">执行结果</h4>

<p><img src="/assets/404bd5c70040/1*23muCVgUJKmZt746khBMFQ.webp" alt="Demo PR" loading="lazy" decoding="async" width="1200" height="979" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk3OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*23muCVgUJKmZt746khBMFQ.png" /></p>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/pull/11" target="_blank">Demo PR</a></p>

<p>执行完毕并且成功后 PR 如果没有 Asignees 会自动 Assign PR 作者并且 Comment 讯息。(都是用 <code class="language-plaintext highlighter-rouge">github-actions</code> 身份操作)</p>

<p><strong>完整程式码： <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/Automation-PullRequest.yml" target="_blank">Automation-PullRequest.yml</a></strong></p>

<h4 id="测试重开reopened-pr">测试重开(Reopened) PR</h4>

<p><img src="/assets/404bd5c70040/1*mcDa7TZjv6mO7HtwhOE-Vw.webp" alt="" loading="lazy" decoding="async" width="960" height="407" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjAiIGhlaWdodD0iNDA3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*mcDa7TZjv6mO7HtwhOE-Vw.png" /></p>

<p>可看到只会执行 Size Label Job，Auto Assignee Job 被 Skipped 了。</p>

<blockquote>
  <p><em>这个任务也有人包好 Action 可以直接复用，可参考： <a href="https://github.com/pozil/auto-assign-issue" target="_blank">pozil/auto-assign-issue</a> 。</em></p>
</blockquote>

<h3 id="案例--3">案例 — 3</h3>

<p>每日早上 9 点自动统计当前 PR 数量及已开启多久时间发送通知讯息到 Slack 工作寻组、自动关闭已开启超过 3 个月的 PR。</p>

<h4 id="成果图-2">成果图</h4>

<p><img src="/assets/404bd5c70040/1*0stX9KpZi6PcXpG-90wyIg.webp" alt="" loading="lazy" decoding="async" width="508" height="147" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MDgiIGhlaWdodD0iMTQ3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*0stX9KpZi6PcXpG-90wyIg.png" /></p>

<p><img src="/assets/404bd5c70040/1*Nbg3r1zzhx24YIBEjPJnaw.webp" alt="" loading="lazy" decoding="async" width="928" height="187" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjgiIGhlaWdodD0iMTg3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*Nbg3r1zzhx24YIBEjPJnaw.png" /></p>

<ul>
  <li>
    <p>Slack 工作群组每天早上自动收到报告</p>
  </li>
  <li>
    <p>自动关闭超过 90 天的 PR</p>
  </li>
</ul>

<h4 id="运作流程-2">运作流程</h4>

<ul>
  <li>
    <p>GitHub Actions 每天早上 9 点自动触发</p>
  </li>
  <li>
    <p>触发 GitHub Actions Workflow</p>
  </li>
  <li>
    <p>github script 取得 开启中的 PR 列表、统计开启了几天</p>
  </li>
  <li>
    <p>传送统计报告讯息到 Slack</p>
  </li>
  <li>
    <p>关闭超过 90 天的 PR</p>
  </li>
  <li>
    <p>完成</p>
  </li>
</ul>

<h4 id="动手做-2">动手做</h4>

<p>Repo → Actions → New workflow → set up a workflow yourself。</p>

<p><strong>档案名称：</strong> <code class="language-plaintext highlighter-rouge">Automation-PullRequest-Daily.yml</code></p>

<h4 id="automation-pullrequest-dailyyml">Automation-PullRequest-Daily.yml</h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Workflow(Action) 名称</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Pull Reqeust Automation - Daily Checker</span>

<span class="c1"># 触发事件</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># 排程定时自动执行</span>
  <span class="c1"># https://crontab.guru/</span>
  <span class="c1"># UTC 时间</span>
  <span class="na">schedule</span><span class="pi">:</span>
    <span class="c1"># UTC 的 01:00 = 每天 UTC+8 的 09:00</span>
    <span class="pi">-</span> <span class="na">cron</span><span class="pi">:</span> <span class="s1">'</span><span class="s">0</span><span class="nv"> </span><span class="s">1</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*'</span>
  <span class="c1"># 手动触发</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>

<span class="c1"># Job 工作项目</span>
<span class="c1"># Job 会并发执行</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="c1"># Job ID</span>
  <span class="na">caculate-pr-status</span><span class="pi">:</span>
    <span class="c1"># Job 名称 (可省略，有设定在 Log 显示比较好读)</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Caculate PR Status</span>
    <span class="c1"># Runner Label - 使用 GitHub Hosted Runner ubuntu-latest 来执行工作</span>
    <span class="c1"># 如果是 Private Repo 会计算用量，超过可能会产生费用</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>

    <span class="c1"># Job Output</span>
    <span class="na">outputs</span><span class="pi">:</span>
      <span class="na">pr_list</span><span class="pi">:</span> <span class="s">${{ steps.pr-info.outputs.pr_list }}</span>

    <span class="c1"># 工作步骤</span>
    <span class="c1"># 工作步骤会照顺序执行</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="c1"># 步骤名称</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Fetch open PRs and caculate</span>
        <span class="c1"># Step 外部要引用 Output 输出，需设定</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">pr-info</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/github-script@v7</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">script</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">const now = new Date();</span>
            <span class="s">const per_page = 100;</span>
            <span class="s">let page = 1;</span>
            <span class="s">let allPRs = [];</span>
      
            <span class="s">while (true) {</span>
              <span class="s">const { data</span><span class="err">:</span> <span class="s">prs } = await github.rest.pulls.list({</span>
                <span class="s">owner</span><span class="err">:</span> <span class="s">context.repo.owner,</span>
                <span class="s">repo</span><span class="err">:</span> <span class="s">context.repo.repo,</span>
                <span class="s">state</span><span class="err">:</span> <span class="s1">'</span><span class="s">open'</span><span class="err">,</span>
                <span class="s">per_page,</span>
                <span class="s">page,</span>
              <span class="s">});</span>
              <span class="s">if (prs.length === 0) break;</span>
              <span class="s">allPRs = allPRs.concat(prs);</span>
              <span class="s">if (prs.length &lt; per_page) break;</span>
              <span class="s">page++;</span>
            <span class="s">}</span>
      
            <span class="s">const result = allPRs.map(pr =&gt; {</span>
              <span class="s">const created = new Date(pr.created_at);</span>
              <span class="s">const daysOpen = Math.floor((now - created) / (1000 * 60 * 60 * 24));</span>
              <span class="s">return {</span>
                <span class="s">pr</span><span class="err">:</span> <span class="s">pr.number.toString(),</span>
                <span class="s">title</span><span class="err">:</span> <span class="s">pr.title,</span>
                <span class="s">idle</span><span class="err">:</span> <span class="s">daysOpen</span>
              <span class="s">};</span>
            <span class="s">});</span>

            <span class="s">// 设定回 Output，只接受 String</span>
            <span class="s">core.setOutput('pr_list', JSON.stringify(result));</span>
  <span class="c1"># ----</span>
  <span class="na">send-pr-summary-message-to-slack</span><span class="pi">:</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Send PR Summary Messag to Slack</span>
    <span class="c1"># Job 预设是并发，使用 needs 可以迫使当前 Job 等到 need Job 完成时才会执行</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">caculate-pr-status</span><span class="pi">]</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Generate Message</span>
        <span class="c1"># Step 外部要引用 Output 输出，需设定</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">gen-msg</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/github-script@v7</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">script</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">const prList = JSON.parse(`${{ needs.caculate-pr-status.outputs.pr_list }}`);</span>
            <span class="s">const blocks = [];</span>
      
            <span class="s">// 标题</span>
            <span class="s">blocks.push({</span>
              <span class="s">type</span><span class="err">:</span> <span class="s2">"</span><span class="s">section"</span><span class="err">,</span>
              <span class="na">text</span><span class="pi">:</span> <span class="pi">{</span>
                <span class="nv">type</span><span class="pi">:</span> <span class="s2">"</span><span class="s">mrkdwn"</span><span class="pi">,</span>
                <span class="nv">text</span><span class="pi">:</span> <span class="err">`</span><span class="nv">📬 *Open PR Report*\nTotal</span><span class="pi">:</span> <span class="err">*</span><span class="nv">$</span><span class="pi">{</span><span class="nv">prList.length</span><span class="pi">}</span><span class="err">*</span> <span class="nv">PR(s)`</span>
              <span class="pi">}</span>
          <span class="err">  }</span><span class="s">);</span>
      
            <span class="s">// 每个 PR 一行</span>
            <span class="s">for (const pr of prList) {</span>
              <span class="s">blocks.push({</span>
                <span class="s">type</span><span class="err">:</span> <span class="s2">"</span><span class="s">section"</span><span class="err">,</span>
                <span class="na">text</span><span class="pi">:</span> <span class="pi">{</span>
                  <span class="nv">type</span><span class="pi">:</span> <span class="s2">"</span><span class="s">mrkdwn"</span><span class="pi">,</span>
                  <span class="nv">text</span><span class="pi">:</span> <span class="err">`</span><span class="nv">• &lt;https</span><span class="pi">:</span><span class="nv">//github.com/$</span><span class="pi">{</span><span class="nv">context.repo.owner</span><span class="pi">}</span><span class="nv">/$</span><span class="pi">{</span><span class="nv">context.repo.repo</span><span class="pi">}</span><span class="nv">/pull/$</span><span class="pi">{</span><span class="nv">pr.pr</span><span class="pi">}</span><span class="nv">\\|PR</span> <span class="c1">#${pr.pr}&gt; *${pr.title}* - 🕒 ${pr.idle} day(s)`</span>
                <span class="pi">}</span>
          <span class="err">    }</span><span class="s">);</span>
            <span class="s">}</span>

            <span class="s">// 设定回 Output，只接受 String</span>
            <span class="s">core.setOutput('blocks', JSON.stringify(blocks));</span>

            
      <span class="c1"># 使用 Slack 官方封装好的 Slack API Github Actions</span>
      <span class="c1"># https://tools.slack.dev/slack-github-action/sending-techniques/sending-data-slack-api-method/</span>
      <span class="c1"># 发送讯息</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Post text to a Slack channel</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">slackapi/slack-github-action@v2.1.0</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">method</span><span class="pi">:</span> <span class="s">chat.postMessage</span>
          <span class="na">token</span><span class="pi">:</span> <span class="s">${{ secrets.SLACK_BOT_TOKEN }}</span>
          <span class="na">payload</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">channel</span><span class="err">:</span> <span class="s">${{ vars.SLACK_TEAM_CHANNEL_ID }}</span>
            <span class="s">blocks</span><span class="err">:</span> <span class="s">${{ steps.gen-msg.outputs.blocks }}</span>
  <span class="c1"># ----</span>
  <span class="na">auto-close-old-prs</span><span class="pi">:</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Auto Close Old PRs</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">caculate-pr-status</span><span class="pi">]</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>

    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Auto close PRs opened more than 90 days</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/github-script@v7</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">script</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">const prList = JSON.parse(`${{ needs.caculate-pr-status.outputs.pr_list }}`);</span>
            <span class="s">const oldPRs = prList.filter(pr =&gt; pr.idle &gt; 90);</span>

            <span class="s">for (const pr of oldPRs) {</span>
              <span class="s">await github.rest.pulls.update({</span>
                <span class="s">owner</span><span class="err">:</span> <span class="s">context.repo.owner,</span>
                <span class="s">repo</span><span class="err">:</span> <span class="s">context.repo.repo,</span>
                <span class="s">pull_number</span><span class="err">:</span> <span class="s">parseInt(pr.pr),</span>
                <span class="s">state</span><span class="err">:</span> <span class="s1">'</span><span class="s">closed'</span>
              <span class="err">}</span><span class="s">);</span>

              <span class="s">await github.rest.issues.createComment({</span>
                <span class="s">owner</span><span class="err">:</span> <span class="s">context.repo.owner,</span>
                <span class="s">repo</span><span class="err">:</span> <span class="s">context.repo.repo,</span>
                <span class="s">issue_number</span><span class="err">:</span> <span class="s">parseInt(pr.pr),</span>
                <span class="s">body</span><span class="err">:</span> <span class="err">`</span><span class="s">⚠️ This pull request has been automatically closed because it has been open for more than 90 days. Please reopen if needed.`</span>
              <span class="s">});</span>
            <span class="s">}</span>
            <span class="s">console.log(`Closed ${oldPRs.length} PR(s)`);</span>
</code></pre></div></div>

<p>在这个范例中我们使用：</p>

<ul>
  <li>
    <p>on: schedule Crontab 排程自动触发跟 workflow_dispatch 支援手动触发</p>
  </li>
  <li>
    <p>Job output/Step output (都只能是字串)</p>
  </li>
  <li>
    <p>多个 Jobs 预设是并发但可以用 <code class="language-plaintext highlighter-rouge">needs</code> 时间依赖等待关系</p>
  </li>
  <li>
    <p>从 Repo Secrets/Variables 取得设定</p>
  </li>
  <li>
    <p>串接 Slack API</p>
  </li>
</ul>

<p><strong>Repo Secrets — 新增</strong> <code class="language-plaintext highlighter-rouge">SLACK_BOT_TOKEN</code></p>

<p><img src="/assets/404bd5c70040/1*YC4DBHtKmX5XGgcSSzaE5A.webp" alt="" loading="lazy" decoding="async" width="1200" height="970" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk3MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*YC4DBHtKmX5XGgcSSzaE5A.png" /></p>

<ul>
  <li>Slack App 建立、发讯息权限设定可参考我 <a href="/posts/zrealm-dev/slack-app-整合-chatgpt-利用-openai-api-与-google-cloud-functions-自建智能助理-bd94cc88f9c9/">之前的文章</a></li>
</ul>

<p><strong>Repo Variables — 新增</strong> <code class="language-plaintext highlighter-rouge">SLACK_TEAM_CHANNEL_ID</code></p>

<p><img src="/assets/404bd5c70040/1*X4gZ5_IRvsiehAL0O9AleQ.webp" alt="" loading="lazy" decoding="async" width="1174" height="998" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTc0IiBoZWlnaHQ9Ijk5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*X4gZ5_IRvsiehAL0O9AleQ.png" /></p>

<p>Commit 档案到 Repo 主分支之后，回到 Actions 手动触发看看：</p>

<blockquote>
  <p><em>日后会每日自动触发。</em></p>
</blockquote>

<p><img src="/assets/404bd5c70040/1*WNFKXl-QC2WGyaSWep5-DA.webp" alt="" loading="lazy" decoding="async" width="1048" height="438" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDQ4IiBoZWlnaHQ9IjQzOCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*WNFKXl-QC2WGyaSWep5-DA.png" /></p>

<p>Actions → Pull Request Automation — Daily Checker → Run workflow → Branch: main → Run workflow。</p>

<p><strong>执行后可以点击进入查看执行状况：</strong></p>

<p><img src="/assets/404bd5c70040/1*4mvOxnd1uS4ZlxnNoNdHaQ.webp" alt="" loading="lazy" decoding="async" width="1087" height="545" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDg3IiBoZWlnaHQ9IjU0NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*4mvOxnd1uS4ZlxnNoNdHaQ.png" /></p>

<p><img src="/assets/404bd5c70040/1*BluzFgY2tM2E7DwoVq1jQw.webp" alt="" loading="lazy" decoding="async" width="1030" height="458" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDMwIiBoZWlnaHQ9IjQ1OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*BluzFgY2tM2E7DwoVq1jQw.png" /></p>

<p>因为有 <code class="language-plaintext highlighter-rouge">needs</code> 的限制，Jobs 流程就会是 <code class="language-plaintext highlighter-rouge">Cacluate PR Status</code> 先完成后才会并发执行 <code class="language-plaintext highlighter-rouge">Auto Close Old PRs</code> 和 <code class="language-plaintext highlighter-rouge">Send PR Summary Message to Slack</code> 。</p>

<h4 id="执行结果-2">执行结果</h4>

<p><strong>任务都成功执行后可以查看 Slack 讯息：</strong></p>

<p><img src="/assets/404bd5c70040/1*0stX9KpZi6PcXpG-90wyIg.webp" alt="" loading="lazy" decoding="async" width="508" height="147" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MDgiIGhlaWdodD0iMTQ3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*0stX9KpZi6PcXpG-90wyIg.png" /></p>

<p>成功 🚀🚀🚀</p>

<p><strong>完整程式码： <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/Automation-PullRequest-Daily.yml" target="_blank">Automation-PullRequest-Daily.yml</a></strong></p>

<h3 id="小结">小结</h3>

<blockquote>
  <p>希望上面三个案例能让您对 GitHub Actions 有个初步的了解也希望有激起你的自动化工作创意，可以自己发想工作流程(请务必先参考 <a href="https://docs.github.com/en/actions/reference/events-that-trigger-workflows" target="_blank">触发事件</a> )，然后撰写脚本执行；也记得先去 <a href="https://github.com/marketplace?type=actions" target="_blank"><strong>Marketplace</strong></a> 找找现有的步骤可以站在巨人的肩膀直接使用。</p>
</blockquote>

<p>本篇只是入门基础(甚至没 Checkout Code)，下一篇「 <a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/"><strong>CI/CD 实战指南（三）：使用 GitHub Actions 实作 App 专案的 CI 与 CD 工作流程</strong></a> 」会在介绍更复杂深入的 GitHub Actions Workflow。</p>

<h4 id="github-自动化延伸议题">GitHub 自动化延伸议题</h4>

<p>GitHub 可以与 Slack 整合，订阅 Repo 的 PR 更新通知、Push Default Branch 通知…等等。</p>

<p><img src="/assets/404bd5c70040/1*BMTT4koRBIIsQ7_mklC86w.webp" alt="" loading="lazy" decoding="async" width="439" height="430" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MzkiIGhlaWdodD0iNDMwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*BMTT4koRBIIsQ7_mklC86w.png" /></p>

<p><strong>问题 1. GitHub 讯息无法标记到人，只标记了 GitHub 帐号，Slack 帐号收不到通知：</strong></p>

<p><img src="/assets/404bd5c70040/1*Ddp0cEtXE10hScM1rozmtg.webp" alt="" loading="lazy" decoding="async" width="1200" height="873" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg3MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*Ddp0cEtXE10hScM1rozmtg.png" /></p>

<p><img src="/assets/404bd5c70040/1*uHGJ7l__AdYoWT9KpvihLQ.webp" alt="" loading="lazy" decoding="async" width="1043" height="775" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDQzIiBoZWlnaHQ9Ijc3NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*uHGJ7l__AdYoWT9KpvihLQ.png" /></p>

<p><a href="https://slack.github.com/" target="_blank">Slack App</a> or Apps 搜寻 GitHub → 打开讯息视窗 →完成 <strong>Connect GitHub Account</strong> 步骤，这样 GitHub 才知道你对应的 Slack UID 是什么，才能标记你。</p>

<p><strong>问题 2. Pull Request Reminder</strong></p>

<p>我记得这本来是第三方开发的功能，后来直接整合在 GitHub 里面了，不要傻傻的自己用 GitHub Actions 写脚本做！</p>

<p><img src="/assets/404bd5c70040/1*BpMd2K0NBDE6xB1XzFY94Q.webp" alt="" loading="lazy" decoding="async" width="1008" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDA4IiBoZWlnaHQ9IjEyMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/404bd5c70040/1*BpMd2K0NBDE6xB1XzFY94Q.png" /></p>

<blockquote>
  <p><a href="https://docs.github.com/en/organizations/organizing-members-into-teams/managing-scheduled-reminders-for-your-team" target="_blank"><strong><em>GitHub 内建的是 by Team 设置，你需要先为组织增加 Team、Repo 加入 Team 然后才能设置 Pull Request Reminder。</em></strong></a></p>
</blockquote>

<ul>
  <li>输入完 Slack Channel 跟规则储存之后每天就会自动传送提示讯息跟标记 Reviewer 了，设置可 <a href="https://michaelheap.com/github-scheduled-reminders/" target="_blank">参考</a> ，结果如下图：</li>
</ul>

<p><img src="/assets/404bd5c70040/1*kvqFXkIKIxP79Wm8vIaN0Q.webp" alt="&lt;https://michaelheap.com/github-scheduled-reminders/&gt;" loading="lazy" decoding="async" width="500" height="315" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MDAiIGhlaWdodD0iMzE1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*kvqFXkIKIxP79Wm8vIaN0Q.png" /></p>

<p><a href="https://michaelheap.com/github-scheduled-reminders/" target="_blank">https://michaelheap.com/github-scheduled-reminders/</a></p>

<p><strong>问题 4. GitHub PR 讯息，作者收不到通知：</strong></p>

<p><img src="/assets/404bd5c70040/1*wmtXwXAcQZDXqInRd0ivPw.webp" alt="" loading="lazy" decoding="async" width="792" height="535" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3OTIiIGhlaWdodD0iNTM1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*wmtXwXAcQZDXqInRd0ivPw.png" /></p>

<blockquote>
  <p><em>这是一个万年的问题，就是 PR 的 Slack 讯息 <strong>其实作者并不知道有人 Reply Threads 讨论</strong> ，GitHub 发的这则 Slack 讯息只会标记 Reviewers，不会标记 Assignee or PR 作者。</em></p>
</blockquote>

<p>这时候 GitHub Actions 做自动化小工具就派上用场了，我们可以加一个 Job 在 PR Description 最后 Append 标记作者，这样讯息传到 Slack 也会一并标记到作者的 Slack:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Workflow(Action) 名称</span>
name: Pull Reqeust Automation
<span class="c"># 请参考前文，略....</span>

  <span class="c"># ---------</span>
  append-author-to-pr-description:
    name: Append author to PR description
    <span class="c"># 因为是共用触发事件，所以在 Job 上自己判断，当是 Pull Request Opened(首次建立) 时才执行 Job 否则会 Skipped</span>
    <span class="k">if</span>: github.event_name <span class="o">==</span> <span class="s1">'pull_request'</span> <span class="o">&amp;&amp;</span> github.event.action <span class="o">==</span> <span class="s1">'opened'</span>
    
    <span class="c"># 如果这个 Job 失败，不影响整个 Workflow，继续其他 Job</span>
    <span class="k">continue</span><span class="nt">-on-error</span>: <span class="nb">true</span>
    
    <span class="c"># 设定最长 Timeout 时间，防止异常情况发生时无止尽的等待</span>
    timeout-minutes: 10
    
    <span class="c"># Runner Label - 使用 GitHub Hosted Runner ubuntu-latest 来执行工作</span>
    <span class="c"># 如果是 Private Repo 会计算用量，超过可能会产生费用</span>
    <span class="c"># 但这种自动化小工作不太容易用过量</span>
    runs-on: ubuntu-latest
    steps:
      - name: Append author to PR description
        <span class="nb">env</span>:
          <span class="c"># secrets.GITHUB_TOKEN 是 GitHub Actions 执行时自动产生的 Token，不需自行在 Secrets 设定，拥有一些 GitHub Repo API Scopes 权限</span>
          <span class="c"># gh(GitHub) cli 需要注入 GH_TOKEN 到 ENV，gh 才有权限操作</span>
          <span class="c"># https://docs.github.com/en/actions/how-tos/security-for-github-actions/security-guides/use-github_token-in-workflows</span>
          GH_TOKEN: <span class="k">${</span><span class="p">{ secrets.GITHUB_TOKEN </span><span class="k">}</span><span class="o">}</span>

          <span class="c">#   ${{ github.xxx }} 是 GitHub Actions Context 表达式</span>
          <span class="c">#   不是 Shell 变数，而是 YAML 解析阶段由 GitHub Actions 替换成对应值</span>
          <span class="c">#   其他参数：https://docs.github.com/en/actions/learn-github-actions/contexts#github-context</span>
          PR_NUMBER: <span class="k">${</span><span class="p">{ github.event.pull_request.number </span><span class="k">}</span><span class="o">}</span>
          AUTHOR_TAG: <span class="s1">'@${{ github.event.pull_request.user.login }}'</span>
        run: <span class="se">\\</span>|
          <span class="nv">PR_BODY</span><span class="o">=</span><span class="si">$(</span>gh <span class="nb">pr </span>view <span class="nv">$PR_NUMBER</span> <span class="nt">--repo</span> <span class="k">${</span><span class="p">{ github.repository </span><span class="k">}</span><span class="o">}</span> <span class="nt">--json</span> body <span class="nt">-q</span> <span class="s2">".body"</span><span class="si">)</span>
          <span class="nv">NEW_BODY</span><span class="o">=</span><span class="si">$(</span><span class="nb">printf</span> <span class="s2">"%s</span><span class="se">\n\n</span><span class="s2">Created by %s"</span> <span class="s2">"</span><span class="nv">$PR_BODY</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$AUTHOR_TAG</span><span class="s2">"</span><span class="si">)</span>
          gh <span class="nb">pr </span>edit <span class="nv">$PR_NUMBER</span> <span class="nt">--repo</span> <span class="k">${</span><span class="p">{ github.repository </span><span class="k">}</span><span class="o">}</span> <span class="nt">--body</span> <span class="s2">"</span><span class="nv">$NEW_BODY</span><span class="s2">"</span>
</code></pre></div></div>

<p><strong>完整程式码： <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/Automation-PullRequest.yml" target="_blank">Automation-PullRequest.yml</a></strong></p>

<p>开 PR 时会自动在描述后加上作者资讯、Slack 讯息也会正确的标记作者：</p>

<p><img src="/assets/404bd5c70040/1*UtTDtIQJ0vJks79UzCQSAQ.webp" alt="" loading="lazy" decoding="async" width="953" height="370" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTMiIGhlaWdodD0iMzcwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*UtTDtIQJ0vJks79UzCQSAQ.png" /></p>

<p><img src="/assets/404bd5c70040/1*MjVsFqE--xAq1zSQfCNVdQ.webp" alt="" loading="lazy" decoding="async" width="416" height="244" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MTYiIGhlaWdodD0iMjQ0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*MjVsFqE--xAq1zSQfCNVdQ.png" /></p>

<p><strong>问题 5. GitHub 疯狂寄通知信到信箱很干扰：</strong></p>

<p>GitHub Repo 通知跟 Slack 都有设定好之后，统一都在 Slack 收通知了，可以去 GitHub 个人设定把 Email 通知关掉：</p>

<p><img src="/assets/404bd5c70040/1*INgfO9B2bNFy-Nd1ZjnzOw.webp" alt="" loading="lazy" decoding="async" width="1306" height="686" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzA2IiBoZWlnaHQ9IjY4NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*INgfO9B2bNFy-Nd1ZjnzOw.png" /></p>

<h4 id="其他">其他</h4>

<p>Actions 目前没有目录结构，但可以在 Actions 页，置顶(Pin) 五个 Actions；也可以使用 Disable 暂停某个 Action。</p>

<p><img src="/assets/404bd5c70040/1*ZD-5xkparhJqtnm2REeu6A.webp" alt="" loading="lazy" decoding="async" width="1238" height="599" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjM4IiBoZWlnaHQ9IjU5OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*ZD-5xkparhJqtnm2REeu6A.png" /></p>

<p>可以在 Insights 查看 GitHub Actions 用量跟执行成效：</p>

<p><img src="/assets/404bd5c70040/1*re91ZRtQ0frOF6GVJ-MKrw.webp" alt="" loading="lazy" decoding="async" width="1271" height="626" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjcxIiBoZWlnaHQ9IjYyNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*re91ZRtQ0frOF6GVJ-MKrw.png" /></p>

<h3 id="reuse-workflow-补充">Reuse Workflow 补充</h3>

<p><a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/">下一篇文章</a> 有用到同个 Repo 拆 Reuse Workflow，这边补充一下不同 Repo 拆 Reuse Workflow 的范例。</p>

<p>先定义一个 Reuse Workflow: <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo-share-actions/blob/main/.github/workflows/Automation-label-pr-base-branch.yml" target="_blank"><strong>Automation-label-pr-base-branch.yml:</strong></a> <strong>在 <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo-share-actions/blob/main/.github/workflows/Automation-label-pr-base-branch.yml" target="_blank">ZhgChgLi/github-actions-ci-cd-demo-share-actions</a> Repo</strong> 。</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Automation-label-pr-base-branch</span>
<span class="na">run-name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">[Automation-label-pr-base-branch]</span><span class="nv"> </span><span class="s">${{</span><span class="nv"> </span><span class="s">github.event.inputs.PR_NUMBER</span><span class="nv"> </span><span class="se">\\</span><span class="s">|</span><span class="se">\\</span><span class="s">|</span><span class="nv"> </span><span class="s">github.ref</span><span class="nv"> </span><span class="s">}}"</span>

<span class="na">concurrency</span><span class="pi">:</span>
  <span class="na">group</span><span class="pi">:</span> <span class="s">${{ github.workflow }}-${{ github.event.inputs.PR_NUMBER \\|\\| github.ref }}</span>
  <span class="na">cancel-in-progress</span><span class="pi">:</span> <span class="kc">true</span>

<span class="c1"># 触发事件</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="c1"># 其他 Workflow 呼叫此 Workflow 触发</span>
  <span class="na">workflow_call</span><span class="pi">:</span>
    <span class="c1"># 资料输入</span>
    <span class="na">inputs</span><span class="pi">:</span>
      <span class="c1"># PR Number</span>
      <span class="na">PR_NUMBER</span><span class="pi">:</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">true</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
    <span class="c1"># 密钥输入</span>
    <span class="na">secrets</span><span class="pi">:</span>
      <span class="na">GH_TOKEN</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">GitHub</span><span class="nv"> </span><span class="s">token</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">API</span><span class="nv"> </span><span class="s">access"</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">label-pr-base-branch</span><span class="pi">:</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Label PR Base Branch</span>
    <span class="na">continue-on-error</span><span class="pi">:</span> <span class="kc">true</span>
    <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">10</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>

    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Label PR by Base Branch</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">label-pr-base-branch</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">GH_TOKEN</span><span class="pi">:</span> <span class="s">${{ secrets.GITHUB_TOKEN }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">PR_NUMBER="${{ inputs.PR_NUMBER }}"</span>
          <span class="s">REPO="${{ github.repository }}"</span>

          <span class="s">echo "📦 Processing PR</span> <span class="c1">#$PR_NUMBER in repo $REPO"</span>

          <span class="c1"># 取得 PR 的 base branch</span>
          <span class="s">BASE_BRANCH=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json baseRefName --jq '.baseRefName')</span>
          <span class="s">echo "🔖 PR Base Branch</span><span class="err">:</span> <span class="s">$BASE_BRANCH"</span>

          <span class="s"># 允许的 base branch labels</span>
          <span class="s">BRANCH_LABELS=("develop" "main" "master")</span>

          <span class="s"># Label 是否在允许列表</span>
          <span class="s">if [[ " ${BRANCH_LABELS[@]} " =~ " ${BASE_BRANCH} " ]]; then</span>
            <span class="s">LABEL="$BASE_BRANCH"</span>
          <span class="s">else</span>
            <span class="s">echo "⚠️ Base branch '$BASE_BRANCH' not in allowed list, skipping label."</span>
            <span class="s">exit </span><span class="m">0</span>
          <span class="s">fi</span>

          <span class="s"># 移除现有的 base branch labels</span>
          <span class="s">EXISTING_LABELS=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json labels --jq '.labels[].name')</span>
          <span class="s">for EXISTING in $EXISTING_LABELS; do</span>
            <span class="s">if [[ " ${BRANCH_LABELS[@]} " =~ " ${EXISTING} " ]]; then</span>
              <span class="s">echo "🧹 Removing existing base branch label</span><span class="err">:</span> <span class="s">$EXISTING"</span>
              <span class="s">gh pr edit "$PR_NUMBER" --repo "$REPO" --remove-label "$EXISTING"</span>
            <span class="s">fi</span>
          <span class="s">done</span>

          <span class="s"># 如果 Label 不存在则建立</span>
          <span class="s">if ! gh label list --repo "$REPO" \\| grep -q "^$LABEL$"; then</span>
            <span class="s">echo "🆕 Creating missing label</span><span class="err">:</span> <span class="s">$LABEL"</span>
            <span class="s">gh label create "$LABEL" --repo "$REPO" --description "PR targeting $LABEL branch" --color "ededed"</span>
          <span class="s">else</span>
            <span class="s">echo "✅ Label '$LABEL' already exists"</span>
          <span class="s">fi</span>

          <span class="s"># 加上 base branch label</span>
          <span class="s">echo "🏷️ Adding label '$LABEL' to PR</span> <span class="c1">#$PR_NUMBER"</span>
          <span class="s">gh pr edit "$PR_NUMBER" --repo "$REPO" --add-label "$LABEL"</span>
</code></pre></div></div>

<p>回到我们的 <strong>主 <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/Demo-Reuse-Action-From-Another-Repo.yml" target="_blank">ZhgChgLi/github-actions-ci-cd-demo</a> Repo，</strong> 新增一个主 <strong>Workflow <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/Demo-Reuse-Action-From-Another-Repo.yml" target="_blank">Demo-Reuse-Action-From-Another-Repo.yml</a> :</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Automation-label-pr-base-branch</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">pull_request</span><span class="pi">:</span>
    <span class="na">types</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">opened</span><span class="pi">]</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">call-label-pr-workflow</span><span class="pi">:</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Call Base Branch Label Workflow</span>
    <span class="c1"># ✅ 如果被呼叫的 workflow 在同一个 repo：</span>
    <span class="c1">#    uses: ./.github/workflows/Automation-label-pr-base-branch.yml</span>
    <span class="c1">#    注意：这种写法无法指定分支（固定使用 caller workflow 的 branch）</span>
    <span class="c1">#    参考范例：</span>
    <span class="c1">#    - CD-Deploy-Form.yml 呼叫本 repo workflow</span>
    <span class="c1">#    - CD-Deploy.yml 呼叫跨 repo workflow</span>
    <span class="c1">#</span>
    <span class="c1"># ✅ 如果被呼叫的 workflow 在其他 repo：</span>
    <span class="c1">#    uses: {owner}/{repo}/.github/workflows/{file}.yml@{branch_or_tag}</span>
    <span class="c1">#    可以指定 branch 或 tag</span>
    <span class="c1">#    ref: https://github.com/ZhgChgLi/github-actions-ci-cd-demo-share-actions/blob/main/.github/workflows/Automation-label-pr-base-branch.yml</span>
    <span class="na">uses</span><span class="pi">:</span> <span class="s">ZhgChgLi/github-actions-ci-cd-demo-share-actions/.github/workflows/Automation-label-pr-base-branch.yml@main</span>
    <span class="na">with</span><span class="pi">:</span>
      <span class="na">PR_NUMBER</span><span class="pi">:</span> <span class="s">${{ github.event.number }}</span>
      
    <span class="c1"># 如果所有 secrets 都要继承 caller workflow，直接用 `inherit`</span>
    <span class="c1"># secrets: inherit</span>
    <span class="c1">#</span>
    <span class="c1"># 如果只要传特定 secrets，个别指定</span>
    <span class="na">secrets</span><span class="pi">:</span>
      <span class="na">GH_TOKEN</span><span class="pi">:</span> <span class="s">${{ secrets.GITHUB_TOKEN }}</span>
</code></pre></div></div>

<p>Commit 档案后开 PR 试试看。</p>

<p><strong>工作流程：主 Repo 的 <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/Demo-Reuse-Action-From-Another-Repo.yml" target="_blank">Demo-Reuse-Action-From-Another-Repo.yml</a> → 呼叫并把参数传到另一个 Repo 的 <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo-share-actions/blob/main/.github/workflows/Automation-label-pr-base-branch.yml" target="_blank">Automation-label-pr-base-branch.yml</a> 执行任务 → 回到主 Repo 回报结果。</strong></p>

<p><img src="/assets/404bd5c70040/1*13bqlAgpBkHM7UthTJAuOg.webp" alt="" loading="lazy" decoding="async" width="1119" height="453" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTE5IiBoZWlnaHQ9IjQ1MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*13bqlAgpBkHM7UthTJAuOg.png" /></p>

<p><img src="/assets/404bd5c70040/1*CAF3HzS4PHBveDQYu3H73g.webp" alt="" loading="lazy" decoding="async" width="402" height="145" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MDIiIGhlaWdodD0iMTQ1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*CAF3HzS4PHBveDQYu3H73g.png" /></p>

<p>成功！</p>

<h4 id="private-repo-存取问题">Private Repo 存取问题</h4>

<p>这边要注意一个安全性问题，Public Repo 完全没问题，但如果 Reuse Workflow 在 Private Repo 当中，只有在 <strong>同个组织下的其他 Repo + Repo 同样也是 Private + 设定允许</strong> =才能存取使用 Private Repo Reuse Workflow。</p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">Public — ZhgChgLi/ReuseRepo</code> + <code class="language-plaintext highlighter-rouge">Private or Public-ZhgChgli or harry/myRepo</code> = ✅</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">Private — ZhgChgLi/ReuseRepo</code> + <code class="language-plaintext highlighter-rouge">Private or Public— harry/myRepo</code> = ❌</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">Private — ZhgChgLi/ReuseRepo</code> + <code class="language-plaintext highlighter-rouge">Public — ZhgChgLi/anotherRepo</code> = ❌</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">Private — ZhgChgLi/ReuseRepo</code> + <code class="language-plaintext highlighter-rouge">Private — ZhgChgLi/anotherRepo</code> = ✅</p>
  </li>
</ul>

<p><strong>设定允许的方式，要去 Reuse Workflow Repo → Settings → Actions → General → Acces:</strong></p>

<p><img src="/assets/404bd5c70040/1*iZCEifgyArTJS3URMSk01g.webp" alt="" loading="lazy" decoding="async" width="725" height="300" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MjUiIGhlaWdodD0iMzAwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*iZCEifgyArTJS3URMSk01g.png" /></p>

<p>改勾选：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Accessible from repositories in the 'ZhgChgLi' organization
Workflows in other repositories that are part of the 'ZhgChgLi' organization can access the actions and reusable workflows in this repository. Access is allowed only from private repositories.
</code></pre></div></div>

<p>点击「Save」储存，完成。</p>

<p><strong>如果没权限存取会出现以下错误讯息：</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Invalid workflow file: .github/workflows/Demo-reuse-action-from-another-repo.yml#L21
error parsing called workflow
<span class="s2">".github/workflows/Demo-reuse-action-from-another-repo.yml"</span>
-&gt; <span class="s2">"ZhgChgLi/github-actions-ci-cd-demo-share-actions/.github/workflows/Automation-label-pr-base-branch.yml@main"</span>
: workflow was not found.
</code></pre></div></div>

<h3 id="github-actions-script-语法补充">GitHub Actions Script 语法补充</h3>

<p>补充一下大家可能会感到疑惑的 <code class="language-plaintext highlighter-rouge">${{ XXX }}</code> or <code class="language-plaintext highlighter-rouge">${XXX}</code> or <code class="language-plaintext highlighter-rouge">$XXX</code> 变数语法。</p>

<p><strong>Demo-Env-Vars- .yml:</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Demo-Env-Vars</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">print-env-vars</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>

    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">print-env</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">env</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">context-vars-vs-vars</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">SAY_MY_NAME</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Heisenberg"</span>
          <span class="c1"># GitHub Actions Context 表达式，同下方解释</span>
          <span class="na">FROM_REF</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">github.ref</span><span class="nv"> </span><span class="s">}}"</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s"># Sehll Script</span><span class="err">:</span>
          <span class="c1"># 引用自订注入的 ENV 变数内容</span>
          <span class="c1"># ${SAY_MY_NAME} or $SAY_MY_NAME 都可以</span>
          <span class="c1"># ${XX} 遇到字串拼接比较好用:</span>
          <span class="s">echo "HI</span><span class="err">:</span> <span class="s">${SAY_MY_NAME}"</span>
          
          <span class="s"># 💡 GitHub Actions Context 表达式</span>
          <span class="s"># 这不是 shell 变数，而是 YAML 解析阶段由 GitHub Actions 替换成对应值</span>
          <span class="s"># ⚠ 在本机或非 GitHub Actions 环境执行会失败</span>
          <span class="s"># 🔗 https://docs.github.com/en/actions/learn-github-actions/contexts#github-context</span>
          <span class="s">BRANCH_NAME_FROM_CONTEXT="${{ github.ref }}"</span>
          
          <span class="s"># 💡 GitHub Actions 执行阶段的环境变数</span>
          <span class="s"># 这些变数在 runner 执行 shell 时由 GitHub Actions 自动注入</span>
          <span class="s"># ✅ 在其他环境可用 export 或 ENV 预先定义相同变数</span>
          <span class="s"># 🔗 https://docs.github.com/en/actions/learn-github-actions/environment-variables</span>
          <span class="s">BRANCH_NAME_FROM_ENV_VARS="${GITHUB_REF}"</span>
          
          <span class="s">echo "FROM_REF</span><span class="err">:</span> <span class="s">${FROM_REF}"</span>
          <span class="s">echo "BRANCH_NAME_FROM_CONTEXT</span><span class="err">:</span> <span class="s">${BRANCH_NAME_FROM_CONTEXT}"</span>
          <span class="s">echo "BRANCH_NAME_FROM_ENV_VARS</span><span class="err">:</span> <span class="s">${BRANCH_NAME_FROM_ENV_VARS}"</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">print-github-script-env</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/github-script@v7</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">SAY_MY_NAME</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Heisenberg"</span>
          <span class="c1"># GitHub Actions Context 表达式，同上方解释</span>
          <span class="na">FROM_REF</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${{</span><span class="nv"> </span><span class="s">github.ref</span><span class="nv"> </span><span class="s">}}"</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">script</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">// GitHub Script</span><span class="na">: (JavaScript (Node.js))</span><span class="pi">:</span>
            <span class="s">// 从 process.env 取 ENV 值</span>
            <span class="s">console.log(`HI</span><span class="err">:</span> <span class="s">${process.env.SAY_MY_NAME}`);</span>
            <span class="s">console.log(`FROM_REF</span><span class="err">:</span> <span class="s">${process.env.FROM_REF}`);</span>
            <span class="s">// github-script 中会自动注入到 context 变数供 javascript 直接引用</span>
            <span class="s">// https://docs.github.com/en/actions/learn-github-actions/contexts#github-context</span>
            <span class="s">const branch_name_from_context_vars = context.ref;</span>
            <span class="s">console.log(`branch_name_from_context_vars</span><span class="err">:</span> <span class="s">${branch_name_from_context_vars}`);</span>
            <span class="s">// 同样也能用 GitHub Actions Context 表达式(只是意义不大)</span><span class="err">:</span>
            <span class="s">const branch_name_from_context = "${{ github.ref }}";</span>
            <span class="s">console.log(`branch_name_from_context</span><span class="err">:</span> <span class="s">${branch_name_from_context}`);</span>
            
            <span class="s">for (const [key, value] of Object.entries(process.env)) {</span>
              <span class="s">console.log(`${key}=${value}`);</span>
            <span class="s">}</span>
            <span class="s">// github-script 中的 github 物件是 Octokit REST API 实例</span>
            <span class="s">// 用来操作 github api 使用</span>
            <span class="s">// 例如：</span>
            <span class="s">// await github.rest.pulls.list({</span>
            <span class="s">//   owner</span><span class="err">:</span> <span class="s">context.repo.owner,</span>
            <span class="s">//   repo</span><span class="err">:</span> <span class="s">context.repo.repo,</span>
            <span class="s">//   state</span><span class="err">:</span> <span class="s2">"</span><span class="s">open"</span>
            <span class="s">//  });</span>
      <span class="c1"># gh CLI does NOT use GITHUB_TOKEN by default; requires GH_TOKEN</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">gh CLI without GH_TOKEN (expected to fail)</span>
        <span class="na">continue-on-error</span><span class="pi">:</span> <span class="kc">true</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">PR_COUNT=$(gh pr list --repo $GITHUB_REPOSITORY --json number --jq 'length')</span>
          <span class="s">echo "Found $PR_COUNT open pull requests"</span>
      
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">gh CLI with GH_TOKEN (expected to succeed)</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="c1"># Assign GH_TOKEN so gh CLI can authenticate</span>
          <span class="c1"># https://docs.github.com/en/actions/how-tos/security-for-github-actions/security-guides/use-github_token-in-workflows</span>
          <span class="na">GH_TOKEN</span><span class="pi">:</span> <span class="s">${{ secrets.GITHUB_TOKEN }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">PR_COUNT=$(gh pr list --repo $GITHUB_REPOSITORY --json number --jq 'length')</span>
          <span class="s">echo "Found $PR_COUNT open pull requests"</span>
      
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">github-script auto-authentication (no GH_TOKEN needed)</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/github-script@v7</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">script</span><span class="pi">:</span> <span class="s">\\|</span>
            <span class="s">// github = Octokit REST client (auto-authenticated with GITHUB_TOKEN)</span>
            <span class="s">const pulls = await github.rest.pulls.list({</span>
              <span class="s">owner</span><span class="err">:</span> <span class="s">context.repo.owner,</span>
              <span class="s">repo</span><span class="err">:</span> <span class="s">context.repo.repo,</span>
              <span class="s">state</span><span class="err">:</span> <span class="s2">"</span><span class="s">open"</span>
            <span class="err">}</span><span class="s">);</span>
            <span class="s">console.log(`Found ${pulls.data.length} open pull requests`);</span>
</code></pre></div></div>

<h4 id="--xxx---github-actions-context-表达式">${ { XXX } } GitHub Actions Context 表达式</h4>

<p><img src="/assets/404bd5c70040/1*e3jpPuwdmf005cjbaXjAwQ.webp" alt="" loading="lazy" decoding="async" width="789" height="684" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3ODkiIGhlaWdodD0iNjg0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*e3jpPuwdmf005cjbaXjAwQ.png" /></p>

<p><img src="/assets/404bd5c70040/1*ed5Wm7Xk48xuP8yQzHpJ9w.webp" alt="" loading="lazy" decoding="async" width="880" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4ODAiIGhlaWdodD0iODAwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*ed5Wm7Xk48xuP8yQzHpJ9w.png" /></p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">${{ XXX }}</code> 是 GitHub Actions Context 表达式， <strong>在YAML 解析阶段由 GitHub Actions 替换成对应值</strong> (如上图 <code class="language-plaintext highlighter-rouge">BRANCH_NAME_FROM_CONTEXT</code> )</p>
  </li>
  <li>
    <p>完整可用表达式可 <a href="https://docs.github.com/en/actions/learn-github-actions/contexts#github-context" target="_blank">参考官方文件</a></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">${XXX}</code> or <code class="language-plaintext highlighter-rouge">$XXX</code> 是真实环境变数， <code class="language-plaintext highlighter-rouge">${XXX}</code> 在字串拼接比较好用</p>
  </li>
  <li>
    <p>GitHub Actions 预设会注入一些环境变数，完整可 <a href="https://docs.github.com/en/actions/learn-github-actions/environment-variables" target="_blank">参考官方文件</a></p>
  </li>
</ul>

<h4 id="actionsgithub-scriptv7">actions/github-script@v7</h4>

<p><img src="/assets/404bd5c70040/1*TjJQnlAAU3VRwS9_dFz1yA.webp" alt="" loading="lazy" decoding="async" width="718" height="913" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MTgiIGhlaWdodD0iOTEzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*TjJQnlAAU3VRwS9_dFz1yA.png" /></p>

<p><img src="/assets/404bd5c70040/1*5bHEdjrGsVdWnYSQgpnsZA.webp" alt="" loading="lazy" decoding="async" width="1018" height="1150" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDE4IiBoZWlnaHQ9IjExNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/404bd5c70040/1*5bHEdjrGsVdWnYSQgpnsZA.png" /></p>

<ul>
  <li>
    <p>在 <code class="language-plaintext highlighter-rouge">github-script</code> 中同样可以用 <code class="language-plaintext highlighter-rouge">${{ XXX }}</code> 是 GitHub Actions Context 表达式，但是意义不大；因为 <strong>在 github-scirpt 环境中预设会注入 context 变数可以直接在 javascript 中引用</strong></p>
  </li>
  <li>
    <p>在 <code class="language-plaintext highlighter-rouge">github-script</code> 中 <code class="language-plaintext highlighter-rouge">github</code> 物件是 Octokit REST API 实例</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">github-script</code> 也能从 <code class="language-plaintext highlighter-rouge">env:</code> 注入变数，但是要用 <code class="language-plaintext highlighter-rouge">${process.env.xxx}</code> 存取</p>
  </li>
  <li>
    <p>同样预设会注入一些环境变数，完整可 <a href="https://docs.github.com/en/actions/learn-github-actions/environment-variables" target="_blank">参考官方文件</a> <code class="language-plaintext highlighter-rouge">${process.env.xxx}</code> 存取；但是已经有 <code class="language-plaintext highlighter-rouge">context</code> 变数了，从这存取意义也不大</p>
  </li>
</ul>

<p><img src="/assets/404bd5c70040/1*oW85Sju0sN4caXiaLSg32A.webp" alt="" loading="lazy" decoding="async" width="735" height="408" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MzUiIGhlaWdodD0iNDA4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*oW85Sju0sN4caXiaLSg32A.png" /></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">github-script</code> 会自动带入 <code class="language-plaintext highlighter-rouge">github-token</code> ，无需指定</li>
</ul>

<h4 id="gh-cli-gh_token">gh cli GH_TOKEN</h4>

<p><img src="/assets/404bd5c70040/1*NUfaaKIobZWVBuXrGg0TPw.webp" alt="" loading="lazy" decoding="async" width="866" height="431" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjYiIGhlaWdodD0iNDMxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*NUfaaKIobZWVBuXrGg0TPw.png" /></p>

<ul>
  <li>
    <p>在 GitHub Actions Shell Script 使用 <code class="language-plaintext highlighter-rouge">gh cli</code> 需指定 <code class="language-plaintext highlighter-rouge">GH_TOKEN</code> 参数</p>
  </li>
  <li>
    <p>可以直接带入预设 Token — <code class="language-plaintext highlighter-rouge">secrets.GITHUB_TOKEN</code> (GitHub Actions 执行时自动产生)</p>
  </li>
  <li>
    <p><strong>预设 Token 有一些基本权限，如果要操作的指令权限不够就要改用 <a href="https://docs.github.com/en/actions/how-tos/security-for-github-actions/security-guides/use-github_token-in-workflows" target="_blank">Personal Access Token</a></strong> ，团队使用建议用共用帐号建立 PAT。</p>
  </li>
</ul>

<p><strong>完整程式码： <a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/blob/main/.github/workflows/Demo-Env-Vars-.yml" target="_blank">Demo-Env-Vars- .yml</a></strong></p>

<p>GitHub Actions 已经开发好了，下一步我们可以抽换 GitHub Hosted Runner 成自己的 Self-hosted Runner。</p>

<blockquote>
  <p><em>GitHub Hosted Runner 有免费额度 2,000 分钟一个月(起)，跑这种小的自动化任务花不了多少时间，而且是跑在 linux 机器花费很低，可能还用不到免费上限； <strong>不一定要改成 Self-hosted Runner</strong> ，改 Runner 还要确保 Runner 环境正确(例如 GitHub Hosted Runner 自带 gh cli，self-hosted Runner 就记得要自己安装好)， <strong>本文纯粹是因为教学才会这样抽换</strong> 。</em></p>
</blockquote>

<blockquote>
  <p><em>如果是用在执行 CI/CD 任务才必须要用 Self-hosted Runner。</em></p>
</blockquote>

<h4 id="新增-self-hosted-runner">新增 Self-hosted Runner</h4>

<blockquote>
  <p><em>本文以 <strong>macOS M1</strong> 为例。</em></p>
</blockquote>

<p><img src="/assets/404bd5c70040/1*mEInaj-tLaprMAa2OfowCw.webp" alt="" loading="lazy" decoding="async" width="1225" height="1136" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjI1IiBoZWlnaHQ9IjExMzYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/404bd5c70040/1*mEInaj-tLaprMAa2OfowCw.png" /></p>

<ul>
  <li>
    <p>Settings → Actions → Runners → New self-hosted runner。</p>
  </li>
  <li>
    <p><strong>Runner image:</strong> macOS</p>
  </li>
  <li>
    <p><strong>Architecture</strong> : M1 记得选 ARM64 执行比较快</p>
  </li>
</ul>

<p><strong>在实体电脑上开一个 Termnial。</strong></p>

<p><strong>按照 Download 步骤在本地电脑完成：</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 在你想要的路径，建立 Runner 目录</span>
<span class="nb">mkdir </span>actions-runner <span class="o">&amp;&amp;</span> <span class="nb">cd </span>actions-runner
<span class="c"># 下载 Runner image</span>
curl <span class="nt">-o</span> actions-runner-osx-x64-2.325.0.tar.gz <span class="nt">-L</span> https://github.com/actions/runner/releases/download/v2.325.0/actions-runner-osx-x64-2.325.0.tar.gz

<span class="c"># Optional: Validate the hash</span>
<span class="nb">echo</span> <span class="s2">"0562bd934b27ca0c6d8a357df00809fbc7b4d5524d4aeb6ec152e14fd520a4c3  actions-runner-osx-x64-2.325.0.tar.gz"</span> <span class="se">\\</span>| shasum <span class="nt">-a</span> 256 <span class="nt">-c</span>

<span class="c"># 解压缩</span>
<span class="nb">tar </span>xzf ./actions-runner-osx-x64-2.325.0.tar.gz
</code></pre></div></div>

<blockquote>
  <p><em>以上只是参考；建议照你设定页里的步骤来做，才会是最新版本的 Runner image。</em></p>
</blockquote>

<p><img src="/assets/404bd5c70040/1*Q0k0EPjrY2V4owseESe5lg.webp" alt="" loading="lazy" decoding="async" width="1161" height="197" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTYxIiBoZWlnaHQ9IjE5NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*Q0k0EPjrY2V4owseESe5lg.png" /></p>

<p><strong>设定 Configure:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 请参考设定页指令，Token 会随时间改变</span>
./config.sh <span class="nt">--url</span> https://github.com/ORG/REPO <span class="nt">--token</span> XXX
</code></pre></div></div>

<p>会依序要你输入：</p>

<ul>
  <li>
    <p>Enter the name of the runner group to add this runner to: [press Enter for Default] <strong>直接 Enter</strong>
*只有注册到 Organization 组织层级的 Runner 才有 Group 分组功能</p>
  </li>
  <li>
    <p>Enter the name of runner: [press Enter for ZhgChgLideMacBook-Pro] <strong>可以输入想设定的 Runner 名称 e.g.</strong> <code class="language-plaintext highlighter-rouge">app-runner-1</code> <strong>或直接 Enter</strong></p>
  </li>
  <li>
    <p>This runner will have the following labels: ‘self-hosted’, ‘macOS’, ‘X64’
Enter any additional labels (ex. label-1,label-2): [press Enter to skip]
<strong>输入想要设定的 Runner label，可以多输入自订 Label 方便之后使用</strong>
同前述 GitHub Acitons/Runner 是依照对应 Label 找任务来做， <strong>如果只用 default label，Runner 可能会捡到组织内的其他 Runner 来执行工作，自订一个最保险</strong> 。
这边我自己乱定了一个 label <code class="language-plaintext highlighter-rouge">self-hosted-zhgchgli</code></p>
  </li>
  <li>
    <p>Enter name of work folder: [press Enter for _work] <strong>直接 Enter</strong></p>
  </li>
</ul>

<p>出现 √ Settings Saved. 代表设定完成了。</p>

<p><img src="/assets/404bd5c70040/1*yxLfii0rWhzsiFuYVmPgFw.webp" alt="" loading="lazy" decoding="async" width="929" height="501" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjkiIGhlaWdodD0iNTAxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*yxLfii0rWhzsiFuYVmPgFw.png" /></p>

<p><strong>启动 Runner:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./run.sh
</code></pre></div></div>

<p>出现 √ Connected to GitHub、Listening for Jobs 就代表已经在监听 Actions 任务了：</p>

<p><img src="/assets/404bd5c70040/1*1RmPPOosAoCxHA9tg_WE2w.webp" alt="" loading="lazy" decoding="async" width="290" height="98" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOTAiIGhlaWdodD0iOTgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/404bd5c70040/1*1RmPPOosAoCxHA9tg_WE2w.png" /></p>

<blockquote>
  <p><strong><em>这个 Terminal 视窗不关闭就会持续接收任务来做。</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>🚀🚀🚀同一台电脑开多个 Terminal 在不同目录就能起多个 Runner。</em></strong></p>
</blockquote>

<p><strong>回到 Repo 设定页也能看到 Runner 正在等待任务：</strong></p>

<p><img src="/assets/404bd5c70040/1*jjq5NTPYMuC3gH3ey_VTtg.webp" alt="" loading="lazy" decoding="async" width="802" height="247" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MDIiIGhlaWdodD0iMjQ3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*jjq5NTPYMuC3gH3ey_VTtg.png" /></p>

<p><strong>Status:</strong></p>

<ul>
  <li>
    <p>Idle: 闲置，在等待任务</p>
  </li>
  <li>
    <p>Active: 有任务正在执行</p>
  </li>
  <li>
    <p>Offline: Runner 不在线上</p>
  </li>
</ul>

<h4 id="workflowgithub-actions-runner-改用-self-hosted-runner">Workflow(GitHub Actions) Runner 改用 Self-hosted Runner</h4>

<p>以 <code class="language-plaintext highlighter-rouge">Automation-PullRequest.yml</code> 为例：</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 请参考前文，略....</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">label-pr-by-file-count</span><span class="pi">:</span>
    <span class="c1"># 请参考前文，略....</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">self-hosted-zhgchgli</span><span class="pi">]</span>
    <span class="c1"># 请参考前文，略....</span>
  <span class="c1"># ---------</span>
  <span class="na">assign-self-if-no-assignee</span><span class="pi">:</span>
    <span class="c1"># 请参考前文，略....</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">self-hosted-zhgchgli</span><span class="pi">]</span>

    <span class="na">steps</span><span class="pi">:</span>
      <span class="c1"># 请参考前文，略....</span>
</code></pre></div></div>

<p>Commit 档案到 Repo 主分支之后，重新开 PR 触发验证一下 Actions。</p>

<p><strong>回到 Runner Terminal 就能看到有新的任务进来了，正在执行跟执行结果：</strong></p>

<p><img src="/assets/404bd5c70040/1*Hu0DxKQbenPmBEw8swv65A.webp" alt="" loading="lazy" decoding="async" width="628" height="100" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MjgiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*Hu0DxKQbenPmBEw8swv65A.png" /></p>

<p>失败了，因为我本机电脑没有安装 <a href="https://github.com/cli/cli" target="_blank">gh cli</a> 环境：</p>

<p><img src="/assets/404bd5c70040/1*9xguacdPATIeEZdbFszmHw.webp" alt="" loading="lazy" decoding="async" width="973" height="123" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NzMiIGhlaWdodD0iMTIzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*9xguacdPATIeEZdbFszmHw.png" /></p>

<p>使用 <code class="language-plaintext highlighter-rouge">brew install gh</code> 在实体电脑上安装完 gh 后再次触发执行：</p>

<p><img src="/assets/404bd5c70040/1*TbkAt00K89Ysbix33dK8ZA.webp" alt="" loading="lazy" decoding="async" width="631" height="29" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MzEiIGhlaWdodD0iMjkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/404bd5c70040/1*TbkAt00K89Ysbix33dK8ZA.png" /></p>

<p>成功！现在这个任务就完全是使用我们自己的电脑在执行，不使用 GitHub Hosted Runner、不计费使用。</p>

<p><strong>我们可以点进去 Action Log 查看任务执行在的 Runner、机器是哪一个：</strong></p>

<p><img src="/assets/404bd5c70040/1*oqLcWfn6cbWsCt9fVsrikQ.webp" alt="" loading="lazy" decoding="async" width="1092" height="826" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDkyIiBoZWlnaHQ9IjgyNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/404bd5c70040/1*oqLcWfn6cbWsCt9fVsrikQ.png" /></p>

<h4 id="runs-on--runner-label-设定">runs-on: [ <strong>Runner Label] 设定</strong></h4>

<p>这里是 AND 不是 OR，GitHub Runner 暂不支援 OR 挑选 Runner 执行。</p>

<p>例如： <code class="language-plaintext highlighter-rouge">[self-hosted, macOS, app]</code> → 代表 Runner 要 <strong>同时有</strong> <code class="language-plaintext highlighter-rouge">self-hosted, macOS, app</code> 这 3 个 Labels 才会匹配接任务来执行。</p>

<p>如果一个 Job 想同时测试不同 Runner 环境下的结果可以使用 <code class="language-plaintext highlighter-rouge">matrix</code> 参数：</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">jobs</span><span class="pi">:</span>
  <span class="na">test</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">${{ matrix.runner }}</span>
    <span class="na">strategy</span><span class="pi">:</span>
      <span class="na">matrix</span><span class="pi">:</span>
        <span class="na">runner</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="pi">[</span><span class="nv">self-hosted</span><span class="pi">,</span> <span class="nv">linux</span><span class="pi">,</span> <span class="nv">high-memory</span><span class="pi">]</span>
          <span class="pi">-</span> <span class="pi">[</span><span class="nv">self-hosted</span><span class="pi">,</span> <span class="nv">macos</span><span class="pi">,</span> <span class="nv">xcode-15</span><span class="pi">]</span>

    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">echo "Running on ${{ matrix.runner }}"</span>
</code></pre></div></div>

<p>这样这个 Job 会在下列两个 Runner Labels Runner 中并行各执行一次：</p>

<ul>
  <li>
    <p>self-hosted, linux, high-memory</p>
  </li>
  <li>
    <p>self-hosted, macos, xcode-15</p>
  </li>
</ul>

<blockquote>
  <p><strong><em>Runner 暂不支援：</em></strong></p>
</blockquote>

<blockquote>
  <p><em>- OR 挑选 Runner</em></p>
</blockquote>

<blockquote>
  <p><em>- Runner 权重设定</em></p>
</blockquote>

<h4 id="注册-runner-成-service">注册 Runner 成 Service</h4>

<p>可以参考官方文件「 <a href="https://docs.github.com/en/actions/how-tos/hosting-your-own-runners/managing-self-hosted-runners/configuring-the-self-hosted-runner-application-as-a-service?platform=mac" target="_blank">Configuring the self-hosted runner application as a service</a> 」将 Runner 直接注册成系统 Service，这样就能在背景执行(不用开 Terminal 在前景)、开机后也会自动启动。</p>

<p>有多个 Runner 记得调整「 <a href="https://docs.github.com/en/actions/how-tos/hosting-your-own-runners/managing-self-hosted-runners/configuring-the-self-hosted-runner-application-as-a-service?platform=mac#customizing-the-self-hosted-runner-service-1" target="_blank">Customizing the self-hosted runner service</a> 」设定注册不同名称。</p>

<blockquote>
  <p><em>iOS 这边我有一个待研究排除的问题， <strong>就是我改用背景 Service 之后在 Archive 会遇到错误(疑似是跟 keychain 权限有关)</strong> ，当时没时间解决，就先用起前景 Terminal Runner 了。</em></p>
</blockquote>

<p>如果是传统前景要做到开机自动启动就要去 <code class="language-plaintext highlighter-rouge">~/Library/LaunchAgents</code> 新增一个自动启动设定档案：</p>

<p><code class="language-plaintext highlighter-rouge">actions.runner.REPO.RUNNER_NAME.plist</code> ：</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cp">&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;</span>
<span class="nt">&lt;plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">&gt;</span>
 <span class="nt">&lt;dict&gt;</span>
  <span class="nt">&lt;key&gt;</span>Label<span class="nt">&lt;/key&gt;</span>
  <span class="nt">&lt;string&gt;</span>actions.runner.REPO.RUNNER_NAME<span class="nt">&lt;/string&gt;</span>
  <span class="c">&lt;!-- 指定 Terminal.app 来启动 --&gt;</span>
  <span class="nt">&lt;key&gt;</span>ProgramArguments<span class="nt">&lt;/key&gt;</span>
  <span class="nt">&lt;array&gt;</span>
   <span class="nt">&lt;string&gt;</span>/usr/bin/open<span class="nt">&lt;/string&gt;</span>
   <span class="nt">&lt;string&gt;</span>-a<span class="nt">&lt;/string&gt;</span>
   <span class="nt">&lt;string&gt;</span>Terminal<span class="nt">&lt;/string&gt;</span>
   <span class="nt">&lt;string&gt;</span>/Users/zhgchgli/Documents/actions-runner/run.sh<span class="nt">&lt;/string&gt;</span>
  <span class="nt">&lt;/array&gt;</span>
  <span class="nt">&lt;key&gt;</span>RunAtLoad<span class="nt">&lt;/key&gt;</span>
  <span class="nt">&lt;true/&gt;</span>
  <span class="nt">&lt;key&gt;</span>WorkingDirectory<span class="nt">&lt;/key&gt;</span>
  <span class="nt">&lt;string&gt;</span>/Users/zhgchgli/Documents/actions-runner<span class="nt">&lt;/string&gt;</span>
 <span class="nt">&lt;/dict&gt;</span>
<span class="nt">&lt;/plist&gt;</span>
</code></pre></div></div>

<blockquote>
  <p><em>有兴趣深入研究 DevOps 的朋友可参考官方 <a href="https://docs.github.com/en/actions/concepts/runners/about-actions-runner-controller#scaling-runners" target="_blank">k8s Runner</a> 文件。</em></p>
</blockquote>

<h4 id="完整专案-repo">完整专案 Repo</h4>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo" target="_blank"><img src="https://opengraph.githubassets.com/8b25f8eae56bc35c92b97c5d7e7834aa5cb87673e718a1ce829f5bb80f3edebb/ZhgChgLi/github-actions-ci-cd-demo" alt="" /></a></p>

<h3 id="官方文件">官方文件</h3>

<p><a href="https://docs.github.com/en/actions/get-started/quickstart" target="_blank"><img src="https://docs.github.com/assets/cb-345/images/social-cards/actions.png" alt="" /></a></p>

<p>更细节的设置方式请务必参考官方手册。</p>

<h4 id="ai-can-help">AI Can Help!</h4>

<p><img src="/assets/404bd5c70040/1*JecNUCqujV1oeAvHA14X-g.webp" alt="" loading="lazy" decoding="async" width="1114" height="1140" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTE0IiBoZWlnaHQ9IjExNDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/404bd5c70040/1*JecNUCqujV1oeAvHA14X-g.png" /></p>

<p>实测给 ChatGPT 完整的步骤跟时机点就能帮你写好 GitHub Actions 直接使用!</p>

<h3 id="总结">总结</h3>

<p>现在你应该已经对 GitHub Actions + Self-hosted Runner 有了一定程度的了解，下一篇我将开始以 App (iOS) CI/CD 为案例，手把手建置整套流程。</p>

<h3 id="系列文章">系列文章：</h3>

<ul>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-是什么-打造高效稳定开发团队的关键流程与工具选择-c008a9e8ceca/"><strong>CI/CD 实战指南（一）：CI/CD 是什么？如何透过 CI/CD 打造稳定高效的开发团队？工具选择？</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-self-hosted-runner-详解与实战案例-ci-cd-自动化工作流程建置-404bd5c70040/"><strong>CI/CD 实战指南（二）：GitHub Actions 与 self-hosted Runner 使用与建置大全</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/"><strong>CI/CD 实战指南（三）：使用 GitHub Actions 实作 App 专案的 CI 与 CD 工作流程</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/"><strong>CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</strong></a></p>
  </li>
</ul>

<h4 id="-buy-me-a-beer-on-paypal"><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank">🍺 Buy me a beer on PayPal</a></h4>

<blockquote>
  <p><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank"><strong><em>本系列文章花费了大量的时间精力撰写，如果内容对您有帮助、对您的团队有实质提升工作效率与产品品质；欢迎请我喝杯咖啡，感谢支持！</em></strong></a></p>
</blockquote>

<p><img src="/assets/404bd5c70040/1*QJj54G9gOjtQS-rbHVT1SQ.webp" alt="Buy me a coffee" loading="lazy" decoding="async" width="700" height="700" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDAiIGhlaWdodD0iNzAwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/404bd5c70040/1*QJj54G9gOjtQS-rbHVT1SQ.png" /></p>

<p><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank">🍺 Buy me a beer on PayPal</a></p>]]></content>
  </entry><entry>
    <title type="html">CI/CD 是什么｜打造高效稳定开发团队的关键流程与工具选择</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/ci-cd-%E6%98%AF%E4%BB%80%E4%B9%88-%E6%89%93%E9%80%A0%E9%AB%98%E6%95%88%E7%A8%B3%E5%AE%9A%E5%BC%80%E5%8F%91%E5%9B%A2%E9%98%9F%E7%9A%84%E5%85%B3%E9%94%AE%E6%B5%81%E7%A8%8B%E4%B8%8E%E5%B7%A5%E5%85%B7%E9%80%89%E6%8B%A9-c008a9e8ceca/" rel="alternate" type="text/html" title="CI/CD 是什么｜打造高效稳定开发团队的关键流程与工具选择" />
    <published>2025-06-30T15:10:16+08:00</published>
    <updated>2025-12-18T00:24:11+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/c008a9e8ceca</id><summary type="html">针对 iOS App 团队，解析无 CI/CD 流程的痛点，透过 GitHub Actions 与 self-hosted Runner 自动化测试与打包，减少人力浪费与错误，提升团队稳定性与开发效率，搭配 Google Apps Script Web App 实现跨职能便捷操作。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="ios-app-development" /><category term="cicd" /><category term="github-actions" /><category term="jenkins" /><category term="agile" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/c008a9e8ceca/1*vokpvb4dyWHOnVnF3WGbfw.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/ci-cd-%E6%98%AF%E4%BB%80%E4%B9%88-%E6%89%93%E9%80%A0%E9%AB%98%E6%95%88%E7%A8%B3%E5%AE%9A%E5%BC%80%E5%8F%91%E5%9B%A2%E9%98%9F%E7%9A%84%E5%85%B3%E9%94%AE%E6%B5%81%E7%A8%8B%E4%B8%8E%E5%B7%A5%E5%85%B7%E9%80%89%E6%8B%A9-c008a9e8ceca/"><![CDATA[<h3 id="cicd-实战指南一cicd-是什么如何透过-cicd-打造稳定高效的开发团队工具选择">CI/CD 实战指南（一）：CI/CD 是什么？如何透过 CI/CD 打造稳定高效的开发团队？工具选择？</h3>

<p>以 App (iOS) Team 为例，带您从 0 认识 CI/CD 与导入后能带来的实质价值。</p>

<p><img src="/assets/c008a9e8ceca/1*vokpvb4dyWHOnVnF3WGbfw.webp" alt="Photo by Leif Christoph Gottwald" loading="lazy" decoding="async" width="1200" height="675" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY3NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/c008a9e8ceca/1*vokpvb4dyWHOnVnF3WGbfw.jpeg" /></p>

<p>Photo by <a href="https://unsplash.com/@project2204?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank">Leif Christoph Gottwald</a></p>

<h3 id="2026-update--pricing-changes-for-github-actions-including-self-hosted-runner">2026 Update — Pricing changes for GitHub Actions (including Self-hosted Runner)</h3>

<blockquote>
  <p><a href="https://resources.github.com/actions/2026-pricing-changes-for-github-actions/" target="_blank">TLDR — On January 1, 2026, we are lowering the price of hosted runners, and beginning March 1, 2026, we are charging $0.002 per-minute across self-hosted runners. The vast majority of customers will not see a change to their bill. Actions will remain free in public repositories.</a></p>
</blockquote>

<p>GitHub 2025/12/14 <a href="https://resources.github.com/actions/2026-pricing-changes-for-github-actions/" target="_blank">最新公告</a> ：</p>

<ul>
  <li>
    <p>2026 年 1 月 1 日：GitHub-hosted Runner 更便宜了，价格下调最高 39%。</p>
  </li>
  <li>
    <p>2026 年 3 月 1 日： <strong>使用 Self-hosted Runner 需要多支付服务维运费，每分钟 $0.002 美元(不分 OS)、等于 500 分钟花费 1 美元，目前来看还是划算。</strong> ️</p>
  </li>
  <li>
    <p>Public repository 仍保持相同免费额度。</p>
  </li>
</ul>

<p><strong>GitHub 也会投入更多资源提升 GitHub Actions 功能：</strong></p>

<ul>
  <li>
    <p><strong>Scale Set Client：</strong> 简化 Self-hosted Runner 的 <strong>Autoscaling</strong> 。</p>
  </li>
  <li>
    <p><strong>multi-label：支援重启</strong> ，改进 Runner 标签体验。</p>
  </li>
  <li>
    <p><strong>Actions Runner Controller (ARC)</strong> 更新：提升配置、可观察性与版本管理。</p>
  </li>
  <li>
    <p><strong>Actions Data Stream：</strong> 提供接近实时的 workflow/runner 事件数据串流，用于监控跟分析。</p>
  </li>
</ul>

<p><a href="https://github.com/pricing/calculator" target="_blank"><strong>官方的价格计算器也更新了</strong></a> <strong>：</strong></p>

<p><img src="/assets/c008a9e8ceca/1*CuNXq0t_70UiVY0N3JEacA.webp" alt="" loading="lazy" decoding="async" width="1144" height="921" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTQ0IiBoZWlnaHQ9IjkyMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/c008a9e8ceca/1*CuNXq0t_70UiVY0N3JEacA.png" /></p>

<ul>
  <li>
    <p>GitHub Hosted Runner — macOS 3-core(M1): $0.062 USD/分钟、1,000 分钟等于 $62 USD</p>
  </li>
  <li>
    <p>Self-Hosted Runner — $0.002 USD/分钟、1,000 分钟等于 $2 USD</p>
  </li>
</ul>

<blockquote>
  <p><em>自己买一台最新型号的 <a href="https://www.apple.com/tw/shop/buy-mac/mac-mini" target="_blank">Mac Mini 10-core(M4)</a> <strong>约 $600 USD</strong> ，放在办公室当 Self-hosted Runner 大约一年就回本了；说效能更好更快而且用量几乎等于无上限( <strong>维运费微乎其微</strong> )。</em></p>
</blockquote>

<blockquote>
  <p><em>也可以用汰换下来的旧 M1 MacBook Pro 当 Runner = 0 元。</em></p>
</blockquote>

<blockquote>
  <p>*以上不考虑电费跟网路费。</p>
</blockquote>

<h4 id="前言">前言</h4>

<p>历经了两次在不同开发团队建置 App CI/CD 的经验，最近终于有时间整理这段从「为什么要做」到「该怎么做」的心路历程；不敢保证是最标准的 CI/CD 工作流程，但绝对是一个值得参考的起点，帮助您的团队开始导入、提升产品稳定性与整体开发效率。</p>

<h4 id="章节">章节</h4>

<p>本系列文章会从「CI/CD 是什么、能带来哪些价值」开始讲起，接著开始手把手实作「如何用 GitHub Actions + self-hosted Runner 搭建 CI/CD 环境」并「以 App 开发为例，实际导入 CI 和 CD」，最后还会介绍如何「使用Google Apps Script Web App 结合 GitHub Actions，打造一个方便跨团队使用的 App 打包平台」希望这系列内容对你有所帮助。</p>

<ul>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-是什么-打造高效稳定开发团队的关键流程与工具选择-c008a9e8ceca/"><strong>CI/CD 实战指南（一）：CI/CD 是什么？如何透过 CI/CD 打造稳定高效的开发团队？工具选择？</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-self-hosted-runner-详解与实战案例-ci-cd-自动化工作流程建置-404bd5c70040/"><strong>CI/CD 实战指南（二）：GitHub Actions 与 self-hosted Runner 使用与建置大全</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/"><strong>CI/CD 实战指南（三）：使用 GitHub Actions 实作 App 专案的 CI 与 CD 工作流程</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/"><strong>CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</strong></a></p>
  </li>
</ul>

<h4 id="最终成果">最终成果</h4>

<p>废话不多说，先上最终结果。</p>

<p><img src="/assets/c008a9e8ceca/1*7-abScyjHQno1XzH4aGkaw.webp" alt="Demo PR" loading="lazy" decoding="async" width="1265" height="1093" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjY1IiBoZWlnaHQ9IjEwOTMiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/c008a9e8ceca/1*7-abScyjHQno1XzH4aGkaw.png" /></p>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/pull/11" target="_blank">Demo PR</a></p>

<p><img src="/assets/c008a9e8ceca/1*yXMeaOELhqdvMCxIJ5ElBw.gif" alt="Demo Web App (首次使用请参考下方教学)" loading="lazy" decoding="async" width="1048" height="822" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDQ4IiBoZWlnaHQ9IjgyMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<p><a href="https://script.google.com/macros/s/AKfycbwNW6N5ozKbIz_E1HK6yFEUtA8KQrUciS-jcPsQptvIKlARmKgLxbQzNu8ksVeg-BmEfg/exec" target="_blank">Demo Web App (首次使用请参考下方教学)</a></p>

<p>CI/CD — 全部都使用 GitHub Actions 开发，好维护、好扩充。</p>

<p><strong>CI:</strong></p>

<ul>
  <li>
    <p>发 PR 自动触发单元测试</p>
  </li>
  <li>
    <p>依照改动档案范围执行对应测试</p>
  </li>
  <li>
    <p>测试通过 (passed) 后才能 Merge PR</p>
  </li>
</ul>

<p><strong>CD:</strong></p>

<ul>
  <li>
    <p>Google Apps Script Web App (CD 打包介面) 工程师、QA、PM 都可以透过这个网站在电脑或手机上打包 App</p>
  </li>
  <li>
    <p>GitHub Actions Self-hosted Runner 使用自己的机器跑 CI/CD 用量吃到饱</p>
  </li>
  <li>
    <p>串接 Firebase App Distribution API 直接取得打包的测试版下载连结</p>
  </li>
</ul>

<p><strong>Automation</strong> :</p>

<ul>
  <li>
    <p>发 PR 自动 Assign self</p>
  </li>
  <li>
    <p>发 PR 自动随机指定 Reviewer</p>
  </li>
  <li>
    <p>标记 PR Size Label</p>
  </li>
</ul>

<h4 id="demo-web-appproject">Demo Web App/Project</h4>

<ul>
  <li><a href="https://script.google.com/macros/s/AKfycbwNW6N5ozKbIz_E1HK6yFEUtA8KQrUciS-jcPsQptvIKlARmKgLxbQzNu8ksVeg-BmEfg/exec" target="_blank">Online Demo</a> 初次使用请参考下图授权(Only For Demo App)：</li>
</ul>

<p><img src="/assets/c008a9e8ceca/1*0cD7NrUr9J9roqIe4Upfzg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1215" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEyMTUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/c008a9e8ceca/1*0cD7NrUr9J9roqIe4Upfzg.png" /></p>

<p><a href="https://script.google.com/home/projects/1CBB39OMedqP9Ro1WSlvgDnMBin4-ksyhgly2h_KrbOuFiPHTalNgwHOp/edit?pli=1" target="_blank"><img src="https://www.gstatic.com/devrel-devsite/prod/ve08add287a6b4bdf8961ab8a1be50bf551be3816cdd70b7cc934114ff3ad5f10/developers/images/opengraph/white.png" alt="" /></a></p>

<p><a href="https://github.com/ZhgChgLi/github-actions-ci-cd-demo/" target="_blank"><img src="https://opengraph.githubassets.com/1f6ece1b633e29e5f817f1a2771b0d19233ab1d921be17b9d9103d8a8147da61/ZhgChgLi/github-actions-ci-cd-demo" alt="" /></a></p>

<h3 id="cicd-是什么">CI/CD 是什么？</h3>

<h4 id="故事--无-cicd-的开发流程">故事 — 无 CI/CD 的开发流程</h4>

<p>在谈 CI/CD 究竟是什么之前我们先抛开「CI/CD」这个词，先来回想一下一个初创什么工作流程都没有导入的开发团队，会是怎么工作的，大致简略为下图流程：</p>

<p><img src="/assets/c008a9e8ceca/1*rg4hbs7MsYDU9HZoehrvjQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="801" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjgwMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/c008a9e8ceca/1*rg4hbs7MsYDU9HZoehrvjQ.png" /></p>

<ol>
  <li>
    <p>产品有一个 Bug，Developer T 从主分支开分支 fix/bug-c 分支进行修正，修正完后 Merge 回主分支。</p>
  </li>
  <li>
    <p>紧接著 Developer Z 从主分支开分支 feature/a 做 需求 A，做到一半发现功能怪怪的， <strong>查了一下才发现原来当前功能被改坏、测试也坏了</strong> ，回头通知 Developer T 进行修正。</p>
  </li>
  <li>
    <p>一切开发完毕后，Developer Z <strong>使用他的电脑打包版本给 QA 测试，来来回回修正跟打包</strong> ，最后没问题后将功能回到主分支。</p>
  </li>
  <li>
    <p>很快地也到了 Sprint 尾声需要打包释出给使用者；Developer Z <strong>先放下手上工作</strong> ，协助从主分支打包给 QA 进行 Regression 测试，同样 <strong>来来回回修正问题跟重新打包</strong> ，完成后打包送审 App。</p>
  </li>
  <li>
    <p>Apple/Google 审核完毕后发布给使用者使用。</p>
  </li>
</ol>

<h4 id="问题">问题</h4>

<p>在以上故事中我们可以归纳出两个大问题。</p>

<p><strong>Question 1: 对当前正确的功能异动无任何统一检查机制。</strong></p>

<ul>
  <li>
    <p>不符合 Coding Style 的程式码也能 Merge</p>
  </li>
  <li>
    <p>就算 Build 不起来我也能 Merge</p>
  </li>
  <li>
    <p>异动后基本的 Unit Tests、重要检查项目都没过也能 Merge</p>
  </li>
  <li>
    <p>我的环境功能正确但其他人不一定正确</p>
  </li>
  <li>
    <p>影响到其他正在开发的人</p>
  </li>
</ul>

<p><strong>Question 2: 耗费大量人力时间在打包工作上。</strong></p>

<ul>
  <li>
    <p>打包要透过工程师人力打包，中断当前开发工作</p>
  </li>
  <li>
    <p>来回在打包与开发之间，心流切换成本极高</p>
  </li>
  <li>
    <p>打包等待时间无法进行其他开发工作</p>
  </li>
  <li>
    <p>工程师的时间成本就是金钱</p>
  </li>
  <li>
    <p>人工操作可能出错</p>
  </li>
  <li>
    <p>QA 要请工程师打包 (来回沟通)</p>
  </li>
</ul>

<h4 id="ci--continuous-integration-持续整合">CI — Continuous Integration 持续整合</h4>

<p>对应 Question 1「持续整合」旨在确保所有变动都能自动执行统一环境的 Build &amp; Test 确保进入生产环境之前的改动都通过所有测试案例及符合团队规范 — 「持续地自动确保正确的程式码整合到生产环境」。</p>

<p>另外也可以增加 Nightly Build、更多的自动化测试环节，确保稳定性。</p>

<h4 id="cd--continuous-delivery--deployment-持续交付部署">CD — Continuous Delivery / Deployment 持续交付/部署</h4>

<p>对应 Question 2「持续部署」旨在确保程式码在 CI 环节无异常之后，将改动结果自动完成打包部署繁琐流程给内部测试(QA, Debug, Staging, Beta…)或外部上线(Production, Release…)。</p>

<ul>
  <li>
    <p><strong>Continuous Deployment:</strong> 全自动直接部署到 Production 环境</p>
  </li>
  <li>
    <p><strong>Continuous Delivery:</strong> 只自动部署到 Staging/Debug 环境可，需手动验证确认没问题之后才会再部署到 Production 环境</p>
  </li>
</ul>

<p>依照 App 开发的场景，比较偏向是 <strong>Continuous Delivery 持续交付</strong> ，我们希望 App 最终上线之前是由人工把关确认完全无问题后才发布，确保释出时间与功能正确性。</p>

<h4 id="故事--透过-cicd-打造稳定高效的开发团队">故事 — <strong>透过 CI/CD 打造稳定高效的开发团队</strong></h4>

<p><img src="/assets/c008a9e8ceca/1*rszgT5yFKCcfCUka_t9b3g.webp" alt="" loading="lazy" decoding="async" width="1400" height="961" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk2MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/c008a9e8ceca/1*rszgT5yFKCcfCUka_t9b3g.png" /></p>

<p><strong>回头看我们的故事，导入 CI/CD 后：</strong></p>

<ul>
  <li>
    <p>CI
所有人的调整都需要经过 自动化测试验证通过后才能进入主分支、增加 Nightly Build 定时自动化测试环节提升稳定性。</p>
  </li>
  <li>
    <p>CD
统一都使用 CD 打包，Developer T 和 Developer Z 可以完全专注在业务开发上、减少人工沟通与操作错误。</p>
  </li>
</ul>

<blockquote>
  <p>团队工作效率与产品稳定性 🚀🚀🚀🚀🚀</p>
</blockquote>

<h3 id="cicd-的价值">CI/CD 的价值</h3>

<p>结合敏捷开发的核心理念「小步快跑，快速迭代」CI/CD 为其提供了「频繁持续迭代功能」时的稳定性与工作效率的基石。</p>

<p><strong>自动统一验证迭代结果</strong></p>

<ul>
  <li>确保所有调整都符合正确的预期结果、不影响其他功能、不影响其他成员</li>
</ul>

<p><strong>自动执行繁琐的部署流程</strong></p>

<ul>
  <li>让团队成员可以专注在主要业务开发、减少人工操作错误</li>
</ul>

<h4 id="cicd-的成效">CI/CD 的成效</h4>

<p>回顾 2021 年在 Pinkoi 的演讲「 <a href="/posts/pinkoi-engineering/高效率工程团队大解密-pinkoi-团队协作与自动化实践提升工作效率-11f6c8568154/"><strong>2021 Pinkoi Tech Career Talk — 高效率工程团队大解密</strong></a> 」其实说来说去都是差不多的内容，不外乎就是「自动化、减少人跟人的依赖、专注在主要业务上」导入 CI/CD 也完全符合上述三个方向，借此我们也可以用同样的方法来估算成效。</p>

<p><strong>另外有一点需要再次 Highlight 的是 <a href="https://zh.wikipedia.org/wiki/%E5%BF%83%E6%B5%81%E7%90%86%E8%AB%96" target="_blank">心流切换成本</a> ：</strong></p>

<p><img src="/assets/c008a9e8ceca/1*xOzjG-lSiFmdT-C4GHf0JA.webp" alt="" loading="lazy" decoding="async" width="960" height="540" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjAiIGhlaWdodD0iNTQwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/c008a9e8ceca/1*xOzjG-lSiFmdT-C4GHf0JA.png" /></p>

<p>当我们持续投入工作一段时间后就会进入「心流」状态，此时的思绪、生产力都达到巅峰，能提供做好最有效的产出；但如果被打断，要重新回到心流，又会再需要一段时间，这边以 30 分钟为例。</p>

<p><strong>在无 CI/CD 的场景中可能是：</strong> 花很多时间才发现是被改坏再回头沟通调整(CI)、QA/PM 来请工程师帮忙打包测试版 App (CD)。</p>

<h4 id="cicd-成效估算">CI/CD 成效估算</h4>

<p><img src="/assets/c008a9e8ceca/1*SinoHlHKbtXiRubUS8Bm9Q.webp" alt="团队人数 6 人 / 一个月来计算" loading="lazy" decoding="async" width="1200" height="790" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc5MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/c008a9e8ceca/1*SinoHlHKbtXiRubUS8Bm9Q.png" /></p>

<p>团队人数 6 人 / 一个月来计算</p>

<p>这边我们以每个月为基准，假设在无 CI/CD 流程时，每个月会发生 4 次意外改坏主分支的问题，造成后续修正、沟通的成本，约花费 720 分钟；加上每个月打包测试版、正式版及因人工操作造成错误的可能，总和约 1,010 分钟；以工程师月薪 8 万计算，每个月就造成约 1 万 3 的成本浪费。</p>

<blockquote>
  <p><em>这里漏估了 <a href="https://resources.github.com/actions/2026-pricing-changes-for-github-actions/" target="_blank">2026–03–01 起 Self-hosted 需要支付每分钟 $0.002 USD 维运费用</a> ，等于执行 500 分钟需要缴 $1 USD。</em></p>
</blockquote>

<h4 id="cicd-建置成本">CI/CD <strong>建置成本</strong></h4>

<ul>
  <li>
    <p>人力成本：
照本系列文章建置，粗估需投入人力 1 人花费 10 天 = <strong>4,800 分钟</strong> 能完成。(~= <strong>NT$36,384</strong> )</p>
  </li>
  <li>
    <p>设备与执行成本：
使用 GitHub Actions self-hosted Runner 只需在前期采购 1–2 台 <a href="https://www.apple.com/tw/shop/buy-mac/mac-mini/m4" target="_blank">Mac-Mini</a> 或直接使用现有汰换的 MacBook Pro 就能当成 CI/CD Runner 提供服务使用。
以 6 人团队采购一台全新的 Mac Mini 为例：32G RAM M4 Mini (= <strong>NT$40,900</strong> )</p>
  </li>
</ul>

<p>总花费成本约 <strong>NT$80,000</strong> 元就能完成建置，约半年后开始享受效益。</p>

<blockquote>
  <p><strong><em>声明：</em></strong> <em>这里只是提出一种效益计算的方式，不一定是最准确的；只是给大家一个概念去延伸， <strong>让管理决策层能看到 CI/CD 的效益</strong> 进而授权推动完成整个工作流程。</em></p>
</blockquote>

<h3 id="cicd-的工具选择">CI/CD 的工具选择</h3>

<h4 id="云服务-bitrise--xcode-cloud">云服务 Bitrise / XCode Cloud</h4>

<ul>
  <li>
    <p><strong>Bitrise：</strong> 最早期主打提供 App CI/CD 的云服务，第一次接触 CI/CD 也是使用 Bitrise，它提供友善直觉的步骤编辑工具，可以很快的设定好 App CI/CD 流程。
<strong>缺点：</strong> 最早期是 $99 镁吃到饱，Apple M 系列处理器刚出来的时候一度改成用量计费( <strong>养套杀</strong> )，那时候估团队用量每个月至少要花 $500 镁，索性就迁移至 GitHub Actions 了。
但最近看官网，现在有提供 1 App / 1 Concurrent / 吃到饱 / $89 镁 / 月。</p>
  </li>
  <li>
    <p><strong>XCode Cloud：</strong> 100 小时 / 1 个月 / $50 镁，优点是与 XCode、App 开发高度整合；但缺点同样是，无法提供 Android 使用、要客制化一些步骤会有些困难；但如果是纯 iOS 的小型 App 我会再次考虑直接使用。</p>
  </li>
</ul>

<blockquote>
  <p><em>实在很怕 <strong>云服务又养套杀</strong> 、希望可控性在自己手上，所以改考虑地端服务。</em></p>
</blockquote>

<h4 id="地端服务-jenkins--github-actions--gitlab-cicd">地端服务 Jenkins / GitHub Actions / Gitlab CI/CD</h4>

<ul>
  <li>
    <p><strong>Gitlab CI/CD：</strong>
比 GitHub Actions 推出的时间更早、功能更完整，但是我们的专案是托管在 GitHub 上所以就不考虑用 Gitlab CI/CD 了；但是两边功能类似，本系列文章会以使用 GitHub Actions 为例。</p>
  </li>
  <li>
    <p><strong>GitHub Actions</strong>
GitHub 2018 年才推出的 CI/CD 服务，跟 GitHub 专案直接绑定，在这几年持续更新完善功能，有很多封装好的步骤 ( <a href="https://github.com/marketplace?type=actions" target="_blank">Marketplace</a> ) 可以直接使用；支援 self-hosted runner 可以使用自己的机器无限使用。(等于混合云了)</p>
  </li>
  <li>
    <p><strong>Jenkins：</strong>
一个专门处理 CI/CD 的开源免费工具、古老但是功能强大；从应用层任务设计、权限管理到底层服务派发执行，Jenkins 全包；同样有 <a href="https://plugins.jenkins.io/" target="_blank">Plugins</a> 可以直接搭配使用，是早期 DevOps CI/CD 的必备工具。</p>
  </li>
</ul>

<h3 id="jenkins-vs-github-actions">Jenkins v.s. GitHub Actions</h3>

<h4 id="tldr"><strong>TL;DR</strong></h4>

<blockquote>
  <p><em>在没有专门做 DevOps 的 App Team，要 App 开发者从 0 到 1 架设维护 Jenkins 环境门槛太高、会的人也不多还会衍生出网路安全问题；选择直接用 GitHub Actions，App 开发者只需专注在 CI/CD 流程设计，大概扫一下官方文件怎么撰写跟启动 Runner，就能快速搭建出免费稳定又安全的 CI/CD 服务。</em></p>
</blockquote>

<p><img src="/assets/c008a9e8ceca/1*qg8SkzoJqNVvWPxx2Lh6uA.webp" alt="" loading="lazy" decoding="async" width="504" height="434" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MDQiIGhlaWdodD0iNDM0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/c008a9e8ceca/1*qg8SkzoJqNVvWPxx2Lh6uA.png" /></p>

<blockquote>
  <p><em>以下仅以 App CI/CD 架设为出发点做比较，并不适用所有技术场景。</em></p>
</blockquote>

<h4 id="架设与维护难易度-jenkins--github-actions"><strong>架设与维护难易度</strong> Jenkins &gt;&gt;&gt; GitHub Actions</h4>

<p><img src="/assets/c008a9e8ceca/1*k2XGXjV_VZEt618DnDm0lA.webp" alt="" loading="lazy" decoding="async" width="999" height="1117" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5OTkiIGhlaWdodD0iMTExNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/c008a9e8ceca/1*k2XGXjV_VZEt618DnDm0lA.png" /></p>

<p>这边先用一张不是很专业的结构分层图来说明两者的差异，Jenkins 如前述是从上到下功能全包，所以在自架上会复杂许多；而 GitHub Actions，GitHub Actions 本身只需要在 GitHub 上撰写 YAML 工作流程，本地机器只需要注册好 GitHub self-hosted Runner (5 个指令就完成)，GitHub 就会自动派发任务给本地机器执行了，其他包涵 Github Actions/Runner 版本升级或是任务派发问题都是 GitHub 负责维护，我们无需处理。</p>

<p>还有另一个比较麻烦的点是 Jenkins 是独立于 Git 的服务，之间要透过 API (e.g. GitHub API/WebHook) 进行沟通，设定又更复杂了。</p>

<p>之前也从身边能接触到的 iOS 开发者(约 30 位)做过调查，懂 Jenkins 的屈指可数( 2 位) 而有在使用 GitHub Actions 的则超过 (10 位) 毕竟就是写一写 YAML 就能完成 CI/CD 任务。</p>

<h4 id="学习难易度-jenkins-github-actions">学习难易度 Jenkins »&gt; GitHub Actions</h4>

<p>同上只需参考官方文件学习 GitHub Actions 可用 YAML 指令跟如何在本地起自己的 Runner 即可。</p>

<h4 id="稳定性-github-actions--jenkins">稳定性 GitHub Actions &gt; Jenkins</h4>

<p>这点我觉得 GitHub Actions 略胜 Jenkins。</p>

<p>Jeknins 有机会因为系统升级或装到有冲突的 Plugin 导致服务崩溃 (不过如果跑得好好的不去动它基本上没有问题)。</p>

<p>GitHub Actions 受限于 <a href="https://www.githubstatus.com/" target="_blank">GitHub 服务状态</a> (如果 GitHub 挂也会跟著挂)，但是发生频率不高，平均在线率都能维持在 99.9%；真出问题也不用处理，坐等修复。</p>

<h4 id="安全性-github-actions--jenkins">安全性 GitHub Actions &gt; Jenkins</h4>

<p>考量到 GitHub Actions/Runner 服务本身是 GitHub 在维护跟自动更新这点可能会比 Jenkins 需要手动更新来的更安全。</p>

<p>另外 Jenkins 跟 GitHub 沟通之间需要开 API/WebHook 口相对比较危险，GitHub 与 GitHub Actions 之间是无痛整合、GitHub Actions 与 self-hosted Runner 之间是观察者模式，self-hosted Runner 会去跟 GitHub 要任务回来做，所以 Runner 本身不需开对外接口。</p>

<p>但如果是全封闭网路环境，Jenkins 会比 GitHub Actions 安全。</p>

<h4 id="权限控管-jenkins-github-actions">权限控管 Jenkins »&gt; GitHub Actions</h4>

<p>这点需要特别挑出来比较，Jenkins 可以另外设定帐号登入权限进行控管；GitHub Actions 则直接与 GitHub Repo 进行绑定，要有 Repo 权限的人才能使用。</p>

<blockquote>
  <p><em>*因此后面的文章才会又用 GAS Web App 搭建跨团队的操作平台。</em></p>
</blockquote>

<h4 id="使用广度-jenkins-github-actions">使用广度 Jenkins »&gt; GitHub Actions</h4>

<p>在有完整 DevOps Team 的团队无庸置疑的应该还是会选择 Jenkins，毕竟在其他领域 (例如 Web, 后端, Java…) 还是 Jenkins 运行最久、Plugin 做多最好用，并且可以统一建置一套 CI/CD 服务所有团队使用方便控管，或是后端部署完前端自动部署这种复杂的 CI/CD 场景。</p>

<blockquote>
  <p><em>*GitHub Actions 后来也支援跨 Repo Actions/Runner 了。</em></p>
</blockquote>

<h4 id="第三方套件丰富度-jenkins--github-actions">第三方套件丰富度 Jenkins &gt; GitHub Actions</h4>

<p>就数量上 GitHub Actions 大于 Jenkins，但是 Jenkins 理的 CI/CD 功能比较有深度跟强大，GitHub Actions 很多只是自动化的功能。</p>

<h4 id="功能深度-jenkins-github-actions">功能深度 Jenkins »&gt; GitHub Actions</h4>

<p>这点没法比，Jenkins 已做了快 20 年，GitHub Actions 还有很多功能需要再补上；例如：权限管理、Secret 管理(目前只限纯文字，密钥档案的话要先转成纯文字)、Cache/Artifact 目前只支援 Cloud…等等</p>

<p><strong>扩展上，GitHub Self-hosted Runner 也支援 <a href="https://docs.github.com/en/actions/concepts/runners/about-actions-runner-controller#scaling-runners" target="_blank">Docker or k8s</a> 。</strong></p>

<h4 id="客制化深度-jenkins-github-actions">客制化深度 Jenkins »&gt; GitHub Actions</h4>

<p>Jenkins 从头到尾都掌控在自己手上，客制化的权限比较大，可以影响到整个系统，GitHub Actions 只能在应用层客制化不同步骤而已。</p>

<p>例如目前 GitHub Actions 内建的 Artifacts 不支援 self-hosted，那也只能在步骤中改成 sh copy 到其他目录，无法自行客制化实现 Artifacts。</p>

<blockquote>
  <p><em>*App CI/CD 场景也用不到太深度的功能。</em></p>
</blockquote>

<h4 id="易用性-github-actions-jenkins">易用性 GitHub Actions »&gt; Jenkins</h4>

<p>介面上 GitHub Actions 是新的工具在介面使用上比 Jenkins 更容易使用； 脚本设定上 Jenkins 是 Pipeline Script 储存在 Jenkins 上、GitHub Actions 是 YAML 档跟著专案 Git 管理，也比 Jenkins 容易设定。</p>

<h4 id="费用风险-jenkins--github-actions">费用风险 Jenkins &gt; GitHub Actions</h4>

<p>Jenkins 全开源免费权掌握在手，GitHub Actions 部分开源但任务派发与执行是 GitHub 封闭的 SAAS 服务；目前政策是 GitHub Actions 完全免费，使用 GitHub Runner 才要付费、使用 self-hosted Runner <a href="https://resources.github.com/actions/2026-pricing-changes-for-github-actions/" target="_blank">自 2026-03-01 起也需要支付每分钟 $0.002 USD 维运费用</a> ；以上收费 Public Repo 都有免费额度。</p>

<h3 id="google-apps-script-web-app-的用途与为何选择">Google Apps Script Web App 的用途与为何选择</h3>

<p>另一个工具选择是 Google Apps Script Web App，会需要多一个这个的原因是 GitHub Actions 自带的表单功能过于阳春(介面太工程、只能静态)并且执行权限跟 GitHub Repo 绑定在一起，如果我们需要提供给其他职能伙伴使用会非常的麻烦。</p>

<p><strong>如下：</strong></p>

<p><img src="/assets/c008a9e8ceca/1*kULMefCX5D6I5z9xt71A5A.webp" alt="" loading="lazy" decoding="async" width="348" height="447" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNDgiIGhlaWdodD0iNDQ3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/c008a9e8ceca/1*kULMefCX5D6I5z9xt71A5A.png" /></p>

<p>CD 打包会希望让操作人填写一些资讯，例如 Release Notes。</p>

<p>因此我们需要一个「介面」工具提供给其他伙伴使用或甚至是自己工程师更方便的使用。</p>

<p><strong>所需情境：</strong></p>

<blockquote>
  <p><em>在这个比较好用的「介面」上填写需要的资讯，串接专案管理工具(e.g. Jira, Asana) 取得 Task 或是 GitHub 直接取得 PR 列表，直接下拉选单选择后送出，再透过 GitHub API 触发 GitHub Actions 进行打包。</em></p>
</blockquote>

<h4 id="slack">Slack</h4>

<p>第一次导入 CI/CD 的时候我们选择串接 Slack API 达成类似如下效果：</p>

<p><img src="/assets/c008a9e8ceca/1*m85bTTlrwAmCxoVqVXo2fg.webp" alt="&lt;https://slack.com/intl/zh-tw/blog/productivity/workflow-builder-tools-automation-examples&gt;" loading="lazy" decoding="async" width="647" height="497" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NDciIGhlaWdodD0iNDk3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/c008a9e8ceca/1*m85bTTlrwAmCxoVqVXo2fg.png" /></p>

<p><a href="https://slack.com/intl/zh-tw/blog/productivity/workflow-builder-tools-automation-examples" target="_blank">https://slack.com/intl/zh-tw/blog/productivity/workflow-builder-tools-automation-examples</a></p>

<ul>
  <li>伙伴可以直接在 Slack 中使用表单填写资讯、并触发 CD 打包、收到 Slack 通知</li>
</ul>

<p>使用操作起来很顺畅并且统一在日常的办公工具上(SSOT) 不需重新学习；但是他背后的问题是 <strong>开发跟维护成本非常的高</strong> ，其中有一个原因是 Slack Outgoing-Webhook API 对响应要求非常高 (需要在 3 秒内)，因此基本上可以直接排除使用 FAAS 服务简单串接了 (e.g. Cloud Functions, GAS, Lambda…)。</p>

<p><strong>之前的做法是有一位对自动化跟后端很有兴趣的伙伴自己用 Kotlin+ktor 开发了一整套后端服务，然后再 GCP 起伺服器供 Slack 串接使用。</strong></p>

<blockquote>
  <p><strong><em>开发与维护成本非常非常高而且很难交接。</em></strong></p>
</blockquote>

<h4 id="google-apps-script--web-app">Google Apps Script — Web App</h4>

<p>之前有分享过「 <a href="/posts/zrealm-dev/google-apps-script-web-app-打造-github-action-ci-cd-自订表单提升开发效率-4cb4437818f2/">使用 Google Apps Script Web App 表单串接 Github Action CI/CD 工作</a> 」:</p>

<p><img src="/assets/c008a9e8ceca/1*Gr4PnV2J2AB9cVFuXMLjcA.webp" alt="" loading="lazy" decoding="async" width="1209" height="600" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjA5IiBoZWlnaHQ9IjYwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/c008a9e8ceca/1*Gr4PnV2J2AB9cVFuXMLjcA.png" /></p>

<p><img src="/assets/c008a9e8ceca/1*NJRcY2ULVylZlsKnBtM27A.webp" alt="Demo Web App Form URL" loading="lazy" decoding="async" width="428" height="559" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MjgiIGhlaWdodD0iNTU5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/c008a9e8ceca/1*NJRcY2ULVylZlsKnBtM27A.png" /></p>

<p><a href="https://script.google.com/macros/s/AKfycbwNW6N5ozKbIz_E1HK6yFEUtA8KQrUciS-jcPsQptvIKlARmKgLxbQzNu8ksVeg-BmEfg/exec" target="_blank">Demo Web App Form URL</a></p>

<p><strong>使用 Google Apps Script — Web App 的优势是：</strong></p>

<ul>
  <li>
    <p>网站 Web</p>
  </li>
  <li>
    <p>同 Google Workspace 企业帐号权限管理，可设定只有组织内的 Google 帐号才能存取</p>
  </li>
  <li>
    <p><strong>完全免费</strong></p>
  </li>
  <li>
    <p><strong>Function as a Service 不需自行架设维护伺服器</strong></p>
  </li>
  <li>
    <p>较容易维护与交接</p>
  </li>
  <li>
    <p>手机上可以操作</p>
  </li>
  <li>
    <p><strong>AI Can Help!</strong>
<strong>不管是 ChatGPT 或其他 AI 工具对 GAS 都非常熟悉，可以直接动口请他帮我们制作打包表单与串接 GitHub API</strong></p>
  </li>
  <li>
    <p>一样能串接 Jira,Asana,Slack 通知 API</p>
  </li>
</ul>

<p>第二推广我就改用 GAS Web App 给伙伴使用，同样得到很好的反响，跟 Slack 差别就只在要多记一个网址到书签，需要打包的时候打开网址从网页表单操作打包。</p>

<h3 id="app-cicd-完整工具流程">App CI/CD 完整工具流程</h3>

<p>这边先附上完整的工作流程，下篇开始会逐步介绍每个工具如何使用与串接。</p>

<p><img src="/assets/c008a9e8ceca/1*pQ-2Jj6s2qlvwTrLghJSjg.webp" alt="" loading="lazy" decoding="async" width="1200" height="573" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjU3MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/c008a9e8ceca/1*pQ-2Jj6s2qlvwTrLghJSjg.png" /></p>

<h4 id="工具角色">工具角色：</h4>

<ul>
  <li>
    <p><strong>GitHub Actions</strong> : CI/CD 逻辑脚本程式码</p>
  </li>
  <li>
    <p><strong>GitHub Actions — Self-hosted Runner</strong> : CI/CD 实际执行的地方，使用自己架设的 Runner 执行，只需要负担机器购买成本，就能无限制使用量的执行任务。</p>
  </li>
  <li>
    <p><strong>Google Apps Script Web App</strong> : 因打包不一定是工程师负责，需要有一个平台给跨职能伙伴可以使用； GAS Web App 能快速打造一个 Web 工具分享网址给其他人操作使用。</p>
  </li>
  <li>
    <p><strong>Asana/Jira</strong> : 专案管理工具，可与 GAS Web App 串接让 QA/PM 可以直接选择想把包的 Task 进行打包。</p>
  </li>
  <li>
    <p><strong>Slack</strong> : 负责接收执行结果通知</p>
  </li>
</ul>

<h4 id="场景">场景：</h4>

<ul>
  <li>
    <p>End-User (QA/PM/PD/Developer): 使用 GAS Web App 送出打包表单 (捞取 Jira or Asana 任务单对应的 Branch) -&gt; GAS 打 GitHub API -&gt; 触发 CD 打包 Github Actions &lt;- GitHub self-hosted runner 监听到任务拉回机器执行 -&gt; 执行完毕 Slack 通知、更新 GAS Web App 打包状态。</p>
  </li>
  <li>
    <p>End-User (Developer): 开 PR、Push new commit 到 PR -&gt; 触发 CI 测试流程 &lt;- GitHub self-hosted runner 监听到任务拉回机器执行 -&gt; 执行完毕 Comment 测试结果、更新 Checks。</p>
  </li>
</ul>

<h3 id="总结">总结</h3>

<p>本篇主要是带大家初步了解 CI/CD 是什么跟带来的效益，下一篇开始会进入技术环节，手把手带您了解、实作 GitHub Actions CI/CD 到最终完成前文的最终成果。</p>

<h3 id="系列文章">系列文章：</h3>

<ul>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-是什么-打造高效稳定开发团队的关键流程与工具选择-c008a9e8ceca/"><strong>CI/CD 实战指南（一）：CI/CD 是什么？如何透过 CI/CD 打造稳定高效的开发团队？工具选择？</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-self-hosted-runner-详解与实战案例-ci-cd-自动化工作流程建置-404bd5c70040/"><strong>CI/CD 实战指南（二）：GitHub Actions 与 self-hosted Runner 使用与建置大全</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-actions-ios-ci-cd-完整实作自动化建置-测试与部署流程教学-4b001d2e8440/"><strong>CI/CD 实战指南（三）：使用 GitHub Actions 实作 App 专案的 CI 与 CD 工作流程</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/"><strong>CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</strong></a></p>
  </li>
</ul>

<h4 id="-buy-me-a-beer-on-paypal"><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank">🍺 Buy me a beer on PayPal</a></h4>

<blockquote>
  <p><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank"><strong><em>本系列文章花费了大量的时间精力撰写，如果内容对您有帮助、对您的团队有实质提升工作效率与产品品质；欢迎请我喝杯咖啡，感谢支持！</em></strong></a></p>
</blockquote>

<p><img src="/assets/c008a9e8ceca/1*QJj54G9gOjtQS-rbHVT1SQ.webp" alt="Buy me a coffee" loading="lazy" decoding="async" width="700" height="700" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDAiIGhlaWdodD0iNzAwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/c008a9e8ceca/1*QJj54G9gOjtQS-rbHVT1SQ.png" /></p>

<p><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank">🍺 Buy me a beer on PayPal</a></p>]]></content>
  </entry><entry>
    <title type="html">XCode 升级必测：Build Settings 优化等级调整快速定位 Release 版幽灵闪退问题｜iOS 开发实战技巧</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/xcode-%E5%8D%87%E7%BA%A7%E5%BF%85%E6%B5%8B-build-settings-%E4%BC%98%E5%8C%96%E7%AD%89%E7%BA%A7%E8%B0%83%E6%95%B4%E5%BF%AB%E9%80%9F%E5%AE%9A%E4%BD%8D-release-%E7%89%88%E5%B9%BD%E7%81%B5%E9%97%AA%E9%80%80%E9%97%AE%E9%A2%98-ios-%E5%BC%80%E5%8F%91%E5%AE%9E%E6%88%98%E6%8A%80%E5%B7%A7-7508328d8b8d/" rel="alternate" type="text/html" title="XCode 升级必测：Build Settings 优化等级调整快速定位 Release 版幽灵闪退问题｜iOS 开发实战技巧" />
    <published>2025-04-11T22:50:31+08:00</published>
    <updated>2025-04-11T22:50:31+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/7508328d8b8d</id><summary type="html">iOS 开发者遇到 Release 版才出现的闪退或逻辑异常，借由将 Debug 优化等级调整与 Release 同步，快速在本地复现问题，节省测试时间并精准定位 XCode 优化造成的 Bug，提升发布稳定度与维护效率。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="simplified-chinese" /><category term="ios-app-development" /><category term="xcode" /><category term="build-settings" /><category term="swift" /><category term="troubleshooting" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/7508328d8b8d/1*j4gTyeQwM-T7Ad3Fi29saQ.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/xcode-%E5%8D%87%E7%BA%A7%E5%BF%85%E6%B5%8B-build-settings-%E4%BC%98%E5%8C%96%E7%AD%89%E7%BA%A7%E8%B0%83%E6%95%B4%E5%BF%AB%E9%80%9F%E5%AE%9A%E4%BD%8D-release-%E7%89%88%E5%B9%BD%E7%81%B5%E9%97%AA%E9%80%80%E9%97%AE%E9%A2%98-ios-%E5%BC%80%E5%8F%91%E5%AE%9E%E6%88%98%E6%8A%80%E5%B7%A7-7508328d8b8d/"><![CDATA[<h3 id="通灵笔记-xcode-升级时最好测一下的事">[通灵笔记] XCode 升级时最好测一下的事…</h3>

<p>遇到仅在 Build Configuration Release (正式版、线上版)才会出现的幽灵闪退或程式逻辑问题，但是 Debug 安然无恙。</p>

<p><img src="/assets/7508328d8b8d/1*j4gTyeQwM-T7Ad3Fi29saQ.webp" alt="Photo by Tommaso Pecchioli" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/7508328d8b8d/1*j4gTyeQwM-T7Ad3Fi29saQ.jpeg" /></p>

<p>Photo by <a href="https://unsplash.com/@pecchio?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank">Tommaso Pecchioli</a></p>

<h3 id="tldr">TL;DR</h3>

<p>使用新 XCode 打包发布专案之前，除了直接 Build &amp; Run 玩玩看有没有跑版或异常， <strong>请记得也试试看</strong> ：</p>

<ol>
  <li>
    <p>App Target</p>
  </li>
  <li>
    <p>选择 <code class="language-plaintext highlighter-rouge">Build Settings</code></p>
  </li>
  <li>
    <p>搜寻 <code class="language-plaintext highlighter-rouge">Optimization Level</code></p>
  </li>
  <li>
    <p>找到 <code class="language-plaintext highlighter-rouge">Optimization Level</code> 区块</p>
  </li>
  <li>
    <p>将 <code class="language-plaintext highlighter-rouge">Debug</code> 环境也设定同 <code class="language-plaintext highlighter-rouge">Release</code> 的值 (e.g. <code class="language-plaintext highlighter-rouge">Fastest, Smallest [-Os]</code> )</p>
  </li>
  <li>
    <p>Build &amp; Run 测看看有没有异常</p>
  </li>
</ol>

<p><img src="/assets/7508328d8b8d/1*CUqYYFVjyXtxGkMlyd0Suw.webp" alt="" loading="lazy" decoding="async" width="832" height="401" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MzIiIGhlaWdodD0iNDAxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/7508328d8b8d/1*CUqYYFVjyXtxGkMlyd0Suw.png" /></p>

<p>不选择直接打包上 Testflight 测试是为了方便我们遇到问题的时候，能即时用断点找到问题根源。</p>

<blockquote>
  <p><em>如果遇到使用者在 Release (正式版、线上版) 回报的问题(闪退或行为异常)，但开发者无法在本地复现，也可以试试改这个设定在本地试试看。</em></p>
</blockquote>

<h4 id="可能出现的问题"><strong>可能出现的问题</strong></h4>

<ul>
  <li>
    <p>程式上看正确，但结果异常</p>
  </li>
  <li>
    <p>程式上看不会闪退的地方，却会闪退</p>
  </li>
</ul>

<p>以上在 Debug 环境 <code class="language-plaintext highlighter-rouge">Optimization Level = None [-O0]</code> 都是正常的，只会出现在 <code class="language-plaintext highlighter-rouge">Optimization Level = Fastest, Smallest [-Os]</code> 也就是 Release 的设定值。</p>

<h4 id="解法">解法</h4>

<p><strong>有问题的话，问题多半跟开发者无关</strong> ；是 XCode 优化的 Bug 导致，若一定要用这版 XCode 打包那只能先自己调整程式 Workaround，等待新版 XCode 出来再测看看是否正常。</p>

<blockquote>
  <p><strong><em>不建议直接把 Release 改成 None，因为可能会有更多其他问题。</em></strong></p>
</blockquote>

<h3 id="说故事时间">说故事时间</h3>

<p>以下是这几年工作中实际被这坑坑过的问题场景。</p>

<h4 id="故事-1--app-一直跳邀请评价-app-popup">故事 1 — App 一直跳邀请评价 App Popup</h4>

<p>我们的 App 之前有一个功能是打开 App 时会「邀请使用者去应用商城给评价」规则是跳三次之后就不会在跳；但是收到很多使用者回报每次开 App 都会跳，持续很久了，一直问一直问很烦。</p>

<p>但是我们从 Code 上看跟在本地 Build &amp; Run 在模拟器或实机上都没问题，也试过各种 edge case 场景都无法复现；我甚至撰写了一个 UI Test 疯狂重跑路径、清除资料重试…跑了几千次都没遇到问题。</p>

<p>记得那次我苦恼到半夜三点多，万念俱灰实在想不到是什么问题，开始漫无目的的查看专案设定，突然灵机一动想说那把 <code class="language-plaintext highlighter-rouge">Build Settings</code> 都改成 <code class="language-plaintext highlighter-rouge">Release</code> 的值试试看好了，这才发现问题在 <code class="language-plaintext highlighter-rouge">Optimization Level = Fastest, Smallest [-Os]</code> 能重现，也因此才定位到出问题的位置。</p>

<p><strong>Pseudocode</strong></p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="nv">invitedTimes</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1">//  Loaded from UserDefaults; will be saved back after update</span>
<span class="kd">func</span> <span class="nf">requestAppStoreReviewIfNeeded</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">defer</span> <span class="p">{</span>
    <span class="n">invitedTimes</span> <span class="o">+=</span> <span class="mi">1</span> <span class="c1">// Works for now, but may have unintended side effects</span>
  <span class="p">}</span>

  <span class="k">guard</span> <span class="n">invitedTimes</span> <span class="o">&lt;</span> <span class="mi">3</span> <span class="k">else</span> <span class="p">{</span>
    <span class="k">return</span>
  <span class="p">}</span>
  
  <span class="k">self</span><span class="o">.</span><span class="nf">present</span><span class="p">(</span><span class="kt">AppStoreReviewRequestAlert</span><span class="p">())</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p><em>这段程式是前人开发的，从程式上看这段程式码虽然有 side effect，可是逻辑无问题、可以正常 Compile、在执行上之前的版本也都没有问题。</em></p>
</blockquote>

<p>但当我把 <code class="language-plaintext highlighter-rouge">Optimization Level = Fastest, Smallest [-Os]</code> 之后下断点 Print 值就发现异常了， <code class="language-plaintext highlighter-rouge">invitedTimes += 1</code> 之后会直接爆炸变成 <code class="language-plaintext highlighter-rouge">-24760045646797946</code> 一个极大的负数，也因此使用者每次都会跳邀请评价。</p>

<p>当时先直接改掉这边 defer 的写法，就再也没有使用者回报类似的问题了；后来回头测试后续的 XCode 版本，相同的写法、 <code class="language-plaintext highlighter-rouge">Optimization Level = Fastest, Smallest [-Os]</code> 也能正常运作了。</p>

<h4 id="故事-2--某个页面会直接闪退">故事 2 — 某个页面会直接闪退</h4>

<p>Release (Testflight) 版在内测的时候发现有一个页面(WebView) 只要一点击就会闪退，可是工程师怎么 Build &amp; Run 在模拟器或实机上都没问题；每每猜测一个问题点就打包一个埋 Log 或是尝试修正的版本上 Testflight 测试，非常痛苦费时；这时又唤起我上次被支配的恐惧，立刻请同事把本地的设定改成 <code class="language-plaintext highlighter-rouge">Optimization Level = Fastest, Smallest [-Os]</code> 然后在 Build &amp; Run 果然在本地复现了闪退的问题点。</p>

<p>主要问题是出在我们自己特化的 WebView Obj-c Code 中有一个变数在 <code class="language-plaintext highlighter-rouge">ptimization Level = Fastest, Smallest [-Os]</code> 时会变 null，原因不明，只能先多加判断保护；在之前版本也都正常，只能等新的 XCode 推出后再试试看是否正常。</p>

<h3 id="总结">总结</h3>

<p>其实不只被这个坑坑了两次，有些已经不记得了，总之就是留个心法：</p>

<ol>
  <li>
    <p>使用新 XCode 版本第一次打包上版时，最好测一下这个</p>
  </li>
  <li>
    <p>问题只发生在 Release (正式版、线上版)，基本上就是这个问题，可以直接改设定在本地看能不能复现</p>
  </li>
</ol>]]></content>
  </entry><entry>
    <title type="html">Medium 1,000 追踪者里程碑｜自学 iOS 开发与持续分享经验的成长历程</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/medium-1-000-%E8%BF%BD%E8%B8%AA%E8%80%85%E9%87%8C%E7%A8%8B%E7%A2%91-%E8%87%AA%E5%AD%A6-ios-%E5%BC%80%E5%8F%91%E4%B8%8E%E6%8C%81%E7%BB%AD%E5%88%86%E4%BA%AB%E7%BB%8F%E9%AA%8C%E7%9A%84%E6%88%90%E9%95%BF%E5%8E%86%E7%A8%8B-6fd11e9704f2/" rel="alternate" type="text/html" title="Medium 1,000 追踪者里程碑｜自学 iOS 开发与持续分享经验的成长历程" />
    <published>2025-04-03T20:51:56+08:00</published>
    <updated>2025-04-03T20:51:56+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/6fd11e9704f2</id><summary type="html">累积超过 800 小时与 112 篇文章，从自学 iOS 开发到达成 Medium 1,000 追踪者，透过持续分享实战经验与教学内容，帮助开发者突破学习瓶颈，实现稳定成长与影响力提升。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="simplified-chinese" /><category term="ios-app-development" /><category term="medium" /><category term="writer" /><category term="followers" /><category term="milestones" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/6fd11e9704f2/1*OMahkVPjT8XjSrYpDdpu-g.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/medium-1-000-%E8%BF%BD%E8%B8%AA%E8%80%85%E9%87%8C%E7%A8%8B%E7%A2%91-%E8%87%AA%E5%AD%A6-ios-%E5%BC%80%E5%8F%91%E4%B8%8E%E6%8C%81%E7%BB%AD%E5%88%86%E4%BA%AB%E7%BB%8F%E9%AA%8C%E7%9A%84%E6%88%90%E9%95%BF%E5%8E%86%E7%A8%8B-6fd11e9704f2/"><![CDATA[<h3 id="a-milestone-of-1000-followers-on-medium"><strong>A Milestone of 1,000 Followers On Medium</strong></h3>

<p>经营 Medium 七年，终于达成 1,000 追踪者里程碑！</p>

<p><img src="/assets/6fd11e9704f2/1*OMahkVPjT8XjSrYpDdpu-g.webp" alt="" loading="lazy" decoding="async" width="1200" height="556" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjU1NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6fd11e9704f2/1*OMahkVPjT8XjSrYpDdpu-g.png" /></p>

<blockquote>
  <p><em>English version down below.</em></p>
</blockquote>

<p>经营 Medium 7 年、累积 112 篇文章、约 13 万字，投入超过 800 小时，终于在 2025 年 4 月 2 日达成了梦想中的目标 — — 1,000 Followers。</p>

<p>说来话长，从 2018 年开始，自己从 Web 转战 App 开发，一切对我来说都充满新鲜感，总是抱著求知若渴的心态，不断自行查阅资料，边学边做，最终完成并上架了自己的第一个 App 作品。</p>

<p>由于完全自学，当时从许多前辈们留下的网路文章中获益良多，也因此萌生了撰写文章「教学相长」的念头，希望自己也能创造出一个良善的循环。</p>

<p>一开始，也曾陷入「分享迷思」，总担心内容不够完整、担心被人挑惕，更怕对读者毫无帮助。
但后来转念一想，写文章就像是在种下一颗种子，总有一天，一位遇到类似问题的开发者能从我的文章中得到帮助，或者借此进一步深入探索。
即使写的内容不一定会被看见，但若不开始，这些美好的可能性就无法发生，也因为这样不断地坚持写作，才逐渐提升了自己的能力，让文章内容更加丰富，更有机会帮助到他人。</p>

<p>那段期间正好搭上时代的顺风车，App 与软体工程蓬勃发展。日常持续学习、开发新功能，并且将自己的经验转化为文章不断分享出去；同时，也有源源不绝的新鲜人加入开发行列，因此每次发文总能获得新的追踪者。</p>

<p>近几年，随著产业降温、AI 对数位内容创作领域的冲击，以及 Medium SEO 政策的变化，新追踪人数的增长明显放缓；对于达成「1K 目标」开始抱持佛系心态，但内心依旧保有最初的分享精神，继续坚持记录并协助遇到相似问题的朋友。
此外也开始分享一些日常生活、旅行游记、开箱文，以及个人兴趣的自动化（RPA）相关内容。</p>

<p>1K 只是个里程碑，未来还请大家多多指教。
不论之后是否继续撰写 iOS 开发内容，都会持续分享自己所经历的问题和所学到的经验。</p>

<p>由衷感谢大家这 7 年来的支持与陪伴！</p>

<p><strong>Harry,</strong>
<strong>2025/04/02.</strong></p>

<h4 id="english">English</h4>

<p>After seven years on Medium, publishing 112 articles, approximately 130,000 words, and investing over 800 hours, I finally reached my long-awaited milestone of 1,000 followers on April 2, 2025.</p>

<p>It’s been quite a journey. Back in 2018, when I switched my focus from web development to app development, everything felt new and exciting. With an insatiable curiosity, I constantly searched for resources, learned by doing, and eventually completed and published my first app.</p>

<p>As someone entirely self-taught, I gained a tremendous amount from online articles shared by many seasoned developers. This inspired me to begin writing myself, driven by the idea of “learning by teaching,” hoping to foster a positive cycle of knowledge-sharing.</p>

<p>Initially, I was caught up in doubts about sharing — always concerned whether my content was thorough enough, whether I’d be criticized, or even worse, whether it provided no real value to readers.</p>

<p>Eventually, I shifted my mindset. Writing is like planting a seed — someday, a developer encountering a similar problem might find help or inspiration through my posts. Even if my articles weren’t immediately seen, if I never started writing, those possibilities would never materialize. With continuous writing and persistence, I gradually improved my skills, enriching my content and increasing its potential to benefit others.</p>

<p>Fortunately, I rode the wave of rapid growth in apps and software engineering. Day after day, I learned, built new features, and shared my experiences through writing. There was also a steady influx of new developers entering the field, and each article brought new followers.</p>

<p>In recent years, growth has notably slowed, impacted by industry cooling, AI-driven changes to digital content creation, and shifts in Medium’s SEO policies. Gradually, I adopted a more relaxed approach towards reaching the 1,000-follower mark. Yet, I never lost the initial passion for sharing and continued documenting my experiences to help those encountering similar issues. Additionally, I started sharing daily life stories, travel experiences, product reviews, and content about my personal interest in automation (RPA) .</p>

<p>Reaching 1,000 followers is just a milestone, and I look forward to your continued support in the future. Regardless of whether I continue writing about iOS development, I’ll keep sharing the problems I encounter and the knowledge I gain.</p>

<p>I sincerely thank everyone for your support and companionship over these past seven years!</p>

<p><strong>Harry,</strong>
<strong>2025/04/02.</strong></p>]]></content>
  </entry><entry>
    <title type="html">Google Apps Script｜快速串接 Firebase App Distribution API 教学与进阶设定</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/google-apps-script-%E5%BF%AB%E9%80%9F%E4%B8%B2%E6%8E%A5-firebase-app-distribution-api-%E6%95%99%E5%AD%A6%E4%B8%8E%E8%BF%9B%E9%98%B6%E8%AE%BE%E5%AE%9A-71400d408dc8/" rel="alternate" type="text/html" title="Google Apps Script｜快速串接 Firebase App Distribution API 教学与进阶设定" />
    <published>2025-03-20T22:12:48+08:00</published>
    <updated>2025-07-10T21:00:24+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/71400d408dc8</id><summary type="html">解决 Google Apps Script 串接 Firebase App Distribution API 权限与 GCP 专案设定问题，掌握 OAuthScopes、进阶服务启用步骤，10 行程式码轻松完成下载连结整合，提升 CI/CD 自动化效率。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Robotic Process Automation" /><category term="simplified-chinese" /><category term="ios-app-development" /><category term="firebase-app-distribution" /><category term="google-apps-script" /><category term="google-api" /><category term="google-cloud-platform" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/71400d408dc8/1*O6JWKIIS5oxyrOS3q9NXRQ.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/google-apps-script-%E5%BF%AB%E9%80%9F%E4%B8%B2%E6%8E%A5-firebase-app-distribution-api-%E6%95%99%E5%AD%A6%E4%B8%8E%E8%BF%9B%E9%98%B6%E8%AE%BE%E5%AE%9A-71400d408dc8/"><![CDATA[<h3 id="google-apps-script-x-google-apis-快速串接整合方式">Google Apps Script x Google APIs 快速串接整合方式</h3>

<p>以 Google Apps Script x Firebase App Distribution API 串接为例</p>

<h3 id="背景">背景</h3>

<p>之前写了之前写了好几篇关于使用 Google Apps Script 的文章，其中「 <a href="/posts/zrealm-robotic-process-automation/google-apps-script-打造每日数据报表自动化-rpa-快速串接-google-analytics-与-google-sheet-f6713ba3fee3/">使用 Google Apps Script 实现每日数据报表 RPA 自动化</a> 」、「 <a href="/posts/zrealm-robotic-process-automation/ga4-自动数据通知机器人-3-步骤用-google-apps-script-串接-telegram-bot-1e85b8df2348/">简单 3 步骤 — 打造免费 GA4 自动数据通知机器人</a> 」介绍了如何使用 Google Apps Script 串接 Google Analytics 和 Google Sheet, Web App, Slack, Telegram… 快速建置可视化数据中台及通知服务；另外上个月发的文章「 <a href="/posts/zrealm-dev/google-apps-script-web-app-打造-github-action-ci-cd-自订表单提升开发效率-4cb4437818f2/">使用 Google Apps Script Web App 表单串接 Github Action CI/CD 工作</a> 」则是直接使用 Google Apps Script Web App 串接 Github API 作为 CI/CD GUI 表单服务；以上要马是直接使用 Google Apps Script 内建的服务进行串接或是直接串接外部服务 (Slack, Github…) 都没碰到需要串接 Google APIs 的场景。</p>

<blockquote>
  <p><em>这次在优化 CI/CD GUI 表单时希望打包内测版后能在 Web App 上直接显示 Firebase Distribution 下载连结，这块就只能串接 Google APIs 才能达成。</em></p>
</blockquote>

<h4 id="google-apps-script-x-firebase-app-distribution-api-v1">Google Apps Script x <a href="https://firebase.google.com/docs/reference/app-distribution/rest/" target="_blank">Firebase App Distribution API v1</a></h4>

<p><img src="/assets/71400d408dc8/1*O6JWKIIS5oxyrOS3q9NXRQ.webp" alt="" loading="lazy" decoding="async" width="771" height="740" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NzEiIGhlaWdodD0iNzQwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/71400d408dc8/1*O6JWKIIS5oxyrOS3q9NXRQ.png" /></p>

<p>如上图，与以往串接 Google Analytics 有内建服务「AnalyticsData」不同，Firebase App Distribution 并没有提供内建串接服务，所以要用进阶方式进行串接。</p>

<blockquote>
  <p><em>本来以为要自行使用 Service Account 完成 Access Token 产生、交换（有点麻烦，可参考我之前的 <a href="https://github.com/ZhgChgLi/ZReviewTender/blob/main/lib/GoogleAPI.rb" target="_blank">评价机器人开源专案</a> ）， <strong>但其实不用这么麻烦。</strong></em></p>
</blockquote>

<h3 id="google-apps-script-x-google-apis-进阶服务串接">Google Apps Script x Google APIs 进阶服务串接</h3>

<h4 id="串接设定">串接设定</h4>

<p><strong>参考 <a href="https://developers.google.com/apps-script/guides/services/advanced?hl=zh-tw#requirements" target="_blank">官方文件描述</a> ，我们需要照以下步骤进行进阶设定：</strong></p>

<ol>
  <li>
    <p>您必须在指令码专案中 <a href="https://developers.google.com/apps-script/guides/services/advanced?hl=zh-tw#enable_advanced_services" target="_blank">启用进阶服务</a> 。</p>
  </li>
  <li>
    <p>您必须确认在指令码使用的 <a href="https://developers.google.com/apps-script/guides/cloud-platform-projects?hl=zh-tw" target="_blank">Cloud Platform (GCP) 专案</a> 中，已启用对应进阶服务的 API。</p>
  </li>
  <li>
    <p>如果指令码专案使用的是 2019 年 4 月 8 日当天或之后建立的 <a href="https://developers.google.com/apps-script/guides/cloud-platform-projects?hl=zh-tw#default_cloud_platform_projects" target="_blank">预设 GCP 专案</a> ，您启用进阶服务并储存指令码专案后，API 就会自动启用。如果您尚未同意，系统可能也会要求您同意《 <a href="https://cloud.google.com/terms/?hl=zh-tw" target="_blank">Google Cloud</a> 》和《 <a href="https://developers.google.com/terms?hl=zh-tw" target="_blank">Google API</a> 》服务条款。</p>
  </li>
  <li>
    <p>如果指令码专案使用 <a href="https://developers.google.com/apps-script/guides/cloud-platform-projects?hl=zh-tw#standard_cloud_platform_projects" target="_blank">标准 GCP 专案</a> 或较旧的预设 GCP 专案，您必须手动在 GCP 专案中 <a href="https://developers.google.com/apps-script/guides/cloud-platform-projects?hl=zh-tw#enabling_an_api_in_a_standard_gcp_project" target="_blank">启用进阶服务的对应 API</a> 。您必须具备 GCP 专案的编辑权限，才能进行这项变更。</p>
  </li>
</ol>

<h4 id="1-专案设定-设定关联的-google-cloud-platform-gcp-专案">1. 专案设定 —设定关联的 Google Cloud Platform (GCP) 专案</h4>

<p>Google Apps Script x Google APIs 进阶服务串接会需要你建立 GCP 专案并关联到 Google Apps Script，Google APIs 使用权限是依照 GCP 设定。</p>

<p>因此你需要建立一个 GCP 专案(同 Firebase GCP 专案亦可)，记下资讯主页的「 <code class="language-plaintext highlighter-rouge">专案编号</code> 」并确定这个 GCP 专案有启用你想使用的 Google APIs 及当前登入帐号或欲使用的帐号是有该 GCP 专案、Google APIs 权限。</p>

<p><img src="/assets/71400d408dc8/1*-BlhyGAEtkcDRrZ86H2BHg.webp" alt="" loading="lazy" decoding="async" width="1013" height="767" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDEzIiBoZWlnaHQ9Ijc2NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/71400d408dc8/1*-BlhyGAEtkcDRrZ86H2BHg.png" /></p>

<p><img src="/assets/71400d408dc8/1*fycqt1HNNO9qiu6RZ-WMlw.webp" alt="" loading="lazy" decoding="async" width="912" height="871" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTIiIGhlaWdodD0iODcxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/71400d408dc8/1*fycqt1HNNO9qiu6RZ-WMlw.png" /></p>

<blockquote>
  <p><strong><em>本文以「 <a href="https://firebase.google.com/docs/reference/app-distribution/rest/" target="_blank">Firebase App Distribution API</a> 」为例。</em></strong></p>
</blockquote>

<p><img src="/assets/71400d408dc8/1*T13M_lq7z-ui0_cLZtuHXg.webp" alt="" loading="lazy" decoding="async" width="869" height="830" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjkiIGhlaWdodD0iODMwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/71400d408dc8/1*T13M_lq7z-ui0_cLZtuHXg.png" /></p>

<p>将 <code class="language-plaintext highlighter-rouge">专案编号</code> 输入到 Goolge Apps Script 专案设定下方的 Google Cloud Platform 专案编号中，当前登入帐号有该 GCP 专案权限就能自动绑定设定成功。</p>

<h4 id="2-专案设定--启用-在编辑器中显示appsscriptjson资讯清单档案">2. 专案设定 — 启用 在编辑器中显示「appsscript.json」资讯清单档案</h4>

<p><img src="/assets/71400d408dc8/1*YnhdxRSyr_CYB2CFnO_31Q.webp" alt="" loading="lazy" decoding="async" width="765" height="498" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjUiIGhlaWdodD0iNDk4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/71400d408dc8/1*YnhdxRSyr_CYB2CFnO_31Q.png" /></p>

<p>启用后回到编辑器，档案列表就会出现「 <code class="language-plaintext highlighter-rouge">appsscript.json</code> 」设定档：</p>

<p><img src="/assets/71400d408dc8/1*r8bheyYWj-TX7vFIum2GIQ.webp" alt="" loading="lazy" decoding="async" width="845" height="358" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NDUiIGhlaWdodD0iMzU4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/71400d408dc8/1*r8bheyYWj-TX7vFIum2GIQ.png" /></p>

<p>确保 oauthScopes 中包含以下两个描述设定：</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w">  </span><span class="nl">"oauthScopes"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="s2">"https://www.googleapis.com/auth/script.external_request"</span><span class="p">,</span><span class="w">
    </span><span class="s2">"https://www.googleapis.com/auth/cloud-platform"</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<p>如果没有请手动贴上储存。</p>

<h4 id="3撰写串接程式码">3.撰写串接程式码</h4>

<p>设定好 GCP 专案之后我们就能开始撰写串接程式码，直接参考想串接的 Google APIs 官方文件， <a href="https://firebase.google.com/docs/reference/app-distribution/rest/" target="_blank">Firebase App Distribution API v1</a> ：</p>

<p><img src="/assets/71400d408dc8/1*N0Zg4TEZQwTTLGCsaTdx8A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1193" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjExOTMiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/71400d408dc8/1*N0Zg4TEZQwTTLGCsaTdx8A.png" /></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">project</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">projects/[Firebase Project ID]/apps/[Firebase APP ID]</span><span class="dl">"</span><span class="p">;</span> <span class="c1">// 请换成你的 Project ID &amp; App ID</span>

<span class="kd">function</span> <span class="nf">debug</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">releases</span> <span class="o">=</span> <span class="nf">firebaseDistribution</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span>

  <span class="nx">releases</span><span class="p">.</span><span class="nf">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">release</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Release Object: https://firebase.google.com/docs/reference/app-distribution/rest/v1/projects.apps.releases?hl=zh-tw#Release</span>
    <span class="nx">Logger</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">release</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span><span class="s2"> Download URL: </span><span class="p">${</span><span class="nx">release</span><span class="p">.</span><span class="nx">testingUri</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
  <span class="p">});</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">firebaseDistribution</span><span class="p">(</span><span class="nx">releaseNote</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">https://firebaseappdistribution.googleapis.com/v1/</span><span class="dl">"</span><span class="o">+</span><span class="nx">project</span><span class="o">+</span><span class="dl">"</span><span class="s2">/releases?filter=releaseNotes.text%3D*</span><span class="dl">"</span><span class="o">+</span><span class="nx">releaseNote</span><span class="o">+</span><span class="dl">"</span><span class="s2">*</span><span class="dl">"</span><span class="p">;</span>
  <span class="c1">// Filter: https://firebase.google.com/docs/reference/app-distribution/rest/v1/projects.apps.releases/list?hl=zh-tw</span>
  <span class="kd">const</span> <span class="nx">headers</span> <span class="o">=</span> <span class="p">{</span>
    <span class="dl">"</span><span class="s2">Content-Type</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/json; charset=UTF-8</span><span class="dl">"</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">Authorization</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Bearer </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">ScriptApp</span><span class="p">.</span><span class="nf">getOAuthToken</span><span class="p">(),</span> <span class="c1">// 直接使用当前帐号换取权杖</span>
  <span class="p">};</span>
  
  <span class="kd">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
    <span class="dl">"</span><span class="s2">method</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">get</span><span class="dl">"</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">headers</span><span class="dl">"</span><span class="p">:</span> <span class="nx">headers</span>
  <span class="p">};</span>
  <span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
  <span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">()).</span><span class="nx">releases</span><span class="p">;</span>
  
  <span class="k">if </span><span class="p">(</span><span class="nx">result</span> <span class="o">==</span> <span class="kc">undefined</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">[];</span>
  <span class="p">}</span>

  <span class="k">return</span> <span class="nx">result</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">[Firebase Project ID]</code> <strong>与 <code class="language-plaintext highlighter-rouge">[Firebase APP ID]</code> 可在 Firebase 专案设定中取得：</strong></p>

<p><img src="/assets/71400d408dc8/1*oql_FnmO7_ct8S3cOhP8lg.webp" alt="" loading="lazy" decoding="async" width="1338" height="1172" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzM4IiBoZWlnaHQ9IjExNzIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/71400d408dc8/1*oql_FnmO7_ct8S3cOhP8lg.png" /></p>

<p>贴上程式码后，第一次执行需要完成权限授权。</p>

<p><img src="/assets/71400d408dc8/1*sW3ZjQA3dKS8HhAOCDsmBA.webp" alt="" loading="lazy" decoding="async" width="1125" height="647" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTI1IiBoZWlnaHQ9IjY0NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/71400d408dc8/1*sW3ZjQA3dKS8HhAOCDsmBA.png" /></p>

<p><img src="/assets/71400d408dc8/0*p-Zl0cob4mPrsNO6.webp" alt="" loading="lazy" decoding="async" width="700" height="557" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDAiIGhlaWdodD0iNTU3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/71400d408dc8/0*p-Zl0cob4mPrsNO6.png" /></p>

<ul>
  <li>
    <p>点击「审查权限」</p>
  </li>
  <li>
    <p>选择要执行的身份帐户，通常等于当前 Google Apps Script 帐户</p>
  </li>
</ul>

<p><img src="/assets/71400d408dc8/0*m7enb51ZiNlWYeoT.webp" alt="" loading="lazy" decoding="async" width="700" height="557" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDAiIGhlaWdodD0iNTU3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/71400d408dc8/0*m7enb51ZiNlWYeoT.png" /></p>

<p><img src="/assets/71400d408dc8/0*SN-0owiePlKXIxLk.webp" alt="" loading="lazy" decoding="async" width="700" height="557" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDAiIGhlaWdodD0iNTU3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/71400d408dc8/0*SN-0owiePlKXIxLk.png" /></p>

<ul>
  <li>
    <p>选择「进阶」展开 -&gt; 点击「前往 XXX」
这是我们自己写给自己用的应用程式，不需经过 Google 验证。</p>
  </li>
  <li>
    <p>点击「允许」</p>
  </li>
</ul>

<blockquote>
  <p><em>以上画面不一定会出现，没有可忽略。</em></p>
</blockquote>

<p><strong>允许之后再点「侦错」或「执行」就能执行程式：</strong></p>

<p>如果出现错误：</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Exception</span><span class="o">:</span> <span class="nc">Request</span> <span class="n">failed</span> <span class="k">for</span> <span class="n">https</span><span class="o">://</span><span class="n">firebaseappdistribution</span><span class="mf">.</span><span class="n">googleapis</span><span class="mf">.</span><span class="n">com</span> <span class="n">returned</span> <span class="n">code</span> <span class="mf">403.</span> <span class="nc">Truncated</span> <span class="n">server</span> <span class="n">response</span><span class="o">:</span> <span class="p">{</span>
  <span class="s2">"error"</span><span class="o">:</span> <span class="p">{</span>
    <span class="s2">"code"</span><span class="o">:</span> <span class="mi">403</span><span class="p">,</span>
    <span class="s2">"message"</span><span class="o">:</span> <span class="s2">"Request had insufficient authentication scopes."</span><span class="p">,</span>
    <span class="s2">"status"</span><span class="o">:</span> <span class="s2">"PERMISSION_DENIED"</span><span class="p">,</span>
    <span class="s2">"details"</span><span class="o">:...</span> <span class="p">(</span><span class="kn">use</span> <span class="n">muteHttpExceptions</span> <span class="n">option</span> <span class="n">to</span> <span class="n">examine</span> <span class="n">full</span> <span class="n">response</span><span class="p">)</span>
<span class="mf">...</span>
</code></pre></div></div>

<p>或</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Exception: Specified permissions are not sufficient to call UrlFetchApp.fetch. Required permissions: https://www.googleapis.com/auth/script.external_request
</code></pre></div></div>

<p>请确认 <code class="language-plaintext highlighter-rouge">appsscript.json</code> 的 oauthScopes 中包含以下两个描述设定(参考步骤 2)：</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"oauthScopes"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="s2">"https://www.googleapis.com/auth/script.external_request"</span><span class="p">,</span><span class="w">
    </span><span class="s2">"https://www.googleapis.com/auth/cloud-platform"</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<p>如果出现错误：</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Exception</span><span class="o">:</span> <span class="nc">Request</span> <span class="n">failed</span> <span class="k">for</span> <span class="n">https</span><span class="o">://</span><span class="n">firebaseappdistribution</span><span class="mf">.</span><span class="n">googleapis</span><span class="mf">.</span><span class="n">com</span> <span class="n">returned</span> <span class="n">code</span> <span class="mf">401.</span> <span class="nc">Truncated</span> <span class="n">server</span> <span class="n">response</span><span class="o">:</span> <span class="p">{</span>
  <span class="s2">"error"</span><span class="o">:</span> <span class="p">{</span>
    <span class="s2">"code"</span><span class="o">:</span> <span class="mi">401</span><span class="p">,</span>
    <span class="s2">"message"</span><span class="o">:</span> <span class="s2">"Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or othe... (use muteHttpExceptions option to examine full response)
</span></code></pre></div></div>

<p>代表尚未设定绑定的 GCP 专案 (参考步骤 1. ) 或是该 GCP 专案尚未启用欲使用的 Google APIs 或是当前帐号无该 GCP / Google APIs 使用权限或无该 Firebase App 权限，请检查设定。</p>

<p>如果出现错误：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Exception: Request failed for https://firebaseappdistribution.googleapis.com returned code 404. Truncated server response:
</code></pre></div></div>

<p>或</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Exception</span><span class="o">:</span> <span class="nc">Request</span> <span class="n">failed</span> <span class="k">for</span> <span class="n">https</span><span class="o">://</span><span class="n">firebaseappdistribution</span><span class="mf">.</span><span class="n">googleapis</span><span class="mf">.</span><span class="n">com</span> <span class="n">returned</span> <span class="n">code</span> <span class="mf">400.</span> <span class="nc">Truncated</span> <span class="n">server</span> <span class="n">response</span><span class="o">:</span> <span class="p">{</span>
  <span class="s2">"error"</span><span class="o">:</span> <span class="p">{</span>
    <span class="s2">"code"</span><span class="o">:</span> <span class="mi">400</span><span class="p">,</span>
    <span class="s2">"message"</span><span class="o">:</span> <span class="s2">"Request contains an invalid argument."</span><span class="p">,</span>
    <span class="s2">"status"</span><span class="o">:</span> <span class="s2">"INVALID_ARGUMENT"</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>请确认 Google APIs 请求路径是否正确。</p>

<h4 id="串接成功">串接成功🎉🎉🎉</h4>

<p><img src="/assets/71400d408dc8/1*9OyoPtblFnGGIBRvlGw10Q.webp" alt="" loading="lazy" decoding="async" width="1026" height="474" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI2IiBoZWlnaHQ9IjQ3NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/71400d408dc8/1*9OyoPtblFnGGIBRvlGw10Q.png" /></p>

<p>可以看到短短不到 10 行程式码就能无痛串接 Google APIs，真的非常方；有兴趣的朋友可以看一下相较之下， <a href="https://github.com/ZhgChgLi/ZReviewTender/blob/main/lib/GoogleAPI.rb" target="_blank">自己实作</a> Google APIs 串接时身份验证权杖交换的程式步骤，非常繁琐。</p>

<h4 id="下一步">下一步：</h4>

<p>搭配之前的文章「 <a href="/posts/zrealm-dev/google-apps-script-web-app-打造-github-action-ci-cd-自订表单提升开发效率-4cb4437818f2/">使用 Google Apps Script Web App 表单串接 Github Action CI/CD 工作</a> 」串上 CI/CD 工作项目，将 Firebase App Distribution 下载连结也呈现在 Web App 上方便同仁直接在上面下载。</p>

<p><img src="/assets/71400d408dc8/1*nK3H3e3KgHEg8qz-KZ9ZGA.webp" alt="Demo Result" loading="lazy" decoding="async" width="797" height="716" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3OTciIGhlaWdodD0iNzE2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/71400d408dc8/1*nK3H3e3KgHEg8qz-KZ9ZGA.png" /></p>

<p>Demo Result</p>

<blockquote>
  <p><em>其他 Google APIs 也能以此类推串接。</em></p>
</blockquote>

<h3 id="202507-update">2025/07 Update:</h3>

<p>此功能已整合到实际打包工具使用，可参考最新文章案例：「 <a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/"><strong>CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</strong></a> 」</p>]]></content>
  </entry><entry>
    <title type="html">XCode 虚拟目录转实体目录｜解决专案结构混乱与 XcodeGen、Tuist 整合痛点</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/xcode-%E8%99%9A%E6%8B%9F%E7%9B%AE%E5%BD%95%E8%BD%AC%E5%AE%9E%E4%BD%93%E7%9B%AE%E5%BD%95-%E8%A7%A3%E5%86%B3%E4%B8%93%E6%A1%88%E7%BB%93%E6%9E%84%E6%B7%B7%E4%B9%B1%E4%B8%8E-xcodegen-tuist-%E6%95%B4%E5%90%88%E7%97%9B%E7%82%B9-fd719053b376/" rel="alternate" type="text/html" title="XCode 虚拟目录转实体目录｜解决专案结构混乱与 XcodeGen、Tuist 整合痛点" />
    <published>2025-03-02T20:21:31+08:00</published>
    <updated>2025-03-09T15:59:17+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/fd719053b376</id><summary type="html">针对 XCode 早期虚拟目录造成专案结构混乱、难以使用 XcodeGen 与 Tuist，提供纯 Swift 开源工具 XCFolder，快速转换虚拟目录为实体目录，降低合并冲突风险，提升团队协作与 CI/CD 效率。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="simplified-chinese" /><category term="ios-app-development" /><category term="xcode" /><category term="swift" /><category term="tuist" /><category term="xcodegen" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/fd719053b376/1*fYk27y-BjMBjBFnwDfhxlw.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/xcode-%E8%99%9A%E6%8B%9F%E7%9B%AE%E5%BD%95%E8%BD%AC%E5%AE%9E%E4%BD%93%E7%9B%AE%E5%BD%95-%E8%A7%A3%E5%86%B3%E4%B8%93%E6%A1%88%E7%BB%93%E6%9E%84%E6%B7%B7%E4%B9%B1%E4%B8%8E-xcodegen-tuist-%E6%95%B4%E5%90%88%E7%97%9B%E7%82%B9-fd719053b376/"><![CDATA[<h3 id="xcode-虚拟目录万年问题探究与我的开源工具解决方案">XCode 虚拟目录万年问题探究与我的开源工具解决方案</h3>

<p>Apple 开发者职业伤害之 Xcode 早期使用虚拟目录，导致目录结构混乱且难以整合 XcodeGen, Tuist 等现代工具。</p>

<p><img src="/assets/fd719053b376/1*fYk27y-BjMBjBFnwDfhxlw.webp" alt="Photo by Saad Salim" loading="lazy" decoding="async" width="1400" height="971" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk3MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/fd719053b376/1*fYk27y-BjMBjBFnwDfhxlw.jpeg" /></p>

<p>Photo by <a href="https://unsplash.com/@saadx?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank">Saad Salim</a></p>

<h4 id="english-version-of-this-post">English version of this post:</h4>

<h4 id="exploring-the-long-standing-issues-of-xcode-virtual-directories-and-my-open-source-tool-solution"><a href="/posts/zrealm-dev/xcode-虚拟目录转实体目录-解决专案结构混乱与-xcodegen-tuist-整合痛点-fd719053b376/">Exploring the Long-Standing Issues of XCode Virtual Directories and My Open Source Tool Solution</a></h4>

<h3 id="背景">背景</h3>

<p>随著团队规模与专案的成长，XCode 专案档 ( .xcodeproj) 的体积会逐渐增大，依照专案复杂程度可以到十万行、甚至百万行，加上多人多条线并行开发，免不了会出现冲突问题； <strong>XcodeProj 档案一旦出现冲突就跟 Storyboard / .xib 的冲突一样难解</strong> ，因也是纯描述档，很容易在解冲突时不小心把别人新增的档案移除或是别人移除的档案参照又跑回来。</p>

<p>另外的问题是随著模组化推进，在 XCode 专案档 ( .xcodeproj) 建立、管理模组的流程非常不友善，模组有变动一样只能从 XCode 专案档 的 Diff 中查看，整体不利于团队朝模组化迈进。</p>

<blockquote>
  <p><em>如果只是为了防止冲突可以简单地在 pre-commit 做 <a href="https://github.com/chiahsien/sort-Xcode-project-file" target="_blank">File Sorting</a> ，现有的脚本 Github 上很多，可以直接参考设置。</em></p>
</blockquote>

<h4 id="xcfolder"><a href="https://github.com/ZhgChgLi/XCFolder" target="_blank">XCFolder</a></h4>

<p><a href="https://github.com/ZhgChgLi/XCFolder" target="_blank"><img src="https://repository-images.githubusercontent.com/941421589/27855f06-b938-4458-a20f-3e317b4283b7" alt="" /></a></p>

<blockquote>
  <p><strong><em>长话短说</em></strong> <em>，开发了一个工具可以帮你把 XCode 早期的虚拟目录转依照 XCode 里的目录结构换成实体目录。</em></p>
</blockquote>

<p><img src="/assets/fd719053b376/1*eFNN12WDaAk6mr49OzmC_g.webp" alt="" loading="lazy" decoding="async" width="1400" height="484" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjQ4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/fd719053b376/1*eFNN12WDaAk6mr49OzmC_g.jpeg" /></p>

<blockquote>
  <p><em>下滑继续看故事…</em></p>
</blockquote>

<h4 id="现代化-xcode-project-档案管理">现代化 Xcode Project 档案管理</h4>

<p>具体思维同我们在多人开发时不鼓励使用 Storyboard or .xib 一样， <strong>我们需要一个好维护、可迭代、可被 Code Review 的介面来管理「XCode 专案档」</strong> ，目前市场主流有两套免费工具可以使用：</p>

<ul>
  <li>
    <p><a href="https://github.com/yonaskolb/XcodeGen" target="_blank">XCodeGen</a> ：老牌工具，使用 YAML 定义 XCode 专案内容，再透过它转换成 XCode 专案档 ( .xcodeproj)。
直接使用 YAML 定义结构、导入难度及学习成本较低、但是对模组化或是依赖管理功能较弱、YAML 动态设置弱。</p>
  </li>
  <li>
    <p><a href="https://github.com/tuist/tuist" target="_blank">Tuist</a> ：近几年出的新工具，使用 Swift DSL 定义 XCode 专案内容，再透过它转换成 XCode 专案档 ( .xcodeproj)。
更稳定多变，内建模组化及依赖管理功能，但学习与导入门槛较高。</p>
  </li>
</ul>

<p><strong>不论是那一套我们的核心工作流程都会变成是：</strong></p>

<ol>
  <li>
    <p><strong>建立 XCode 专案内容设定档 (XCodeGen <code class="language-plaintext highlighter-rouge">project.yaml</code> or Tuist <code class="language-plaintext highlighter-rouge">Project.swift</code> )</strong></p>
  </li>
  <li>
    <p>将 XCodeGen or Tuist 加入开发者与 CI/CD Server 环境中</p>
  </li>
  <li>
    <p><strong>使用 XCodeGen or Tuist 透过设定档产生 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> XCode 专案档</strong></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">/*.xcodeproj</code> 目录档案 加入 <code class="language-plaintext highlighter-rouge">.gitignore</code></p>
  </li>
  <li>
    <p>调整开发者流程，切换 Branch 时需要跑 XCodeGen or Tuist 透过设定档产生 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> XCode 专案档</p>
  </li>
  <li>
    <p>调整 CI/CD 流程，需要跑 XCodeGen or Tuist 透过设定档产生 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> XCode 专案档</p>
  </li>
  <li>
    <p>完成</p>
  </li>
</ol>

<p><code class="language-plaintext highlighter-rouge">.xcodeproj</code> XCode 专案档是由 XCodeGen or Tuist 基于 YAML of Swift DSL 设定档产生的，同一份设定档 &amp; 同个工具版本会产生相同结果；因此我们不需要再把 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> XCode 专案档上到 Git 当中，就此可以保证以后不会再有 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> 档案冲突；专案构建的改变、模组的新增改动我们都会回到定义的设定档中做调整，因为是 Yaml or Swift 写成的，我们可以很轻易地进行迭代跟 Code Review。</p>

<p><strong>Tuist Swift 范例：</strong> <code class="language-plaintext highlighter-rouge">Project.swift</code></p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">import</span> <span class="nc">ProjectDescription</span>

<span class="n">let</span> <span class="n">project</span> <span class="o">=</span> <span class="nf">Project</span><span class="p">(</span>
    <span class="n">name</span><span class="o">:</span> <span class="s2">"MyApp"</span><span class="p">,</span>
    <span class="n">targets</span><span class="o">:</span> <span class="p">[</span>
        <span class="nf">Target</span><span class="p">(</span>
            <span class="n">name</span><span class="o">:</span> <span class="s2">"MyApp"</span><span class="p">,</span>
            <span class="n">platform</span><span class="o">:</span> <span class="mf">.</span><span class="n">iOS</span><span class="p">,</span>
            <span class="n">product</span><span class="o">:</span> <span class="mf">.</span><span class="n">app</span><span class="p">,</span>
            <span class="n">bundleId</span><span class="o">:</span> <span class="s2">"com.example.myapp"</span><span class="p">,</span>
            <span class="n">deploymentTarget</span><span class="o">:</span> <span class="mf">.</span><span class="nf">iOS</span><span class="p">(</span><span class="n">targetVersion</span><span class="o">:</span> <span class="s2">"15.0"</span><span class="p">,</span> <span class="n">devices</span><span class="o">:</span> <span class="p">[</span><span class="mf">.</span><span class="n">iphone</span><span class="p">,</span> <span class="mf">.</span><span class="n">ipad</span><span class="p">]),</span>
            <span class="n">infoPlist</span><span class="o">:</span> <span class="mf">.</span><span class="k">default</span><span class="p">,</span>
            <span class="n">sources</span><span class="o">:</span> <span class="p">[</span><span class="s2">"Sources/**"</span><span class="p">],</span>
            <span class="n">resources</span><span class="o">:</span> <span class="p">[</span><span class="s2">"Resources/**"</span><span class="p">],</span>
            <span class="n">dependencies</span><span class="o">:</span> <span class="p">[]</span>
        <span class="p">),</span>
        <span class="nf">Target</span><span class="p">(</span>
            <span class="n">name</span><span class="o">:</span> <span class="s2">"MyAppTests"</span><span class="p">,</span>
            <span class="n">platform</span><span class="o">:</span> <span class="mf">.</span><span class="n">iOS</span><span class="p">,</span>
            <span class="n">product</span><span class="o">:</span> <span class="mf">.</span><span class="n">unitTests</span><span class="p">,</span>
            <span class="n">bundleId</span><span class="o">:</span> <span class="s2">"com.example.myapp.tests"</span><span class="p">,</span>
            <span class="n">deploymentTarget</span><span class="o">:</span> <span class="mf">.</span><span class="nf">iOS</span><span class="p">(</span><span class="n">targetVersion</span><span class="o">:</span> <span class="s2">"15.0"</span><span class="p">,</span> <span class="n">devices</span><span class="o">:</span> <span class="p">[</span><span class="mf">.</span><span class="n">iphone</span><span class="p">,</span> <span class="mf">.</span><span class="n">ipad</span><span class="p">]),</span>
            <span class="n">infoPlist</span><span class="o">:</span> <span class="mf">.</span><span class="k">default</span><span class="p">,</span>
            <span class="n">sources</span><span class="o">:</span> <span class="p">[</span><span class="s2">"Tests/**"</span><span class="p">],</span>
            <span class="n">dependencies</span><span class="o">:</span> <span class="p">[</span><span class="mf">.</span><span class="nf">target</span><span class="p">(</span><span class="n">name</span><span class="o">:</span> <span class="s2">"MyApp"</span><span class="p">)]</span>
        <span class="p">)</span>
    <span class="p">]</span>
<span class="p">)</span>
</code></pre></div></div>

<p><strong>XCodeGen YAML 范例：</strong> <code class="language-plaintext highlighter-rouge">project.yaml</code></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">MyApp</span>
<span class="na">options</span><span class="pi">:</span>
  <span class="na">bundleIdPrefix</span><span class="pi">:</span> <span class="s">com.example</span>
  <span class="na">deploymentTarget</span><span class="pi">:</span>
    <span class="na">iOS</span><span class="pi">:</span> <span class="s1">'</span><span class="s">15.0'</span>

<span class="na">targets</span><span class="pi">:</span>
  <span class="na">MyApp</span><span class="pi">:</span>
    <span class="na">type</span><span class="pi">:</span> <span class="s">application</span>
    <span class="na">platform</span><span class="pi">:</span> <span class="s">iOS</span>
    <span class="na">sources</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">Sources</span><span class="pi">]</span>
    <span class="na">resources</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">Resources</span><span class="pi">]</span>
    <span class="na">info</span><span class="pi">:</span>
      <span class="na">path</span><span class="pi">:</span> <span class="s">Info.plist</span>
      <span class="na">properties</span><span class="pi">:</span>
        <span class="na">UILaunchScreen</span><span class="pi">:</span> <span class="pi">{}</span>
    <span class="na">dependencies</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">framework</span><span class="pi">:</span> <span class="s">Vendor/SomeFramework.framework</span>
      <span class="pi">-</span> <span class="na">sdk</span><span class="pi">:</span> <span class="s">UIKit.framework</span>
      <span class="pi">-</span> <span class="na">package</span><span class="pi">:</span> <span class="s">Alamofire</span>

  <span class="na">MyAppTests</span><span class="pi">:</span>
    <span class="na">type</span><span class="pi">:</span> <span class="s">bundle.unit-test</span>
    <span class="na">platform</span><span class="pi">:</span> <span class="s">iOS</span>
    <span class="na">sources</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">Tests</span><span class="pi">]</span>
    <span class="na">dependencies</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">target</span><span class="pi">:</span> <span class="s">MyApp</span>
</code></pre></div></div>

<h4 id="档案目录结构">档案目录结构</h4>

<p>XCodeGen or Tuist 会依照档案实际目录、位置产生 XCode 专案档 ( .xcodeproj) 的目录结构， <strong>实际目录即为 XCode 专案档案目录</strong> 。</p>

<p><img src="/assets/fd719053b376/1*rYgdRpEDwRiZoMLzM0WpSQ.webp" alt="" loading="lazy" decoding="async" width="1080" height="752" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDgwIiBoZWlnaHQ9Ijc1MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/fd719053b376/1*rYgdRpEDwRiZoMLzM0WpSQ.png" /></p>

<p>因此档案的实际目录位置就很重要，我们会直接用它来当 XCode 专案档案目录。</p>

<p>这在现代的 XCode / XCode 专案中，这两个目录的位置相等是再日常不过的事，但这个议题就是本文想要探究的项目。</p>

<h3 id="早期-xcode-使用虚拟目录">早期 Xcode 使用虚拟目录</h3>

<p>在早期的 XCode 中在档案目录上按右键「New Group」是不会建立实际目录的，档案会被放在专案根目录下并在 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> XCode 专案档做 File Reference，因此目录只有在 XCode 专案档中可见，实际没有。</p>

<p><img src="/assets/fd719053b376/1*LPuedcbhL4OUJuLcO0xSPw.webp" alt="" loading="lazy" decoding="async" width="1168" height="746" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTY4IiBoZWlnaHQ9Ijc0NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/fd719053b376/1*LPuedcbhL4OUJuLcO0xSPw.png" /></p>

<p>随著时代演变，Apple 在 XCode 上逐渐汰换了这个诡异的设计，后来的 XCode 从加上「New Group with Folder」到预设会建实体目录、不要建要选「New Group without Folder」在到 <strong>现在 (XCode 16) 只剩「New Group」＋ 自动根据实体目录产生XCode 专案档案目录</strong> 。</p>

<h4 id="虚拟目录的问题">虚拟目录的问题</h4>

<ul>
  <li>
    <p><strong>无法使用 XCodeGen or Tuist，因为都需要实体目录位置产生 XCode 专案档 ( .xcodeproj)。</strong></p>
  </li>
  <li>
    <p>Code Review 困难：在 Git Web GUI 上看不到目录结构，整个档案都是摊平的。</p>
  </li>
  <li>
    <p>DevOps, 第三方工具整合困难：例如 Sentry, Github 可以依照目录派发警告或 Auto-Assigner，没有目录只有档案无法设定。</p>
  </li>
  <li>
    <p>专案目录结构极为复杂，一大堆档案摊平在根目录。</p>
  </li>
</ul>

<blockquote>
  <p><em>对于一个年代久远并且没有在早期意识到虚拟目录问题的专案，虚拟目录的档案有 3,000+ 个，手动对照搬移的话搬完应该就辞职去卖状元糕了，这真的可以称得上是「 <a href="https://x.com/1star_therapist" target="_blank"><strong>Apple 开发者职业伤害</strong></a> <strong>😔</strong> 」。</em></p>
</blockquote>

<h3 id="xcode-专案虚拟目录-转-实体目录">Xcode 专案虚拟目录 转 实体目录</h3>

<p>基于上述种种原因，我们急迫的需要把 XCode 专案的虚拟目录转成实体目录，否则后续的专案现代化、更高效的开发流程都无法推进。</p>

<h4 id="-xcode-16-convert-to-folder选项">❌ Xcode 16 「Convert to folder」选项</h4>

<p><img src="/assets/fd719053b376/1*FlhWWH5Qz4aLfB4hYVUgNA.webp" alt="XCode 16" loading="lazy" decoding="async" width="285" height="562" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyODUiIGhlaWdodD0iNTYyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/fd719053b376/1*FlhWWH5Qz4aLfB4hYVUgNA.png" /></p>

<p>XCode 16</p>

<p>去年 XCode 16 刚出时有关注到这个选单新选项，本来的期待是它可以自动帮我们把虚拟目录档案转换成实体目录。</p>

<p>但实际并不然，他需要你先把档案建好目录、放到对应的实体位置，点击「Convert to folder」后会帮你改成新的 XCode Project 目录设定方式「 <code class="language-plaintext highlighter-rouge">PBXFileSystemSynchronizedRootGroup</code> 」，说实话 <strong>对转换没有任何用，这比较是转换后可以升级成新的目录设定方式。</strong></p>

<p>目录没有建立、档案没有放好，点「Convert to folder」就会报以下错误：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Missing Associated Folder
Each group must have an associated folder. The following groups are not associated with a folder:
• xxxx
Use the file inspector to associate a folder with each group, or delete the groups after moving their content to another group.
</code></pre></div></div>

<h4 id="-开源专案-venmo--synx">🫥 开源专案 <a href="https://github.com/venmo" target="_blank">venmo</a> / <a href="https://github.com/venmo/synx" target="_blank">synx</a></h4>

<p><a href="https://github.com/venmo/synx" target="_blank"><img src="https://opengraph.githubassets.com/21a6a82c910b246448d4f8c4a75a2213626f31d9743d5600022620f8f2318f18/venmo/synx" alt="" /></a></p>

<p>在 Github 搜寻许久只找到这个使用 Ruby 撰写的虚拟转实体目录开源专案工具，实际跑下来是有效果的但因年久失修 (~= 10 年未更新) 很多档案还是需要手动对应搬移，无法完全转换，因此放弃。</p>

<blockquote>
  <p><em>不过还是很感谢这个开源专案的启发，我才想说可以自己开发转换工具。</em></p>
</blockquote>

<h4 id="-我的开源专案-zhgchgli--xcfolder">✅ 我的开源专案 <a href="https://github.com/ZhgChgLi" target="_blank">ZhgChgLi</a> / <a href="https://github.com/ZhgChgLi/XCFolder" target="_blank">XCFolder</a></h4>

<p><a href="https://github.com/ZhgChgLi/XCFolder" target="_blank"><img src="https://repository-images.githubusercontent.com/941421589/27855f06-b938-4458-a20f-3e317b4283b7" alt="" /></a></p>

<p>使用纯 Swift 开发的 Command Line Tools，基于 <a href="https://github.com/tuist/XcodeProj" target="_blank">XcodeProj</a> 解析 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> XCode 专案档，读取所有档案取得所属目录、解析目录将虚拟目录转换成实体目录，将档案搬移到正确位置、最后再调整 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> XCode 专案档目录设定，即可完成转换。</p>

<p><img src="/assets/fd719053b376/1*eFNN12WDaAk6mr49OzmC_g.webp" alt="" loading="lazy" decoding="async" width="1400" height="484" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjQ4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/fd719053b376/1*eFNN12WDaAk6mr49OzmC_g.jpeg" /></p>

<p><strong>使用方式</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/ZhgChgLi/XCFolder.git
<span class="nb">cd</span> ./XCFolder
swift run XCFolder YOUR_XCODEPROJ_FILE.xcodeproj ./Configuration.yaml
</code></pre></div></div>

<p><strong>For Example:</strong></p>

<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">swift</span> <span class="n">run</span> <span class="n">XCFolder</span> <span class="p">.</span><span class="o">/</span><span class="n">TestProject</span><span class="o">/</span><span class="n">DCDeviceTest</span><span class="p">.</span><span class="n">xcodeproj</span> <span class="p">.</span><span class="o">/</span><span class="n">Configuration</span><span class="p">.</span><span class="n">yaml</span>
</code></pre></div></div>

<p><strong>CI/CD 模式 (</strong> <code class="language-plaintext highlighter-rouge">Non Interactive Mode</code> <strong>)：</strong></p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">swift</span> <span class="n">run</span> <span class="kt">XCFolder</span> <span class="kt">YOUR_XCODEPROJ_FILE</span><span class="o">.</span><span class="n">xcodeproj</span> <span class="o">./</span><span class="kt">Configuration</span><span class="o">.</span><span class="n">yaml</span> <span class="o">--</span><span class="k">is</span><span class="o">-</span><span class="n">non</span><span class="o">-</span><span class="n">interactive</span><span class="o">-</span><span class="n">mode</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Configuration.yaml</code> 可以设定想要的执行参数：</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 忽略的目录，不会解析转换</span>
ignorePaths:
- <span class="s2">"Pods"</span>
- <span class="s2">"Frameworks"</span>
- <span class="s2">"Products"</span>

<span class="c"># 忽略的档案类型，不会被转换搬移</span>
ignoreFileTypes:
- <span class="s2">"wrapper.framework"</span> <span class="c"># Frameworks</span>
- <span class="s2">"wrapper.pb-project"</span> <span class="c"># Xcode project files</span>
<span class="c">#- "wrapper.application" # Applications</span>
<span class="c">#- "wrapper.cfbundle" # Bundles</span>
<span class="c">#- "wrapper.plug-in" # Plug-ins</span>
<span class="c">#- "wrapper.xpc-service" # XPC services</span>
<span class="c">#- "wrapper.xctest" # XCTest bundles</span>
<span class="c">#- "wrapper.app-extension" # App extensions</span>

<span class="c"># 只建立目录、搬移档案，不调整 .xcodeproj XCode 专案档目录设定</span>
moveFileOnly: <span class="nb">false</span>

<span class="c"># 优先使用 git mv 指令搬移档案</span>
gitMove: <span class="nb">true</span>
</code></pre></div></div>

<p>⚠️ <strong>执行前请注意：</strong></p>

<ul>
  <li>
    <p>请确保 Git 无任何未 Commit 改变，因为怕脚本有误污染你的专案目录
(脚本执行会检查，若有未 Commit 改变会抛错误 <code class="language-plaintext highlighter-rouge">❌ Error: There are uncommitted changes in the repository</code> )</p>
  </li>
  <li>
    <p>预设优先使用 <code class="language-plaintext highlighter-rouge">git mv</code> 指令搬移档案以确保 git file log 纪录完整，如果搬移失败或是非 Git 专案才会使用 FileSystem Move 搬移档案。</p>
  </li>
</ul>

<p><strong>等待执行完成即可：</strong></p>

<p><img src="/assets/fd719053b376/1*IL_-Ht1SH5ZCYogZHXULbQ.webp" alt="" loading="lazy" decoding="async" width="638" height="439" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MzgiIGhlaWdodD0iNDM5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/fd719053b376/1*IL_-Ht1SH5ZCYogZHXULbQ.png" /></p>

<p><img src="/assets/fd719053b376/1*8JNbDbR7pvZLhcoQLU_B6A.webp" alt="" loading="lazy" decoding="async" width="682" height="483" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2ODIiIGhlaWdodD0iNDgzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/fd719053b376/1*8JNbDbR7pvZLhcoQLU_B6A.png" /></p>

<p>⚠️ <strong>执行后请注意：</strong></p>

<ul>
  <li>
    <p>请检查专案目录是否有遗漏(红色)的档案，数量少可以手动修正，数量多请确认 Configuration.yaml 里的 ignorePaths, ignoreFileTypes 设定是否正确，或是 <a href="https://github.com/ZhgChgLi/XCFolder/issues" target="_blank"><strong>建立一个 Issue</strong></a> 让我知道。</p>
  </li>
  <li>
    <p>检查 Build Setting 里的相关路径 e.g. <code class="language-plaintext highlighter-rouge">LIBRARY_SEARCH_PATHS</code> 是否需要手动更动路径</p>
  </li>
  <li>
    <p>建议 Clean &amp; Build 看看</p>
  </li>
  <li>
    <p><strong>如果懒得管现在的 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> XCode 专案档，也可以直接开始使用 XCodeGen or Tuist 直接重新产生目录档案</strong></p>
  </li>
</ul>

<p><strong>修改脚本：</strong></p>

<p>直接点击 <code class="language-plaintext highlighter-rouge">./Package.swift</code> 就能开启专案调整脚本内容。</p>

<h4 id="其他开发随记">其他开发随记</h4>

<ul>
  <li>
    <p>得力于 <a href="https://github.com/tuist/XcodeProj" target="_blank">XcodeProj</a> 我们可以很轻易的使用 Swift 物件方式存取 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> <strong>XCode 专案档案内容</strong></p>
  </li>
  <li>
    <p>同样使用 Clean Architecture 架构开发</p>
  </li>
  <li>
    <p>PBXGroup 设定中若没有 path 只有 name 则为虚拟目录，反之则为实体目录</p>
  </li>
  <li>
    <p>XCode 16 新的目录设定 <code class="language-plaintext highlighter-rouge">PBXFileSystemSynchronizedRootGroup</code> 只需宣告主目录就会自动从实体目录解析，不需要再把每个目录跟档案都宣告在 <code class="language-plaintext highlighter-rouge">.xcodeproj</code> XCode 专案档案内</p>
  </li>
  <li>
    <p>直接用 SPM (Package.swift) 方式开发 Command line tool 真的很方便！</p>
  </li>
</ul>]]></content>
  </entry><entry>
    <title type="html">自动备份 Medium 文章到 Github Pages｜Jekyll 静态备份与部署全攻略</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/%E8%87%AA%E5%8A%A8%E5%A4%87%E4%BB%BD-medium-%E6%96%87%E7%AB%A0%E5%88%B0-github-pages-jekyll-%E9%9D%99%E6%80%81%E5%A4%87%E4%BB%BD%E4%B8%8E%E9%83%A8%E7%BD%B2%E5%85%A8%E6%94%BB%E7%95%A5-5bb7d3a4954f/" rel="alternate" type="text/html" title="自动备份 Medium 文章到 Github Pages｜Jekyll 静态备份与部署全攻略" />
    <published>2025-01-18T23:12:33+08:00</published>
    <updated>2025-03-08T22:48:25+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/5bb7d3a4954f</id><summary type="html">透过自制工具将 Medium 文章自动转成 Markdown，并利用 Jekyll Chirpy Theme 部署到 Github Pages，解决文章遗失风险与滚动卡顿问题，实现免费且稳定的持续备份与客制化展示。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="simplified-chinese" /><category term="medium" /><category term="jekyll" /><category term="automation" /><category term="ios-app-development" /><category term="github-pages" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/5bb7d3a4954f/1*oM79EdbsiBYiWnqb0mH8QQ.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/%E8%87%AA%E5%8A%A8%E5%A4%87%E4%BB%BD-medium-%E6%96%87%E7%AB%A0%E5%88%B0-github-pages-jekyll-%E9%9D%99%E6%80%81%E5%A4%87%E4%BB%BD%E4%B8%8E%E9%83%A8%E7%BD%B2%E5%85%A8%E6%94%BB%E7%95%A5-5bb7d3a4954f/"><![CDATA[<h3 id="自动备份-medium-文章到-github-pages-jekyll-的那些事">自动备份 Medium 文章到 Github Pages (Jekyll) 的那些事</h3>

<p>个人 Medium 文章备份镜像站搭建、维护、升级、客制化的一些纪录</p>

<h4 id="前言">前言</h4>

<p>经营 Medium 来到了第 6 年，文章总数在去年突破 100 篇；随著经营时间越长、文章越多，越怕哪天 Medium 突然关闭或是帐号异常造成所有文章心血付之一炬，有的文章含金量不高道无妨，但更多的是记录技术架构跟当时的解题思维，我时常也会回来看之前写的文章，重新复习知识；另外后面几年也开始记录出国旅游游记，都是回忆并且流量表现不错；这些内容一但遗失就不可能再重新撰写了。</p>

<h4 id="自行开发备份工具">自行开发备份工具</h4>

<p>我习惯都是直接在 Medium 平台上撰写文章，没有自己的备份，因此在 2022 年过年期间花时间开发了一个 Medium 文章下载＆转换成 Markdown 文件(包含文章图片、文章内嵌的程式码…等内容) 的工具 <strong>— <a href="https://github.com/ZhgChgLi/ZMediumToMarkdown" target="_blank">ZMediumToMarkdown</a> ：</strong></p>

<p><a href="https://github.com/ZhgChgLi/ZMediumToMarkdown" target="_blank"><img src="https://repository-images.githubusercontent.com/493527574/9b5b7025-cc95-4e81-84a9-b38706093c27" alt="" /></a></p>

<p>并延伸使用此工具将下载下来的 Markdown 使用 <a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank">Jekyll (Chirpy Theme)</a> 做为静态备份镜像网站部署在 Github Pages 上 — <a href="https://zhgchg.li/" target="_blank">https://zhgchg.li/</a></p>

<p><img src="/assets/5bb7d3a4954f/1*oM79EdbsiBYiWnqb0mH8QQ.webp" alt="&lt;https://zhgchg.li/&gt;" loading="lazy" decoding="async" width="1200" height="564" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjU2NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/5bb7d3a4954f/1*oM79EdbsiBYiWnqb0mH8QQ.png" /></p>

<p><a href="https://zhgchg.li/" target="_blank">https://zhgchg.li/</a></p>

<p>那时候把这整套整合成一个 Github Template Repo 给有同样需求的朋友可以快速部署使用 — <a href="https://github.com/ZhgChgLi/ZMediumToJekyll" target="_blank">ZMediumToJekyll</a> ，在此之后(2022)，我就没有再更新过 <a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank">Jekyll (Chirpy Theme)</a> 的版本跟设定了； <a href="https://github.com/ZhgChgLi/ZMediumToMarkdown" target="_blank"><strong>ZMediumToMarkdown</strong></a> <strong>持续有在维护，偶尔会发现格式解析错误就会立刻修正，目前趋于稳定。</strong></p>

<p>那时候使用的 <a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank">Jekyll (Chirpy Theme)</a> 版本是 v5.x 没有太大的问题，该有的功能也都有(e.g. 置顶、分类、标签、封面图、留言…)；只有在画面滚动时很常会出现无法滚动问题，但是在滑个几下又正常，一个操作体验缺憾，曾经尝试升级到 v6.x 还是有、回报给官方也没得到回应；再加上随著版本提升升级会遇到的冲突就越多，因此后来完全放弃升级这个念头。</p>

<p>近期才下定决心要解决 <a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank">Jekyll (Chirpy Theme)</a> 问题、升级版本、顺手重新优化快速部署工具 <a href="https://github.com/ZhgChgLi/ZMediumToJekyll" target="_blank">ZMediumToJekyll</a> 。</p>

<h3 id="new-medium-to-jekyll-starter-">New! medium-to-jekyll-starter 🎉🎉</h3>

<h4 id="medium-to-jekyll-startergithubio"><a href="https://github.com/ZhgChgLi/medium-to-jekyll-starter.github.io" target="_blank">medium-to-jekyll-starter.github.io</a></h4>

<p><a href="https://github.com/ZhgChgLi/medium-to-jekyll-starter.github.io" target="_blank"><img src="https://repository-images.githubusercontent.com/918538745/779cd996-4dc3-4ee0-88b7-951b39fc4463" alt="" /></a></p>

<p>我将 <a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank"><strong>Jekyll (Chirpy Theme)</strong></a> 最新版 v7.x 加上我的 <a href="https://github.com/ZhgChgLi/ZMediumToMarkdown" target="_blank"><strong>ZMediumToMarkdown</strong></a> Medium 文章下载转换工具重新整合成新的 — <a href="https://github.com/ZhgChgLi/medium-to-jekyll-starter.github.io" target="_blank">medium-to-jekyll-starter.github.io</a> Github Template Repo。</p>

<p>大家可以直接使用这个范本 Repo 快速设定搭建自己的 Medium 镜像内容备份网站， <strong>一次设定永久持续自动备份、部署在 Github Pages 上完全免费</strong> 。</p>

<blockquote>
  <p><strong><em>手把手设定教学请参考此篇文章： <a href="https://zhgchg.li/posts/medium-to-jekyll/" target="_blank">https://zhgchg.li/posts/medium-to-jekyll/</a></em></strong></p>
</blockquote>

<h4 id="成果">成果</h4>

<p><img src="/assets/5bb7d3a4954f/1*Nyg7Fg93sDUAIMZQfN5QTg.webp" alt="&lt;https://zhgchg.li/&gt;" loading="lazy" decoding="async" width="1200" height="852" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/5bb7d3a4954f/1*Nyg7Fg93sDUAIMZQfN5QTg.png" /></p>

<p><a href="https://zhgchg.li/" target="_blank">https://zhgchg.li/</a></p>

<blockquote>
  <p><strong>上面的所有文章都是 **自动</strong> 从我的 Medium 下载所有内容＆转换成 Markdown 格式＆重新上传。*</p>
</blockquote>

<blockquote>
  <p><strong><em>附上随便一篇文章的转换成果作为比较范例：</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em><a href="https://shorturl.at/CG9ua" target="_blank">Medium 上的原始内容</a> / <a href="/posts/pinkoi-engineering/design-patterns-实战应用-封装-socket-io-即时通讯架构与七大设计模式解析-78507a8de6a5/">转换后在个人网站的结果</a></em></strong></p>
</blockquote>

<p>升级后没再出现滚动卡住的问题了，借由这次升级也多加上了客制化动态内容 (显示 Medium 追踪人数)。</p>

<h3 id="一些技术纪录">一些技术纪录</h3>

<p><a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank">Jekyll (Chirpy Theme)</a> 在 Github Pages 上的部署设定方式主要是直接参考官方 Start Repo：</p>

<p><a href="https://github.com/cotes2020/chirpy-starter/tree/main" target="_blank"><img src="https://opengraph.githubassets.com/7b39deed9baa802c582cb4a5f4e20a29855cfa6bbf513e42cb3ecf1a5a411119/cotes2020/chirpy-starter" alt="" /></a></p>

<blockquote>
  <p><em>上个月也参考这个专案的方式，做了一个新的开源专案 — <a href="https://github.com/ZhgChgLi/linkyee" target="_blank">Linkyee</a> 开源版的 Link Tree 个人连结页面。</em></p>
</blockquote>

<p><img src="/assets/5bb7d3a4954f/1*OTotv1Nw-KnhsflSSiNgkg.webp" alt="&lt;https://link.zhgchg.li/&gt;" loading="lazy" decoding="async" width="1400" height="854" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijg1NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/5bb7d3a4954f/1*OTotv1Nw-KnhsflSSiNgkg.png" /></p>

<p><a href="https://link.zhgchg.li/" target="_blank">https://link.zhgchg.li/</a></p>

<h4 id="jekyll-客制化方式-1--override-html">Jekyll 客制化方式 (1) — Override HTML</h4>

<p><a href="https://jekyllrb.com/" target="_blank">Jekyll</a> 是一套很强大的 Ruby 静态内容网站生成引擎， <a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank">Jekyll (Chirpy Theme)</a> 只是一套基于 Jekyll 的主题，比较过其他主题还是 <a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank">Chirpy Theme</a> 最有质感跟操作体验优异、功能俱全。</p>

<p>Jekyll 的页面具有继承性，我们可以在 <code class="language-plaintext highlighter-rouge">./_layouts</code> 新增 <a href="https://github.com/cotes2020/jekyll-theme-chirpy/tree/master/_layouts" target="_blank">与 Jekyll 相同的页面档案名</a> ，引擎在产生网站内容时就会使用你自订的页面内容取代掉原本的。</p>

<p>例如我希望在每个文章页末尾加上一行文字，我先把原本的文章页面档案( <a href="https://github.com/cotes2020/jekyll-theme-chirpy/blob/master/_layouts/post.html" target="_blank">post.html</a> )复制出来，放到 <code class="language-plaintext highlighter-rouge">./_layouts</code> 目录下：</p>

<p><img src="/assets/5bb7d3a4954f/1*oDykwzZ0P5o8GEw8lc3WPQ.webp" alt="" loading="lazy" decoding="async" width="133" height="38" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzMiIGhlaWdodD0iMzgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/5bb7d3a4954f/1*oDykwzZ0P5o8GEw8lc3WPQ.png" /></p>

<p>使用编辑器打开 post.html 在相应的位置加上文字或客制化，重新部署网站就能看到客制化结果。</p>

<p><img src="/assets/5bb7d3a4954f/1*7ni973_1JykXoj8le78v1A.webp" alt="" loading="lazy" decoding="async" width="303" height="124" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMDMiIGhlaWdodD0iMTI0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/5bb7d3a4954f/1*7ni973_1JykXoj8le78v1A.png" /></p>

<p>也可以建立一个 <code class="language-plaintext highlighter-rouge">./_include</code> 目录，放一些想要共用的页面内容档案：</p>

<p><img src="/assets/5bb7d3a4954f/1*rExx8jMcMfEQZ3LfvhwT2w.webp" alt="" loading="lazy" decoding="async" width="193" height="163" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOTMiIGhlaWdodD0iMTYzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/5bb7d3a4954f/1*rExx8jMcMfEQZ3LfvhwT2w.png" /></p>

<p>然后再 <code class="language-plaintext highlighter-rouge">post.html</code> 中我们就可以直接使用 <code class="language-plaintext highlighter-rouge">{% include buymeacoffee.html %}</code> 引入刚档案的 HTML 内容重复使用。</p>

<blockquote>
  <p><em>复写 HTML Layout 档案的优点是 100% 客制化，页面内容、排版要怎么呈现都可以随意调整；缺点是这次在升级的过程就会遇到冲突或是预期外结果，要自己重新检视一次客制化的内容。</em></p>
</blockquote>

<h4 id="jekyll-客制化方式-2--plugin">Jekyll 客制化方式 (2) — Plugin</h4>

<p>第二种方式是使用 <a href="https://jekyllrb.com/docs/plugins/" target="_blank">Plugin</a> 中的 <a href="https://jekyllrb.com/docs/plugins/hooks/#built-in-hook-owners-and-events" target="_blank">Hook</a> 方法，在 Jekyll 产生静态内容阶段注入自己想要的客制化内容。</p>

<p><img src="/assets/5bb7d3a4954f/1*JI-uJ8tIKnomJyQk9cVfyQ.webp" alt="" loading="lazy" decoding="async" width="651" height="423" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NTEiIGhlaWdodD0iNDIzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/5bb7d3a4954f/1*JI-uJ8tIKnomJyQk9cVfyQ.png" /></p>

<p><img src="/assets/5bb7d3a4954f/1*GrUJn6HXoBqYXUQMKrnqTA.webp" alt="Built-in Hook Owners and Events" loading="lazy" decoding="async" width="647" height="285" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NDciIGhlaWdodD0iMjg1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/5bb7d3a4954f/1*GrUJn6HXoBqYXUQMKrnqTA.png" /></p>

<p>[Built-in Hook Owners and Events</p>

<p>Hook 事件](https://jekyllrb.com/docs/plugins/hooks/#built-in-hook-owners-and-events){:target=”_blank”} 有很多，这边只附上我用到的 <code class="language-plaintext highlighter-rouge">site:pre_render</code> 跟 <code class="language-plaintext highlighter-rouge">post:pre_render</code></p>

<p>新增方式也很简单，只要在 <code class="language-plaintext highlighter-rouge">./_plugins</code> 新增一个 Ruby 档案即可。</p>

<p><img src="/assets/5bb7d3a4954f/1*1QTCNuYJbJPlfJoMrc6v5g.webp" alt="posts-lastmod-hook.rb 是原本就有的 Plugin" loading="lazy" decoding="async" width="216" height="66" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMTYiIGhlaWdodD0iNjYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/5bb7d3a4954f/1*1QTCNuYJbJPlfJoMrc6v5g.png" /></p>

<p>posts-lastmod-hook.rb 是原本就有的 Plugin</p>

<p>我想要几个「伪」动态内容功能，第一个是在个人资料下显示 Medium 追踪人数还有在页底显示页面内容最后更新时间。</p>

<p><img src="/assets/5bb7d3a4954f/1*6JA9ONLP_A0eNL_q-5b6yg.webp" alt="" loading="lazy" decoding="async" width="1081" height="802" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDgxIiBoZWlnaHQ9IjgwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/5bb7d3a4954f/1*6JA9ONLP_A0eNL_q-5b6yg.png" /></p>

<p>在 <code class="language-plaintext highlighter-rouge">./_plugins</code> 下建立了一个 <code class="language-plaintext highlighter-rouge">zhgchgli-customize.rb</code> ：</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env ruby</span>
<span class="c1">#</span>
<span class="nb">require</span> <span class="s1">'net/http'</span>
<span class="nb">require</span> <span class="s1">'nokogiri'</span>
<span class="nb">require</span> <span class="s1">'uri'</span>
<span class="nb">require</span> <span class="s1">'date'</span>


<span class="k">def</span> <span class="nf">load_medium_followers</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">limit</span> <span class="o">=</span> <span class="mi">10</span><span class="p">)</span>
  <span class="k">return</span> <span class="mi">0</span> <span class="k">if</span> <span class="n">limit</span><span class="p">.</span><span class="nf">zero?</span>

  <span class="n">uri</span> <span class="o">=</span> <span class="no">URI</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
  <span class="n">response</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="p">.</span><span class="nf">get_response</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
  <span class="k">case</span> <span class="n">response</span>
  <span class="k">when</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTPSuccess</span> <span class="k">then</span>
      <span class="n">document</span> <span class="o">=</span> <span class="no">Nokogiri</span><span class="o">::</span><span class="no">HTML</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="nf">body</span><span class="p">)</span>

      <span class="n">follower_count_element</span> <span class="o">=</span> <span class="n">document</span><span class="p">.</span><span class="nf">at</span><span class="p">(</span><span class="s1">'span.pw-follower-count &gt; a'</span><span class="p">)</span>
      <span class="n">follower_count</span> <span class="o">=</span> <span class="n">follower_count_element</span><span class="o">&amp;</span><span class="p">.</span><span class="nf">text</span><span class="o">&amp;</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="s1">' '</span><span class="p">)</span><span class="o">&amp;</span><span class="p">.</span><span class="nf">first</span>

      <span class="k">return</span> <span class="n">follower_count</span> <span class="p">\\</span><span class="o">|</span><span class="p">\\</span><span class="o">|</span> <span class="mi">0</span>
  <span class="k">when</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTPRedirection</span> <span class="k">then</span>
    <span class="n">location</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s1">'location'</span><span class="p">]</span>
    <span class="k">return</span> <span class="n">load_medium_followers</span><span class="p">(</span><span class="n">location</span><span class="p">,</span> <span class="n">limit</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
  <span class="k">else</span>
      <span class="k">return</span> <span class="mi">0</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="vg">$medium_url</span> <span class="o">=</span> <span class="s2">"https://medium.com/@zhgchgli"</span>
<span class="c1"># could also define in _config.yml and retrieve in Jekyll::Hooks.register :site, :pre_render do \\|site\\| site.config</span>

<span class="vg">$medium_followers</span> <span class="o">=</span> <span class="n">load_medium_followers</span><span class="p">(</span><span class="vg">$medium_url</span><span class="p">)</span>

<span class="vg">$medium_followers</span> <span class="o">=</span> <span class="mi">1000</span> <span class="k">if</span> <span class="vg">$medium_followers</span> <span class="o">==</span> <span class="mi">0</span>
<span class="vg">$medium_followers</span> <span class="o">=</span> <span class="vg">$medium_followers</span><span class="p">.</span><span class="nf">to_s</span><span class="p">.</span><span class="nf">reverse</span><span class="p">.</span><span class="nf">scan</span><span class="p">(</span><span class="sr">/\d{1,3}/</span><span class="p">).</span><span class="nf">join</span><span class="p">(</span><span class="s1">','</span><span class="p">).</span><span class="nf">reverse</span>


<span class="no">Jekyll</span><span class="o">::</span><span class="no">Hooks</span><span class="p">.</span><span class="nf">register</span> <span class="ss">:site</span><span class="p">,</span> <span class="ss">:pre_render</span> <span class="k">do</span> <span class="p">\\</span><span class="o">|</span><span class="n">site</span><span class="p">\\</span><span class="o">|</span>

  <span class="n">tagline</span> <span class="o">=</span> <span class="n">site</span><span class="p">.</span><span class="nf">config</span><span class="p">[</span><span class="s1">'tagline'</span><span class="p">]</span>
  
  <span class="n">followMe</span> <span class="o">=</span> <span class="o">&lt;&lt;-</span><span class="no">HTML</span><span class="sh">
  &lt;a href="</span><span class="si">#{</span><span class="vg">$medium_url</span><span class="si">}</span><span class="sh">" target="_blank" style="display: block;text-align: center;font-style: normal;/* text-decoration: underline; */font-size: 1.2em;color: var(--heading-color);"&gt;</span><span class="si">#{</span><span class="vg">$medium_followers</span><span class="si">}</span><span class="sh">+ Followers on Medium&lt;/a&gt;
</span><span class="no">  HTML</span>

  <span class="n">site</span><span class="p">.</span><span class="nf">config</span><span class="p">[</span><span class="s1">'tagline'</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="n">followMe</span><span class="si">}</span><span class="s2">"</span><span class="p">;</span>
  <span class="n">site</span><span class="p">.</span><span class="nf">config</span><span class="p">[</span><span class="s1">'tagline'</span><span class="p">]</span> <span class="o">+=</span> <span class="n">tagline</span><span class="p">;</span>

  <span class="n">meta_data</span> <span class="o">=</span> <span class="n">site</span><span class="p">.</span><span class="nf">data</span><span class="p">.</span><span class="nf">dig</span><span class="p">(</span><span class="s1">'locales'</span><span class="p">,</span> <span class="s1">'en'</span><span class="p">,</span> <span class="s1">'meta'</span><span class="p">);</span>
  <span class="c1"># only impletation in en, could impletation to all langs.</span>

  <span class="k">if</span> <span class="n">meta_data</span>
    <span class="n">gmt_plus_8</span> <span class="o">=</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">.</span><span class="nf">getlocal</span><span class="p">(</span><span class="s2">"+08:00"</span><span class="p">)</span>
    <span class="n">formatted_time</span> <span class="o">=</span> <span class="n">gmt_plus_8</span><span class="p">.</span><span class="nf">strftime</span><span class="p">(</span><span class="s2">"%Y-%m-%d %H:%M:%S"</span><span class="p">)</span>
    <span class="n">site</span><span class="p">.</span><span class="nf">data</span><span class="p">[</span><span class="s1">'locales'</span><span class="p">][</span><span class="s1">'en'</span><span class="p">][</span><span class="s1">'meta'</span><span class="p">]</span> <span class="o">+=</span> <span class="s2">"&lt;br/&gt;Last updated: </span><span class="si">#{</span><span class="n">formatted_time</span><span class="si">}</span><span class="s2"> +08:00"</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<ul>
  <li>
    <p>原理是注册一个 Hook 在网站 Render 前，对 config 中的 <code class="language-plaintext highlighter-rouge">tagline</code> 个人资料下方介绍内容区块，多塞上 Medium 追踪人数显示 HTML。</p>
  </li>
  <li>
    <p>Medium 追踪人数会在每次执行都去爬取拿到最新数字</p>
  </li>
  <li>
    <p>页底最后更新时间逻辑也差不多，就是对 locales-&gt;en-&gt;meta 在产生网站时多塞上最后更新时间字串</p>
  </li>
  <li>
    <p>补充如果是 Hook 文章产生前，可以拿到 Markdown、Hook 文章产生后，可以拿到产生后的 HTML</p>
  </li>
</ul>

<p>储存后可以先在本机下 <code class="language-plaintext highlighter-rouge">bundle exec jekyll s</code> 测试结果：</p>

<p><img src="/assets/5bb7d3a4954f/1*T1idAZIWAJ2N9J054-PFSA.webp" alt="" loading="lazy" decoding="async" width="710" height="483" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MTAiIGhlaWdodD0iNDgzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/5bb7d3a4954f/1*T1idAZIWAJ2N9J054-PFSA.png" /></p>

<p>用浏览器打开 <code class="language-plaintext highlighter-rouge">127.0.0.1:4000</code> 查看结果。</p>

<p><img src="/assets/5bb7d3a4954f/1*6JA9ONLP_A0eNL_q-5b6yg.webp" alt="" loading="lazy" decoding="async" width="1081" height="802" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDgxIiBoZWlnaHQ9IjgwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/5bb7d3a4954f/1*6JA9ONLP_A0eNL_q-5b6yg.png" /></p>

<p>最后在 Github Pages Repo 上的 Actions 加上排程定时自动重新产生网站，就完成了：</p>

<p><img src="/assets/5bb7d3a4954f/1*2BFHmkhnytEwHTkNHwZsTg.webp" alt="" loading="lazy" decoding="async" width="1050" height="589" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDUwIiBoZWlnaHQ9IjU4OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/5bb7d3a4954f/1*2BFHmkhnytEwHTkNHwZsTg.png" /></p>

<p>在 <a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank">Jekyll (Chirpy Theme)</a> Repo 专案中的 Actions 找到「 <code class="language-plaintext highlighter-rouge">pages-deploy.yml</code> 」在 <code class="language-plaintext highlighter-rouge">on:</code> 新增：</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="na">schedule</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">cron</span><span class="pi">:</span> <span class="s2">"</span><span class="s">10</span><span class="nv"> </span><span class="s">1</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*"</span> <span class="c1"># 每天 UTC 01:10 自动执行一次, https://crontab.guru</span>
</code></pre></div></div>

<blockquote>
  <p><em>Plugin 的优点是可以达到动态内容效果(排程更新内容)、不影响网站架构不会在升级时遇到冲突；缺点就是能调整的内容、显示位置有局限。</em></p>
</blockquote>

<h4 id="jekyll-chirpy-theme-v7x-后的-github-pages-部署问题"><a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank">Jekyll (Chirpy Theme)</a> v7.x 后的 Github Pages 部署问题</h4>

<p>除了网站架构的调整外，v.7.x 的部署脚本也有改变；移除了原本的 <a href="https://github.com/ZhgChgLi/medium-to-jekyll-starter.github.io/blob/main/tools/deploy.sh" target="_blank">deploy.sh</a> 部署脚本，直接使用 Github Actions 的部署步骤：</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># build:</span>
<span class="c1"># ...</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Upload site artifact</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/upload-pages-artifact@v3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_site${{</span><span class="nv"> </span><span class="s">steps.pages.outputs.base_path</span><span class="nv"> </span><span class="s">}}"</span>

<span class="err">  </span><span class="na">deploy</span><span class="pi">:</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="na">name</span><span class="pi">:</span> <span class="s">github-pages</span>
      <span class="na">url</span><span class="pi">:</span> <span class="s">${{ steps.deployment.outputs.page_url }}</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="s">build</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy to GitHub Pages</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">deployment</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/deploy-pages@v4</span>
</code></pre></div></div>

<p>但是我在部署的过程遇到了问题：</p>

<p><code class="language-plaintext highlighter-rouge">Uploaded artifact size of 1737778940 bytes exceeds the allowed size of 1 GB</code> 因为我的网站内容太大了，导致 Upload Artifact 失败；但是之前的部署脚本是可以的，所以只好退回去用原本的 <a href="https://github.com/ZhgChgLi/medium-to-jekyll-starter.github.io/blob/main/tools/deploy.sh" target="_blank">deploy.sh</a> ＋ <a href="https://github.com/ZhgChgLi/zhgchgli.github.io/blob/main/.github/workflows/pages-deploy.yml" target="_blank">注解掉上面这一段</a> 。</p>

<h4 id="github-pages-部署时-test-site-步骤一直不通过">Github Pages 部署时 Test Site 步骤一直不通过</h4>

<p><a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank">Jekyll (Chirpy Theme)</a> 部署有一个步骤是 Test Site 自检测网页内容是否正确，例如连结是否正常、HTML 标签是否有缺漏…等等</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># build:</span>
<span class="c1"># ...</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Test site</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">bundle exec htmlproofer _site \</span>
            <span class="s">\-\-disable-external \</span>
            <span class="s">\-\-no-enforce-https \</span>
            <span class="s">\-\-ignore-empty-alt \</span>
            <span class="s">\-\-ignore-urls "/^http:\/\/127.0.0.1/,/^http:\/\/0.0.0.0/,/^http:\/\/localhost/"</span>
</code></pre></div></div>

<p>我自己多加了 <code class="language-plaintext highlighter-rouge">--no-enforce-https</code> <code class="language-plaintext highlighter-rouge">--ignore-empty-alt</code> 忽略 https、html tag没有 alt 的检查， <strong>忽略这两条让检查通过(因为暂时无法去改内容)</strong> 。</p>

<p><a href="https://github.com/gjtorikian/html-proofer" target="_blank">htmlproofer</a> 的 CLI 指令官方文件没有提，翻了好久才在某个 Issue 的 <a href="https://github.com/gjtorikian/html-proofer/issues/727#issuecomment-1334430268" target="_blank">Comment</a> 找到规则：</p>

<p><img src="/assets/5bb7d3a4954f/1*kn6TE3wlIqIA8Nxe8OqTww.webp" alt="&lt;https://github.com/gjtorikian/html-proofer/issues/727#issuecomment-1334430268&gt;" loading="lazy" decoding="async" width="814" height="234" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MTQiIGhlaWdodD0iMjM0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/5bb7d3a4954f/1*kn6TE3wlIqIA8Nxe8OqTww.png" /></p>

<p><a href="https://github.com/gjtorikian/html-proofer/issues/727#issuecomment-1334430268" target="_blank">https://github.com/gjtorikian/html-proofer/issues/727#issuecomment-1334430268</a></p>

<h4 id="其他文章补充">其他文章补充</h4>

<ul>
  <li>
    <p><a href="/posts/zrealm-dev/github-pages-自订网域教学-namecheap-购域设定完整流程与部署指引-483af5d93297/">Github Pages 自订网域教学</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-robotic-process-automation/github-pages-免费快速建置个人-linktree-连结页面-linkyee-开源模板教学-70aeddb1fd9b/">Linkyee — 使用 GitHub Pages 快速免费建立个人类 LinkTree 连结页面</a></p>
  </li>
</ul>]]></content>
  </entry><entry>
    <title type="html">[正体中文] Medium to Jekyll 安装设定教学</title>
    <link href="https://zh-hans.zhgchg.li/posts/tools/%E6%AD%A3%E4%BD%93%E4%B8%AD%E6%96%87-medium-to-jekyll-%E5%AE%89%E8%A3%85%E8%AE%BE%E5%AE%9A%E6%95%99%E5%AD%A6-medium-to-jekyll/" rel="alternate" type="text/html" title="[正体中文] Medium to Jekyll 安装设定教学" />
    <published>2025-01-17T08:00:00+08:00</published>
    <updated>2025-01-17T08:00:00+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/tools/medium-to-jekyll</id><summary type="html">Meidum to Jekyll 安装设定教学</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="tools" /><category term="meidum" /><category term="github" /><category term="jekyll" /><category term="ruby" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/images/zmediumtomarkdown.jpeg" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/tools/%E6%AD%A3%E4%BD%93%E4%B8%AD%E6%96%87-medium-to-jekyll-%E5%AE%89%E8%A3%85%E8%AE%BE%E5%AE%9A%E6%95%99%E5%AD%A6-medium-to-jekyll/"><![CDATA[<h1 id="start">Start!</h1>

<p><a href="https://github.com/ZhgChgLi/medium-to-jekyll-starter.github.io"><img src="https://opengraph.githubassets.com/91a5dd913bf4d51e6b76fbcc7442c845023bdf93cb1a0ce1ac1c8a40d554f781/ZhgChgLi/medium-to-jekyll-starter.github.io" alt="" /></a></p>

<h2 id="1-前往-template-repo---medium-to-jekyll-startergithubio">1. 前往 Template Repo -&gt; <a href="https://github.com/ZhgChgLi/medium-to-jekyll-starter.github.io">medium-to-jekyll-starter.github.io</a></h2>

<p><img src="/assets/medium-to-jekyll-starter/start-6.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<p>点击右上角「Use this template」-&gt;「Create a new repository」</p>

<h2 id="2-create-a-new-repository">2. Create a new repository</h2>

<p><img src="/assets/medium-to-jekyll-starter/start-2.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<ul>
  <li>
    <p>Repository name: 通常为 <code class="language-plaintext highlighter-rouge">帐号或组织名称.github.io</code>，必须以 <code class="language-plaintext highlighter-rouge">*.github.io</code> 为结尾。</p>
  </li>
  <li>
    <p>必须为 <code class="language-plaintext highlighter-rouge">Public</code> Repo 才能使用 Github Pages</p>
  </li>
</ul>

<h3 id="调整-github-actions-执行权限">调整 GitHub Actions 执行权限</h3>

<p><img src="/assets/medium-to-jekyll-starter/github-action-permissions.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<ul>
  <li>建立后，由于 GitHub 的安全性设定，您需要前往储存库设定中启用 GitHub Actions 的执行权限。</li>
</ul>

<h2 id="3-create-gh-pages-branch-if-needed">3. Create gh-pages branch if needed</h2>

<p><img src="/assets/medium-to-jekyll-starter/start-3.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<ul>
  <li>
    <p>在 Repo 主页点击「<code class="language-plaintext highlighter-rouge">main</code>」分支选单，输入「<code class="language-plaintext highlighter-rouge">gh-pages</code>」，若无则选择「Create branch <code class="language-plaintext highlighter-rouge">gh-pages</code> from <code class="language-plaintext highlighter-rouge">main</code>」</p>
  </li>
  <li>
    <p>若 <code class="language-plaintext highlighter-rouge">gh-pages</code> 分支已存在、或建立时出现「Sorry, that branch already exists.」则可跳过此步骤</p>
  </li>
</ul>

<h2 id="4-enable-github-pages前往-settings---pages---build-and-deployment">4. Enable Github Pages，前往 Settings -&gt; Pages -&gt; Build and deployment</h2>

<p><img src="/assets/medium-to-jekyll-starter/start-4.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<ul>
  <li>选择「<code class="language-plaintext highlighter-rouge">gh-pages</code>」分支，点击「<code class="language-plaintext highlighter-rouge">Save</code>」储存设定</li>
</ul>

<h3 id="执行首次部署">执行首次部署</h3>

<p><img src="/assets/medium-to-jekyll-starter/first-deploy.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<ul>
  <li>Repo -&gt; 「Actions」-&gt;「Build and Deploy」-&gt;「Run workflow」-&gt;「Branch: main, Run workflow」</li>
</ul>

<h2 id="5-等待所有部署工作完成">5. 等待所有部署工作完成</h2>

<p><img src="/assets/medium-to-jekyll-starter/start-5.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<ul>
  <li>
    <p>🟢 pages build and deployment</p>
  </li>
  <li>
    <p>🟢 Build and Deploy</p>
  </li>
</ul>

<h2 id="6-前往网站查看结果">6. 前往网站查看结果</h2>

<blockquote>
  <p>https://<code class="language-plaintext highlighter-rouge">帐号或组织名称.github.io</code></p>
</blockquote>

<p><img src="/assets/medium-to-jekyll-starter/done.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<h3 id="troubleshooting">Troubleshooting</h3>

<p>如果页面只显示：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>--- layout: home # Index page ---
</code></pre></div></div>

<p>代表 Github Pages 设定错误或还在部署中、或是之前的页面 Cache，请使用强制刷新货无痕浏览器重新打开一次网页。</p>

<blockquote>
  <p>首次部署成功！🎉🎉🎉请继续设定成同步您的 Medium 帐号。</p>
</blockquote>

<hr />

<h1 id="github-repo-github-actions-设定">Github Repo (Github Actions) 设定</h1>

<h2 id="1-前往所属-github-repo-的-github-actions-页面---点击zmediumtomarkdown--点击zmediumtomarkdownyml">1. 前往所属 Github Repo 的 Github Actions 页面 -&gt; 点击「ZMediumToMarkdown」-&gt; 点击「ZMediumToMarkdown.yml」</h2>

<p><img src="/assets/medium-to-jekyll-starter/github-1.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<blockquote>
  <p>https://github.com/{ORG}/{REPO_NAME}/blob/main/.github/workflows/ZMediumToMarkdown.yml</p>

  <h2 id="2-点击右方编辑按钮">2. 点击右方编辑按钮</h2>

  <p><img src="/assets/medium-to-jekyll-starter/github-2.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>
</blockquote>

<h2 id="3-设定-medium-文章自动同步参数">3. 设定 Medium 文章自动同步参数</h2>

<p><img src="/assets/medium-to-jekyll-starter/github-3.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">ZMediumToMarkdown</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>
  <span class="na">schedule</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">cron</span><span class="pi">:</span> <span class="s2">"</span><span class="s">10</span><span class="nv"> </span><span class="s">1</span><span class="nv"> </span><span class="s">15</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*"</span> <span class="c1"># Runs at 01:10(UTC), everyday.</span>
    <span class="c1"># 设定排程多久自动同步一次</span>
    <span class="c1"># ref: https://crontab.guru/</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">ZMediumToMarkdown</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">ZMediumToMarkdown Automatic Bot</span>
      <span class="na">uses</span><span class="pi">:</span> <span class="s">ZhgChgLi/ZMediumToMarkdown@main</span>
      <span class="na">with</span><span class="pi">:</span>
        <span class="na">command</span><span class="pi">:</span> <span class="s2">"</span><span class="s">--cookie_uid</span><span class="nv"> </span><span class="s">${{</span><span class="nv"> </span><span class="s">secrets.MEDIUM_COOKIE_UID</span><span class="nv"> </span><span class="s">}}</span><span class="nv"> </span><span class="s">--cookie_sid</span><span class="nv"> </span><span class="s">${{</span><span class="nv"> </span><span class="s">secrets.MEDIUM_COOKIE_SID</span><span class="nv"> </span><span class="s">}}</span><span class="nv"> </span><span class="s">-j</span><span class="nv"> </span><span class="s">zhgchgli_test"</span>
        <span class="c1"># zhgchgli_test 替换成你的 Meidum 使用者</span>
        <span class="c1"># 例如 https://medium.com/@zhgchgli -&gt; zhgchgli</span>
        <span class="c1"># ref: https://github.com/ZhgChgLi/ZMediumToMarkdown?tab=readme-ov-file#usage</span>
</code></pre></div></div>

<h3 id="提供有存取权限的-medium-帐号-cookies">提供有存取权限的 Medium 帐号 Cookies。</h3>

<ul>
  <li>
    <p>若您有在 Paywall 的文章则必须提供</p>
  </li>
  <li>
    <p>若发现 Medium 文章同步不完整 (缺漏文章)，代表同步时被 Medium 防火墙阻挡，也必须提供</p>
  </li>
</ul>

<h4 id="取得-meidum-帐号-cookies-medium_cookie_uid--medium_cookie_sid-步骤">取得 Meidum 帐号 Cookies MEDIUM_COOKIE_UID &amp; MEDIUM_COOKIE_SID 步骤：</h4>

<p><img src="/assets/medium-to-jekyll-starter/github-4.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<ol>
  <li>
    <p>登入拥有存取权限的 Medium 帐号，进入 <a href="https://medium.com/me/stats">Medium 后台</a></p>
  </li>
  <li>
    <p>在空白处点击右键</p>
  </li>
  <li>
    <p>选择「Inspect」</p>
  </li>
  <li>
    <p>出现 Developer Console 后选择「Application」</p>
  </li>
  <li>
    <p>选择「Cookies」-&gt;「https://medium.com」</p>
  </li>
  <li>
    <p>往下滚动找到「<code class="language-plaintext highlighter-rouge">sid</code>」「<code class="language-plaintext highlighter-rouge">uid</code>」</p>
  </li>
  <li>
    <p>点两下复制这两个栏位的值</p>
  </li>
</ol>

<h4 id="将-meidum-帐号-cookies-安全存放在-github-repo-secrets">将 Meidum 帐号 Cookies 安全存放在 Github Repo Secrets</h4>

<h5 id="1-前往-github-repo-settings---secrets-and-variables---actions---new-repository-secret">1. 前往 Github Repo Settings -&gt; Secrets and variables -&gt; Actions -&gt; New repository secret</h5>

<p><img src="/assets/medium-to-jekyll-starter/github-5.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<ul>
  <li>
    <p>Name: <code class="language-plaintext highlighter-rouge">MEDIUM_COOKIE_SID</code></p>
  </li>
  <li>
    <p>Secret: 贴上上一步复制的 Medium 帐号 <code class="language-plaintext highlighter-rouge">sid</code> 值</p>
  </li>
</ul>

<blockquote>
  <p>https://github.com/{ORG}/{REPO_NAME}/settings/secrets/actions/new</p>

  <h5 id="2-new-secret---medium_cookie_sid">2. New secret - MEDIUM_COOKIE_SID</h5>

  <p><img src="/assets/medium-to-jekyll-starter/github-6.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>
</blockquote>

<h5 id="3-new-secret---medium_cookie_uid">3. New secret - MEDIUM_COOKIE_UID</h5>

<p><img src="/assets/medium-to-jekyll-starter/github-7.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<ul>
  <li>
    <p>Name: <code class="language-plaintext highlighter-rouge">MEDIUM_COOKIE_UID</code></p>
  </li>
  <li>
    <p>Secret: 贴上上一步复制的 Medium 帐号 <code class="language-plaintext highlighter-rouge">uid</code> 值</p>
  </li>
</ul>

<h5 id="完成">完成</h5>

<p>帐号无特别登出或遇到问题，Cookies 不会失效。</p>

<p>如果在同步中出现以下讯息并且同步的文章不完整：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>This post is behind Medium's paywall. You must provide valid Medium Member login cookies to download the full post.
</code></pre></div></div>

<p>代表 Cookies 已失效，请重新照上述步骤重新设定。</p>

<h2 id="4-首次手动同步repo---github-actions---点击zmediumtomarkdown--点击enable-workflow">4. 首次手动同步，Repo -&gt; Github Actions -&gt; 点击「ZMediumToMarkdown」-&gt; 点击「Enable workflow」</h2>

<p>初次执行，我们可以自己手动同步一次检查设定是否正确。
<img src="/assets/medium-to-jekyll-starter/github-9.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<h2 id="5-等待同步文章与网站部署工作完成">5. 等待同步文章与网站部署工作完成</h2>

<p><img src="/assets/medium-to-jekyll-starter/github-10.png" alt="" loading="lazy" decoding="async" width="1200" height="800" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" /></p>

<p>等待以下三个 Actions 工作执行完成并且没有错误：</p>

<ul>
  <li>
    <p>🟢 ZMediumToMarkdown</p>
  </li>
  <li>
    <p>🟢 pages build and deployment</p>
  </li>
  <li>
    <p>🟢 Build and Deploy</p>
  </li>
</ul>

<h2 id="6-重整网页查看结果enjoy">6. 重整网页查看结果，Enjoy!</h2>

<blockquote>
  <p>⚠️ 请注意！所有档案变更都会触发：</p>

  <ul>
    <li>
      <p>🟢 pages build and deployment</p>
    </li>
    <li>
      <p>🟢 Build and Deploy</p>
    </li>
  </ul>

  <p>需等待以上两个部署工作完成，网站更改才会生效。</p>
</blockquote>

<hr />

<h1 id="jekyll-网站设定">Jekyll 网站设定</h1>

<h2 id="网站基本设定">网站基本设定</h2>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">./_config.yml</code></p>

    <p><strong>请务必调整</strong> 其中的 <code class="language-plaintext highlighter-rouge">url:</code> 改成您的 Github Pages 网址以及其他网站资料设定。</p>
  </li>
  <li>
    <p>分享功能设定：<code class="language-plaintext highlighter-rouge">./_data/share.yml</code></p>
  </li>
  <li>
    <p>定义文章作者资讯：<code class="language-plaintext highlighter-rouge">./_data/authors.yml</code></p>
  </li>
</ul>

<h2 id="左侧-sidebar-设定">左侧 Sidebar 设定</h2>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">./tabs</code></p>
  </li>
  <li>
    <p>底部连结按钮：<code class="language-plaintext highlighter-rouge">./_data/contact.yml</code></p>
  </li>
</ul>

<h2 id="网站底部及其他文字内容设定">网站底部及其他文字内容设定</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">./locales/{Lang}.yml</code> default is <code class="language-plaintext highlighter-rouge">/locales/en.yml</code></li>
</ul>

<h2 id="本地测试">本地测试</h2>

<ol>
  <li>
    <p>确定你的环境有安装并使用 Ruby &gt;= 3.1 版本</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">cd ./</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">bundle install</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">bundle exec jekyll s</code></p>
  </li>
  <li>
    <p>Go to <a href="http://127.0.0.1:4000/">http://127.0.0.1:4000/</a> 查看结果</p>
  </li>
  <li>
    <p>Press <code class="language-plaintext highlighter-rouge">Ctrl-c</code> to stop.</p>
  </li>
</ol>

<p>*网站基本设定档案有调整需要重新执行才会生效。</p>]]></content>
  </entry><entry>
    <title type="html">Google Apps Script Web App｜打造 Github Action CI/CD 自订表单提升开发效率</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/google-apps-script-web-app-%E6%89%93%E9%80%A0-github-action-ci-cd-%E8%87%AA%E8%AE%A2%E8%A1%A8%E5%8D%95%E6%8F%90%E5%8D%87%E5%BC%80%E5%8F%91%E6%95%88%E7%8E%87-4cb4437818f2/" rel="alternate" type="text/html" title="Google Apps Script Web App｜打造 Github Action CI/CD 自订表单提升开发效率" />
    <published>2025-01-11T19:19:43+08:00</published>
    <updated>2025-12-17T23:45:42+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/4cb4437818f2</id><summary type="html">针对缺乏动态 GUI 表单的 Github Action CI/CD，使用 Google Apps Script Web App 建立组织内专属表单，串接 Github API 自动取得分支并触发工作流程，并整合 Slack 通知与 Jira、Asana 工单查询，实现免维护、低成本的自动化打包工具。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="ios-app-development" /><category term="google-apps-script" /><category term="github-actions" /><category term="slack" /><category term="github" /><category term="simplified-chinese" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/4cb4437818f2/1*TiGXBQdPaCM6r2J1RHrgnA.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/google-apps-script-web-app-%E6%89%93%E9%80%A0-github-action-ci-cd-%E8%87%AA%E8%AE%A2%E8%A1%A8%E5%8D%95%E6%8F%90%E5%8D%87%E5%BC%80%E5%8F%91%E6%95%88%E7%8E%87-4cb4437818f2/"><![CDATA[<h3 id="使用-google-apps-script-web-app-表单串接-github-action-cicd-工作">使用 Google Apps Script Web App 表单串接 Github Action CI/CD 工作</h3>

<p>Github Action Workflow 表单优化与整合其他工作流程工具(Jira, Asana, Slack. . )提升开发效率。</p>

<p><img src="/assets/4cb4437818f2/1*TiGXBQdPaCM6r2J1RHrgnA.webp" alt="左：原始的 Github Action Workflow Form / 右： 最终成果 (GAS Web App Form)" loading="lazy" decoding="async" width="1222" height="692" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjIyIiBoZWlnaHQ9IjY5MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4cb4437818f2/1*TiGXBQdPaCM6r2J1RHrgnA.png" /></p>

<p>左：原始的 Github Action Workflow Form / 右： <a href="https://script.google.com/macros/s/AKfycbw8SuK7lLLMdY86y3jxMJyzXqa5tdxJryRnteOnNi-lK--j6CmKYXj7UuU58DiS0NSVvA/exec" target="_blank">最终成果 (GAS Web App Form)</a></p>

<h3 id="202507-update">2025/07 Update:</h3>

<p>此功能已整合到实际打包工具使用，可参考最新文章案例：「 <a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/"><strong>CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</strong></a> 」</p>

<h3 id="背景">背景</h3>

<p>之前的团队使用 Github Action &amp; Self-hosted Github Runner + Slack 搭建整套 CI/CD 服务；整体效果不错，对于 App 开发者来说建置与维护相对容易，只需照著官方文件提供的 YAML 参数完成设定就会自动触发、机器方面也可以轻易的使用自己的机器当成 Runner 使用，服务本身都是由 Github 维护，我们不需在意版本升级等问题并且 Runner 是反向跟 Github 要任务下来做，不需要特别开对外网路开口。</p>

<blockquote>
  <p><em>等于同时享受到类似 Bitrise 的 GUI YAML 建置方式又有像 Jenkins 那样使用自架机器的弹性跟较低的建置成本，但不用像 Jenkins 那样需要花时间维护服务本身。</em></p>
</blockquote>

<blockquote>
  <p><strong>未来有时间再写一篇完整的 App CI/CD x Github Action 搭建过程。</strong></p>
</blockquote>

<h4 id="问题github-action-cicd-gui-form">问题：Github Action CI/CD GUI Form</h4>

<p><img src="/assets/4cb4437818f2/1*55tCLFvuHtTyyvSLSv1vMA.webp" alt="Github Action GUI Form" loading="lazy" decoding="async" width="406" height="499" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MDYiIGhlaWdodD0iNDk5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*55tCLFvuHtTyyvSLSv1vMA.png" /></p>

<p>Github Action GUI Form</p>

<blockquote>
  <p><em>在 App 开发中，在 CD 触发打包测试版、正式版或送审时通常会需要提供一些外部参数或是依照需求选择环境、分支，才会开始执行工作。</em></p>
</blockquote>

<p>不同于 Jenkins 是自建服务，有完整的 Web GUI；Github Action 没有，唯一的 Web GUI Form 是在 Actions 中点击 Run workflow 可以自订一个简易的表单供使用者输入外部参数，然后触发 CI/CD 工作流程。</p>

<p>通常会使用这个 CD 打包的使用者，不一定是 App 开发者本身、也不一定拥有这个专案的权限；例如 QA 需要打包指定版本、PM/Backend 需要打包某个开发中版本进行测试；Github Action Form 需要有该专案的权限才能使用，但使用者不要说能不能有专案权限、甚至是不一定有工程背景。</p>

<p><strong>而且我们无法在这边做动态表单或资料验证。</strong></p>

<blockquote>
  <p><em>因此我们需要另外拉一个 GUI 服务给其他使用者操作使用。</em></p>
</blockquote>

<h4 id="自建-slack-app-解决">自建 Slack App 解决</h4>

<p>之前团队是有热爱做自动化的同仁自己用 Kotlin+Ktor 搭建了一个完整的 Slack App 网路服务，串接 Slack 讯息、表单、指令…等功能，接收、转发 CD 打包请求，触发 Github Action 执行操作并将结果串回 Slack。</p>

<blockquote>
  <p><em>目前没有开发资源跟之前一样使用 Kotlin+Ktor 建置服务</em></p>
</blockquote>

<h4 id="自己写-webiosmacos-app-工具">自己写 Web/iOS/macOS App 工具</h4>

<p>目前团队原本是使用 Jenkins 有基础的 Web 可以给其他使用者登入使用、另外还有自行开发了一个 App 串接 Jenkins 封装一些参数让非工程背景的使用者更方便使用。</p>

<blockquote>
  <p><strong><em>不过迁移到 Github Action 之后这整套就废弃了。</em></strong></p>
</blockquote>

<h4 id="-private-github-pages">❌ Private Github Pages</h4>

<p>应该有机会直接建置 Github Pages 来当 CI/CD Web GUI，但是目前只有 Github <a href="https://docs.github.com/en/enterprise-server@3.13/admin/configuration/configuring-your-enterprise/configuring-github-pages-for-your-enterprise#enabling-public-sites-for-github-pages" target="_blank">Enterprise</a> 可以设定 Github Pages 存取权限，其他方案就算是 Private Repo 也会是公开的；无安全性可言。</p>

<h4 id="-slack-app但使用-google-apps-script-建置">❌ Slack App，但使用 Google Apps Script 建置</h4>

<p>一开始想说依照之前团队的经验使用 Slack App 做为 CI/CD GUI Form 服务，但是目前没有资源跟之前一样使用 Kotlin+Ktor 建置服务；所以想说先使用 Function as a Service 服务快速尝试建置。</p>

<p>Function as a Service 有很多种， <a href="https://cloud.google.com/functions?hl=zh-tw" target="_blank">Cloud Functions</a> 的自由度比较高，但由于组织 IT 限制，无法随意新增 Public Cloud Functions 并且有收费问题；因此还是回到我们的老朋友 — Google Apps Script。</p>

<blockquote>
  <p><em>之前写过好几篇关于 Google Apps Script 做自动化的文章，有兴趣的朋友可以参考：</em></p>
</blockquote>

<blockquote>
  <p><em>1. <strong>「 <a href="/posts/zrealm-robotic-process-automation/google-apps-script-打造每日数据报表自动化-rpa-快速串接-google-analytics-与-google-sheet-f6713ba3fee3/">使用 Google Apps Script 实现每日数据报表 RPA 自动化</a> 」</strong></em></p>
</blockquote>

<blockquote>
  <p><em>2. 「 <a href="https://medium.com/zrealm-robotic-process-automation/%E7%B0%A1%E5%96%AE-3-%E6%AD%A5%E9%A9%9F-%E6%89%93%E9%80%A0%E5%85%8D%E8%B2%BB-ga4-%E8%87%AA%E5%8B%95%E6%95%B8%E6%93%9A%E9%80%9A%E7%9F%A5%E6%A9%9F%E5%99%A8%E4%BA%BA-1e85b8df2348?source=collection_home---6------1-----------------------" target="_blank">简单 3 步骤 — 打造免费 GA4 自动数据通知机器人</a> 」</em></p>
</blockquote>

<blockquote>
  <p><em>3. 「 <a href="https://medium.com/zrealm-robotic-process-automation/crashlytics-google-analytics-%E8%87%AA%E5%8B%95%E6%9F%A5%E8%A9%A2-app-crash-free-users-rate-793cb8f89b72?source=collection_home---6------8-----------------------" target="_blank">Crashlytics + Google Analytics 自动查询 App Crash-Free Users Rate</a> 」</em></p>
</blockquote>

<blockquote>
  <p><em>4. 「 <a href="https://medium.com/zrealm-robotic-process-automation/crashlytics-big-query-%E6%89%93%E9%80%A0%E6%9B%B4%E5%8D%B3%E6%99%82%E4%BE%BF%E5%88%A9%E7%9A%84-crash-%E8%BF%BD%E8%B9%A4%E5%B7%A5%E5%85%B7-e77b80cc6f89?source=collection_home---6------9-----------------------" target="_blank">Crashlytics + Big Query 打造更即时便利的 Crash 追踪工具</a> 」</em></p>
</blockquote>

<p>总而言之，Google Apps Script 是 Google 另一个 Function as a Service 服务，主要特色是免费跟与 Google 服务之间可以快速整合；但是限制也较多，例如只能用它的语言、执行时间不能超过 6 分钟、有执行次数上限、不支援多执行绪…等等，细节可以参考 <a href="/posts/zrealm-robotic-process-automation/google-apps-script-打造每日数据报表自动化-rpa-快速串接-google-analytics-与-google-sheet-f6713ba3fee3/">我之前的文章</a> 。</p>

<p>结论是不可行，原因是：</p>

<ul>
  <li>
    <p><a href="https://www.cloudflare.com/zh-tw/learning/serverless/what-is-serverless/" target="_blank">Function as a Service 冷启动问题</a> 。
服务一段时间没呼叫会进入睡眠，再次呼叫要花较长时间启动(3~≥ 5 秒)； <strong>Slack App 对于 API 响应时间非常严格，服务需要在 3 秒内回应否则视为失败</strong> ，Slack 这边就会直接喷错误、事件监听也会被认为丢失，导致重复发送。</p>
  </li>
  <li>
    <p><strong>Google Apps Script doGet, doPost 方法无法取得 Headers。</strong>
<strong>这会导致无法走 <a href="https://api.slack.com/authentication/verifying-requests-from-slack" target="_blank">官方的安全验证</a> 、无法关闭 <a href="https://api.slack.com/authentication/verifying-requests-from-slack" target="_blank">Slack Retry</a> 。</strong></p>
  </li>
  <li>
    <p>Google Apps Script 单执行绪问题。
如果要串接其他服务响应时间都会超过 3 秒，直接被 Slack 判定为失败。</p>
  </li>
</ul>

<p>有勉强使用 Slack 讯息、Block Kit、Form 串接完整个流程，但是太容易触发上述问题，后来直接放弃。</p>

<blockquote>
  <p><strong><em>如果要做这套还是要走自己起伺服器、服务，不要走 Function as a Service! !</em></strong></p>
</blockquote>

<h4 id="-slack-workflow-form">❌ Slack Workflow Form</h4>

<p><img src="/assets/4cb4437818f2/1*KWBMdFswvl1KPdnTLStzhQ.webp" alt="" loading="lazy" decoding="async" width="1136" height="812" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTM2IiBoZWlnaHQ9IjgxMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/4cb4437818f2/1*KWBMdFswvl1KPdnTLStzhQ.png" /></p>

<p><img src="/assets/4cb4437818f2/1*hnDPyOfGCTW_yJf71krMnA.webp" alt="Slack Workflow Form (❌ 无法客制化)" loading="lazy" decoding="async" width="519" height="458" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTkiIGhlaWdodD0iNDU4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*hnDPyOfGCTW_yJf71krMnA.png" /></p>

<p><a href="https://slack.com/intl/zh-tw/help/articles/24720245025555-%E8%87%AA%E5%8B%95%E5%8C%96%EF%BC%9A%E4%BD%BF%E7%94%A8%E7%B0%A1%E6%98%93%E8%A1%A8%E5%96%AE%E6%94%B6%E9%9B%86%E8%B3%87%E8%A8%8A" target="_blank">Slack Workflow Form</a> (❌ 无法客制化)</p>

<p>另外也尝试过 Slack 内建的自动化功能 Workflow Form，不过他无法做到动态表单内容 (e.g. 捞分支让使用者选)，唯一能客制化的只有后续送资料的步骤。</p>

<h3 id="-google-apps-script-web-app-gui-form-表单">✅ Google Apps Script Web App GUI Form 表单</h3>

<p>山不转路转，转念一想好像也不用纠结在一定要用 Slack 整合上，用 Slack 整合是最好的方案，因为是直接整进既有的团队协作工具，不需要发散额外去学新工具；但是迫于资源限制，我们只能退而求其次找其他稳定又好用的方法。</p>

<blockquote>
  <p><em>回头想到 Google Apps Script 本身就能部署成 Web App，可以在 Web doGet 时回应 GUI Form 表单，送出表单后触发后续的 Github 串接处理。</em></p>
</blockquote>

<h4 id="最终成果-">最终成果 🎉</h4>

<p><img src="/assets/4cb4437818f2/1*pzW-Yki-4HbE2nYXC4q-Aw.webp" alt="Demo Web App Form" loading="lazy" decoding="async" width="653" height="672" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NTMiIGhlaWdodD0iNjcyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*pzW-Yki-4HbE2nYXC4q-Aw.png" /></p>

<p><a href="https://script.google.com/macros/s/AKfycbw8SuK7lLLMdY86y3jxMJyzXqa5tdxJryRnteOnNi-lK--j6CmKYXj7UuU58DiS0NSVvA/exec" target="_blank">Demo Web App Form</a></p>

<h4 id="工作流程"><strong>工作流程</strong></h4>

<p>我们使用 Google Apps Script Web App 建置 CI/CD 表单，直接绑定 Google Workspace 帐号，设定只有组织内的使用者可以存取；自动获取当前登入的使用者信箱、使用 Github Repo 共用帐号(或借用某个有权限的帐号)的 Personal Access Token 打 Github API 获得分支列表，送出后同样打 API 触发 Github Action 开始执行 CI/CD 工作。</p>

<p>另外，我们可以用使用者的信箱透过 Slack App 去打 Slack API，取得该使用者的 Slack ID，再透过 Slack App 传送讯息，通知 CI/CD 任务执行情况。</p>

<p>也可以再与其他工具、开发流程进行整合，例如先从 Asana, Jira 取得工单，选择后再透过 Github API 查找分支、触发 Github Action，最后再透过 Slack 通知给使用者。</p>

<h4 id="step-1-建立-google-apps-script-web-app-form">Step 1. 建立 Google Apps Script Web App Form</h4>

<p>前往 &gt; <a href="https://script.google.com/home" target="_blank">Google Apps Script</a> ，新增专案。</p>

<p><img src="/assets/4cb4437818f2/1*T3if7Dfo0iJaa4N5VZyA1Q.webp" alt="" loading="lazy" decoding="async" width="928" height="370" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjgiIGhlaWdodD0iMzcwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*T3if7Dfo0iJaa4N5VZyA1Q.png" /></p>

<h4 id="step-2-建立表单内容gas-程式">Step 2. 建立表单内容、GAS 程式</h4>

<p>太久没有写 HTML,CSS 也懒得自己设计样式，直接请 ChatGPT 产一个有一点设计的 HTML 表单范本。</p>

<p><img src="/assets/4cb4437818f2/1*IPv0afE5FAFj40F22s8Umg.webp" alt="" loading="lazy" decoding="async" width="1200" height="1039" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwMzkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/4cb4437818f2/1*IPv0afE5FAFj40F22s8Umg.png" /></p>

<p><img src="/assets/4cb4437818f2/1*F_HrfV_k16g_ojm1WIDDuA.webp" alt="" loading="lazy" decoding="async" width="978" height="608" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NzgiIGhlaWdodD0iNjA4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*F_HrfV_k16g_ojm1WIDDuA.png" /></p>

<p>在 GAS 左方档案列表点「+」新增档案，输入档案名称「 <code class="language-plaintext highlighter-rouge">Form.html</code> 」并把 GPT 产的 HTML 表单范本内容贴上。</p>

<p><code class="language-plaintext highlighter-rouge">Form.html：</code></p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!--HTML &amp; Style Gen by ChatGPT 4o--&gt;</span>
<span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;head&gt;</span>
  <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;meta</span> <span class="na">name=</span><span class="s">"viewport"</span> <span class="na">content=</span><span class="s">"width=device-width, initial-scale=1.0"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;title&gt;</span><span class="cp">&lt;?=title?&gt;</span><span class="nt">&lt;/title&gt;</span>
  <span class="nt">&lt;style&gt;</span>
    body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 20px;
      background-color: #f7f7f7;
    }
    .form-container {
      max-width: 600px;
      margin: auto;
      padding: 20px;
      background-color: #ffffff;
      border-radius: 8px;
      box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    }
    .form-container h2 {
      margin-bottom: 20px;
      color: #333333;
    }
    .form-group {
      margin-bottom: 15px;
    }
    .form-group label {
      display: block;
      margin-bottom: 5px;
      font-weight: bold;
      color: #555555;
    }
    .form-group input,
    .form-group select,
    .form-group textarea {
      width: 95%;
      padding: 10px;
      border: 1px solid #cccccc;
      border-radius: 4px;
      font-size: 16px;
    }
    .form-group input[type="radio"] {
      width: auto;
      margin-right: 10px;
    }
    .form-group .radio-label {
      display: inline-block;
      margin-right: 20px;
    }
    .form-group button {
      background-color: #4CAF50;
      color: white;
      padding: 10px 20px;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-size: 16px;
    }
    .form-group button:hover {
      background-color: #45a049;
    }
    .message {
      margin-top: 20px;
      padding: 15px;
      border-radius: 5px;
      font-size: 1em;
      text-align: center;
    }
    .message.success {
      background-color: #d4edda;
      color: #155724;
      border: 1px solid #c3e6cb;
    }
    .message.error {
      background-color: #f8d7da;
      color: #721c24;
      border: 1px solid #f5c6cb;
    }
    .hidden {
      display: none;
    }
  <span class="nt">&lt;/style&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-container"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;h2&gt;</span><span class="cp">&lt;?=title?&gt;</span><span class="nt">&lt;/h2&gt;</span>
    <span class="nt">&lt;form</span> <span class="na">id=</span><span class="s">"myForm"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"message-block"</span> <span class="na">class=</span><span class="s">"hidden"</span><span class="nt">&gt;&lt;/div&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"email"</span><span class="nt">&gt;</span>电子邮件：<span class="nt">&lt;/label&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"email"</span> <span class="na">value=</span><span class="s">"&lt;?=email?&gt;"</span> <span class="err">readonly</span><span class="nt">/&gt;</span>
      <span class="nt">&lt;/div&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"buildNumber"</span><span class="nt">&gt;</span>版本号：<span class="nt">&lt;/label&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"number"</span> <span class="na">value=</span><span class="s">"&lt;?=buildNumber?&gt;"</span><span class="nt">/&gt;</span>
      <span class="nt">&lt;/div&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"branch"</span><span class="nt">&gt;</span>Review 中的 PR：<span class="nt">&lt;/label&gt;</span>
        <span class="nt">&lt;select</span> <span class="na">id=</span><span class="s">"branch"</span> <span class="na">name=</span><span class="s">"branch"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;option&gt;</span>请选择<span class="nt">&lt;/option&gt;</span>
          <span class="cp">&lt;? pullRequests.forEach(pullRequest =&gt; { ?&gt;</span>
            <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"&lt;?=pullRequest.head.ref?&gt;"</span><span class="nt">&gt;</span>[<span class="cp">&lt;?=pullRequest.state?&gt;</span>] <span class="cp">&lt;?=pullRequest.title?&gt;</span><span class="nt">&lt;/option&gt;</span>
          <span class="cp">&lt;? }); ?&gt;</span>
        <span class="nt">&lt;/select&gt;</span>
      <span class="nt">&lt;/div&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"message"</span><span class="nt">&gt;</span>更新内容：<span class="nt">&lt;/label&gt;</span>
        <span class="nt">&lt;textarea</span> <span class="na">id=</span><span class="s">"message"</span> <span class="na">name=</span><span class="s">"message"</span> <span class="na">rows=</span><span class="s">"4"</span> <span class="na">placeholder=</span><span class="s">"请输入您的讯息"</span><span class="nt">&gt;&lt;/textarea&gt;</span>
      <span class="nt">&lt;/div&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"submit"</span><span class="nt">&gt;</span>送出<span class="nt">&lt;/button&gt;</span>
      <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/form&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;script&gt;</span>
    function displayMessage(ok, message) {
      const messageBlock = document.getElementById('message-block');
      messageBlock.className = ok ? 'message success' : 'message error';
      messageBlock.innerHTML = message;
      messageBlock.classList.remove('hidden');
    }
    
    document.getElementById("myForm").addEventListener("submit", function(e) {
      e.preventDefault();
      const formData = new FormData(this);
      const formObject = Object.fromEntries(formData);
      google.script.run.withSuccessHandler((response) =&gt; {
        displayMessage(response.ok, response.message);
      }).processForm(formObject);
    });
  <span class="nt">&lt;/script&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<p>表单内容可依照需求自行调整。</p>

<p><code class="language-plaintext highlighter-rouge">程式码.gs：</code></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">doGet</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
  <span class="c1">// 对应到左方档案 Form.html</span>
  <span class="kd">const</span> <span class="nx">htmlTemplate</span> <span class="o">=</span> <span class="nx">HtmlService</span><span class="p">.</span><span class="nf">createTemplateFromFile</span><span class="p">(</span><span class="dl">'</span><span class="s1">Form</span><span class="dl">'</span><span class="p">);</span>
  
  <span class="kd">const</span> <span class="nx">email</span> <span class="o">=</span> <span class="nx">Session</span><span class="p">.</span><span class="nf">getActiveUser</span><span class="p">().</span><span class="nf">getEmail</span><span class="p">();</span>
  <span class="c1">// 取得使用者信箱，只限 执行身份：存取网页程式的使用者 设定有效</span>
  
  <span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">App CD 打包请求表单</span><span class="dl">"</span><span class="p">;</span>
  
  <span class="kd">const</span> <span class="nx">buildNumber</span> <span class="o">=</span> <span class="nf">genBuildNumber</span><span class="p">();</span>

  <span class="nx">htmlTemplate</span><span class="p">.</span><span class="nx">email</span> <span class="o">=</span> <span class="nx">email</span><span class="p">;</span>
  <span class="nx">htmlTemplate</span><span class="p">.</span><span class="nx">title</span> <span class="o">=</span> <span class="nx">title</span><span class="p">;</span>
  <span class="nx">htmlTemplate</span><span class="p">.</span><span class="nx">pullRequests</span> <span class="o">=</span> <span class="p">[];</span> <span class="c1">// 下一步在串接 Github...</span>
  <span class="nx">htmlTemplate</span><span class="p">.</span><span class="nx">buildNumber</span> <span class="o">=</span> <span class="nx">buildNumber</span><span class="p">;</span>

  <span class="kd">const</span> <span class="nx">html</span> <span class="o">=</span> <span class="nx">htmlTemplate</span><span class="p">.</span><span class="nf">evaluate</span><span class="p">();</span>
  <span class="nx">html</span><span class="p">.</span><span class="nf">setTitle</span><span class="p">(</span><span class="nx">title</span><span class="p">);</span>
  <span class="c1">//html.setWidth(600) // 设定页面宽度</span>

  <span class="k">return</span> <span class="nx">html</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">processForm</span><span class="p">(</span><span class="nx">object</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">return</span> <span class="p">{</span><span class="dl">"</span><span class="s2">ok</span><span class="dl">"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="dl">"</span><span class="s2">message</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">请求送出成功！</span><span class="dl">"</span><span class="p">};</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">genBuildNumber</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">now</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Date</span><span class="p">();</span>
  <span class="kd">const</span> <span class="nx">formattedDate</span> <span class="o">=</span> <span class="nx">Utilities</span><span class="p">.</span><span class="nf">formatDate</span><span class="p">(</span><span class="nx">now</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Asia/Taipei</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">yyyyMMddHHmmss</span><span class="dl">"</span><span class="p">);</span>
  <span class="kd">const</span> <span class="nx">milliseconds</span> <span class="o">=</span> <span class="nx">now</span><span class="p">.</span><span class="nf">getMilliseconds</span><span class="p">().</span><span class="nf">toString</span><span class="p">().</span><span class="nf">padStart</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="dl">'</span><span class="s1">0</span><span class="dl">'</span><span class="p">);</span> <span class="c1">// 确保毫秒是 3 位数</span>
  <span class="k">return</span> <span class="s2">`</span><span class="p">${</span><span class="nx">formattedDate</span><span class="p">}${</span><span class="nx">milliseconds</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span> 
<span class="p">}</span>
</code></pre></div></div>

<p>这一步，我们先把表单 GUI 完成，下一步再来串接 Github API 拿到 PR 分支列表。</p>

<p><img src="/assets/4cb4437818f2/1*RN9ftVBdgCA-IL8ra9jvTg.webp" alt="" loading="lazy" decoding="async" width="509" height="324" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MDkiIGhlaWdodD0iMzI0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*RN9ftVBdgCA-IL8ra9jvTg.png" /></p>

<h4 id="step-2-部署-google-apps-script-web-app-form">Step 2. 部署 Google Apps Script Web App Form</h4>

<p>我们先把刚刚的内容部署一次，查看结果。</p>

<p>在 GAS 右上角选择「部署」-&gt; 「新增部署作业」-&gt;「网页应用程式」：</p>

<p><img src="/assets/4cb4437818f2/1*ouVO18FtOcX8vdeGCEtwCw.webp" alt="" loading="lazy" decoding="async" width="330" height="215" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMzAiIGhlaWdodD0iMjE1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*ouVO18FtOcX8vdeGCEtwCw.png" /></p>

<p><img src="/assets/4cb4437818f2/1*4BuEtIA4H_-Q9WALonYxYg.webp" alt="" loading="lazy" decoding="async" width="396" height="302" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzOTYiIGhlaWdodD0iMzAyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*4BuEtIA4H_-Q9WALonYxYg.png" /></p>

<p><img src="/assets/4cb4437818f2/1*JagpVPTGD-W0lhIJ5nrRew.webp" alt="" loading="lazy" decoding="async" width="762" height="599" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjIiIGhlaWdodD0iNTk5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*JagpVPTGD-W0lhIJ5nrRew.png" /></p>

<p>执行身份跟谁可以存取分别可以设置成：</p>

<p><strong>执行身份：</strong></p>

<ul>
  <li>
    <p>我 <code class="language-plaintext highlighter-rouge">统一都用你的帐号身分执行脚本。</code></p>
  </li>
  <li>
    <p>存取网页程式的使用者 <code class="language-plaintext highlighter-rouge">会以当前登入的 Google 帐号使用者身份执行脚本。</code></p>
  </li>
</ul>

<p><strong>谁可以存取：</strong></p>

<ul>
  <li>
    <p>只有我自己</p>
  </li>
  <li>
    <p><strong>XXX 同个组织中的所有使用者</strong> <code class="language-plaintext highlighter-rouge">只有同组织＋已登入的 Google 帐号使用者可以存取。</code></p>
  </li>
  <li>
    <p>所有已登入 Google 帐号的使用者 <code class="language-plaintext highlighter-rouge">已登入的 Google 帐号使用者都可以存取。</code></p>
  </li>
  <li>
    <p>所有人 <code class="language-plaintext highlighter-rouge">不需要登入 Google 帐号、所有人都可以公开存取。</code></p>
  </li>
</ul>

<blockquote>
  <p><em>我们选择「谁可以存取：XXX 同个组织中的所有使用者」＋「执行身份：存取网页程式的使用者」就能 <strong>自动限制只有组织帐号的人可以使用</strong> ，并且用他自己的身份执行！</em></p>
</blockquote>

<blockquote>
  <p><em>是一个很方便权限控管的功能！</em></p>
</blockquote>

<p>选完点击右下「部署」。</p>

<p><img src="/assets/4cb4437818f2/1*dvyqYb5kcta402j3RUYJog.webp" alt="" loading="lazy" decoding="async" width="770" height="605" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NzAiIGhlaWdodD0iNjA1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*dvyqYb5kcta402j3RUYJog.png" /></p>

<p>网页应用程式中的网址，就是 Web App 存取网址。</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://script.google.com/macros/s/AKfycbw8SuK7lLLMdY86y3jxMJyzXqa5tdxJryRnteOnNi-lK--j6CmKYXj7UuU58DiS0NSVvA/exec
</code></pre></div></div>

<blockquote>
  <p><em>网址很长很丑，但是没办法，只能自己找短网址工具缩短一下。</em></p>
</blockquote>

<p><strong>点网址打开页面查看效果：</strong></p>

<p><img src="/assets/4cb4437818f2/1*jbx4IO4DEhqYfwI_UTQk5Q.webp" alt="" loading="lazy" decoding="async" width="709" height="641" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDkiIGhlaWdodD0iNjQxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*jbx4IO4DEhqYfwI_UTQk5Q.png" /></p>

<p><strong>这边要多提两个 GAS 限制：</strong></p>

<ul>
  <li>
    <p>GAS Web App 上方警告提示，预设无法隐藏</p>
  </li>
  <li>
    <p>GAS Web App 是用 IFrame 把我们的页面嵌在里面，因此很难做到 100% RWD 效果
只能使用 <code class="language-plaintext highlighter-rouge">.setWidth()</code> 调整视窗宽度</p>
  </li>
</ul>

<h4 id="google-apps-script-授权警告">Google Apps Script 授权警告</h4>

<p><strong>第一次使用</strong> 、点击「侦错」或「执行」可能会出下以下授权警告：</p>

<p><img src="/assets/4cb4437818f2/1*9q8KZGHER9vdtnbKVVQB9g.webp" alt="" loading="lazy" decoding="async" width="301" height="196" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMDEiIGhlaWdodD0iMTk2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*9q8KZGHER9vdtnbKVVQB9g.png" /></p>

<p><img src="/assets/4cb4437818f2/1*iWrkqMf8vkEGkiwkI1amIw.webp" alt="" loading="lazy" decoding="async" width="521" height="503" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MjEiIGhlaWdodD0iNTAzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*iWrkqMf8vkEGkiwkI1amIw.jpeg" /></p>

<p>选择想要执行的身份帐号，如果有出现「这个应用程式未经 Google 验证」则点击「进阶」-&gt;「前往 XXX (不安全)」，选择「允许」：</p>

<p><img src="/assets/4cb4437818f2/1*ucaqLxh-TOgJIaGyqqFd3A.webp" alt="" loading="lazy" decoding="async" width="504" height="595" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MDQiIGhlaWdodD0iNTk1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*ucaqLxh-TOgJIaGyqqFd3A.png" /></p>

<p><img src="/assets/4cb4437818f2/1*l-tma_YICU24goKvZvl7Ww.webp" alt="" loading="lazy" decoding="async" width="653" height="468" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NTMiIGhlaWdodD0iNDY4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*l-tma_YICU24goKvZvl7Ww.png" /></p>

<p><img src="/assets/4cb4437818f2/1*JAs_3__Qt2XeDcQiKEUNhg.webp" alt="" loading="lazy" decoding="async" width="504" height="789" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MDQiIGhlaWdodD0iNzg5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*JAs_3__Qt2XeDcQiKEUNhg.png" /></p>

<p>如果 GAS 程式权限有变动(例如：多加存取 Google Sheet…etc)才会需要再重新授权，不然点过一次就不会再出现。</p>

<blockquote>
  <p><em>如遇到：已封锁存取权「XXX」未完成 Google 验证程序， <a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/">可参考我最新文章的 GCP 设定。</a></em></p>
</blockquote>

<h4 id="step-3-串接-github-api-取得-pr-分支列表">Step 3. 串接 Github API 取得 PR 分支列表</h4>

<p>我们新增一个 <code class="language-plaintext highlighter-rouge">Github.gs</code> 程式档案存放 Github API 相关逻辑。</p>

<p><code class="language-plaintext highlighter-rouge">Github.gs：</code></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SECRET</span>
<span class="kd">const</span> <span class="nx">githubPersonalAccessToken</span> <span class="o">=</span> <span class="dl">""</span>
<span class="c1">// 使用你的 Github 帐号或组织共用的 Github 帐号创建 PAT</span>
<span class="c1">// https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens</span>

<span class="c1">// 方式 1: Restful API 存取</span>
<span class="kd">function</span> <span class="nf">githubAPI</span><span class="p">(</span><span class="nx">method</span><span class="p">,</span> <span class="nx">path</span><span class="p">,</span> <span class="nx">payload</span> <span class="o">=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">try</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">https://api.github.com</span><span class="dl">"</span><span class="o">+</span><span class="nx">path</span><span class="p">;</span>  
    <span class="kd">var</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
      <span class="na">method</span><span class="p">:</span> <span class="nx">method</span><span class="p">,</span>
      <span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
        <span class="dl">"</span><span class="s2">Accept</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/vnd.github+json</span><span class="dl">"</span><span class="p">,</span>
        <span class="dl">"</span><span class="s2">Authorization</span><span class="dl">"</span><span class="p">:</span> <span class="s2">`Bearer </span><span class="p">${</span><span class="nx">githubPersonalAccessToken</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span>
        <span class="dl">"</span><span class="s2">X-GitHub-Api-Version</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">2022-11-28</span><span class="dl">"</span>
      <span class="p">}</span>
    <span class="p">};</span>

    <span class="k">if </span><span class="p">(</span><span class="nx">method</span><span class="p">.</span><span class="nf">toLowerCase</span><span class="p">().</span><span class="nf">trim</span><span class="p">()</span> <span class="o">==</span> <span class="dl">"</span><span class="s2">post</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">options</span><span class="p">.</span><span class="nx">payload</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">payload</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
    <span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>
    <span class="k">return</span> <span class="nx">data</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">throw</span> <span class="nx">error</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 方式 2: GraphQL 存取</span>
<span class="c1">// Github API 部分更细的查询功能只有 GraphQL API 有提供</span>
<span class="c1">// https://docs.github.com/en/graphql</span>
<span class="kd">function</span> <span class="nf">githubGraphQL</span><span class="p">(</span><span class="nx">query</span><span class="p">,</span> <span class="nx">variables</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">https://api.github.com/graphql</span><span class="dl">"</span><span class="p">;</span>
  <span class="kd">const</span> <span class="nx">payload</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">query</span><span class="p">:</span> <span class="nx">query</span><span class="p">,</span>
    <span class="na">variables</span><span class="p">:</span> <span class="nx">variables</span>
  <span class="p">};</span>

  <span class="kd">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">method</span><span class="p">:</span> <span class="dl">"</span><span class="s2">post</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">contentType</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/json</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
      <span class="dl">"</span><span class="s2">Accept</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/vnd.github+json</span><span class="dl">"</span><span class="p">,</span>
      <span class="dl">"</span><span class="s2">Authorization</span><span class="dl">"</span><span class="p">:</span> <span class="s2">`Bearer </span><span class="p">${</span><span class="nx">githubPersonalAccessToken</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span>
      <span class="dl">"</span><span class="s2">X-GitHub-Api-Version</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">2022-11-28</span><span class="dl">"</span>
    <span class="p">},</span>
    <span class="na">payload</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">payload</span><span class="p">)</span>
  <span class="p">};</span>

  <span class="k">try</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
    <span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>
    <span class="k">return</span> <span class="nx">data</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">throw</span> <span class="nx">error</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// GraphQL Example:</span>
<span class="c1">// const query = `</span>
<span class="c1">//   query($owner: String!, $repo: String!) {</span>
<span class="c1">//     repository(owner: $owner, name: $repo) {</span>
<span class="c1">//       pullRequests(states: OPEN, first: 100, orderBy: { field: CREATED_AT, direction: DESC }) {</span>
<span class="c1">//         nodes {</span>
<span class="c1">//           title</span>
<span class="c1">//           url</span>
<span class="c1">//           number</span>
<span class="c1">//           createdAt</span>
<span class="c1">//           author {</span>
<span class="c1">//             login</span>
<span class="c1">//           }</span>
<span class="c1">//           headRefName</span>
<span class="c1">//           baseRefName</span>
<span class="c1">//           body</span>
<span class="c1">//         }</span>
<span class="c1">//         pageInfo {</span>
<span class="c1">//           hasNextPage</span>
<span class="c1">//           endCursor</span>
<span class="c1">//         }</span>
<span class="c1">//       }</span>
<span class="c1">//     }</span>
<span class="c1">//   }</span>
<span class="c1">// `;</span>
<span class="c1">// const variables = {</span>
<span class="c1">//   owner: "swiftlang",</span>
<span class="c1">//   repo: "swift"</span>
<span class="c1">// };</span>
<span class="c1">// const response = githubGraphQL(query, variables);</span>
</code></pre></div></div>

<p>Github API 有两种存取方式，一种是传统的 Restful，另一种是更弹性的 GraphQL；本文以 Restful 为例。</p>

<p><code class="language-plaintext highlighter-rouge">程式码.gs：</code></p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">function</span> <span class="nf">doGet</span><span class="p">(</span><span class="n">e</span><span class="p">)</span> <span class="p">{</span>
  <span class="c1">// 对应到左方档案 Form.html</span>
  <span class="k">const</span> <span class="n">htmlTemplate</span> <span class="p">=</span> <span class="nc">HtmlService</span><span class="p">.</span><span class="nf">createTemplateFromFile</span><span class="p">(</span><span class="err">'</span><span class="nc">Form</span><span class="err">'</span><span class="p">);</span>
  
  <span class="k">const</span> <span class="n">email</span> <span class="p">=</span> <span class="nc">Session</span><span class="p">.</span><span class="nf">getActiveUser</span><span class="p">().</span><span class="nf">getEmail</span><span class="p">();</span>
  <span class="c1">// 取得使用者信箱，只限 执行身份：存取网页程式的使用者 设定有效</span>

  <span class="k">const</span> <span class="n">title</span> <span class="p">=</span> <span class="s">"App CD 打包请求表单"</span><span class="p">;</span>
  
  <span class="k">const</span> <span class="n">pullRequests</span> <span class="p">=</span> <span class="nf">githubAPI</span><span class="p">(</span><span class="s">"get"</span><span class="p">,</span> <span class="s">"/repos/swiftlang/swift/pulls"</span><span class="p">);</span>
  <span class="c1">// 以 https://github.com/swiftlang/swift/pulls 为例</span>
  
  <span class="k">const</span> <span class="n">buildNumber</span> <span class="p">=</span> <span class="nf">genBuildNumber</span><span class="p">();</span>

  <span class="n">htmlTemplate</span><span class="p">.</span><span class="n">email</span> <span class="p">=</span> <span class="n">email</span><span class="p">;</span>
  <span class="n">htmlTemplate</span><span class="p">.</span><span class="n">title</span> <span class="p">=</span> <span class="n">title</span><span class="p">;</span>
  <span class="n">htmlTemplate</span><span class="p">.</span><span class="n">pullRequests</span> <span class="p">=</span> <span class="n">pullRequests</span><span class="p">;</span>
  <span class="n">htmlTemplate</span><span class="p">.</span><span class="n">buildNumber</span> <span class="p">=</span> <span class="n">buildNumber</span><span class="p">;</span>

  <span class="k">const</span> <span class="n">html</span> <span class="p">=</span> <span class="n">htmlTemplate</span><span class="p">.</span><span class="nf">evaluate</span><span class="p">();</span>
  <span class="n">html</span><span class="p">.</span><span class="nf">setTitle</span><span class="p">(</span><span class="n">title</span><span class="p">);</span>
  <span class="c1">//html.setWidth(600) // 设定页面宽度</span>

  <span class="k">return</span> <span class="n">html</span>
<span class="p">}</span>

<span class="n">function</span> <span class="nf">processForm</span><span class="p">(</span><span class="k">object</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="k">object</span><span class="p">.</span><span class="n">buildNumber</span> <span class="p">==</span> <span class="s">""</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">{</span><span class="s">"ok"</span><span class="p">:</span> <span class="k">false</span><span class="p">,</span> <span class="s">"message"</span><span class="p">:</span> <span class="s">"请输入版本号！"</span><span class="p">};</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="k">object</span><span class="p">.</span><span class="n">branch</span> <span class="p">==</span> <span class="s">""</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">{</span><span class="s">"ok"</span><span class="p">:</span> <span class="k">false</span><span class="p">,</span> <span class="s">"message"</span><span class="p">:</span> <span class="s">"请选择分支版本！"</span><span class="p">};</span>
  <span class="p">}</span>

  <span class="c1">// 带上你要带到 Github Action 的参数</span>
  <span class="k">const</span> <span class="n">payload</span> <span class="p">=</span> <span class="p">{</span>
    <span class="n">ref</span><span class="p">:</span> <span class="k">object</span><span class="p">.</span><span class="n">branch</span><span class="p">,</span>
    <span class="n">inputs</span><span class="p">:</span> <span class="p">{</span>
      <span class="n">buildNumber</span><span class="p">:</span> <span class="k">object</span><span class="p">.</span><span class="n">buildNumber</span>
    <span class="p">}</span>
  <span class="p">};</span>
  
  <span class="c1">//  </span>
  <span class="k">try</span> <span class="p">{</span>
    <span class="k">const</span> <span class="n">response</span> <span class="p">=</span> <span class="nf">githubAPI</span><span class="p">(</span><span class="s">"post"</span><span class="p">,</span> <span class="s">"/repos/zhgchgli0718/ios-project-for-github-action-ci-cd-demo/actions/workflows/CD-Job.yml/dispatches"</span><span class="p">,</span> <span class="n">payload</span><span class="p">);</span>
    <span class="c1">// 以 https://github.com/zhgchgli0718/ios-project-for-github-action-ci-cd-demo/blob/main/.github/workflows/CD-Job.yml 为例</span>

    <span class="k">return</span> <span class="p">{</span><span class="s">"ok"</span><span class="p">:</span> <span class="k">true</span><span class="p">,</span> <span class="s">"message"</span><span class="p">:</span> <span class="err">`打包请求发送成功</span><span class="p">!&lt;</span><span class="n">br</span><span class="p">/&gt;</span><span class="err">对应分支：</span><span class="p">&lt;</span><span class="n">strong</span><span class="p">&gt;</span><span class="err">$</span><span class="p">{</span><span class="k">object</span><span class="p">.</span><span class="n">branch</span><span class="p">}&lt;/</span><span class="n">strong</span><span class="p">&gt;&lt;</span><span class="n">br</span><span class="p">/&gt;</span><span class="err">版号：</span><span class="p">&lt;</span><span class="n">strong</span><span class="p">&gt;</span><span class="err">$</span><span class="p">{</span><span class="k">object</span><span class="p">.</span><span class="n">buildNumber</span><span class="p">}&lt;/</span><span class="n">strong</span><span class="p">&gt;</span><span class="err">`</span><span class="p">};</span>
  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">{</span><span class="s">"ok"</span><span class="p">:</span> <span class="k">false</span><span class="p">,</span> <span class="s">"message"</span><span class="p">:</span> <span class="s">"发生错误："</span><span class="p">+</span><span class="n">error</span><span class="p">.</span><span class="n">message</span><span class="p">};</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">processForm</code> 方法中处理表单回传的内容，也可以多加上更多吃</p>

<h4 id="gas-x-github-api-x-github-action">GAS x Github API x Github Action</h4>

<p>这边多补充一下对应到的 Github Action。</p>

<p><code class="language-plaintext highlighter-rouge">CD-Job.yml：</code></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># CD 打包工作</span>

<span class="na">name</span><span class="pi">:</span> <span class="s">CD-Job</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>
    <span class="na">inputs</span><span class="pi">:</span>
      <span class="na">buildNumber</span><span class="pi">:</span> <span class="c1"># 对应 GAS payload.inpus.xxx</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">版本号码'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="c1"># ...More</span>
      <span class="c1"># Inputs 类型可参考官方文件：https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onworkflow_dispatchinputs</span>
      
<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">some-job</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Print Inputs</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">\\|</span>
          <span class="s">echo "Release Build Number</span><span class="err">:</span> <span class="s">${{ github.event.inputs.buildNumber }}"</span>    
</code></pre></div></div>

<h4 id="step-4-重新部署-google-apps-script-web-app-form">Step 4. 重新部署 Google Apps Script Web App Form</h4>

<blockquote>
  <p><strong><em>⚠️请注意，GAS 程式码的任何调整都需要重新部署，才会生效。⚠️</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>⚠️请注意，GAS 程式码的任何调整都需要重新部署，才会生效。⚠️</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>⚠️请注意，GAS 程式码的任何调整都需要重新部署，才会生效。⚠️</em></strong></p>
</blockquote>

<p>GAS 右上角选择「部署」-&gt; 选择右上角「编辑」-&gt; 版本选择「建立新版本」</p>

<p><img src="/assets/4cb4437818f2/1*ZMAB_m6HmsSsGSqqfZiRpA.webp" alt="" loading="lazy" decoding="async" width="208" height="238" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDgiIGhlaWdodD0iMjM4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*ZMAB_m6HmsSsGSqqfZiRpA.png" /></p>

<p><img src="/assets/4cb4437818f2/1*rUWlfzASAaeXcXUh4LavZw.webp" alt="" loading="lazy" decoding="async" width="776" height="619" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NzYiIGhlaWdodD0iNjE5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*rUWlfzASAaeXcXUh4LavZw.png" /></p>

<p><img src="/assets/4cb4437818f2/1*HAr5TZtpnQeG-Ril0Rjf-g.webp" alt="" loading="lazy" decoding="async" width="782" height="612" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3ODIiIGhlaWdodD0iNjEyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*HAr5TZtpnQeG-Ril0Rjf-g.png" /></p>

<p>点击「部署」-&gt; 完成。</p>

<p><img src="/assets/4cb4437818f2/1*z6lw7R8ivUseSzR4IZgPdg.webp" alt="" loading="lazy" decoding="async" width="777" height="611" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NzciIGhlaWdodD0iNjExIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*z6lw7R8ivUseSzR4IZgPdg.png" /></p>

<p><img src="/assets/4cb4437818f2/1*eTdgKGQ1lRM7sCRXQgZ-DA.webp" alt="" loading="lazy" decoding="async" width="770" height="610" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NzAiIGhlaWdodD0iNjEwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*eTdgKGQ1lRM7sCRXQgZ-DA.png" /></p>

<p><strong>再回到网页上重新整理，就能看到修改后的结果了：</strong></p>

<p><img src="/assets/4cb4437818f2/1*iI49OJC1uTyMEgzGTBowxQ.webp" alt="" loading="lazy" decoding="async" width="657" height="583" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NTciIGhlaWdodD0iNTgzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*iI49OJC1uTyMEgzGTBowxQ.png" /></p>

<blockquote>
  <p><strong><em>⚠️请注意，GAS 程式码的任何调整都需要重新部署，才会生效。⚠️</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>⚠️请注意，GAS 程式码的任何调整都需要重新部署，才会生效。⚠️</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>⚠️请注意，GAS 程式码的任何调整都需要重新部署，才会生效。⚠️</em></strong></p>
</blockquote>

<h3 id="done-">Done! 🎉🎉🎉</h3>

<p><img src="/assets/4cb4437818f2/1*pzW-Yki-4HbE2nYXC4q-Aw.webp" alt="" loading="lazy" decoding="async" width="653" height="672" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NTMiIGhlaWdodD0iNjcyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*pzW-Yki-4HbE2nYXC4q-Aw.png" /></p>

<p><img src="/assets/4cb4437818f2/1*9aaNeemezNPRlSgbLFrseA.webp" alt="Demo Web App Form" loading="lazy" decoding="async" width="648" height="628" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NDgiIGhlaWdodD0iNjI4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*9aaNeemezNPRlSgbLFrseA.png" /></p>

<p><a href="https://script.google.com/macros/s/AKfycbw8SuK7lLLMdY86y3jxMJyzXqa5tdxJryRnteOnNi-lK--j6CmKYXj7UuU58DiS0NSVvA/exec" target="_blank">Demo Web App Form</a></p>

<p>现在你可以在组织内分享这个连结给其他伙伴，他们可以直接使用这个网页 GUI 执行 CI/CD 工作。</p>

<h4 id="延伸-1-用使用者的信箱查询-slack-user-id--发送更新进度通知">延伸 (1)— 用使用者的信箱查询 Slack User ID &amp; 发送、更新进度通知</h4>

<p>前文有提到，我们希望及时通知使用者 CI/CD 执行状况，我们可以使用使用者提供的信箱去查 Slack User ID。</p>

<p><code class="language-plaintext highlighter-rouge">Slack.gs：</code></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">slackBotToken</span> <span class="o">=</span> <span class="dl">""</span>
<span class="c1">// https://medium.com/zrealm-robotic-process-automation/slack-chatgpt-integration-bd94cc88f9c9</span>

<span class="kd">function</span> <span class="nf">slackRequest</span><span class="p">(</span><span class="nx">path</span><span class="p">,</span> <span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">method</span><span class="p">:</span> <span class="dl">"</span><span class="s2">post</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">contentType</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/json</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">Authorization</span><span class="p">:</span> <span class="s2">`Bearer </span><span class="p">${</span><span class="nx">slackBotToken</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span> <span class="c1">// Use the bot token for authorization,</span>
      <span class="dl">'</span><span class="s1">X-Slack-No-Retry</span><span class="dl">'</span><span class="p">:</span> <span class="mi">1</span>
    <span class="p">},</span>
    <span class="na">payload</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span>
  <span class="p">};</span>

  <span class="k">try</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="dl">"</span><span class="s2">https://slack.com/api/</span><span class="dl">"</span><span class="o">+</span><span class="nx">path</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
    <span class="kd">const</span> <span class="nx">responseData</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">responseData</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="nx">responseData</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="s2">`Slack: </span><span class="p">${</span><span class="nx">responseData</span><span class="p">.</span><span class="nx">error</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">throw</span> <span class="nx">error</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 用信箱查询 Slask UID</span>
<span class="kd">function</span> <span class="nf">getSlackUserId</span><span class="p">(</span><span class="nx">email</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">return</span> <span class="nf">slackRequest</span><span class="p">(</span><span class="s2">`users.lookupByEmail?email=</span><span class="p">${</span><span class="nf">encodeURIComponent</span><span class="p">(</span><span class="nx">email</span><span class="p">)}</span><span class="s2">`</span><span class="p">)?.</span><span class="nx">user</span><span class="p">?.</span><span class="nx">id</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// 发送讯息给目标 Slack UID (channelID)</span>
<span class="kd">function</span> <span class="nf">sendSlackMessage</span><span class="p">(</span><span class="nx">channelId</span><span class="p">,</span> <span class="nx">ts</span> <span class="o">=</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span>  <span class="p">{</span>
  <span class="kd">var</span> <span class="nx">content</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">channel</span><span class="p">:</span> <span class="nx">channelId</span>
  <span class="p">};</span>

  <span class="k">if </span><span class="p">(</span><span class="nx">ts</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">content</span><span class="p">.</span><span class="nx">thread_ts</span> <span class="o">=</span> <span class="nx">ts</span><span class="p">;</span>
  <span class="p">}</span>
  
  <span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span> <span class="o">===</span> <span class="dl">"</span><span class="s2">string</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">content</span><span class="p">.</span><span class="nx">text</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="nx">content</span><span class="p">.</span><span class="nx">blocks</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="nf">slackRequest</span><span class="p">(</span><span class="dl">"</span><span class="s2">chat.postMessage</span><span class="dl">"</span><span class="p">,</span> <span class="nx">content</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// 更新发送的讯息内容</span>
<span class="kd">function</span> <span class="nf">updateSlackMessage</span><span class="p">(</span><span class="nx">channelId</span><span class="p">,</span> <span class="nx">ts</span> <span class="o">=</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span>  <span class="p">{</span>
  <span class="kd">var</span> <span class="nx">content</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">channel</span><span class="p">:</span> <span class="nx">channelId</span>
  <span class="p">};</span>

  <span class="k">if </span><span class="p">(</span><span class="nx">ts</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">content</span><span class="p">.</span><span class="nx">ts</span> <span class="o">=</span> <span class="nx">ts</span><span class="p">;</span>
  <span class="p">}</span>
  
  <span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span> <span class="o">===</span> <span class="dl">"</span><span class="s2">string</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">content</span><span class="p">.</span><span class="nx">text</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="nx">content</span><span class="p">.</span><span class="nx">blocks</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="nf">slackRequest</span><span class="p">(</span><span class="dl">"</span><span class="s2">chat.update</span><span class="dl">"</span><span class="p">,</span> <span class="nx">content</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Slack API 使用请参考 <a href="https://api.slack.com/methods/chat.postMessage" target="_blank">官方文件</a> 。</p>

<p><strong>Githun Action YAML 可以使用这个 Action 持续更新讯息、发送 Slack 讯息：</strong></p>

<p><a href="https://github.com/slackapi/slack-github-action" target="_blank"><img src="https://opengraph.githubassets.com/5555fcbf805f8a008fa2b940b89782a63a551ae458330d39dbdf96ee8f309739/slackapi/slack-github-action" alt="" /></a></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ...</span>
<span class="na">on</span><span class="pi">:</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>
    <span class="na">inputs</span><span class="pi">:</span>
      <span class="na">buildNumber</span><span class="pi">:</span> <span class="c1"># 对应 GAS payload.inpus.xxx</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">版本号码'</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">false</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="c1"># ...More</span>
      <span class="na">SLACK_USER_ID</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Slack</span><span class="nv"> </span><span class="s">User</span><span class="nv"> </span><span class="s">Id</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">receive</span><span class="nv"> </span><span class="s">action</span><span class="nv"> </span><span class="s">notification'</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="na">SLACK_CHANNEL_ID</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Slack</span><span class="nv"> </span><span class="s">Channel</span><span class="nv"> </span><span class="s">Id</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">receive</span><span class="nv"> </span><span class="s">action</span><span class="nv"> </span><span class="s">notification'</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      <span class="na">SLACK_THREAD_TS</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Slack</span><span class="nv"> </span><span class="s">message</span><span class="nv"> </span><span class="s">ts'</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
      
<span class="na">jobs</span><span class="pi">:</span>
  <span class="c1"># some jobs...</span>

  <span class="na">if-deploy-failed-message</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">failure()</span>
      <span class="s">- name</span><span class="err">:</span> <span class="s">update slack message</span>
        <span class="s">uses</span><span class="err">:</span> <span class="s">slackapi/slack-github-action@v2.0.0</span>
        <span class="s">with</span><span class="err">:</span>
            <span class="na">method</span><span class="pi">:</span> <span class="s">chat.update</span>
            <span class="na">token</span><span class="pi">:</span> <span class="s">${{ secrets.SLACK_BOT_TOKEN }}</span>
            <span class="na">payload</span><span class="pi">:</span> <span class="s">\\|</span>
              <span class="s">channel</span><span class="err">:</span> <span class="s">${{ github.event.inputs.SLACK_CHANNEL_ID }}</span>
              <span class="s">ts</span><span class="err">:</span> <span class="s">${{ github.event.inputs.SLACK_THREAD_TS }}</span>
              <span class="s">text</span><span class="err">:</span> <span class="s2">"</span><span class="s">❌</span><span class="nv"> </span><span class="s">打包任务失败，请检查执行状况结果或稍后再试。</span><span class="se">\n</span><span class="s">&lt;${{</span><span class="nv"> </span><span class="s">github.server_url</span><span class="nv"> </span><span class="s">}}/${{</span><span class="nv"> </span><span class="s">github.repository</span><span class="nv"> </span><span class="s">}}/actions/runs/${{</span><span class="nv"> </span><span class="s">github.run_id</span><span class="nv"> </span><span class="s">}}</span><span class="se">\\</span><span class="s">|点此查看执行状况&gt;</span><span class="nv"> </span><span class="s">cc'ed</span><span class="nv"> </span><span class="s">&lt;@${{</span><span class="nv"> </span><span class="s">github.event.inputs.SLACK_USER_ID</span><span class="nv"> </span><span class="s">}}&gt;"</span>
</code></pre></div></div>

<p><strong>效果：</strong></p>

<p><img src="/assets/4cb4437818f2/1*-w5jqjkx6p2alpzlLcz_Nw.webp" alt="" loading="lazy" decoding="async" width="428" height="559" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MjgiIGhlaWdodD0iNTU5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/4cb4437818f2/1*-w5jqjkx6p2alpzlLcz_Nw.png" /></p>

<blockquote>
  <p><strong><em>Slack App 串接细节可参考我之前的文章： <a href="/posts/zrealm-dev/slack-app-整合-chatgpt-利用-openai-api-与-google-cloud-functions-自建智能助理-bd94cc88f9c9/">Slack &amp; ChatGPT Integration</a> 。</em></strong></p>
</blockquote>

<h4 id="延伸-2-查询-jira-工单">延伸 (2) —查询 Jira 工单</h4>

<p><code class="language-plaintext highlighter-rouge">Jira.gs：</code></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">jiraPersonalAccessToken</span> <span class="o">=</span> <span class="dl">""</span>
<span class="c1">// https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html</span>

<span class="kd">function</span> <span class="nf">getJiraTickets</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="s2">`https://xxx.atlassian.net/rest/api/3/search`</span><span class="p">;</span>

  <span class="c1">// JQL query</span>
  <span class="kd">const</span> <span class="nx">jql</span> <span class="o">=</span> <span class="s2">`project = XXX`</span><span class="p">;</span>
  <span class="kd">const</span> <span class="nx">queryParams</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">jql</span><span class="p">:</span> <span class="nx">jql</span><span class="p">,</span>
    <span class="na">maxResults</span><span class="p">:</span> <span class="mi">50</span><span class="p">,</span> <span class="c1">// Adjust as needed</span>
  <span class="p">};</span>

  <span class="kd">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">method</span><span class="p">:</span> <span class="dl">"</span><span class="s2">get</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">Authorization</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Basic </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">jiraPersonalAccessToken</span><span class="p">,</span>
      <span class="dl">"</span><span class="s2">Content-Type</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/json</span><span class="dl">"</span><span class="p">,</span>
    <span class="p">},</span>
    <span class="na">muteHttpExceptions</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
  <span class="p">};</span>

  <span class="kd">const</span> <span class="nx">queryString</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nf">keys</span><span class="p">(</span><span class="nx">queryParams</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="nx">key</span> <span class="o">=&gt;</span> <span class="s2">`</span><span class="p">${</span><span class="nf">encodeURIComponent</span><span class="p">(</span><span class="nx">key</span><span class="p">)}</span><span class="s2">=</span><span class="p">${</span><span class="nf">encodeURIComponent</span><span class="p">(</span><span class="nx">queryParams</span><span class="p">[</span><span class="nx">key</span><span class="p">])}</span><span class="s2">`</span><span class="p">).</span><span class="nf">join</span><span class="p">(</span><span class="dl">"</span><span class="s2">&amp;</span><span class="dl">"</span><span class="p">);</span>
  <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="nx">url</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">?</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">queryString</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">&amp;fields=</span><span class="dl">"</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
  <span class="c1">// could specify only return some fields</span>

  <span class="k">if </span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getResponseCode</span><span class="p">()</span> <span class="o">===</span> <span class="mi">200</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">issues</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">()).</span><span class="nx">issues</span><span class="p">;</span>
    <span class="k">return</span> <span class="nx">issues</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="nx">Logger</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="s2">`Error: </span><span class="p">${</span><span class="nx">response</span><span class="p">.</span><span class="nf">getResponseCode</span><span class="p">()}</span><span class="s2"> - </span><span class="p">${</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">()}</span><span class="s2">`</span><span class="p">);</span>
    <span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Failed to fetch Jira issues.</span><span class="dl">"</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span> 
</code></pre></div></div>

<p>其他 Jira API 使用请参考 <a href="https://developer.atlassian.com/cloud/jira/platform/rest/v3/" target="_blank">官方文件</a> 。</p>

<h4 id="延伸-3--查询-asana-工单">延伸 (3) — 查询 Asana 工单</h4>

<p><code class="language-plaintext highlighter-rouge">Asana.gs：</code></p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="n">asanaPersonalAccessToken</span> <span class="p">=</span> <span class="s">""</span>
<span class="c1">// https://developers.asana.com/docs/personal-access-token</span>

<span class="n">function</span> <span class="nf">asanaAPI</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">method</span> <span class="p">=</span> <span class="s">"GET"</span><span class="p">,</span> <span class="n">data</span> <span class="p">=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="py">options</span> <span class="p">=</span> <span class="p">{</span>
      <span class="s">"method"</span> <span class="p">:</span> <span class="n">method</span><span class="p">,</span>
      <span class="s">"contentType"</span> <span class="p">:</span> <span class="s">"application/json"</span><span class="p">,</span>
      <span class="s">"headers"</span><span class="p">:</span> <span class="p">{</span>
          <span class="s">"Authorization"</span><span class="p">:</span>  <span class="s">"Bearer "</span><span class="p">+</span><span class="n">asanaPersonalAccessToken</span>
      <span class="p">}</span>
    <span class="p">};</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">data</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">options</span><span class="p">[</span><span class="s">"payload"</span><span class="p">]</span> <span class="p">=</span> <span class="nc">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">({</span><span class="s">"data"</span><span class="p">:</span><span class="n">data</span><span class="p">});</span>
    <span class="p">}</span>

    <span class="k">const</span> <span class="n">url</span> <span class="p">=</span> <span class="s">"https://app.asana.com/api/1.0"</span><span class="p">+</span><span class="n">endpoint</span><span class="p">;</span>
    <span class="k">const</span> <span class="n">res</span> <span class="p">=</span> <span class="nc">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">options</span><span class="p">);</span>
    <span class="k">const</span> <span class="n">data</span> <span class="p">=</span> <span class="nc">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>
    <span class="k">return</span> <span class="n">data</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// 查找 tasks in project</span>
<span class="c1">// asanaAPI("/projects/PROJECT_ID/tasks");</span>
</code></pre></div></div>

<p>其他 Asana API 使用请参考 <a href="https://developers.asana.com/reference/gettasksforproject" target="_blank">官方文件</a> 。</p>

<h3 id="总结">总结</h3>

<p>自动化、工作及开发流程优化缺的永远不是技术，而是想法；只要有想法我们都能找到适合的技术来实现，共勉之！</p>

<h3 id="202507-update-1">2025/07 Update:</h3>

<p>此功能已整合到实际打包工具使用，可参考最新文章案例：「 <a href="/posts/zrealm-dev/ci-cd-打包工具平台-使用-google-apps-script-web-app-串接-github-actions-提升跨团队效率-4273e57e7148/"><strong>CI/CD 实战指南（四）：使用 Google Apps Script Web App 串接 GitHub Actions 建置免费易用的打包工具平台</strong></a> 」</p>]]></content>
  </entry><entry>
    <title type="html">Swift 原生类型扩展｜打造 Namespace 容器避免命名冲突，提升模组化维护性</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-dev/swift-%E5%8E%9F%E7%94%9F%E7%B1%BB%E5%9E%8B%E6%89%A9%E5%B1%95-%E6%89%93%E9%80%A0-namespace-%E5%AE%B9%E5%99%A8%E9%81%BF%E5%85%8D%E5%91%BD%E5%90%8D%E5%86%B2%E7%AA%81-%E6%8F%90%E5%8D%87%E6%A8%A1%E7%BB%84%E5%8C%96%E7%BB%B4%E6%8A%A4%E6%80%A7-a8925ad9ed01/" rel="alternate" type="text/html" title="Swift 原生类型扩展｜打造 Namespace 容器避免命名冲突，提升模组化维护性" />
    <published>2025-01-01T22:02:32+08:00</published>
    <updated>2025-01-01T22:02:32+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-dev/a8925ad9ed01</id><summary type="html">iOS 开发中扩充原生类型常导致命名冲突与介面混乱，透过 Swift 泛型容器与协议封装扩展方法，实现 Namespace 功能，有效区隔自订与原生 API，提升专案模组化与维护效率。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Dev." /><category term="simplified-chinese" /><category term="ios-app-development" /><category term="swift" /><category term="wrapper" /><category term="app-modularization" /><category term="ios" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/a8925ad9ed01/1*kJFHiAuTZ8TP-4aTa_daqA.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-dev/swift-%E5%8E%9F%E7%94%9F%E7%B1%BB%E5%9E%8B%E6%89%A9%E5%B1%95-%E6%89%93%E9%80%A0-namespace-%E5%AE%B9%E5%99%A8%E9%81%BF%E5%85%8D%E5%91%BD%E5%90%8D%E5%86%B2%E7%AA%81-%E6%8F%90%E5%8D%87%E6%A8%A1%E7%BB%84%E5%8C%96%E7%BB%B4%E6%8A%A4%E6%80%A7-a8925ad9ed01/"><![CDATA[<h3 id="swift-一个优雅的-原生类型扩展方式">[Swift] 一个优雅的 <strong>原生类型扩展方式</strong></h3>

<p>自行封装扩充方法，使其有 Namespace 的功能</p>

<p><img src="/assets/a8925ad9ed01/1*kJFHiAuTZ8TP-4aTa_daqA.webp" alt="&lt;https://www.swift.org/&gt;" loading="lazy" decoding="async" width="1200" height="430" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQzMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/a8925ad9ed01/1*kJFHiAuTZ8TP-4aTa_daqA.png" /></p>

<p><a href="https://www.swift.org/" target="_blank">https://www.swift.org/</a></p>

<blockquote>
  <p><em>做法实际出处不详，是从厉害同事的 Code 上学到的。</em></p>
</blockquote>

<h3 id="原生类型扩展">原生类型扩展</h3>

<p>在日常的 iOS/Swift 开发中，我们常常需要对原生 API 进行扩充、撰写自己的 Helper。</p>

<p><strong>以下以扩充 UIColor 为例，我们希望扩充 UIColor 使其能转换成 HEX Color String：</strong></p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">extension</span> <span class="kt">UIColor</span> <span class="p">{</span>
    <span class="c1">/// Convert a UIColor to a hex string representation.</span>
    <span class="c1">/// - Returns: A hex string (e.g., "#RRGGBB" or "#RRGGBBAA").</span>
    <span class="kd">func</span> <span class="nf">toHexString</span><span class="p">(</span><span class="nv">includeAlpha</span><span class="p">:</span> <span class="kt">Bool</span> <span class="o">=</span> <span class="kc">false</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">String</span><span class="p">?</span> <span class="p">{</span>
        <span class="k">var</span> <span class="nv">red</span><span class="p">:</span> <span class="kt">CGFloat</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">var</span> <span class="nv">green</span><span class="p">:</span> <span class="kt">CGFloat</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">var</span> <span class="nv">blue</span><span class="p">:</span> <span class="kt">CGFloat</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">var</span> <span class="nv">alpha</span><span class="p">:</span> <span class="kt">CGFloat</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="k">guard</span> <span class="k">self</span><span class="o">.</span><span class="nf">getRed</span><span class="p">(</span><span class="o">&amp;</span><span class="n">red</span><span class="p">,</span> <span class="nv">green</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">green</span><span class="p">,</span> <span class="nv">blue</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">blue</span><span class="p">,</span> <span class="nv">alpha</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">alpha</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kc">nil</span> <span class="c1">// Color could not be represented in RGB space</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="n">includeAlpha</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kt">String</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="s">"#%02X%02X%02X%02X"</span><span class="p">,</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">red</span> <span class="o">*</span> <span class="mi">255</span><span class="p">),</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">green</span> <span class="o">*</span> <span class="mi">255</span><span class="p">),</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">blue</span> <span class="o">*</span> <span class="mi">255</span><span class="p">),</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">alpha</span> <span class="o">*</span> <span class="mi">255</span><span class="p">))</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kt">String</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="s">"#%02X%02X%02X"</span><span class="p">,</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">red</span> <span class="o">*</span> <span class="mi">255</span><span class="p">),</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">green</span> <span class="o">*</span> <span class="mi">255</span><span class="p">),</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">blue</span> <span class="o">*</span> <span class="mi">255</span><span class="p">))</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>直接对 UIColor 进行扩充 (Extension) 后的存取方式如下：</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">color</span> <span class="o">=</span> <span class="kt">UIColor</span><span class="o">.</span><span class="n">blue</span>
<span class="n">color</span><span class="o">.</span><span class="nf">toHexString</span><span class="p">()</span> <span class="c1">// #0000ff</span>
</code></pre></div></div>

<h4 id="问题">问题</h4>

<p>当我们自定义的扩充方式越来越多会让存取介面开始变得混乱，例如：</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">color</span> <span class="o">=</span> <span class="kt">UIColor</span><span class="o">.</span><span class="n">blue</span>
<span class="n">color</span><span class="o">.</span><span class="nf">getRed</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">color</span><span class="o">.</span><span class="nf">getWhite</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">color</span><span class="o">.</span><span class="nf">getHue</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">color</span><span class="o">.</span><span class="nf">getCMYK</span><span class="p">()</span> <span class="c1">// 自行扩充的方法</span>
<span class="n">color</span><span class="o">.</span><span class="nf">toHexString</span><span class="p">()</span> <span class="c1">// 自行扩充的方法</span>
<span class="n">color</span><span class="o">.</span><span class="nf">withAlphaComponent</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">color</span><span class="o">.</span><span class="nf">setFill</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">color</span><span class="o">.</span><span class="nf">setToBlue</span><span class="p">()</span> <span class="c1">// 自行扩充的方法</span>

<span class="c1">// A Module</span>
<span class="kd">public</span> <span class="kd">extension</span> <span class="kt">UIColor</span> <span class="p">{</span>
  <span class="kd">func</span> <span class="nf">getCMYK</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// ...</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// B Module</span>
<span class="c1">// Invalid redeclaration of 'getCMYK()'</span>
<span class="kd">public</span> <span class="kd">extension</span> <span class="kt">UIColor</span> <span class="p">{</span>
  <span class="kd">func</span> <span class="nf">getCMYK</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// ...</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>我们自行扩充的方法跟原生提供的方法全部混合在一起，难以区分；另外专案规模越大、引用的套件越多也有可能遇到 Extension 命名冲突，例如两个套件都对 UIColor Extension 也都叫 <code class="language-plaintext highlighter-rouge">getCMYK()</code> 就会有问题。</p>

<h3 id="自订扩展-namespace-容器">自订扩展 Namespace 容器</h3>

<p>我们可以运用 Swift Protocol, Computed Property 与 泛型的特型来自行封装扩充方法，使其有 Namespace 的功能。</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 宣告一个泛型容器 ExtensionContainer&lt;Base&gt;：</span>
<span class="kd">public</span> <span class="kd">struct</span> <span class="kt">ExtensionContainer</span><span class="o">&lt;</span><span class="kt">Base</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="kd">public</span> <span class="k">let</span> <span class="nv">base</span><span class="p">:</span> <span class="kt">Base</span>
    <span class="kd">public</span> <span class="nf">init</span><span class="p">(</span><span class="n">_</span> <span class="nv">base</span><span class="p">:</span> <span class="kt">Base</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="o">.</span><span class="n">base</span> <span class="o">=</span> <span class="n">base</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 定义 for AnyObject, Class(Reference) Type 实现的接口：</span>
<span class="c1">// 例如 Foundation 中的 NSXXX 类别</span>
<span class="kd">public</span> <span class="kd">protocol</span> <span class="kt">ExtensionCompatibleObject</span><span class="p">:</span> <span class="kt">AnyObject</span> <span class="p">{}</span>
<span class="c1">// 定义 for Struct(Value) Type 实现的接口：</span>
<span class="kd">public</span> <span class="kd">protocol</span> <span class="kt">ExtensionCompatible</span> <span class="p">{}</span>

<span class="c1">// 自订义 Namespace Computed Property：</span>
<span class="kd">public</span> <span class="kd">extension</span> <span class="kt">ExtensionCompatibleObject</span> <span class="p">{</span>
    <span class="k">var</span> <span class="nv">zhg</span><span class="p">:</span> <span class="kt">ExtensionContainer</span><span class="o">&lt;</span><span class="k">Self</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">return</span> <span class="kt">ExtensionContainer</span><span class="p">(</span><span class="k">self</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kd">public</span> <span class="kd">extension</span> <span class="kt">ExtensionCompatible</span> <span class="p">{</span>
    <span class="k">var</span> <span class="nv">zhg</span><span class="p">:</span> <span class="kt">ExtensionContainer</span><span class="o">&lt;</span><span class="k">Self</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">return</span> <span class="kt">ExtensionContainer</span><span class="p">(</span><span class="k">self</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="扩展原生类型">扩展原生类型</h4>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">extension</span> <span class="kt">UIColor</span><span class="p">:</span> <span class="kt">ExtensionCompatibleObject</span> <span class="p">{}</span>

<span class="kd">extension</span> <span class="kt">ExtensionContainer</span> <span class="k">where</span> <span class="kt">Base</span><span class="p">:</span> <span class="kt">UIColor</span> <span class="p">{</span>
    <span class="c1">/// Convert a UIColor to a hex string representation.</span>
    <span class="c1">/// - Returns: A hex string (e.g., "#RRGGBB" or "#RRGGBBAA").</span>
    <span class="kd">func</span> <span class="nf">toHexString</span><span class="p">(</span><span class="nv">includeAlpha</span><span class="p">:</span> <span class="kt">Bool</span> <span class="o">=</span> <span class="kc">false</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">String</span><span class="p">?</span> <span class="p">{</span>
        <span class="k">var</span> <span class="nv">red</span><span class="p">:</span> <span class="kt">CGFloat</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">var</span> <span class="nv">green</span><span class="p">:</span> <span class="kt">CGFloat</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">var</span> <span class="nv">blue</span><span class="p">:</span> <span class="kt">CGFloat</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">var</span> <span class="nv">alpha</span><span class="p">:</span> <span class="kt">CGFloat</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="k">guard</span> <span class="k">self</span><span class="o">.</span><span class="n">base</span><span class="o">.</span><span class="nf">getRed</span><span class="p">(</span><span class="o">&amp;</span><span class="n">red</span><span class="p">,</span> <span class="nv">green</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">green</span><span class="p">,</span> <span class="nv">blue</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">blue</span><span class="p">,</span> <span class="nv">alpha</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">alpha</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kc">nil</span> <span class="c1">// Color could not be represented in RGB space</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="n">includeAlpha</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kt">String</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="s">"#%02X%02X%02X%02X"</span><span class="p">,</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">red</span> <span class="o">*</span> <span class="mi">255</span><span class="p">),</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">green</span> <span class="o">*</span> <span class="mi">255</span><span class="p">),</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">blue</span> <span class="o">*</span> <span class="mi">255</span><span class="p">),</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">alpha</span> <span class="o">*</span> <span class="mi">255</span><span class="p">))</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kt">String</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="s">"#%02X%02X%02X"</span><span class="p">,</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">red</span> <span class="o">*</span> <span class="mi">255</span><span class="p">),</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">green</span> <span class="o">*</span> <span class="mi">255</span><span class="p">),</span>
                          <span class="kt">Int</span><span class="p">(</span><span class="n">blue</span> <span class="o">*</span> <span class="mi">255</span><span class="p">))</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="使用">使用</h4>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">color</span> <span class="o">=</span> <span class="kt">UIColor</span><span class="o">.</span><span class="n">blue</span>
<span class="n">color</span><span class="o">.</span><span class="n">zhg</span><span class="o">.</span><span class="nf">toHexString</span><span class="p">()</span> <span class="c1">// #0000ff</span>
</code></pre></div></div>

<h4 id="范例-2-url-queryitems-扩充">范例 2. URL .queryItems 扩充</h4>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>extension URL: ExtensionCompatible {}

extension ExtensionContainer where Base == URL {
    
    var queryParameters: [String: String]? {
        URLComponents(url: base, resolvingAgainstBaseURL: true)?
            .queryItems?
            .reduce(into: [String: String]()) { $0[$1.name] = $1.value }
    }
}
</code></pre></div></div>

<h3 id="结合-builder-pattern">结合 <a href="https://refactoring.guru/design-patterns/builder" target="_blank">Builder Pattern</a></h3>

<p>另外我们也可以将此封装方式结合 Builder Pattern 操作：</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">final</span> <span class="kd">class</span> <span class="kt">URLBuilder</span> <span class="p">{</span>
    <span class="kd">private</span> <span class="k">var</span> <span class="nv">components</span><span class="p">:</span> <span class="kt">URLComponents</span>

    <span class="nf">init</span><span class="p">(</span><span class="nv">base</span><span class="p">:</span> <span class="kt">URL</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="o">.</span><span class="n">components</span> <span class="o">=</span> <span class="kt">URLComponents</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="n">base</span><span class="p">,</span> <span class="nv">resolvingAgainstBaseURL</span><span class="p">:</span> <span class="kc">true</span><span class="p">)</span><span class="o">!</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">setQueryParameters</span><span class="p">(</span><span class="n">_</span> <span class="nv">parameters</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">String</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kt">URLBuilder</span> <span class="p">{</span>
        <span class="n">components</span><span class="o">.</span><span class="n">queryItems</span> <span class="o">=</span> <span class="n">parameters</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">.</span><span class="nf">init</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="nv">$0</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="nv">value</span><span class="p">:</span> <span class="nv">$0</span><span class="o">.</span><span class="n">value</span><span class="p">)</span> <span class="p">}</span>
        <span class="k">return</span> <span class="k">self</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">setScheme</span><span class="p">(</span><span class="n">_</span> <span class="nv">scheme</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">URLBuilder</span> <span class="p">{</span>
        <span class="n">components</span><span class="o">.</span><span class="n">scheme</span> <span class="o">=</span> <span class="n">scheme</span>
        <span class="k">return</span> <span class="k">self</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">build</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">URL</span><span class="p">?</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">components</span><span class="o">.</span><span class="n">url</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kd">extension</span> <span class="kt">URL</span><span class="p">:</span> <span class="kt">ExtensionCompatible</span> <span class="p">{}</span>

<span class="kd">extension</span> <span class="kt">ExtensionContainer</span> <span class="k">where</span> <span class="kt">Base</span> <span class="o">==</span> <span class="kt">URL</span> <span class="p">{</span>
    <span class="kd">func</span> <span class="nf">builder</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">URLBuilder</span> <span class="p">{</span>
        <span class="k">return</span> <span class="kt">URLBuilder</span><span class="p">(</span><span class="nv">base</span><span class="p">:</span> <span class="n">base</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">url</span> <span class="o">=</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="s">"https://zhgchg.li"</span><span class="p">)</span><span class="o">!.</span><span class="n">zhg</span><span class="o">.</span><span class="nf">builder</span><span class="p">()</span><span class="o">.</span><span class="nf">setQueryParameters</span><span class="p">([</span><span class="s">"a"</span><span class="p">:</span> <span class="s">"b"</span><span class="p">,</span> <span class="s">"c"</span><span class="p">:</span> <span class="s">"d"</span><span class="p">])</span><span class="o">.</span><span class="nf">setScheme</span><span class="p">(</span><span class="s">"ssh"</span><span class="p">)</span><span class="o">.</span><span class="nf">build</span><span class="p">()</span>
<span class="c1">// ssh://zhgchg.li?a=b&amp;c=d</span>
</code></pre></div></div>]]></content>
  </entry><entry>
    <title type="html">山阴关西自由行攻略｜岛根出云松江鸟取姬路大阪神户7日独旅全记录</title>
    <link href="https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E5%B1%B1%E9%98%B4%E5%85%B3%E8%A5%BF%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E5%B2%9B%E6%A0%B9%E5%87%BA%E4%BA%91%E6%9D%BE%E6%B1%9F%E9%B8%9F%E5%8F%96%E5%A7%AC%E8%B7%AF%E5%A4%A7%E9%98%AA%E7%A5%9E%E6%88%B77%E6%97%A5%E7%8B%AC%E6%97%85%E5%85%A8%E8%AE%B0%E5%BD%95-aacd5f5cacd1/" rel="alternate" type="text/html" title="山阴关西自由行攻略｜岛根出云松江鸟取姬路大阪神户7日独旅全记录" />
    <published>2024-12-03T00:04:56+08:00</published>
    <updated>2025-08-13T13:38:47+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/aacd5f5cacd1</id><summary type="html">规划7天山阴关西独旅，涵盖岛根出云松江、鸟取沙丘、姬路城及大阪神户，详细交通、JR Pass使用与住宿分享，解决行程紧凑与交通难题，助你轻松踩点千公里经典景点。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="Z 度旅行遊記" /><category term="simplified-chinese" /><category term="生活" /><category term="japan" /><category term="travel-writing" /><category term="島根縣" /><category term="旅遊" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/aacd5f5cacd1/1*ucEUq8avIv1nBoNnCMlgRw.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/z-%E5%BA%A6%E6%97%85%E8%A1%8C%E9%81%8A%E8%A8%98/%E5%B1%B1%E9%98%B4%E5%85%B3%E8%A5%BF%E8%87%AA%E7%94%B1%E8%A1%8C%E6%94%BB%E7%95%A5-%E5%B2%9B%E6%A0%B9%E5%87%BA%E4%BA%91%E6%9D%BE%E6%B1%9F%E9%B8%9F%E5%8F%96%E5%A7%AC%E8%B7%AF%E5%A4%A7%E9%98%AA%E7%A5%9E%E6%88%B77%E6%97%A5%E7%8B%AC%E6%97%85%E5%85%A8%E8%AE%B0%E5%BD%95-aacd5f5cacd1/"><![CDATA[<h3 id="游记-2024-山阴广域地区-岛根-出云-松江-鸟取-姬路-大阪-神户-7-日独旅自由行">[游记] 2024 山阴广域地区 岛根 出云 松江 鸟取 姬路 大阪 神户 7 日独旅自由行</h3>

<p>冈山进出，先去山阴岛根县出云松江再去鸟取，最后回到姬路、关西、大阪；7 天 10 万步、交通横跨 1,000 公里，一次踩点山阴关西地区。</p>

<p><img src="/assets/aacd5f5cacd1/1*ucEUq8avIv1nBoNnCMlgRw.webp" alt="宍道湖夕阳" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*ucEUq8avIv1nBoNnCMlgRw.jpeg" /></p>

<p>宍道湖夕阳</p>

<h4 id="前言">前言</h4>

<p>最一开始 2024 下半年是想去仙台的，不过查了一下景点资料，这个时间点去，我的兴趣普普；回想到去年同一周 11/13–18 去了 <strong>「 <a href="/posts/z-度旅行遊記/山阳地区广岛冈山自由行攻略-6日行程-交通-住宿全解析-31b9b3a63abc/">山阳地区 广岛冈山 6 日自由行</a> 」</strong> 对中国地方、山阳、冈山的印象很好 — 景色很美、交通方便、观光客较少；因此想说这次把山阴地区(岛根、鸟取)也走一遍，刚好工作也有空档跟近期心烦意乱急需放空；促成了这次 7 天 6 夜山阴地区(加上关西地区：姬路、大阪)独旅自由行。</p>

<h3 id="准备工作">准备工作</h3>

<h4 id="日期111218">日期：11/12–18</h4>

<p>这次也是 P 人发作，10 月中临时抓到时间空档，随即安排 11/12 出发，11/18 回程。</p>

<h4 id="️机票">✈️机票</h4>

<p><img src="/assets/aacd5f5cacd1/1*XRfz2GcB_EiuvwxLYIFCTw.webp" alt="" loading="lazy" decoding="async" width="1189" height="580" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTg5IiBoZWlnaHQ9IjU4MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*XRfz2GcB_EiuvwxLYIFCTw.png" /></p>

<p>今年没有特别抢虎航秋季活动机票， <strong>去年有买到优惠机票</strong> 时间比较好又比较便宜( <code class="language-plaintext highlighter-rouge">去年：去(11:10)、回(15:25)，含来回 20KG 托运＋选位＋杂费：NT$ 7,012</code> )。</p>

<ul>
  <li>
    <p>去：13:05 TPE 台北桃园国际机场-&gt; <strong>16:30 OKJ</strong> 冈山桃太郎机场</p>
  </li>
  <li>
    <p>回： <strong>17:30 OKJ</strong> 冈山桃太郎机场 -&gt; 19:35 TPE 台北桃园国际机场</p>
  </li>
  <li>
    <p>含来回 20KG 托运＋选位＋杂费价格： <code class="language-plaintext highlighter-rouge">NT$ 9,118</code></p>
  </li>
</ul>

<p>没特别便宜，但还可以接受，如果选同去年的去回时间会更贵，大概要 <code class="language-plaintext highlighter-rouge">NT$ 12,000</code> 。</p>

<h4 id="虎航-2025-新直飞航线">虎航 2025 新直飞航线</h4>

<p><a href="https://chugoku.letsgojp.com/archives/731900" target="_blank">台湾虎航于2025年5月29(四)，起新增「桃园国际机场－鸟取米子机场」直飞航班，去山阴地区就更方便了！</a></p>

<h4 id="️计划">🏝️计划</h4>

<p>没去过山阴地区跟姬路，以这三个地方为主。</p>

<ul>
  <li>
    <p>11/12 晚上抵达冈山，住一晚为明早去岛根做准备</p>
  </li>
  <li>
    <p>11/13 一早搭 JR 前往岛根，先去出云大社、稻佐海滨，下午傍晚去宍道湖看夕阳</p>
  </li>
  <li>
    <p>11/14 早上松江城、松江堀川游船，下午足立美术馆，晚上抵达鸟取</p>
  </li>
  <li>
    <p>11/15 早上白兔神社、下午鸟取沙丘，晚上抵达姬路</p>
  </li>
  <li>
    <p>11/16 姬路城、姬路市区逛街
实际多去：书写山圆教寺</p>
  </li>
  <li>
    <p>11/17 大鸣门桥游歩道 涡之道、鸣门旋涡、明石海峡大桥
实际因天气不佳没去，改去大阪、神户逛街吃东西。</p>
  </li>
  <li>
    <p>11/18 冈山站逛街、回程</p>
  </li>
</ul>

<h4 id="行--日本-jr-pass关西山阴地区铁路周游券emco-电子票">🚅行- <a href="https://www.kkday.com/zh-tw/product/20307-jr-sanin-okayama-area-pass?cid=19365" target="_blank"><strong>日本 JR PASS｜关西&amp;山阴地区铁路周游券｜eMCO 电子票</strong></a></h4>

<p>这次也是长距离移动，必买 JR Pass，本来还怕只有山阴、山阳 JRass，没想到日本 JR 很贴心的把有可能的路线都规划好了，有「 <a href="https://www.kkday.com/zh-tw/product/20307-jr-sanin-okayama-area-pass?cid=19365" target="_blank"><strong>关西&amp;山阴地区铁路周游券 JRPass</strong></a> 」正合我意！</p>

<p><img src="/assets/aacd5f5cacd1/1*H0ztJ3sX7oPQmJz7L2j87w.webp" alt="关西&amp;山阴地区铁路周游券 JRPass 可用范围" loading="lazy" decoding="async" width="1330" height="1080" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzMwIiBoZWlnaHQ9IjEwODAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*H0ztJ3sX7oPQmJz7L2j87w.png" /></p>

<p><a href="https://www.kkday.com/zh-tw/product/20307-jr-sanin-okayama-area-pass?cid=19365" target="_blank">关西&amp;山阴地区铁路周游券 JRPass 可用范围</a></p>

<ul>
  <li>价格： <code class="language-plaintext highlighter-rouge">NT$ 3,779</code> 多送一张 <a href="https://www.kkday.com/zh-tw/product/20307-jr-sanin-okayama-area-pass?cid=19365" target="_blank"><strong>山阴山阳地区PASS周游3日券 (搭配用起来很划算)</strong></a></li>
</ul>

<h4 id="网路">📱网路</h4>

<p>这次也一并从 KKday 买「 <a href="https://www.kkday.com/zh-tw/product/137689-japan-high-speed-daily-unlimited-data-japanese-esim?cid=19365" target="_blank"><strong>日本eSIM卡｜每日高速、总量、无限流量吃到饱方案｜优惠65折</strong></a> 」</p>

<ul>
  <li>
    <p>7 日 无限流量 eSIM 方案</p>
  </li>
  <li>
    <p>价格： <code class="language-plaintext highlighter-rouge">NT$ 847</code></p>
  </li>
</ul>

<p>实际用下来很好，很稳定、没遇到被降速或断线问题。</p>

<blockquote>
  <p><em>eSIM 启用方式、注意事项本文中会附上，请继续阅读。</em></p>
</blockquote>

<h4 id="日币">日币</h4>

<p><img src="/assets/aacd5f5cacd1/1*ljW0bI5fjkI2Xasi4KvA5A.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ljW0bI5fjkI2Xasi4KvA5A.jpeg" /></p>

<p>换了日币新钞。</p>

<blockquote>
  <p><em>建议新旧钞都带一些，部分贩卖机无法吃新钞。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*_Zz6O5dhksVtJvi8TqN1yw.webp" alt="可以吃新钞的贩卖机" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*_Zz6O5dhksVtJvi8TqN1yw.jpeg" /></p>

<p>可以吃新钞的贩卖机</p>

<h4 id="住宿">🏠住宿</h4>

<p>这次很幸运地只有松江一晚没订到 <a href="https://www.toyoko-inn.com/china/index2" target="_blank">东横 Inn</a> ，其他都有订到。</p>

<p><strong>11/12 <a href="https://www.toyoko-inn.com/china/search/detail/00232/" target="_blank">东横INN 冈山站东口</a> (一晚)</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*Kidzn6hm372657rCN8jTgw.webp" alt="出冈山车站走 4 分钟就会到" loading="lazy" decoding="async" width="620" height="289" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MjAiIGhlaWdodD0iMjg5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*Kidzn6hm372657rCN8jTgw.png" /></p>

<p>出冈山车站走 4 分钟就会到</p>

<ul>
  <li>
    <p>禁烟双床房，入住：1 人</p>
  </li>
  <li>
    <p>价格： <code class="language-plaintext highlighter-rouge">NT$ 1,616</code></p>
  </li>
</ul>

<p><strong>11/13 <a href="https://www.station.matsue-urban.co.jp/en/" target="_blank">Matsue Urban Hotel</a> (一晚)</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*9QIJ7lY1W7L94dgKGm6VQQ.webp" alt="松江站出站走 2 分钟就会到" loading="lazy" decoding="async" width="413" height="287" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MTMiIGhlaWdodD0iMjg3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*9QIJ7lY1W7L94dgKGm6VQQ.png" /></p>

<p>松江站出站走 2 分钟就会到</p>

<ul>
  <li>
    <p>Double Room with Small Double Bed — Non-Smoking — Building 2
入住：1 人</p>
  </li>
  <li>
    <p>价格： <code class="language-plaintext highlighter-rouge">NT$ 2,431</code></p>
  </li>
</ul>

<p><strong>11/14 <a href="https://www.toyoko-inn.com/china/search/detail/00046/" target="_blank">东横INN 鸟取站南口</a> (一晚)</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*hIqnM7MaRDWsRoRsydTqCg.webp" alt="鸟取站出站走 4 分钟就会到" loading="lazy" decoding="async" width="587" height="373" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1ODciIGhlaWdodD0iMzczIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*hIqnM7MaRDWsRoRsydTqCg.png" /></p>

<p>鸟取站出站走 4 分钟就会到</p>

<ul>
  <li>
    <p>禁烟双人房，入住：1 人</p>
  </li>
  <li>
    <p>价格： <code class="language-plaintext highlighter-rouge">NT$ 1,595</code></p>
  </li>
</ul>

<p><strong>11/15 <a href="https://www.toyoko-inn.com/china/search/detail/00317/" target="_blank">东横INN 姬路站新干线北口</a> (三晚)</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*P4xut5p60ZVSDtPkpoO6Pw.webp" alt="姬路站出站走 5 分钟会到" loading="lazy" decoding="async" width="777" height="591" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NzciIGhlaWdodD0iNTkxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*P4xut5p60ZVSDtPkpoO6Pw.png" /></p>

<p>姬路站出站走 5 分钟会到</p>

<ul>
  <li>
    <p>禁烟双人房，入住：1 人</p>
  </li>
  <li>
    <p>价格： <code class="language-plaintext highlighter-rouge">NT$ 6,055</code> ， <code class="language-plaintext highlighter-rouge">NT$ 2,018</code> /晚</p>
  </li>
</ul>

<p>虽然几乎都有订到东横，但还是因为预定时间太晚只剩双人房，所以一晚的价格比较高，如果有订到单人房型应该可以压到一晚 <code class="language-plaintext highlighter-rouge">NT$ 1,500</code> 以内；不过以往经验，日期接近就算是双人房也都会全满，可能地点真的比较少人去？</p>

<blockquote>
  <p><em>房间开箱影片本文中会附上，请继续阅读。</em></p>
</blockquote>

<p>—</p>

<blockquote>
  <p><a href="/posts/z-度旅行遊記/京阪神自由行攻略-京都大阪神户8日游全纪录与实用交通住宿指南-76d66c2e34af/"><em>Flight Tracker、iPhone Suica 使用、Visit Japan 预入境申请…之前文章有提过，这篇就不多赘述了。</em></a></p>
</blockquote>

<blockquote>
  <p><em><a href="http://vjw.digital.go.jp/" target="_blank">Visit Japan</a> <strong>唯一跟之前不一样的只有「入境审查」与「海关申报」QR Code 已合并成同一个「入境审查及海关申报的QR码」，没有蓝码黄码区别。</strong></em></p>
</blockquote>

<h4 id="虎航线上自助报到">虎航线上自助报到</h4>

<p>约出发前 1~3 天会收到虎航寄发的行程通知信， <strong>务必！务必！务必！</strong> 在出发前直接完成线上「自助报到」：</p>

<p><img src="/assets/aacd5f5cacd1/1*3K4biik6RnLXrqp453siiA.webp" alt="" loading="lazy" decoding="async" width="1120" height="1153" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTIwIiBoZWlnaHQ9IjExNTMiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*3K4biik6RnLXrqp453siiA.png" /></p>

<p>点击自助报到后会前往虎航官网，确认旅客资料、行李安全，最后会产生、寄发「登机证」。</p>

<p><img src="/assets/aacd5f5cacd1/1*oupKW1tFwXdEwj4pEAL8hw.webp" alt="" loading="lazy" decoding="async" width="511" height="846" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTEiIGhlaWdodD0iODQ2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*oupKW1tFwXdEwj4pEAL8hw.png" /></p>

<p>保存好登机证，凭此去机场就可以直接排「行李自助托运」挂行李，不用浪费时间排长长的「一般报到」柜台。</p>

<h4 id="さあ行こう-出发">さあ行こう 出发！</h4>

<h4 id="kkday-推广-">KKday 推广 🛒</h4>

<ul>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/153331" target="_blank">日本 JR PASS\|鸟取・松江区域周游券\|eMCO 电子票</a>
(如果只去松江、鸟取松江地区可考虑)</p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/20307-jr-sanin-okayama-area-pass?cid=19365" target="_blank"><strong>关西&amp;山阴地区铁路周游券 JRPass</strong></a>
(冈山机场进出最佳选择)</p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/137689-japan-high-speed-daily-unlimited-data-japanese-esim?cid=19365" target="_blank"><strong>日本eSIM卡｜每日高速、总量、无限流量吃到饱方案</strong></a></p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/20315-jr-sanyo-sanin-area-pass?cid=19365" target="_blank">日本 JR PASS｜山阳＆山阴地区铁路周游券｜eMCO 电子票</a>
(一口气玩遍山阳山阴地区)</p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/184144?cid=19365" target="_blank">鸟取沙丘 \| 日本唯一的惊险滑沙体验</a></p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/11463-osaka-bus-tour-tottori-sand-dunes-uratomi-coast-cruise-sand-museum-japan?cid=19365" target="_blank">【鸟取巴士一日游】鸟取砂丘、浦富海岸巡航、砂之美术馆、采梨子体验｜含特色午餐（大阪出发）</a></p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/262558?cid=19365" target="_blank">游览鸟取沙丘和著名的出云大社 2 日巴士之旅（大阪出发）</a></p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/185589?cid=19365" target="_blank">新年参观！出云大社停留3小时【广岛出发】</a></p>
  </li>
</ul>

<h3 id="day-1-1112-周二-出发">Day 1 (11/12 周二) 出发</h3>

<p>下午 13:05 的飞机，早上 8 点起床快 9 点出门，时间上绰绰有余。</p>

<p><img src="/assets/aacd5f5cacd1/1*LyhBB17WajIUYryRUrIgaA.webp" alt="2024/11 撷取自预办登机官网" loading="lazy" decoding="async" width="546" height="338" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NDYiIGhlaWdodD0iMzM4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*LyhBB17WajIUYryRUrIgaA.png" /></p>

<p><a href="https://www.taoyuan-airport.com/ITCI/index.html" target="_blank">2024/11 撷取自预办登机官网</a></p>

<p>虎航 <a href="https://www.taoyuan-airport.com/ITCI/index.html" target="_blank"><strong>预办登机服务(在机捷就报到+挂行李，到机场直接出境)</strong></a> 只能在 <strong>机捷A3新北产业园区站</strong> ；不能在北车，所以就一路搭机捷直达车前往第一航厦了。</p>

<h4 id="-1000-抵达机场">~= 10:00 抵达机场</h4>

<p><img src="/assets/aacd5f5cacd1/1*4_ZTToEL1W6fwNWpo_GvBw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*4_ZTToEL1W6fwNWpo_GvBw.jpeg" /></p>

<p>大约 10:00 就抵达机场，要等 10:20 才开柜。</p>

<h4 id="-1020-排行李自助托运挂行李">~= 10:20 排「行李自助托运」挂行李</h4>

<p><img src="/assets/aacd5f5cacd1/1*4y0Kgdbk8bbcUgajmi27IQ.webp" alt="" loading="lazy" decoding="async" width="951" height="1238" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTEiIGhlaWdodD0iMTIzOCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*4y0Kgdbk8bbcUgajmi27IQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*5_TKj5PZ-iUMi3r3CqrmzA.webp" alt="去程：9 KG" loading="lazy" decoding="async" width="611" height="776" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MTEiIGhlaWdodD0iNzc2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*5_TKj5PZ-iUMi3r3CqrmzA.png" /></p>

<p>去程：9 KG</p>

<p>这时候是先从虎航网站使用网路报到的优势就来了，当天目测现场「一般报到」柜台大排长龙，10:20 就已经排满，预估至少要等 45 分钟到 1 小时；「行李自助托运」这边大概花不到 15 分钟就完成手续，节省很多等待时间。</p>

<blockquote>
  <p><em>现场完成线上报到，再去排「行李自助托运」都比去排「一般报到」快得多。</em></p>
</blockquote>

<h4 id="-1050-完成出境">~= 10:50 完成出境</h4>

<p><img src="/assets/aacd5f5cacd1/1*aD3atJOMZWAhStzpdoaZDg.webp" alt="" loading="lazy" decoding="async" width="937" height="1167" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzciIGhlaWdodD0iMTE2NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*aD3atJOMZWAhStzpdoaZDg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*OLORgiz8R6pOfG-m9P-aOw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*OLORgiz8R6pOfG-m9P-aOw.jpeg" /></p>

<p>这次在第一航厦的 A1 登机门。(终于不用再搭摆渡车了)</p>

<p><img src="/assets/aacd5f5cacd1/1*MDpHGgVgU0QRH0BGFmzLbA.webp" alt="" loading="lazy" decoding="async" width="951" height="1236" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTEiIGhlaWdodD0iMTIzNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*MDpHGgVgU0QRH0BGFmzLbA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ZU4N6uWzEYhp_J2C3JE0Dg.webp" alt="" loading="lazy" decoding="async" width="1200" height="886" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg4NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ZU4N6uWzEYhp_J2C3JE0Dg.png" /></p>

<p>之前来第一航厦每次都吃顶呱呱，这次改吃老董牛肉面，店面位置就在快到 A1 登机门的地方也很顺路。</p>

<h4 id="-1130-候机">~= 11:30 候机</h4>

<p><img src="/assets/aacd5f5cacd1/1*Xaux1WjOTpXcqxeF1-UlXw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*Xaux1WjOTpXcqxeF1-UlXw.jpeg" /></p>

<p>吃饱乱晃一下大约 11:30，A1 登机门的坏处是离 <a href="/posts/z-度旅行遊記/九州自由行攻略-釜山新山茶花号邮轮入境日本博多-深入由布院-大分-福冈等地-cb65fd5ab770/"><strong>一航免费贵宾室</strong></a> 很远，懒得走来走去就直接来候机室了。</p>

<p>没事先处理一下两个网路问题，第一个是我的 <a href="https://123.cht.com.tw/IVRredir/" target="_blank"><strong>中华电信漫游功能是关闭的</strong></a> ，有需要漫游方案无法直接购买；所以先打电话去中华电信解锁漫游功能，以备不时之需。</p>

<p><img src="/assets/aacd5f5cacd1/1*dF9XuqFK3bW2X249DYtqZg.webp" alt="需要打电话给中华电信、确认个人资料后请客服解除锁定。" loading="lazy" decoding="async" width="571" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NzEiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*dF9XuqFK3bW2X249DYtqZg.png" /></p>

<p>需要打电话给中华电信、确认个人资料后请客服解除锁定。</p>

<h4 id="事先启用-esim-iphone-为例">事先启用 eSIM (iPhone 为例)</h4>

<p>第二个网路问题是先在机场启用 eSIM，因 eSIM 输入启用需要连接网路，怕冈山机场的 WiFi 不稳定，所以事先在台湾网路正常的情况下输入启用日本 eSIM。</p>

<blockquote>
  <p><em>如果还是很怕网路造成入境问题， <strong>也可先截图入境 QR Code</strong> 或同步写纸本入境卡，双重保障。</em></p>
</blockquote>

<p>之前去 <a href="/posts/z-度旅行遊記/曼谷自由行攻略-5-日行程规划-必访景点与实用旅游安全提醒-b7e7c0938985/">泰国买的 eSIM 可以直接在购买凭证信、PDF 或截图照片中长按 QR Code 出现「加入 eSIM」点击即可自动加入</a> ，但这次买的日本 eSIM 却没有出现：</p>

<p><img src="/assets/aacd5f5cacd1/1*su5YVQrLdjFXORHuiMZxuw.webp" alt="" loading="lazy" decoding="async" width="567" height="1013" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NjciIGhlaWdodD0iMTAxMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*su5YVQrLdjFXORHuiMZxuw.png" /></p>

<p><strong>有找到一个 <a href="https://www.ptt.cc/bbs/iOS/M.1719797706.A.916.html" target="_blank">网友提供</a> 的方法可以成功出现「加入 eSIM」选项。(感觉是 iOS Bug，iOS 17.4 之后就坏了)：</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*DrYXYUfGj_BddPe8FwbM4A.webp" alt="" loading="lazy" decoding="async" width="578" height="1047" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NzgiIGhlaWdodD0iMTA0NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*DrYXYUfGj_BddPe8FwbM4A.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Z-Ls2JPUbJAw93L7ey91gw.webp" alt="" loading="lazy" decoding="async" width="569" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NjkiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Z-Ls2JPUbJAw93L7ey91gw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*BwNRm45uuwJcWjnYicDIEA.webp" alt="" loading="lazy" decoding="async" width="562" height="1151" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NjIiIGhlaWdodD0iMTE1MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*BwNRm45uuwJcWjnYicDIEA.png" /></p>

<ol>
  <li>
    <p>前往 eSIM 凭证信、PDF 按下手机截图，将截图存在照片相簿中</p>
  </li>
  <li>
    <p>打开手机相机，点左下角进入相簿</p>
  </li>
  <li>
    <p>在相簿中找到 eSIM 照片，长按 QRCode 就会出现「加入 eSIM」选项</p>
  </li>
  <li>
    <p>点击「加入 eSIM」直接带入启用资讯启用 eSIM</p>
  </li>
</ol>

<h4 id="iphone-手动启用-esim">iPhone 手动启用 eSIM</h4>

<p><strong>前往「设定」-&gt;「行动服务」-&gt;「加入 eSIM」-&gt;「使用行动条码」：</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*TUIEbNDhczwvTehfFza_sg.webp" alt="" loading="lazy" decoding="async" width="582" height="1242" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1ODIiIGhlaWdodD0iMTI0MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*TUIEbNDhczwvTehfFza_sg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*7hYiMadhEnU5NOt58ashJw.webp" alt="" loading="lazy" decoding="async" width="553" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*7hYiMadhEnU5NOt58ashJw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*YUjZUpfB6BeLQKNWTMx-5A.webp" alt="" loading="lazy" decoding="async" width="581" height="1239" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1ODEiIGhlaWdodD0iMTIzOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*YUjZUpfB6BeLQKNWTMx-5A.png" /></p>

<p>我有把 eSIM QRCode 印出来，所以我是从这边直接扫描启用的。</p>

<p>如果你什么都没有可以点「手动输入详细资讯」复制贴上 eSIM 凭证资讯手动启用：</p>

<p><img src="/assets/aacd5f5cacd1/1*TdmMDosao98OATMJNa0NLw.webp" alt="" loading="lazy" decoding="async" width="1200" height="1170" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjExNzAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*TdmMDosao98OATMJNa0NLw.png" /></p>

<p>对应信件内容填上 <code class="language-plaintext highlighter-rouge">SM-DP+ 位址</code> 、 <code class="language-plaintext highlighter-rouge">启用码</code> 、 <code class="language-plaintext highlighter-rouge">确认码</code> (这次没有)，点下一步完成启用。</p>

<p><img src="/assets/aacd5f5cacd1/1*cXjnkvYvDGnE-ByT3hcnaw.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*cXjnkvYvDGnE-ByT3hcnaw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*sc6xr-nA3J_BdYMcNBNMFA.webp" alt="" loading="lazy" decoding="async" width="553" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*sc6xr-nA3J_BdYMcNBNMFA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Rh7hWbEiUtLbR3VYXq9NOw.webp" alt="" loading="lazy" decoding="async" width="581" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1ODEiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Rh7hWbEiUtLbR3VYXq9NOw.png" /></p>

<p>输入完成后需要花一点时间启用，可能会卡在「启用中…」一阵子或是跳出启用失败稍后再试之类的；再等一下子就好了，启用成功在「设定」-&gt;「行动服务」中会显示「开启」右上角讯号图标也会出现下面一排 … 显示讯号状况。</p>

<ul>
  <li>行动方案标签可选择「旅游」</li>
</ul>

<blockquote>
  <p><strong><em>我们还在台湾，暂时还无法连接使用 eSIM 日本网路，只要确认启用成功即可。</em></strong></p>
</blockquote>

<h4 id="-1220-开始登机无误点">~= 12:20 开始登机，无误点</h4>

<p><img src="/assets/aacd5f5cacd1/1*R1I1UY831lnjto_6jqwCFw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*R1I1UY831lnjto_6jqwCFw.jpeg" /></p>

<h4 id="-1305-准时起飞">~= 13:05 准时起飞</h4>

<p><img src="/assets/aacd5f5cacd1/1*ovXkaMS4yzLWpm2_YBTPFw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*ovXkaMS4yzLWpm2_YBTPFw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*IQ1kIFLjFgrYHUqulJMO7Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*IQ1kIFLjFgrYHUqulJMO7Q.jpeg" /></p>

<p>此时台湾开始下大雨，但是没什么风对起飞影响不大。</p>

<p><img src="/assets/aacd5f5cacd1/1*Ooxdur72IKkRc4u5q52esQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Ooxdur72IKkRc4u5q52esQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ECU47qVPUd7cv6UcBy6i3Q.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ECU47qVPUd7cv6UcBy6i3Q.jpeg" /></p>

<p>虎航的位子舒适度我觉得算廉航中优秀的了(相较乐桃太小、越捷椅子不好坐)，不过虎航的缺点是 <a href="https://www.threads.net/@kechi.syonen/post/DCYnEQNzU5L/%E4%BB%80%E9%BA%BC%E8%83%BD%E5%B8%B6%E4%B8%8A%E9%A3%9B%E6%A9%9F%E4%BB%80%E9%BA%BC%E4%B8%8D%E8%83%BD%E5%B8%B6%E5%BE%88%E6%B8%85%E6%A5%9A%E4%BB%99%E5%8F%B0%E6%A9%9F%E5%A0%B4" target="_blank"><strong>禁止自带食物</strong></a> ，刚吃饱不饿！</p>

<p>机上无 WiFi 只能听听音乐玩玩单机游戏。</p>

<p><img src="/assets/aacd5f5cacd1/1*LaNvJoYfPvU3LJchfvJHlg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*LaNvJoYfPvU3LJchfvJHlg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*B5bSSUIBkoDGo147pFsEVQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*B5bSSUIBkoDGo147pFsEVQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*9Ibz55I3hZC0C7lSO-4o1A.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*9Ibz55I3hZC0C7lSO-4o1A.jpeg" /></p>

<p>可以从窗外看到日本天气很好。👍👍👍</p>

<h4 id="1630-台湾时间-1530-准时降落">16:30 (台湾时间 15:30) 准时降落</h4>

<p><img src="/assets/aacd5f5cacd1/1*paerDziYhfHNdjAg1QeJBg.webp" alt="" loading="lazy" decoding="async" width="532" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MzIiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*paerDziYhfHNdjAg1QeJBg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*y36b_kkD7RMz1R501bPkIw.webp" alt="" loading="lazy" decoding="async" width="536" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MzYiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*y36b_kkD7RMz1R501bPkIw.png" /></p>

<p>降落日本后我们的日本 eSIM 应该就能收到讯号了。</p>

<blockquote>
  <p><em>有讯号但还无法上网，要再到「设定」-&gt;「行动服务」-&gt; 点选进入 <strong>旅游 日本 eSIM</strong> -&gt; 确认有「开启此号码」跟 <strong>打开「数据漫游」这样才会有网路！⚠️⚠️⚠️</strong></em></p>
</blockquote>

<blockquote>
  <p><em>另外也可以进入 <strong>主要 中华电信</strong> 号码，如果您没有购买中华电信的漫游方案请记得 <strong>关闭这边的「数据漫游」、「开启此号码」可以继续保持启用，这样才能收台湾的简讯！</strong></em></p>
</blockquote>

<blockquote>
  <p><strong><em>请注意：不要随意接电话、海外接国内电话收话方也会被收费！⚠️⚠️⚠️ (只有收简讯免费)</em></strong></p>
</blockquote>

<h4 id="-1700-完成入境拿行李">~= 17:00 完成入境、拿行李</h4>

<ul>
  <li>
    <p>冈山桃太郎机场是非常小的机场，同一时间只有一班国际航班(就是你这班而已)，跟著同机的人一起入境、拿行李，很快。
(本次航班看起来快满载，大约花 30 分钟就出来了)</p>
  </li>
  <li>
    <p>意外的事是机场工作人员都会讲中文</p>
  </li>
  <li>
    <p>可能因为小机场比较严格，如果跟我一样独旅的几乎都被问会待几天？会去哪些地方？有的还被要求出示饭店订单。
(因此自己去的话请提早准备应对)</p>
  </li>
</ul>

<h4 id="机场-wifi">机场 WiFi</h4>

<p><img src="/assets/aacd5f5cacd1/1*evDWJrEApdI2laaMO01asw.webp" alt="" loading="lazy" decoding="async" width="553" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*evDWJrEApdI2laaMO01asw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*YqPFrPIOePpu3WgHmBMXBA.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*YqPFrPIOePpu3WgHmBMXBA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*7sCEBxL7NtIZHBeap-IW-w.webp" alt="" loading="lazy" decoding="async" width="560" height="1127" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NjAiIGhlaWdodD0iMTEyNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*7sCEBxL7NtIZHBeap-IW-w.png" /></p>

<blockquote>
  <p><em>冈山机场免费 WiFi 连上之后要输入电子邮件，去信箱收信点连结启用，才能持续连上使用；如果只是为了 Visit Japan 可以在连上 10 分钟内打开网页叫出入境 QR Code 即可。</em></p>
</blockquote>

<h4 id="-1704-搭上冈山机场前往-jr-冈山车站的巴士">~= 17:04 搭上冈山机场前往 JR 冈山车站的巴士</h4>

<p><img src="/assets/aacd5f5cacd1/1*YNxPMPmNH-YBWNemZR6t-Q.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*YNxPMPmNH-YBWNemZR6t-Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*4c4diTl_B42J1RTeChslgA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*4c4diTl_B42J1RTeChslgA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*k3bf2CWOwFKCWeC1eC1yTQ.webp" alt="最新班次时刻表请参考官网" loading="lazy" decoding="async" width="371" height="634" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNzEiIGhlaWdodD0iNjM0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*k3bf2CWOwFKCWeC1eC1yTQ.png" /></p>

<p><a href="https://www.okayama-airport.org/tw/access/bus" target="_blank">最新班次时刻表请参考官网</a></p>

<ul>
  <li>
    <p>机场很小，顺著路走出来就是往冈山车站的巴士，而且会有工作人员引导、不怕迷路直接上车。</p>
  </li>
  <li>
    <p><strong>航班太少，所以巴士除了按照表定发车时间，还会跟著班机抵达时间，加开班次；也不用怕满员搭不上，满员会再发车。</strong>
(照 <a href="https://www.okayama-airport.org/tw/access/bus" target="_blank">表定要等到 19:05 才有车</a> ，但实际有加班车。)</p>
  </li>
  <li>
    <p><a href="https://www.ptt.cc/bbs/Japan_Travel/M.1730096575.A.AB6.html" target="_blank">2024/11/30 前出示护照可以</a> 免费搭乘；免费接驳不定期举办， <a href="/posts/z-度旅行遊記/山阳地区广岛冈山自由行攻略-6日行程-交通-住宿全解析-31b9b3a63abc/">去年来的时候没有</a> 。</p>
  </li>
</ul>

<h4 id="-1800-抵达-jr-冈山车站">~= 18:00 抵达 JR 冈山车站</h4>

<p><img src="/assets/aacd5f5cacd1/1*8OhJp66_cz7XpEzC8I6WpQ.webp" alt="" loading="lazy" decoding="async" width="942" height="1240" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDIiIGhlaWdodD0iMTI0MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*8OhJp66_cz7XpEzC8I6WpQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*nxBsum1hduuDJJluFTz4DQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1010" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*nxBsum1hduuDJJluFTz4DQ.png" /></p>

<p>遇到下班时间路上有点塞车，18:00 左右才到冈山车站。 <strong>(比预期多 30 分钟)</strong></p>

<h4 id="jr-冈山站兑换-jr-pass--预定明日前往松江的车票">JR 冈山站兑换 JR Pass &amp; 预定明日前往松江的车票</h4>

<p><img src="/assets/aacd5f5cacd1/1*-2saCSONEdJw9FIYeVFZ4Q.webp" alt="" loading="lazy" decoding="async" width="953" height="1192" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTMiIGhlaWdodD0iMTE5MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*-2saCSONEdJw9FIYeVFZ4Q.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*KJeCftSlvW2t-a1Ef5JvEA.webp" alt="" loading="lazy" decoding="async" width="952" height="1232" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTIiIGhlaWdodD0iMTIzMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*KJeCftSlvW2t-a1Ef5JvEA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*t9I2iSC2-97Dv5fX6FNqWw.webp" alt="" loading="lazy" decoding="async" width="640" height="745" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NDAiIGhlaWdodD0iNzQ1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*t9I2iSC2-97Dv5fX6FNqWw.png" /></p>

<ul>
  <li>
    <p>官网可查询 <a href="https://www.westjr.co.jp/global/tc/ticket/receive/?railpass=11&amp;mco=1&amp;area=0" target="_blank">可兑换 JR Pass 的车站</a> ，不是每个站都可以换喔！
(JR 冈山站可以)</p>
  </li>
  <li>
    <p>冈山站找到自动售票处，排中间绿色的机器，只有这一台可以换 JR Pass</p>
  </li>
</ul>

<p><strong>兑换流程：</strong></p>

<p><strong>准备好护照跟购买的 JR Pass 凭证 QR Code，可先选右上语言「繁体中文」，直接点左下「QRコードの読取り(QR码扫描)」黄色按钮兑换。</strong></p>

<blockquote>
  <p><strong><em>可以选择开始使用日</em></strong> <em>，可预约指定席的时间也是从开始使用日开始计算。 <strong>⚠️</strong></em></p>
</blockquote>

<blockquote>
  <p><em>(像我是选择明天开始)</em></p>
</blockquote>

<p>按照步骤扫描 JR Pass QR Code 和护照即可完成兑换。</p>

<p><img src="/assets/aacd5f5cacd1/1*nj6t65muUKTM8rL9b9MnUQ.webp" alt="JR Pass QR Code" loading="lazy" decoding="async" width="845" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NDUiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*nj6t65muUKTM8rL9b9MnUQ.png" /></p>

<p>JR Pass QR Code</p>

<p><strong>兑换结果：</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*A-kqDIwfmGwif12qTiUU1g.webp" alt="上图拿去年去兑换的 JR Pass 为图例" loading="lazy" decoding="async" width="604" height="770" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDQiIGhlaWdodD0iNzcwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*A-kqDIwfmGwif12qTiUU1g.png" /></p>

<p>上图拿去年去兑换的 JR Pass 为图例</p>

<p>兑换完会有三张券，其他两张长方形的是说明书，没有用； <strong>印有 PASS 的这张最重要，车站搭车进出站都是凭这张，要收好！</strong></p>

<h4 id="预约-jr-指定席">预约 JR 指定席</h4>

<p>这边很重要，根据 <a href="https://www.westjr.co.jp/global/tc/ticket/pass/kansai_sanin/" target="_blank">JR Pass 关西＆山阴周游券官网</a> 提供的资讯， <a href="https://www.westjr.co.jp/global/tc/ticket/pass/pdf/Reserved_seats_tc.pdf" target="_blank"><strong>前往山阴地区的 JR YAKUMO 八云 やくも 号 是全车指定席</strong></a> <strong>，无自由座⚠️⚠️⚠️ (</strong> 2024年3月16日开始 <strong>)，均需提前划位。</strong></p>

<blockquote>
  <p><em>应该也可以从网路先预约， <a href="https://medium.com/ztravel/%E9%81%8A%E8%A8%98-2024-%E4%BA%8C%E8%A8%AA%E4%B9%9D%E5%B7%9E-9-%E6%97%A5%E8%87%AA%E7%94%B1%E8%A1%8C-%E7%B6%93%E9%87%9C%E5%B1%B1-%E5%8D%9A%E5%A4%9A%E9%83%B5%E8%BC%AA%E5%85%A5%E5%A2%83-cb65fd5ab770?source=collection_home---4------1-----------------------" target="_blank">之前就是从网路先预约博多到由布院的 JR</a> ，只是要查一下。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*jPSXmntXpBrCzRGnB0Ty5A.webp" alt="" loading="lazy" decoding="async" width="1200" height="1051" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwNTEiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*jPSXmntXpBrCzRGnB0Ty5A.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*YUzrKBjkuis18Az9sZMM5Q.webp" alt="" loading="lazy" decoding="async" width="751" height="575" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NTEiIGhlaWdodD0iNTc1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*YUzrKBjkuis18Az9sZMM5Q.png" /></p>

<blockquote>
  <p><em>Google Map 上的交通资讯不完整，详细班次跟 <strong>列车名称</strong> 可以从 <a href="https://www.westjr.co.jp/global/sc/timetable/" target="_blank">JR 官网查询得知</a> 。 <strong>⚠️⚠️⚠️</strong></em></p>
</blockquote>

<p><strong>JR Pass 预约指定席流程：</strong></p>

<ul>
  <li>
    <p><a href="https://www.westjr.co.jp/global/tc/ticket/pass/kansai_sanin/" target="_blank"><strong>JR Pass 关西＆山阴周游券</strong></a> <strong>的规定是可以使用机器预约 6 次指定席，超过要去人工柜台预约；各地区 JR Pass 次数跟限制不同，请参考官网资讯。</strong></p>
  </li>
  <li>
    <p>先查好出发地点的英文名与要去的地方 <strong>JR 站英文名</strong> ，例如：OKAYAMA(冈山) -&gt; MATSUE(松江)</p>
  </li>
  <li>
    <p>请注意是 JR 站英文名， <em>所以 <a href="/posts/z-度旅行遊記/九州自由行攻略-福冈-长崎-熊本10日独旅全纪录与交通住宿实战经验-d78e0b15a08a/">要去福冈要打 Hakata</a></em> XD</p>
  </li>
  <li>
    <p>第一步先选「繁体中文」</p>
  </li>
  <li>
    <p>第二步直接插入一张「JR Pass 车票」
(同行多人要一起划位会在第四步请你继续插入。)</p>
  </li>
  <li>
    <p>其他步骤照以下影片示范完成预约：</p>
  </li>
</ul>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/oG8xrxEC6mk" title="JR Pass 预约指定席示范" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<blockquote>
  <p><em>影片是我在 安来站 Yasugi 预约前往 鸟取站 Tottori 为例拍摄的整个过程。</em></p>
</blockquote>

<blockquote>
  <p><em>(那站没人在排自动售票机，才敢拿出手机录下整个过程)</em></p>
</blockquote>

<p><strong>预约完成：</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*wdAemMFceaXQ6mZEPJfzWQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*wdAemMFceaXQ6mZEPJfzWQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*9E0CaLNkFZHyp6RfFbW8VQ.webp" alt="" loading="lazy" decoding="async" width="938" height="1226" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzgiIGhlaWdodD0iMTIyNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*9E0CaLNkFZHyp6RfFbW8VQ.png" /></p>

<ul>
  <li>
    <p>因班次与明日行程安排，所以预约早 07:05 的班次先前往松江的饭店寄放行李</p>
  </li>
  <li>
    <p><strong>实际进出站还是用 JR Pass (上面那张)</strong> ⚠️⚠️⚠️，指定券这张只是让你知道你的车厢跟座位编号。</p>
  </li>
  <li>
    <p>已经没靠窗位只能坐走道 QQ</p>
  </li>
</ul>

<p><img src="/assets/aacd5f5cacd1/1*eWbl5HfHDsgs10xMbQByBA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*eWbl5HfHDsgs10xMbQByBA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*flqVSVO61pO1j1rk6sYICw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*flqVSVO61pO1j1rk6sYICw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*cFmuaiXspF7Fk3FeKY_Vwg.webp" alt="" loading="lazy" decoding="async" width="952" height="1225" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTIiIGhlaWdodD0iMTIyNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*cFmuaiXspF7Fk3FeKY_Vwg.png" /></p>

<p>在冈山车站随便买了一个炸牛排便当跟超商买些吃的喝的后就去饭店休息了；冈山车站正在整修，最后一天回程会再回来冈山。</p>

<p><img src="/assets/aacd5f5cacd1/1*5OK4O6vRpvTbBHY1or45Ww.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*5OK4O6vRpvTbBHY1or45Ww.jpeg" /></p>

<p>从桃太郎商店街这边走五分钟就到饭店。</p>

<h4 id="-1900-回饭店开吃休息">~= 19:00 回饭店开吃、休息</h4>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/UfWKBa1FAto" title="东横INN 冈山站东口" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p><img src="/assets/aacd5f5cacd1/1*1JJAxuSJ6NLnq4lRXZPajw.webp" alt="" loading="lazy" decoding="async" width="1400" height="984" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*1JJAxuSJ6NLnq4lRXZPajw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*5aXGicaDQzX-9EREx0ooaw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*5aXGicaDQzX-9EREx0ooaw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*0XBFIrZROFSOuAr7psn7NA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*0XBFIrZROFSOuAr7psn7NA.jpeg" /></p>

<p>便当的份量有点少、冈山白桃这罐水蜜桃酒很好喝！再加上怀念的日本超商(全家的)热狗跟炸鸡，今晚很满足；晚安冈山！为明早早起开始日本行做足准备。</p>

<h4 id="冈山后乐园点灯"><a href="http://genso-teien.okayama.jp/" target="_blank">冈山后乐园点灯</a></h4>

<p>今年 2024 的冈山后乐园点灯是 11月15日(金)～11月24日(日)，来的这天也还没有；如果有点灯可以去看看，很美。</p>

<p><img src="/assets/aacd5f5cacd1/1*tVwuOQS4DytQGzfk3tn52g.webp" alt="去年 2023 山阳邮寄点灯我拍的照片" loading="lazy" decoding="async" width="1200" height="907" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*tVwuOQS4DytQGzfk3tn52g.png" /></p>

<p><a href="/posts/z-度旅行遊記/山阳地区广岛冈山自由行攻略-6日行程-交通-住宿全解析-31b9b3a63abc/">去年 2023 山阳邮寄点灯我拍的照片</a></p>

<h3 id="day-2-1113-周三-岛根--出云大社宍道湖夕阳">Day 2 (11/13 周三) 岛根 — 出云大社、宍道湖夕阳</h3>

<h4 id="0705-搭乘-yakumo-やくも-八云号-1-前往-松江">07:05 搭乘 Yakumo やくも 八云号 1 前往 松江</h4>

<p><img src="/assets/aacd5f5cacd1/1*-ppEnPrSVSls2IfkppB_pA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*-ppEnPrSVSls2IfkppB_pA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*NBhG889zmADfQDGI-7zlAQ.webp" alt="" loading="lazy" decoding="async" width="963" height="751" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjMiIGhlaWdodD0iNzUxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*NBhG889zmADfQDGI-7zlAQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*yb0D7yt38ygSmnGJyEjoEA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*yb0D7yt38ygSmnGJyEjoEA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*168t2gezMC-ucwNzG3_m5g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*168t2gezMC-ucwNzG3_m5g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*0DUCHWLSu7X5LG35oylmBw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*0DUCHWLSu7X5LG35oylmBw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*m4JyAVEfNrUoaIt1Hk3Zeg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*m4JyAVEfNrUoaIt1Hk3Zeg.jpeg" /></p>

<p>车内蛮舒适的，前后有行李区可以直接放行李，座位也有充电座。</p>

<p><img src="/assets/aacd5f5cacd1/1*vg7v1Xz5RlcQ9KqnMwiZjw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*vg7v1Xz5RlcQ9KqnMwiZjw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*M8ciQoiAy5GWHQoa34vo1w.webp" alt="" loading="lazy" decoding="async" width="879" height="994" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzkiIGhlaWdodD0iOTk0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*M8ciQoiAy5GWHQoa34vo1w.png" /></p>

<p>总路程约需 2 小时 45 分钟，可以感受到一路穿山越岭，一大清早的很多地区都还是雾气蒙蒙，颇有穿过山洞来到世外桃源的感觉；可惜没划到靠窗位，一路只能远观。</p>

<h4 id="0949-抵达松江">09:49 抵达松江</h4>

<p><img src="/assets/aacd5f5cacd1/1*RNcfgkoIlBNqAbZiJGXUeA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*RNcfgkoIlBNqAbZiJGXUeA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*wuK_7kxYguDnQoYd5nNXtA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*wuK_7kxYguDnQoYd5nNXtA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*GfeSKNvv30aqgIOUIcVAzw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*GfeSKNvv30aqgIOUIcVAzw.jpeg" /></p>

<p>松江天气超级好☀️，抵达松江站后直接前往今晚入住的饭店「 <a href="https://www.station.matsue-urban.co.jp/en/" target="_blank"><strong>Matsue Urban Hotel</strong></a> 」寄放行李。</p>

<p><img src="/assets/aacd5f5cacd1/1*YCar9o50KKuyrx5blLVipg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*YCar9o50KKuyrx5blLVipg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*58UjwwimiMZZS5fhCc2o7w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*58UjwwimiMZZS5fhCc2o7w.jpeg" /></p>

<p>寄放完再回到松江站此时大约 10:00，重新划位 10:48 从 松江 前往 出云市 的 Yakumo 3 号位子。</p>

<blockquote>
  <p><strong><em>应该昨天划位 冈山到松江 就要顺便再划位一张 松江到出云市 的</em></strong> <em>，因为下午想去看夕阳所以才先在松江寄放行李，不然就直接到出云市不中途浪费时间换车了。</em></p>
</blockquote>

<blockquote>
  <p><em>另外也可以搭乘 一畑电车大社线 前往出云大社，总时间差不多。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*Wvd6qczYLcEb8XywbGV_Vg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Wvd6qczYLcEb8XywbGV_Vg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*602_X70DAMAYJiEI2d024Q.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*602_X70DAMAYJiEI2d024Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Ji2S8d1orIkJB5Wyu3DCSw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Ji2S8d1orIkJB5Wyu3DCSw.jpeg" /></p>

<p>还有一点时间跑去超商买了两个御饭团、咖啡、炸鸡带著当午餐吃。</p>

<p><img src="/assets/aacd5f5cacd1/1*OkaENzl4tJ0nSMqMSznEmw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*OkaENzl4tJ0nSMqMSznEmw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*NNFURE5UfVdWOgkpYuAtrg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*NNFURE5UfVdWOgkpYuAtrg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*5-vTR2_TeMIlIiPggNON5w.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*5-vTR2_TeMIlIiPggNON5w.jpeg" /></p>

<p>一路上会经过宍到湖，超级大一开始以为是海，其实是湖。</p>

<blockquote>
  <p><em>划位可以划 D 靠窗位子才可以直接看宍到湖，我划 A 侧靠山看不到 QQ。</em></p>
</blockquote>

<h4 id="1112-抵达出云市">11:12 抵达出云市</h4>

<p><img src="/assets/aacd5f5cacd1/1*IGzRRA0zChR7eosgVBM30g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*IGzRRA0zChR7eosgVBM30g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*_dWPzssuOTsPLhGlPeaxBg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*_dWPzssuOTsPLhGlPeaxBg.jpeg" /></p>

<p>抵达松江站后一路小跑步，要赶 11:25 一畑电车北松江线 先前往 川迹车站。</p>

<blockquote>
  <p><em>一畑电车无法刷交通卡进站，要先在门口自动售票机(可用电子支付)买车票，不知道怎么买直接跟站务人员说到 <code class="language-plaintext highlighter-rouge">Izumo Taisha</code> (出云大社)即可。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*zOWAvtPBUa4Q6p_O0UI_4A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*zOWAvtPBUa4Q6p_O0UI_4A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*hqp8E0znWzflcoF_wdXbYA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*hqp8E0znWzflcoF_wdXbYA.jpeg" /></p>

<p>在 川迹车站 需要再换车 (跟著大家走到对面月台)，转乘 一畑电车大社线 前往 出云大社前 站。</p>

<h4 id="约-12-点抵达-出云大社">约 12 点抵达 出云大社</h4>

<p><img src="/assets/aacd5f5cacd1/1*DbbHj7dvLzIZ5yucQPqW2Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*DbbHj7dvLzIZ5yucQPqW2Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*TNniVRe3T0Lx2h8ZEO6UoQ.webp" alt="" loading="lazy" decoding="async" width="902" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDIiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*TNniVRe3T0Lx2h8ZEO6UoQ.png" /></p>

<p>大神前的表参道很清幽漂亮，有时间的话这边也有很多小店美食可以逛。</p>

<blockquote>
  <p><em>后来才知道出云四座鸟居也很有名，其中一个白色大鸟居就在出车站表参道往神社反方向走就能在入口找到：</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*PsT0vPHhgZXJUJVbJzg9TA.webp" alt="来源：岛根旅游官网" loading="lazy" decoding="async" width="1200" height="779" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc3OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*PsT0vPHhgZXJUJVbJzg9TA.png" /></p>

<p><a href="https://www.kankou-shimane.com/zh-tw/highlights/1615" target="_blank">来源：岛根旅游官网</a></p>

<blockquote>
  <p><em>详细可参考 <a href="https://www.kankou-shimane.com/zh-tw/highlights/1615" target="_blank">岛根旅游官网</a></em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*l9SL74ldAxYcnEpLmIFgsA.webp" alt="" loading="lazy" decoding="async" width="1200" height="875" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg3NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*l9SL74ldAxYcnEpLmIFgsA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*NmTX-LAuUYpyNxZH1iyOmA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*NmTX-LAuUYpyNxZH1iyOmA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*lL6Lshf934FqRMAHwuf8Sw.webp" alt="" loading="lazy" decoding="async" width="988" height="1029" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5ODgiIGhlaWdodD0iMTAyOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*lL6Lshf934FqRMAHwuf8Sw.png" /></p>

<p>往上走到出云大社入口，来的时间点 <code class="language-plaintext highlighter-rouge">2024/11/13</code> 正好是 <strong>神在祭</strong> 期间 ( <code class="language-plaintext highlighter-rouge">2024 令和 6 年 11/11~11/17</code> )，所以来参拜的日本人非常多。</p>

<blockquote>
  <p><em>日本每年的农历 10 月(西历 11 月)，全国八百万神明齐聚出云「神议」讨论人间事务，如缘分安排与自然调和。</em></p>
</blockquote>

<blockquote>
  <p><em>因此 <strong>这个月份在日本其他区称为「神无月」（神不在）且多半无祭典</strong> 。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>只有在出云这称为「神在月」意即只有出云地区有神。</em></strong></p>
</blockquote>

<blockquote>
  <p><em>祭典包括迎接神明的「神迎祭」、祈求良缘的「縁结大祭」、以及送别神明的「神送り祭」</em></p>
</blockquote>

<blockquote>
  <p><strong><em>出云大社供奉主神：大国主命（おおくにぬしのみこと）</em></strong></p>
</blockquote>

<p>真的很巧，当初在安排时间的时候其实没有刻意选这个时间点，是在查景点资讯的时候才知道。</p>

<p><img src="/assets/aacd5f5cacd1/1*mHn3NX4zb31WmXFITQBOIQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*mHn3NX4zb31WmXFITQBOIQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*iehGyLgSPf4LgUzjhMjfzw.webp" alt="" loading="lazy" decoding="async" width="889" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4ODkiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*iehGyLgSPf4LgUzjhMjfzw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*IVJtJR2htbOjimqgqKvLrg.webp" alt="" loading="lazy" decoding="async" width="962" height="1289" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjIiIGhlaWdodD0iMTI4OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*IVJtJR2htbOjimqgqKvLrg.png" /></p>

<p>穿过入口鸟居后还要再走大约 5 分钟才会到神社。</p>

<h4 id="日本第一大日之丸国旗">日本第一大「日之丸」国旗</h4>

<p><img src="/assets/aacd5f5cacd1/1*WBerwVlV_I8PeYqj2KRX1w.webp" alt="" loading="lazy" decoding="async" width="959" height="1183" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTkiIGhlaWdodD0iMTE4MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*WBerwVlV_I8PeYqj2KRX1w.png" /></p>

<p>进入神社后往左方看就会看到一根耸立的旗竿，上面是日本最大的日之丸国旗(约 75 张榻榻米、137 平方公尺)。</p>

<p>朝这支旗杆的方向走就会来到「神乐殿」这里有日本第一大 <a href="https://sanin-japan.com/zh-tw/special/territory-of-the-gods-yokozuna-and-izumo-taisha/" target="_blank">注连绳</a> 。</p>

<p><img src="/assets/aacd5f5cacd1/1*x8zuQYtIXNILxGLkMjQbJg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1056" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*x8zuQYtIXNILxGLkMjQbJg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*3WjUHQV3lwqRTi3IegRb6w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*3WjUHQV3lwqRTi3IegRb6w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*KeY6bAoW8DsPQf4BtMuhcA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*KeY6bAoW8DsPQf4BtMuhcA.jpeg" /></p>

<p>近看真的超大，尤其跟其他殿的一般注连绳比较，大概是其他的 10 倍大。(长度为 14 公尺、重量为 5 公吨、每隔几年会换一次、纯手工制作)</p>

<blockquote>
  <p><em>请记得最大的在「神乐殿」这里，不要跟我一样一开始以为在本殿。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*KZnzwRAX5CdPvprYWwCzTg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*KZnzwRAX5CdPvprYWwCzTg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*L3BUl_V1wCtc9hiRiiGlqw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*L3BUl_V1wCtc9hiRiiGlqw.jpeg" /></p>

<p>环绕走了一圈，人蛮多的，有的需要排很长的队伍参拜。</p>

<p><img src="/assets/aacd5f5cacd1/1*7iUkAuzNjt8d1wHbtiUWhQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*7iUkAuzNjt8d1wHbtiUWhQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*_DCfvI3CSAqMeC0hnZzCHA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*_DCfvI3CSAqMeC0hnZzCHA.jpeg" /></p>

<blockquote>
  <p><em>出云大社的参拜方式跟其他神社也不同：⚠️⚠️⚠️</em></p>
</blockquote>

<blockquote>
  <p><em>是 <a href="https://www.japan.travel/hk/spot/937/" target="_blank"><strong>先鞠躬两次、拍手四次，最后再鞠躬一次</strong></a> 。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*uKMCGxlcrtLXp_wuz0Okqg.webp" alt="" loading="lazy" decoding="async" width="903" height="1218" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDMiIGhlaWdodD0iMTIxOCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*uKMCGxlcrtLXp_wuz0Okqg.png" /></p>

<p>买了神在祭期间限定的御守。 <strong>(仅此一周贩售)</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*Zg626XNieV5uT7JLszzsXQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Zg626XNieV5uT7JLszzsXQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*kGHi22HqIHPB3-vtdGXShg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*kGHi22HqIHPB3-vtdGXShg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*KUh8eckUM7jasbTZFl3nmw.webp" alt="" loading="lazy" decoding="async" width="815" height="1019" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MTUiIGhlaWdodD0iMTAxOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*KUh8eckUM7jasbTZFl3nmw.png" /></p>

<p>参拜完后拿了一本印章搜集簿，盖出云大社纪念章。</p>

<p><img src="/assets/aacd5f5cacd1/1*M2zO2XrTYc941f8q6n439A.webp" alt="出云神在月神在社巡拜五个神大社位置。" loading="lazy" decoding="async" width="1200" height="569" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjU2OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*M2zO2XrTYc941f8q6n439A.png" /></p>

<p><a href="https://www.google.com/maps/d/u/0/edit?mid=1InF3hfsLjC7uW8T2J2ojcXJ_Ej3Eo0k&amp;usp=sharing" target="_blank">出云神在月神在社巡拜五个神大社位置。</a></p>

<p>因时间有限出云其他神社就没去参拜了，没有自驾感觉也很难搜集。</p>

<h4 id="-1245-徒步前往-稻佐之滨-稻佐海滩-稲佐の浜">~= 12:45 徒步前往 稻佐之滨 稻佐海滩 稲佐の浜</h4>

<p><img src="/assets/aacd5f5cacd1/1*tp8izFV2pcWAkHrOxguusw.webp" alt="" loading="lazy" decoding="async" width="960" height="235" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjAiIGhlaWdodD0iMjM1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*tp8izFV2pcWAkHrOxguusw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*-hHa8tNAXHA8hkuI3ySAVA.webp" alt="" loading="lazy" decoding="async" width="953" height="1245" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTMiIGhlaWdodD0iMTI0NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*-hHa8tNAXHA8hkuI3ySAVA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Yj37xFyP1gByfLvNdDTOtA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Yj37xFyP1gByfLvNdDTOtA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*RQmCSnIsPBVcJW1r9nSS3w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*RQmCSnIsPBVcJW1r9nSS3w.jpeg" /></p>

<p>公车班次太少只能用走的去，大约要 15 分钟，途中会经过出云阿国之墓，一路走到底就是稻佐之滨了。</p>

<blockquote>
  <p><strong><em>稻佐之滨：</em></strong></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*YRUdkflWxYERcA62-AQ2Eg.webp" alt="来源：岛根旅游官网" loading="lazy" decoding="async" width="1200" height="1015" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwMTUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*YRUdkflWxYERcA62-AQ2Eg.png" /></p>

<p><a href="https://www.kankou-shimane.com/zh-tw/destinations/991" target="_blank">来源：岛根旅游官网</a></p>

<blockquote>
  <p><em>日本神话渊源深厚的景点，图中的小岛叫弁天岛，岛上有一座小祠堂。</em></p>
</blockquote>

<blockquote>
  <p><a href="https://www.kankou-shimane.com/zh-tw/destinations/991" target="_blank"><em>日本百大海滩，「日没圣地出云」地标、夕阳从弁天岛背后落入海中的景色十分美丽，并获登录为日本遗产、也是神迎仪式的举办地点，在此恭迎日本全国神祇。</em></a></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*PIyVVCAMngDrgpErhjGRMw.webp" alt="" loading="lazy" decoding="async" width="958" height="1245" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTgiIGhlaWdodD0iMTI0NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*PIyVVCAMngDrgpErhjGRMw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*lYRW_DUWWfI1aDJVkBtphA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*lYRW_DUWWfI1aDJVkBtphA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*tI4HMhJCNhlYlHKkFIJm9w.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*tI4HMhJCNhlYlHKkFIJm9w.jpeg" /></p>

<p>因为到访时间有限，无法待到夕阳，逛了一下就折返离开了。</p>

<blockquote>
  <p><strong><em>回来台湾滑到 IG，才知道这边有 <a href="https://www.japaholic.com/tw/article/detail/887878-%E4%BE%86%E5%B3%B6%E6%A0%B9%E7%B8%A3%E5%87%BA%E9%9B%B2%E5%A4%A7%E7%A4%BE%E6%B1%82%E5%BA%87%E8%AD%B7%E8%A6%81%E6%8C%96%E7%A0%82%EF%BC%9F%E7%A8%BB%E4%BD%90%E4%B9%8B%E6%BF%B1%E5%8F%96%E7%A5%9E%E7%A0%82%E6%B1%82%E5%BE%A1%E5%AE%88%E6%95%99%E5%AD%B8" target="_blank">砂御守可以求</a> ：</em></strong></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*9XZ8oaxmYdrNU3I68EgTnw.webp" alt="https://www.instagram.com/reel/CynStXPyZAX/" loading="lazy" decoding="async" width="696" height="620" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2OTYiIGhlaWdodD0iNjIwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*9XZ8oaxmYdrNU3I68EgTnw.png" /></p>

<p><a href="https://www.instagram.com/reel/CynStXPyZAX/?utm_source=ig_web_copy_link" target="_blank">https://www.instagram.com/reel/CynStXPyZAX/</a></p>

<p>走回出云大社公车站准备搭乘公车回到 JR 出云站。</p>

<p><img src="/assets/aacd5f5cacd1/1*AqsQ2S3q61tJaq7k6fgdIA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*AqsQ2S3q61tJaq7k6fgdIA.jpeg" /></p>

<p>可以看到来参拜等待进入出云大社停车场的车辆绵延不绝。</p>

<p><img src="/assets/aacd5f5cacd1/1*kL0wZHJiMcqSCE3ChzTpNQ.webp" alt="" loading="lazy" decoding="async" width="759" height="415" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NTkiIGhlaWdodD0iNDE1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*kL0wZHJiMcqSCE3ChzTpNQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*8aaLagUno9PZTAYUCpX4-Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*8aaLagUno9PZTAYUCpX4-Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*XrDT2aXpUPfF7NT5IEFFNA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*XrDT2aXpUPfF7NT5IEFFNA.jpeg" /></p>

<p>出云大社公车站在纪念品店穿过厕所后面这边，小小的一开始一直很怕等错。</p>

<p><strong>此时约 13:15，要等 13:40 回 JR 出云站的公车，肚子很饿就先去前面纪念品店跟旁边买些东西拿手上简单吃。</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*FYPk9dJKH166TgfMJbKinA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*FYPk9dJKH166TgfMJbKinA.jpeg" /></p>

<p>在记念品店买了几个中二贴纸。</p>

<h4 id="1340-搭乘公车回-jr-出云站"><strong>13:40 搭乘公车回 JR 出云站</strong></h4>

<p><img src="/assets/aacd5f5cacd1/1*gvzJ1xXYnLyxNU_HAlFyNA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*gvzJ1xXYnLyxNU_HAlFyNA.jpeg" /></p>

<blockquote>
  <p><em>回出云的路上遇到一位日本人跟我借行动电源，他的手机完全挂了，正好问他确认一下(顺便练习我为数不多有记的日文)「 <strong>このバスは JR 出云市駅へ行きますか</strong> 」，他回答「 <strong>はい</strong> 」(我也只听得懂 hai)。</em></p>
</blockquote>

<h4 id="-1415-回到-jr-出云市站">~= 14:15 回到 JR 出云市站</h4>

<p>(赶日落前去看宍道湖夕阳，根据资讯 <strong>当日 17:05 太阳下山</strong> )</p>

<p><img src="/assets/aacd5f5cacd1/1*roLGAz0BE_7yrZ7010cJ1w.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*roLGAz0BE_7yrZ7010cJ1w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*JxPpTZphqlQpjXjOlEmRfA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*JxPpTZphqlQpjXjOlEmRfA.jpeg" /></p>

<p>这次就没搭八云号了，搭 14:54 前往米子的普通区间车，照 Google Map 建议从乃木站下车走路到宍道湖夕日观景点。</p>

<p><img src="/assets/aacd5f5cacd1/1*6-c6bp49Is4qZ_IdbiMPCg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*6-c6bp49Is4qZ_IdbiMPCg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*kXIIylCmu_fP_FA6IGQ3_g.webp" alt="" loading="lazy" decoding="async" width="955" height="1210" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NTUiIGhlaWdodD0iMTIxMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*kXIIylCmu_fP_FA6IGQ3_g.png" /></p>

<blockquote>
  <p><em>往松江方向坐左边(A)的话，经过宍道湖就可以直接看到湖景，没错我又坐错边了，坐到靠山的这边。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>这小站的区间车要按按钮才会开门，第一次遇到。</em></strong> <em>⚠️</em></p>
</blockquote>

<h4 id="1535-抵达-乃木站">~=15:35 抵达 乃木站</h4>

<p><img src="/assets/aacd5f5cacd1/1*4CNzZ0RmgGHRVr4NJ899zA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*4CNzZ0RmgGHRVr4NJ899zA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*5mXpmq_hk-UlrD_KF-x1xg.webp" alt="" loading="lazy" decoding="async" width="489" height="583" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0ODkiIGhlaWdodD0iNTgzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*5mXpmq_hk-UlrD_KF-x1xg.png" /></p>

<p>乃木站非常小，没有站务员也没有检票机， <strong>持 JR Pass 搭乘就直接出站就好，不要傻傻的把 JR Pass 留在收票盒子里。⚠️⚠️⚠️</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*hiBPok9dbi9XGQeAPRQ5NQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*hiBPok9dbi9XGQeAPRQ5NQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*E4Yd7PB_MJh1CyuwFJS3zw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*E4Yd7PB_MJh1CyuwFJS3zw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*MAtnP-62r3MY0NSPPSy0yg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*MAtnP-62r3MY0NSPPSy0yg.jpeg" /></p>

<p>从乃木站走有点失策，这边很荒凉没什么人…</p>

<p>不过还好中途有一家 7–11 买了热狗跟炸鸡、饮料边吃边等夕阳。</p>

<h4 id="1600-宍道湖等夕阳">16:00 宍道湖等夕阳</h4>

<p><img src="/assets/aacd5f5cacd1/1*ptNqLKfhX0azm3b5HxfBZg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*ptNqLKfhX0azm3b5HxfBZg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*krl-46lxVoh33r7TcwgpkQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*krl-46lxVoh33r7TcwgpkQ.jpeg" /></p>

<blockquote>
  <p><a href="https://www.kankou-shimane.com/zh-tw/destinations/985" target="_blank"><em>宍道湖日本第七大湖泊、宍道湖夕阳，日本第一夕日。</em></a></p>
</blockquote>

<blockquote>
  <p><em>图中小岛嫁岛神社，有一个白色小鸟居。</em></p>
</blockquote>

<blockquote>
  <p><em>之前打错打成穴道湖。</em></p>
</blockquote>

<p>有一只鹭。</p>

<p><img src="/assets/aacd5f5cacd1/1*ceThDvVZuO8MOR9OXn74ew.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ceThDvVZuO8MOR9OXn74ew.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*tz5i0B2jBta5vBsz-JMWHQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*tz5i0B2jBta5vBsz-JMWHQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*1oDwRChVUUz-EVOv-HAWkw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*1oDwRChVUUz-EVOv-HAWkw.jpeg" /></p>

<p>往上走会到岛根县立美术馆，那边比较热闹也有咖啡店；但是阶梯平台这边景色角度比较好。</p>

<h4 id="1645-夕阳西下">16:45 夕阳西下</h4>

<p><img src="/assets/aacd5f5cacd1/1*rmwJe1rnyjhQkJ9erx7q_w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*rmwJe1rnyjhQkJ9erx7q_w.jpeg" /></p>

<p>本来没什么感觉，但接近夕日的时候开始体会到第一夕阳的魅力，刚刚的鹭也很配合地融入景色。</p>

<p><img src="/assets/aacd5f5cacd1/1*CdDLOmzP80ovaY94HDD3Wg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*CdDLOmzP80ovaY94HDD3Wg.jpeg" /></p>

<p>夕阳接近地平线后时间用肉眼可见的速度在消逝，每一分每一秒太阳都在下降。</p>

<p><img src="/assets/aacd5f5cacd1/1*pT7mh8XcC_Xt1_BO61SbfQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*pT7mh8XcC_Xt1_BO61SbfQ.jpeg" /></p>

<p>很快地 17:01 就已经看不到太阳了。</p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/K-xDmVjqG9g" title="20241113 宍道湖夕日" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<blockquote>
  <p><strong><em>真的很美、很疗愈。</em></strong></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*OG9M3KjHgChA0KY-MyBQPA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*OG9M3KjHgChA0KY-MyBQPA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*fzAcAYv8VNf8TjnrqwuqSg.webp" alt="" loading="lazy" decoding="async" width="923" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*fzAcAYv8VNf8TjnrqwuqSg.png" /></p>

<p>最后再环顾一下 <a href="https://maps.app.goo.gl/LRQAMZNht9km1DFm6" target="_blank">观夕日阶梯平台</a> 一同看夕阳的人们。</p>

<p><img src="/assets/aacd5f5cacd1/1*sV6sLyOiVzxv0W_K2i8SOQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*sV6sLyOiVzxv0W_K2i8SOQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*VaZo5Kl6x-oLJOs9Id3pYg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*VaZo5Kl6x-oLJOs9Id3pYg.jpeg" /></p>

<p>日落之后转身等公车准备回松江了。</p>

<h4 id="夕阳指数">夕阳指数</h4>

<p><img src="/assets/aacd5f5cacd1/1*gWAukxe8ynZEUN6Yr3-WAg.webp" alt="夕阳指数可参考岛根旅游网站" loading="lazy" decoding="async" width="1035" height="902" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDM1IiBoZWlnaHQ9IjkwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*gWAukxe8ynZEUN6Yr3-WAg.png" /></p>

<p><a href="https://tw.visit-matsue.com/sunset" target="_blank">夕阳指数可参考岛根旅游网站</a></p>

<h4 id="宍道湖游览船">宍道湖游览船</h4>

<p><img src="/assets/aacd5f5cacd1/1*owwW5fWHIBKb0PQU_gMqVg.webp" alt="&lt;https://hakuchougo.jp/timetable/&gt;" loading="lazy" decoding="async" width="1136" height="834" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTM2IiBoZWlnaHQ9IjgzNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*owwW5fWHIBKb0PQU_gMqVg.png" /></p>

<p><a href="https://hakuchougo.jp/timetable/" target="_blank">https://hakuchougo.jp/timetable/</a></p>

<p><a href="https://www.kankou-shimane.com/zh-tw/destinations/1086" target="_blank">宍道湖这边是有游览船的</a> ，可以在接近夕阳的时候搭乘，从船上欣赏夕阳；如果下次再来会想搭搭看。</p>

<p><img src="/assets/aacd5f5cacd1/1*RGoFqjg8YVZwTzpINu4PCQ.webp" alt="" loading="lazy" decoding="async" width="554" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*RGoFqjg8YVZwTzpINu4PCQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*nt2iPompX1qAecOKd_C7hA.webp" alt="" loading="lazy" decoding="async" width="554" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*nt2iPompX1qAecOKd_C7hA.jpeg" /></p>

<blockquote>
  <p><em>可以直接使用 买 JR Pass 送的 <a href="https://www.kkday.com/zh-tw/product/20307-jr-sanin-okayama-area-pass?cid=19365" target="_blank"><strong>山阴山阳地区PASS周游3日券</strong></a> <strong>免费搭乘，现省 1,800 日圆。</strong></em></p>
</blockquote>

<h4 id="1800-回到松江站饭店">18:00 回到松江站、饭店</h4>

<h4 id="在松江站一楼伴手礼店买一些伴手礼">在松江站一楼伴手礼店买一些伴手礼</h4>

<p>想说山阴这边比较特别就在这买伴手礼吧。</p>

<p><img src="/assets/aacd5f5cacd1/1*gEdRChjcIYrXT_A8f6viyw.webp" alt="" loading="lazy" decoding="async" width="1144" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTQ0IiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*gEdRChjcIYrXT_A8f6viyw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*fQj5GAdIRZ8uKKofUerGSw.webp" alt="" loading="lazy" decoding="async" width="1400" height="995" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*fQj5GAdIRZ8uKKofUerGSw.png" /></p>

<p>比较特别的是牛骨汤拉面，一般是豚骨，买了一盒回台湾品尝。</p>

<p><img src="/assets/aacd5f5cacd1/1*n7-mvNNxKfjHJ7eNusg_Dg.webp" alt="" loading="lazy" decoding="async" width="1200" height="801" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*n7-mvNNxKfjHJ7eNusg_Dg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*vqDE5sO1mYFkzrYP2WNsZg.webp" alt="" loading="lazy" decoding="async" width="1400" height="937" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjkzNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*vqDE5sO1mYFkzrYP2WNsZg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*P175dGuAEKQkW-rvGbIIeg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*P175dGuAEKQkW-rvGbIIeg.jpeg" /></p>

<p>买了两大盒饼干(适合分同事)回来分同事，甜的普通但是是出云大社参拜纪念，咸的海鲜煎饼饼干我觉得很好吃！</p>

<h4 id="回饭店">回饭店</h4>

<p><img src="/assets/aacd5f5cacd1/1*kmBiT9EX6g-d743wStYgxQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*kmBiT9EX6g-d743wStYgxQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*9NE5tv23D6k51TvDFNEypw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*9NE5tv23D6k51TvDFNEypw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*MAHLZoAXHY9TYQO4fO8OEw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*MAHLZoAXHY9TYQO4fO8OEw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*VkEob5Q4_DKkVV14e67bQA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*VkEob5Q4_DKkVV14e67bQA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*e3EL2ltwD0nNVb2TbJzonQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*e3EL2ltwD0nNVb2TbJzonQ.jpeg" /></p>

<p>本栋这边没有电梯，订到的是 2 号馆，可以从本栋大厅穿过天桥到 2 号馆，2 号馆 2 楼这边有交谊厅微波炉、洗衣房、贩卖机。</p>

<blockquote>
  <p><em>2 号馆这边体感没有很安全，电梯没有门禁、 <a href="https://www.cubic-room.jp/en/" target="_blank">1, 2 楼是胶囊旅馆</a> 感觉出入比较复杂、离本馆大厅又有距离，因此入住后自己用行李箱把门堵好，怕有怪人闯进来。</em></p>
</blockquote>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/NLHi7arAioA" title="Youtube" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p><img src="/assets/aacd5f5cacd1/1*jXAp31kbI-h2r6EC9p3GTg.webp" alt="" loading="lazy" decoding="async" width="1200" height="920" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkyMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*jXAp31kbI-h2r6EC9p3GTg.png" /></p>

<p>大厅可以拿免费的面膜、咖啡、茶包。</p>

<h4 id="觅食">觅食</h4>

<p><img src="/assets/aacd5f5cacd1/1*bXI0YIH7eaO7vZj8MaAfDA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*bXI0YIH7eaO7vZj8MaAfDA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*O6V7aJeRtLcN5NWwYYtEUw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*O6V7aJeRtLcN5NWwYYtEUw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*rNzPDu9gW2s89oW0oqxWSA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*rNzPDu9gW2s89oW0oqxWSA.jpeg" /></p>

<p>Check-in 后去外面觅食，外面蛮冷的也很暗、冷清，速速去车站周围的餐厅外带便当跟去超商买些吃的喝的就回饭店了。</p>

<p><img src="/assets/aacd5f5cacd1/1*FaaPod-j1hdncbRKhnNUOQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*FaaPod-j1hdncbRKhnNUOQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*UAYwYj0cNQZJsC99V7wq8A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*UAYwYj0cNQZJsC99V7wq8A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Oubxpe7aZ2GPBXI92NEMuQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Oubxpe7aZ2GPBXI92NEMuQ.jpeg" /></p>

<p>牛舌便当好吃，超商买的水蜜桃气泡酒也好喝。</p>

<blockquote>
  <p><em>晚安松江。</em></p>
</blockquote>

<p><strong>还有买几乎每天一样的隔日早餐组合…</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*YTezWlFUnTYd6qv1J-yjTw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*YTezWlFUnTYd6qv1J-yjTw.jpeg" /></p>

<p>全家的这个果肉果汁每次来日本必喝！</p>

<h4 id="松江-宍道湖-24-小时直播">松江 宍道湖 24 小时直播：</h4>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/QYIjp0flsdQ" title="【LIVE】松江・宍道湖ライブカメラ" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>无意间找到的 Youtube 频道，可以看到宍道湖天气景色。</p>

<h3 id="day-3-1114-周四-松江堀川游览船松江城足立美术馆">Day 3 (11/14 周四) 松江堀川游览船、松江城、足立美术馆</h3>

<p>一早先把行李寄放在饭店，到松江公车站搭公车去松江城游船。</p>

<p><img src="/assets/aacd5f5cacd1/1*6Urhj-Bh4CXFgweozc99fQ.webp" alt="" loading="lazy" decoding="async" width="928" height="1183" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjgiIGhlaWdodD0iMTE4MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*6Urhj-Bh4CXFgweozc99fQ.png" /></p>

<p>Google Map 看不出月台，只能现场看，2 号月台这边的车可以到松江城。</p>

<p><img src="/assets/aacd5f5cacd1/1*xXKGKy95X00KjnN50FBzvw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*xXKGKy95X00KjnN50FBzvw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*gdwD77FXsNcNeaKz7NlXBQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*gdwD77FXsNcNeaKz7NlXBQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*4i5NFX226vWGW4yTEqOqIw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*4i5NFX226vWGW4yTEqOqIw.jpeg" /></p>

<p>在县民会馆前下车，一路往松江城走，停车场这边就能看到「堀川游览船」乘船场。</p>

<h4 id="启用买-jr-pass-山阴山阳地区pass周游3日券-免费搭乘-堀川游览船">启用买 JR Pass <a href="https://www.kkday.com/zh-tw/product/20307-jr-sanin-okayama-area-pass?cid=19365" target="_blank"><strong>山阴山阳地区PASS周游3日券</strong></a> <strong>免费搭乘</strong> 堀川游览船</h4>

<p><img src="/assets/aacd5f5cacd1/1*NKAYef5qS_1KVVW7sx2BKg.webp" alt="" loading="lazy" decoding="async" width="554" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*NKAYef5qS_1KVVW7sx2BKg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ksm-qt0AJ9qWES0k9HQ8-g.webp" alt="" loading="lazy" decoding="async" width="843" height="828" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NDMiIGhlaWdodD0iODI4Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*ksm-qt0AJ9qWES0k9HQ8-g.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*dBYTcpDfIH02XoGUtviyTQ.webp" alt="" loading="lazy" decoding="async" width="583" height="1261" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1ODMiIGhlaWdodD0iMTI2MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*dBYTcpDfIH02XoGUtviyTQ.png" /></p>

<ol>
  <li>
    <p>下载 <a href="https://apps.apple.com/tw/app/discover-another-japan/id1530307213" target="_blank">Discover Another Japan App</a></p>
  </li>
  <li>
    <p>复制凭证信中的序号</p>
  </li>
  <li>
    <p>打开 App 选择「输入」贴上序号按下「有效化」</p>
  </li>
</ol>

<p><img src="/assets/aacd5f5cacd1/1*bXVG4mS9rEj5I2nV8hUpqQ.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*bXVG4mS9rEj5I2nV8hUpqQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*6s5mwpiKNIIC3bNIw48qjw.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*6s5mwpiKNIIC3bNIw48qjw.jpeg" /></p>

<p>切换到「使用」填写健康问券，填完会出现 QR Code 相机；扫描店家提供的 QR Code 把结果给他看即完成兑换。</p>

<p>也可点「目标内容」查看可兑换项目。</p>

<blockquote>
  <p><strong><em>实测计算时间是从第一次兑换目标开始</em></strong> <em>，不是输入序号有效化开始(我是 11/13 输入的)。</em></p>
</blockquote>

<p><strong>帮大家整理几个热门可使用地点：</strong></p>

<ul>
  <li>
    <p>宍道湖游览船，原价 1,800 日圆</p>
  </li>
  <li>
    <p>松江城游船，原价 1600 日圆</p>
  </li>
  <li>
    <p>足立美术馆，原价 2300 日圆</p>
  </li>
  <li>
    <p>松江城，原价 680 日圆</p>
  </li>
  <li>
    <p>鸟取沙丘美术馆，原价 800 日圆</p>
  </li>
  <li>
    <p>通天阁，原价 800 日圆</p>
  </li>
  <li>
    <p>冈山后乐园，原价 410 日圆</p>
  </li>
</ul>

<p>真的很划算，光上面这些加总就可以省 8,390 日圆，已经是整个 JR Pass 金额的一半了。</p>

<h4 id="0915-搭乘松江游览船">09:15 搭乘松江游览船</h4>

<p><img src="/assets/aacd5f5cacd1/1*yTUoyuDBmxnZi7Z-LW5scg.webp" alt="" loading="lazy" decoding="async" width="943" height="1191" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDMiIGhlaWdodD0iMTE5MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*yTUoyuDBmxnZi7Z-LW5scg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*D0KiYKloofkru6tcupBTWw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*D0KiYKloofkru6tcupBTWw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*0xbwCSI0IA7-pvoRwIhPVQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="852" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*0xbwCSI0IA7-pvoRwIhPVQ.png" /></p>

<p>直接用 <a href="https://www.kkday.com/zh-tw/product/20307-jr-sanin-okayama-area-pass?cid=19365" target="_blank">周游3日券</a> 免费兑换搭乘。</p>

<ul>
  <li>
    <p>今年比较温暖还没有换暖桌船</p>
  </li>
  <li>
    <p>会有四个过桥点需要下降船身，要小心手头不要夹到</p>
  </li>
  <li>
    <p>全程约 50 分钟</p>
  </li>
  <li>
    <p><strong>上船要脱鞋</strong> ⚠️</p>
  </li>
  <li>
    <p><strong>面向船夫的右边那排才能直接拍到靠松江城的景，离船夫越远离船头越近(=刚进去的位子第一排)</strong> ⚠️ 如下图</p>
  </li>
</ul>

<p><img src="/assets/aacd5f5cacd1/1*NNpCqdpowVo3qcGUB2MtIA.webp" alt="" loading="lazy" decoding="async" width="963" height="1194" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjMiIGhlaWdodD0iMTE5NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*NNpCqdpowVo3qcGUB2MtIA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*mycuhLZJdCqQCLjmdKBVuA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*mycuhLZJdCqQCLjmdKBVuA.jpeg" /></p>

<p>上船啰。</p>

<p><img src="/assets/aacd5f5cacd1/1*OaajDPfbGMPtNGE45b0D7w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*OaajDPfbGMPtNGE45b0D7w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*pnqFPC8vK3sPGShIQY8vwg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*pnqFPC8vK3sPGShIQY8vwg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*_zTAi1v6rP1ObrmmGAyivw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*_zTAi1v6rP1ObrmmGAyivw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*LqE3q-z47EBROFnfkCzONA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*LqE3q-z47EBROFnfkCzONA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*7hUFpDj5m7TYkRzY_QhrOA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*7hUFpDj5m7TYkRzY_QhrOA.jpeg" /></p>

<p>可能是因为枫叶季还没开始，所以没什么人，同船的只有四位，很空。</p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/1dP7cQcqkW8" title="松江堀川游览船过桥" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>有四座桥过桥时会下降船身，要稍微弯腰趴著通过。</p>

<p><img src="/assets/aacd5f5cacd1/1*f71WOF93FIEGnY_AFJ94OQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*f71WOF93FIEGnY_AFJ94OQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*CgP34NWi1KsKk8je60g2Aw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*CgP34NWi1KsKk8je60g2Aw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*mqX7jwzT8WnOhg9hwZKZPA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*mqX7jwzT8WnOhg9hwZKZPA.jpeg" /></p>

<p>一路吹风游河很惬意，船夫也会一路介绍四周景点历史(虽然我只听得懂左边hidari 右边 migi…)。</p>

<p><img src="/assets/aacd5f5cacd1/1*vY1xPWmFrFq7m4ErBFYRAQ.webp" alt="&lt;https://youtube.com/shorts/KA9xKZV16bk&gt;" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*vY1xPWmFrFq7m4ErBFYRAQ.jpeg" /></p>

<p><a href="https://youtube.com/shorts/KA9xKZV16bk" target="_blank">https://youtube.com/shorts/KA9xKZV16bk</a></p>

<p>最后快到回程的地方会有一个松江城拍摄点，可以从这边拍松江城远景。</p>

<p>游船结束大约 10:00。</p>

<h4 id="1015-松江城">10:15 松江城</h4>

<p><img src="/assets/aacd5f5cacd1/1*ceaDL6BSPF0gB-VCXOw3fA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*ceaDL6BSPF0gB-VCXOw3fA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*KTDVdtsyThXmXZC0hlXqPQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*KTDVdtsyThXmXZC0hlXqPQ.jpeg" /></p>

<p>游船回来走回来的方向，另一边就是松江城入口，往上走就会到松江城。</p>

<p><img src="/assets/aacd5f5cacd1/1*1zbsEA6XAM1EhL6AoGwyng.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*1zbsEA6XAM1EhL6AoGwyng.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*PNjiGAlCMJvOWEgPCi6Vrg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*PNjiGAlCMJvOWEgPCi6Vrg.jpeg" /></p>

<p>途经松江神社，来到松江城。</p>

<p><img src="/assets/aacd5f5cacd1/1*rrtm3CezY7W1ZWPIbj5p-A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*rrtm3CezY7W1ZWPIbj5p-A.jpeg" /></p>

<p>因为时间有限想继续前往足立美术馆，就没有上去了。</p>

<p><img src="/assets/aacd5f5cacd1/1*9JAHlSW6QmLNzAWDU0-THA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*9JAHlSW6QmLNzAWDU0-THA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*XmGdiTwZJk7pWY95CCZkrQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*XmGdiTwZJk7pWY95CCZkrQ.jpeg" /></p>

<p>回来到来的时候的反方向县民会馆前公车站等车回去。</p>

<h4 id="1030-回饭店拿行李">~=10:30 回饭店拿行李</h4>

<p><img src="/assets/aacd5f5cacd1/1*z5o-twtGfhsaje84wIlhlA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*z5o-twtGfhsaje84wIlhlA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*cG2vaqw6VB1jXg2Eg78Jnw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*cG2vaqw6VB1jXg2Eg78Jnw.jpeg" /></p>

<p>大约 10:30 回到松江站，回饭店拿行李。</p>

<blockquote>
  <p><strong><em>在这边等红绿灯的时候差点被煞车失灵的脚踏车撞，还好我站的比较后面没撞到我，出门在外还是要小心。</em></strong> <em>⚠️⚠️⚠️</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*J13Zlai29b-V7OR6-NSDuw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*J13Zlai29b-V7OR6-NSDuw.jpeg" /></p>

<p>到车站后同样去划位 Yakumo 14 指定席前往 安来(安来) (足立美术馆)。</p>

<h4 id="1103-前往安来">11:03 前往安来</h4>

<p><img src="/assets/aacd5f5cacd1/1*-eYBNFeXAXeaT3i73YPeRg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*-eYBNFeXAXeaT3i73YPeRg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*5JTFZNrBFGhSKo0M54Rwrg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*5JTFZNrBFGhSKo0M54Rwrg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*49TFnjK8AnLDrYCA-naQtw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*49TFnjK8AnLDrYCA-naQtw.jpeg" /></p>

<p>11:03 才发车，在车站附近买一些吃的在车上果腹。</p>

<blockquote>
  <p><strong><em>再见松江。</em></strong></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*g-Sewe5VgTJrqioiNt32mw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*g-Sewe5VgTJrqioiNt32mw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*gCedzvZrVNY7_hfPkBBtEg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*gCedzvZrVNY7_hfPkBBtEg.jpeg" /></p>

<p>松饼跟盐味烤鸡肉都很好吃。</p>

<h4 id="1112-抵达安来站">11:12 抵达安来站</h4>

<p><img src="/assets/aacd5f5cacd1/1*6VLLQilNbIvambZZ2FqlTg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*6VLLQilNbIvambZZ2FqlTg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*fzfeXO1wERdPoGfoSeImew.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*fzfeXO1wERdPoGfoSeImew.jpeg" /></p>

<p>到安来站先别急著出站，找到观光案内所可以寄放大型行李。
(车站外有自动置物柜但多半都是满的)</p>

<h4 id="1130-搭乘接驳车前往足立美术馆">11:30 搭乘接驳车前往足立美术馆</h4>

<p><img src="/assets/aacd5f5cacd1/1*BHs4S2OQTB2L5GC5beFFCQ.webp" alt="" loading="lazy" decoding="async" width="894" height="942" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4OTQiIGhlaWdodD0iOTQyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*BHs4S2OQTB2L5GC5beFFCQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Ng6cROhDXC8dFa-jX9Rr9g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Ng6cROhDXC8dFa-jX9Rr9g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ZGpQ1IE2Rs3sdSVHF4FKKw.webp" alt="最新时刻表请参考官网" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*ZGpQ1IE2Rs3sdSVHF4FKKw.jpeg" /></p>

<p><a href="https://www.adachi-museum.or.jp/en/shuttle-bus" target="_blank">最新时刻表请参考官网</a></p>

<p>行李安放好之后就去搭乘往足立美术馆的接驳车(免费、排队依序上车)，早上来的时候没什么人。</p>

<p>穿过乡间小巷大约 20 分钟抵达足立美术馆。</p>

<p><img src="/assets/aacd5f5cacd1/1*yWU0ZbZ-BplOe9PpE7gLKw.webp" alt="" loading="lazy" decoding="async" width="947" height="1221" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDciIGhlaWdodD0iMTIyMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*yWU0ZbZ-BplOe9PpE7gLKw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*EzIv3NLDJE4hVA0BgtIQoQ.webp" alt="" loading="lazy" decoding="async" width="934" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzQiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*EzIv3NLDJE4hVA0BgtIQoQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*dKhsS-vXIfeBwam-mmARTQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*dKhsS-vXIfeBwam-mmARTQ.jpeg" /></p>

<p>下车后一路往前走就是足立美术馆入口。</p>

<p><img src="/assets/aacd5f5cacd1/1*pNf0-7iKNi1tn50chXc1-w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*pNf0-7iKNi1tn50chXc1-w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ROq_9K0FNF31iLA7f-A5Ng.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ROq_9K0FNF31iLA7f-A5Ng.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Q_wkpK8esb5iKNWHxOf4vg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Q_wkpK8esb5iKNWHxOf4vg.jpeg" /></p>

<p>一样直接使用 <a href="https://www.kkday.com/zh-tw/product/20307-jr-sanin-okayama-area-pass?cid=19365" target="_blank">周游3日券</a> 免费兑换入场。</p>

<p>第一件事是在入口前柜台依照自己行程安排领取对应时间的「接驳车整理券」，一人一张；在时间到的时候回到下车的地方凭券搭乘回安来站。</p>

<p><img src="/assets/aacd5f5cacd1/1*mxWMQacl1bNSfdRo8X9JQA.webp" alt="" loading="lazy" decoding="async" width="923" height="1185" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjMiIGhlaWdodD0iMTE4NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*mxWMQacl1bNSfdRo8X9JQA.png" /></p>

<p>我的行程预计是搭乘 14:46 从安来出发前往鸟取的 JR，请注意 <strong>往鸟取的班次没有很多⚠️。</strong></p>

<blockquote>
  <p><strong><em>很重要！很重要！很重要！一定要拿，不然不保证有位子能上车。⚠️⚠️⚠️</em></strong></p>
</blockquote>

<blockquote>
  <p><em>我就是那个不知道要拿，本来要搭 13:00 的，结果发现要拿券才回去拿，改搭 13:35 的车回安来。</em></p>
</blockquote>

<blockquote>
  <p><em>还好我时间抓得很宽松。</em></p>
</blockquote>

<h4 id="足立美术馆--日本第一庭园">足立美术馆 — 日本第一庭园</h4>

<p><img src="/assets/aacd5f5cacd1/1*P4YjMlS0gulw8Z9Jr4a2mA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*P4YjMlS0gulw8Z9Jr4a2mA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*cIY8_Z-eP8OSvK-NBQ8Rtw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*cIY8_Z-eP8OSvK-NBQ8Rtw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*bBghMwu_IRFmgbT7fW3EXw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*bBghMwu_IRFmgbT7fW3EXw.jpeg" /></p>

<p>可以静静的坐在这边享受庭院美景。</p>

<p><img src="/assets/aacd5f5cacd1/1*l_vmr2dgh14H2GQ3LV3t4Q.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*l_vmr2dgh14H2GQ3LV3t4Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*U6yP0ur5hbX5RPLBCUJhOA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*U6yP0ur5hbX5RPLBCUJhOA.jpeg" /></p>

<p>除了庭院，足立美术馆核心还是馆藏的诸多艺术品，禁止拍照，一路跟著动线观赏艺术品，跟庭院。</p>

<p><img src="/assets/aacd5f5cacd1/1*wBCdJ9HmdU55eywoII8eZQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*wBCdJ9HmdU55eywoII8eZQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ftl17PV6R9Xvj6u_W2uTeg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ftl17PV6R9Xvj6u_W2uTeg.jpeg" /></p>

<p>外面可看到部分的庭院景观，可以感觉得到花费了很大的时间人力在维护这个造景。</p>

<p><img src="/assets/aacd5f5cacd1/1*jNTMLjG2TDFOdTE4Sl72DA.webp" alt="" loading="lazy" decoding="async" width="919" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MTkiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*jNTMLjG2TDFOdTE4Sl72DA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*tcvXnD0yZU2J36q-7DFPPw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*tcvXnD0yZU2J36q-7DFPPw.jpeg" /></p>

<p>里面有两家吃茶室，除了甜点咖啡也有卖熟食；不妨在此驻足休息吃个东西看看景色。</p>

<blockquote>
  <p><em>因为我一个人来就没有特别停留吃东西了。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*r-y6_oqYcCr7gHBkO2htAw.webp" alt="" loading="lazy" decoding="async" width="1200" height="840" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*r-y6_oqYcCr7gHBkO2htAw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*P2G-cBOftGDBhXjRe93JmA.webp" alt="" loading="lazy" decoding="async" width="1200" height="865" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*P2G-cBOftGDBhXjRe93JmA.png" /></p>

<p>在纪念品店买了幅看到的馆藏画作 <a href="https://artsandculture.google.com/asset/mt-fuji/gQGjCiwQOJy4bg?hl=zh-TW" target="_blank">横山大观《神国日本》(Yokoyama Taikan “Mt.Fuji”) 画作</a> 的纸板复制画当纪念品。</p>

<h4 id="1230-在外面商店街晃晃">12:30 在外面商店街晃晃</h4>

<p>外面有一条小商店街，因为时间还很早就先在这乱晃。</p>

<p><img src="/assets/aacd5f5cacd1/1*F0w3N5TCBhJnHxDTPKvIlw.webp" alt="" loading="lazy" decoding="async" width="942" height="1182" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDIiIGhlaWdodD0iMTE4MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*F0w3N5TCBhJnHxDTPKvIlw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*vUCovPlzvYxsnyfTqahbdg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*vUCovPlzvYxsnyfTqahbdg.jpeg" /></p>

<blockquote>
  <p><em>这个岛根和牛米汉堡 <strong>蛮难吃的</strong> ，就是微波米汉堡饭黏黏的，我吃到的中间和牛还没完全加热冰冰的…</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*04ZXVwciPcQrHZaCi_mP_A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*04ZXVwciPcQrHZaCi_mP_A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*IIi5iKRgO4Z3X-WVGXSAlg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*IIi5iKRgO4Z3X-WVGXSAlg.jpeg" /></p>

<p>如同前述，我一开始不知道要拿整理券，傻傻的就去等车，等到 13:00 发现不能上车，才去拿 13:35 的整理券。</p>

<p><img src="/assets/aacd5f5cacd1/1*_qEUfX9ZPhw4e7GoCkd1mA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*_qEUfX9ZPhw4e7GoCkd1mA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*CYcgaIGY63OyZ8AVqxp6zQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*CYcgaIGY63OyZ8AVqxp6zQ.jpeg" /></p>

<p>拿完整理券又再入场(可再入场)坐在一开始的室内观景区域放空看景等车。</p>

<h4 id="1355-回到安来站">13:55 回到安来站</h4>

<p><img src="/assets/aacd5f5cacd1/1*32LdARFSPE8UZX5Ncpp__Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*32LdARFSPE8UZX5Ncpp__Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*wiaNCbcWfMAr83dH_VyhVg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*wiaNCbcWfMAr83dH_VyhVg.jpeg" /></p>

<p>回安来站的路上有看到很红的枫叶。</p>

<p><img src="/assets/aacd5f5cacd1/1*hmDP79nt4683WCrugG3F6A.webp" alt="" loading="lazy" decoding="async" width="1400" height="989" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*hmDP79nt4683WCrugG3F6A.png" /></p>

<p>这时间前往足立美术馆的人反而比较多。</p>

<p><img src="/assets/aacd5f5cacd1/1*pNI1d_ksSnexO0WKcSSLww.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*pNI1d_ksSnexO0WKcSSLww.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*9O3RZpisQ42q9L5HBVfK2w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*9O3RZpisQ42q9L5HBVfK2w.jpeg" /></p>

<p>这站没什么人、时间也还很早， <a href="https://www.youtube.com/shorts/oG8xrxEC6mk" target="_blank">趁机录了一段示范如何使用 JR Pass 预约指定席的影片</a> 。</p>

<p><img src="/assets/aacd5f5cacd1/1*09Yg8-nz6BzwsrB4MboUmg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*09Yg8-nz6BzwsrB4MboUmg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*hgL7isSy3JI2ynErDWL-bw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*hgL7isSy3JI2ynErDWL-bw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*xtWvh1YCoprT8eqqP_uxoQ.webp" alt="岛根猫" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*xtWvh1YCoprT8eqqP_uxoQ.jpeg" /></p>

<p><a href="https://www.kankou-shimane.com/shimanekko/zh-TW/" target="_blank">岛根猫</a></p>

<p>在观光案内所乱逛消磨时间。</p>

<p><img src="/assets/aacd5f5cacd1/1*90geto8qdEZ4we55uwzlmw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*90geto8qdEZ4we55uwzlmw.jpeg" /></p>

<p>安来这边的清水寺感觉也是一个赏枫秘境。</p>

<p><img src="/assets/aacd5f5cacd1/1*ekgTftsMdymYawBX5WrRZw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ekgTftsMdymYawBX5WrRZw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*9UPTdrAVmNFfUTae3Z4jbQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*9UPTdrAVmNFfUTae3Z4jbQ.jpeg" /></p>

<h4 id="1446-搭乘特急火车前往鸟取">14:46 搭乘特急火车前往鸟取</h4>

<p><img src="/assets/aacd5f5cacd1/1*9xXAaj9MkAymGU2AgeaMKg.webp" alt="" loading="lazy" decoding="async" width="687" height="1177" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2ODciIGhlaWdodD0iMTE3NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*9xXAaj9MkAymGU2AgeaMKg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*4QAm8AK5zXIGMVeIjRc8sg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*4QAm8AK5zXIGMVeIjRc8sg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*2gCmHxDsPcbPLcngamFmpg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*2gCmHxDsPcbPLcngamFmpg.jpeg" /></p>

<p>车型很古老也只有两节列车(一节自由座、一节指定席)，我的 26 寸行李箱放不上上面的行李层(新的 JR 可以但这车型的太小)，忘记可以走到最后一排放最后一排椅子后面，只能硬塞在自己的位子上。</p>

<p>还好一路隔壁都没人，自由座车厢看起来人比较多，指定席这边大概才坐 6 成而已。</p>

<blockquote>
  <p><em>因为行程安排就没有特别去 鬼太郎车站(境港车站) 跟 柯南车站(由良车站)了。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*STYxvjU_ogrZ2fDlL9Y6ng.webp" alt="来源" loading="lazy" decoding="async" width="894" height="667" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4OTQiIGhlaWdodD0iNjY3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*STYxvjU_ogrZ2fDlL9Y6ng.png" /></p>

<p><a href="https://www.pref.tottori.lg.jp/289054.htm" target="_blank">来源</a></p>

<p><img src="/assets/aacd5f5cacd1/1*hZSjEq5-ijzcPGGte6C40g.webp" alt="来源" loading="lazy" decoding="async" width="875" height="595" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzUiIGhlaWdodD0iNTk1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*hZSjEq5-ijzcPGGte6C40g.png" /></p>

<p><a href="https://www.pref.tottori.lg.jp/289055.htm" target="_blank">来源</a></p>

<blockquote>
  <p><em>有兴趣的朋友可以多安排前往。</em></p>
</blockquote>

<h4 id="1558-抵达-jr-鸟取站">15:58 抵达 JR 鸟取站</h4>

<p><img src="/assets/aacd5f5cacd1/1*oPupIuWiEBmo4l8oYjdXEg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*oPupIuWiEBmo4l8oYjdXEg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*BkBOsOOK3AJtMY4Fh4nWlw.webp" alt="" loading="lazy" decoding="async" width="946" height="1195" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDYiIGhlaWdodD0iMTE5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*BkBOsOOK3AJtMY4Fh4nWlw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*kGq-zyfiHwjuwxWFtSTlnA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*kGq-zyfiHwjuwxWFtSTlnA.jpeg" /></p>

<p>前往今晚的饭店 <a href="https://www.toyoko-inn.com/china/search/detail/00046/" target="_blank"><strong>东横INN 鸟取站南口</strong></a> ，北口也有一间东横 INN 没订到，北口那边才是商店街比较热闹。</p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/d8wVYHG4zkA" title="东横INN 鸟取站南口" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<h4 id="1700-鸟取乱逛">17:00 鸟取乱逛</h4>

<p><img src="/assets/aacd5f5cacd1/1*vHGHHoGQxbgvDqexHR0gLQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*vHGHHoGQxbgvDqexHR0gLQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*k3EiMwp0DAViTzXwjie4pw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*k3EiMwp0DAViTzXwjie4pw.jpeg" /></p>

<p>离吃饭时间还有一小时，先去附近的 AEON 逛逛。</p>

<p><img src="/assets/aacd5f5cacd1/1*4ZSUZ9tpUCmTPjwuSXtUBg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*4ZSUZ9tpUCmTPjwuSXtUBg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*mOuFR0sVsVoQ1RxuPH3YlA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*mOuFR0sVsVoQ1RxuPH3YlA.jpeg" /></p>

<p>约莫快 18:00 一路走到鸟取北口商店街附近觅食，前几天都乱吃，今天想找一间餐厅吃好一点。</p>

<p><img src="/assets/aacd5f5cacd1/1*UPSjd6gbL9TCVXl8qXLPvw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*UPSjd6gbL9TCVXl8qXLPvw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*_Qkjzr6Xf_PV642XoYTcgw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*_Qkjzr6Xf_PV642XoYTcgw.jpeg" /></p>

<p>找了一间在大街上评价也不错的鸟取和牛餐厅 — 「 <a href="https://maps.app.goo.gl/pSZF8bCsiRNJ4aSt6" target="_blank">肉料理 Nick</a> 」品尝看看鸟取和牛，不知道是不是平日关系只有我一个人。</p>

<blockquote>
  <p><em>鸟取和牛虽然没有神户牛、近江牛有名，但鸟取是 <strong>日本和牛文化的发源地</strong> 。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*4fDg5JJ-GGjiV8AVasNE3A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*4fDg5JJ-GGjiV8AVasNE3A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*sI_cXfEuxYrVLS6SUqDArQ.webp" alt="" loading="lazy" decoding="async" width="782" height="1143" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3ODIiIGhlaWdodD0iMTE0MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*sI_cXfEuxYrVLS6SUqDArQ.png" /></p>

<p>我点的是「鸟取和牛ひつまぶし」鸟取和牛三吃饭 3,500 日圆，价格上比神户牛便宜很多。</p>

<p><img src="/assets/aacd5f5cacd1/1*2jNeW3RO6WBh83rZqe0ZNA.webp" alt="" loading="lazy" decoding="async" width="1400" height="998" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*2jNeW3RO6WBh83rZqe0ZNA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*qkqZMeWtQcobrIOS8mrBJw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*qkqZMeWtQcobrIOS8mrBJw.jpeg" /></p>

<p>鸟取和牛很嫩，但是牛味较少，第一吃纯吃和牛没什么味道。</p>

<p><img src="/assets/aacd5f5cacd1/1*jkud_7mVWN_F6ALBWCj14g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*jkud_7mVWN_F6ALBWCj14g.jpeg" /></p>

<p>第二、三吃加上它附的汤变茶泡饭就很好吃。</p>

<h4 id="1830-吃饱回车站饭店">18:30 吃饱回车站、饭店</h4>

<p><img src="/assets/aacd5f5cacd1/1*OyxvrME3X2vnxLFRhB_IwQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*OyxvrME3X2vnxLFRhB_IwQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ZDMJBQeQx2jvWFpFmbhB9g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ZDMJBQeQx2jvWFpFmbhB9g.jpeg" /></p>

<p>顺路先去划隔天到姬路的车票。</p>

<p><img src="/assets/aacd5f5cacd1/1*2v_BIl1Ho5wcJS0WYAuDGg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*2v_BIl1Ho5wcJS0WYAuDGg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*21KCGclvNLUL2WojrkxJMA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*21KCGclvNLUL2WojrkxJMA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*VJNLFfTTyZCRFH0kgSGL5w.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*VJNLFfTTyZCRFH0kgSGL5w.jpeg" /></p>

<p>顺路买宵夜回饭店晚上吃，还有 Y1000 养乐多 1000，这次其实没特别喝也都睡得不错…</p>

<blockquote>
  <p><em>晚安鸟取。</em></p>
</blockquote>

<h3 id="day-4-1115-周五-白兔神社鸟取沙丘姬路">Day 4 (11/15 周五) 白兔神社、鸟取沙丘、姬路</h3>

<p>早上先去白兔神社(姻缘)参拜，回到鸟取站北口往公车总站走，穿过公车大厅到后面 4 号月台等公车。</p>

<p><img src="/assets/aacd5f5cacd1/1*XR70UqceYMl6CmDWivqTaQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*XR70UqceYMl6CmDWivqTaQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*mpW7ne5REM1X5yfOAa5m4A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*mpW7ne5REM1X5yfOAa5m4A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*JzTpCld7REqa-Rqt4UpkgA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*JzTpCld7REqa-Rqt4UpkgA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*KJUGKv9wIKoO7sDwEnTYIw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*KJUGKv9wIKoO7sDwEnTYIw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*z_BfpEdl3Z-O_QW6OfC4SA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*z_BfpEdl3Z-O_QW6OfC4SA.jpeg" /></p>

<p>依照 Google Map 搭乘白兔海岸线鹿野营业所 41 前往 白兔神社前。</p>

<blockquote>
  <p><strong><em>鸟取的公车无法刷电子支付，只能付现金</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>鸟取的公车无法刷电子支付，只能付现金</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>鸟取的公车无法刷电子支付，只能付现金</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>请先提前准备好零钱，或是仟元大钞去司机旁边换零钱。</em></strong> <em>⚠️⚠️⚠️</em></p>
</blockquote>

<blockquote>
  <p><em>车资约日圆 610 元。</em></p>
</blockquote>

<p>或先去鸟取车站买观光一日交通券比较划算。</p>

<p><img src="/assets/aacd5f5cacd1/1*9cUeNishMRW8xDRs7-ri_Q.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*9cUeNishMRW8xDRs7-ri_Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*qHL6pCuXKRfxH86xFFs45g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*qHL6pCuXKRfxH86xFFs45g.jpeg" /></p>

<p>下车前依照萤幕显示金额投币，我们是总站上车的无券所以看第一格前一格的金额付钱。</p>

<h4 id="-0930-抵达白兔神社">~= 09:30 抵达白兔神社</h4>

<p><img src="/assets/aacd5f5cacd1/1*40gg6SkBkYmveH13l0nvXQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*40gg6SkBkYmveH13l0nvXQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*-PFzilV6gkDEpOvbXLbG_A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*-PFzilV6gkDEpOvbXLbG_A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*m33qZ2cJ4FwqBjkb-6IsAg.webp" alt="" loading="lazy" decoding="async" width="938" height="1194" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzgiIGhlaWdodD0iMTE5NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*m33qZ2cJ4FwqBjkb-6IsAg.png" /></p>

<p>下车后往回天桥方向走就是白兔神社入口。</p>

<blockquote>
  <p><em>白兔神社源于「因幡的白兔」传说。传说中，大国主命(出云大社)在帮助受伤的白兔恢复健康后，获得白兔的祝福，成功赢得八上比卖公主的爱情。</em></p>
</blockquote>

<blockquote>
  <p><em>白兔神社，象征良缘与治愈，两座神社也共同承载著祈求幸福与缘结的神圣意义。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*69iTu4F0VaHW07l992wjMA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*69iTu4F0VaHW07l992wjMA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*OFRxkKGCLjl2SPMHKOlgcA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*OFRxkKGCLjl2SPMHKOlgcA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*eUPpPJUou85qulUku9cDVA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*eUPpPJUou85qulUku9cDVA.jpeg" /></p>

<p>走到神社的距离不远但路上有很多兔兔神像，都堆满了姻缘石。</p>

<blockquote>
  <p><em>出云大社也有很多因幡白兔雕像只是我忘了拍。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*RKT2AGgUHkzeHVEP7OlkgA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*RKT2AGgUHkzeHVEP7OlkgA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*1awKOYwzIPQ5BHVD0OgePQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*1awKOYwzIPQ5BHVD0OgePQ.jpeg" /></p>

<p>鸟居上也堆满了姻缘石。</p>

<p><img src="/assets/aacd5f5cacd1/1*6JmuOYncQTNDnamDE8lhoA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*6JmuOYncQTNDnamDE8lhoA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*KCuCyqwlHaza-Kz1r2J2Pw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*KCuCyqwlHaza-Kz1r2J2Pw.jpeg" /></p>

<p>神社整体不大，大约 15–20 分钟就可以参拜完。</p>

<p><img src="/assets/aacd5f5cacd1/1*E5qACETPs0VUTwxrsXGXlg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*E5qACETPs0VUTwxrsXGXlg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*l2_nfwxbvPJW78TGZAQdng.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*l2_nfwxbvPJW78TGZAQdng.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*_mqNm0k5ubWNxOFxlWaIuw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*_mqNm0k5ubWNxOFxlWaIuw.jpeg" /></p>

<p>也花了 500 日圆买了姻缘石去雕像摆放。</p>

<p><img src="/assets/aacd5f5cacd1/1*fvYIjtTDJYlLzG5Zi9eJJg.webp" alt="" loading="lazy" decoding="async" width="1233" height="867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjMzIiBoZWlnaHQ9Ijg2NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*fvYIjtTDJYlLzG5Zi9eJJg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*NFlQA9p4TtNZTg6oEcFi-w.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*NFlQA9p4TtNZTg6oEcFi-w.jpeg" /></p>

<p><strong>我买的因幡之白兔：</strong></p>

<ul>
  <li>
    <p>左边：在出云大社外的礼品店买的</p>
  </li>
  <li>
    <p>右边：在白兔神社买的(有诗签)</p>
  </li>
</ul>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/HbxBcKkfCnk" title="一只兔子为何要招惹一群鲨鱼？经历过两次的死而复生，他竟然迎娶了自己祖先的女儿！大国主神话\\|大国主\\|因幡之白兔\\|根之囯\\|日本神话\\|兰爸爸说故事" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>因幡之白兔跟大国主神的故事。</p>

<h4 id="-0950-白兔神社外观光案内所白兔海滩">~= 09:50 白兔神社外观光案内所、白兔海滩</h4>

<p><img src="/assets/aacd5f5cacd1/1*OElc39nUjmOmxt1b2l_8vQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*OElc39nUjmOmxt1b2l_8vQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*y-ATn5pE43fRSQoNCQKHAA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*y-ATn5pE43fRSQoNCQKHAA.jpeg" /></p>

<p>观光案内所里真的有养一只白色兔兔，也有卖一些吃的跟伴手礼，买了一个面包果腹。</p>

<p><img src="/assets/aacd5f5cacd1/1*HHmrUUqcvXrDsCAvzyOkAw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*HHmrUUqcvXrDsCAvzyOkAw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*bs7k1F-QNASY8qe7v9HFzQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*bs7k1F-QNASY8qe7v9HFzQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ayrC4DXTeXmXI1axNs29CA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ayrC4DXTeXmXI1axNs29CA.jpeg" /></p>

<p>白兔海滩很荒凉。</p>

<p><img src="/assets/aacd5f5cacd1/1*yGwYlF_RqRc9JJ6wMFmjug.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*yGwYlF_RqRc9JJ6wMFmjug.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*rXW71tg5gJziOeVd5X3iRw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*rXW71tg5gJziOeVd5X3iRw.jpeg" /></p>

<p>公车要等到 10:45 才有往鸟取站方向的，觉得比较好的时间是更早来搭更早的车回去节省时间。</p>

<p><img src="/assets/aacd5f5cacd1/1*JfxN2JQq74dWK90Tsor_YQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*JfxN2JQq74dWK90Tsor_YQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*PuL80Noe3RS2fR-rkUF8vg.webp" alt="from: 圣炜" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*PuL80Noe3RS2fR-rkUF8vg.jpeg" /></p>

<p>from: 圣炜</p>

<blockquote>
  <p><strong><em>上车记得拿整理券，上面有编号，下车依照编号对应金额硬币连同整理券一同投入。</em></strong> <em>⚠️</em></p>
</blockquote>

<p>车上遇到一位中国福建来的观光客；他的行程刚好跟我相反，他先去姬路再去岛根；于是互相推荐了一下景点，他推荐姬路可以先去书写山圆教寺然后姬路城可以去图中的摄影点拍照。</p>

<blockquote>
  <p><strong><em>感谢他！最后去了觉得很值得。</em></strong></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*ItWdhOq9YNwojhJt9l1pgA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ItWdhOq9YNwojhJt9l1pgA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ZRMhH7FMc8ypC3jQoBKqkA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ZRMhH7FMc8ypC3jQoBKqkA.jpeg" /></p>

<p>在相生町下车，到对向公车站转搭前往鸟取沙丘方向的公车。</p>

<p><img src="/assets/aacd5f5cacd1/1*3hf1z-tdcV_FVh_wW9JSKw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*3hf1z-tdcV_FVh_wW9JSKw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*UjpATzEo91FX4Ptdxtlb4g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*UjpATzEo91FX4Ptdxtlb4g.jpeg" /></p>

<p>搭到的这班要在沙丘东口下车走上去。</p>

<blockquote>
  <p><em>上车整理券拿到 3 号，下车看萤幕对应 3 号的金额投币，以此为例就是要投 250 日圆。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*b3fTmvHBaj__OiMbjr5BpA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*b3fTmvHBaj__OiMbjr5BpA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*KGIqShdtrpqRYB31M253yQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*KGIqShdtrpqRYB31M253yQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*wiMKI8135q9TNJcrhuWiZQ.webp" alt="我混乱的参观路线。" loading="lazy" decoding="async" width="1200" height="917" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkxNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*wiMKI8135q9TNJcrhuWiZQ.png" /></p>

<p>我混乱的参观路线。</p>

<p>下车后回头岔路依照指标往上经过鸟取沙丘美术馆继续走到鸟取沙丘入口。</p>

<p><img src="/assets/aacd5f5cacd1/1*FOByNsR18dk-tExeF5VPUw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*FOByNsR18dk-tExeF5VPUw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*M1l7figNu-hmgZAbR_xjaw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*M1l7figNu-hmgZAbR_xjaw.jpeg" /></p>

<blockquote>
  <p><em>鸟取沙丘禁止事项， <strong>尤其禁止在沙上作画破坏自然</strong> 。⚠️</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*UCu5KdaTZWThGBgaSompbg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*UCu5KdaTZWThGBgaSompbg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*87V9nbswSrqQfx3JcDcVYQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*87V9nbswSrqQfx3JcDcVYQ.jpeg" /></p>

<p>鸟取沙丘真的有够大，此时天空不作美有点阴雨，但如果是大太阳的话应该会很晒。</p>

<h4 id="1200-抵达鸟取沙丘">~=12:00 抵达鸟取沙丘</h4>

<p>日本第一沙丘。</p>

<p><img src="/assets/aacd5f5cacd1/1*WkiGJSHcUrPZi5h7zSJGYA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*WkiGJSHcUrPZi5h7zSJGYA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*lwqbSawD2wG3wO1MyAf2Bg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*lwqbSawD2wG3wO1MyAf2Bg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*NEuDeBgnNxtTSaYVQCd2NQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*NEuDeBgnNxtTSaYVQCd2NQ.jpeg" /></p>

<p>人看起来都很渺小，一路走到沙丘脊上，有点抖而且沙子很松散不好走。</p>

<p><img src="/assets/aacd5f5cacd1/1*Gu98SJFPwWWKTj5PQR0zUw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Gu98SJFPwWWKTj5PQR0zUw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*S44sCcfn1C1zx3--fIIoBw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*S44sCcfn1C1zx3--fIIoBw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*w0d4u78ensGTedfoTINN4g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*w0d4u78ensGTedfoTINN4g.jpeg" /></p>

<p>走到最高点可以鸟瞰整个海岸线，背沙丘面海的场景只有这里有。</p>

<p><img src="/assets/aacd5f5cacd1/1*B-Oqyt2XYx4TVTMblCdEdw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1008" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*B-Oqyt2XYx4TVTMblCdEdw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*9ZoPtPjdHz3aaFTGNDT8iw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*9ZoPtPjdHz3aaFTGNDT8iw.jpeg" /></p>

<p>查网路资料好像可以骑骆驼但今天看起来是因为天气不好所以没有。</p>

<p><img src="/assets/aacd5f5cacd1/1*9WiZqF_alWi6M1PrHwG3sg.webp" alt="" loading="lazy" decoding="async" width="1400" height="994" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*9WiZqF_alWi6M1PrHwG3sg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*JxF65EE6eeACd1uRENVwNQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*JxF65EE6eeACd1uRENVwNQ.jpeg" /></p>

<p>最后离开鸟取沙丘再回头看一眼，真的很巨大；鞋子里不免也积了一些沙子， <strong>看有人直接套塑胶鞋套，很聪明。</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*6cq3xUwokLToOCx38TXV9g.webp" alt="" loading="lazy" decoding="async" width="946" height="1199" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDYiIGhlaWdodD0iMTE5OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*6cq3xUwokLToOCx38TXV9g.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*OacuYCefS-wThnPRbo49xw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*OacuYCefS-wThnPRbo49xw.jpeg" /></p>

<p>这边可以直接搭乘缆车到鸟取沙丘展望台，我想说先去下面吃有名的鸟取第一沙丘布丁，就没搭了；后来顺路用走的上去也不远(~= 15 分钟而已)。</p>

<p><img src="/assets/aacd5f5cacd1/1*SkKPyRhs_REhQrWDiLluNQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*SkKPyRhs_REhQrWDiLluNQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*30ZIWteqj87esh4ptH2w7A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*30ZIWteqj87esh4ptH2w7A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*6LhlMpfWyszDfyJ7PTf1vQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*6LhlMpfWyszDfyJ7PTf1vQ.jpeg" /></p>

<p>一路从停车场这边出来，可以看到对面由隈研吾操刀的鸟取砂丘「Takahama Cafe 高滨咖啡厅」。</p>

<p><img src="/assets/aacd5f5cacd1/1*3OinDP-RDFHBQHLpY0olPw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*3OinDP-RDFHBQHLpY0olPw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*iGxKRD9KvMZrGuuHEjGNcA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*iGxKRD9KvMZrGuuHEjGNcA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*YA0J3gRmOPgWhacPYV0LEg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*YA0J3gRmOPgWhacPYV0LEg.jpeg" /></p>

<p>买了一个尝一尝，味道真的不错，布丁牛奶味浓郁口感像奶酪。</p>

<p><img src="/assets/aacd5f5cacd1/1*cRVlgCNRJysVUNkOkCHgFg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*cRVlgCNRJysVUNkOkCHgFg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*TafJZGPlGd5gft3gYj8Q3A.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*TafJZGPlGd5gft3gYj8Q3A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*sF3liqjkM6eQ6KURqwEfxA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*sF3liqjkM6eQ6KURqwEfxA.jpeg" /></p>

<p>特色是会给你一小包像沙子的砂糖，加下去一起吃。</p>

<p><img src="/assets/aacd5f5cacd1/1*qOmSScKgkmuIBhtPJKcbiA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*qOmSScKgkmuIBhtPJKcbiA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*hv6d0AdzA-Ubx4XTqW8ZXQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*hv6d0AdzA-Ubx4XTqW8ZXQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*30_-rtFKE2Az1z6ikKIOSg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*30_-rtFKE2Az1z6ikKIOSg.jpeg" /></p>

<p>这边路上也有一些餐厅可以吃饭，继续往回走有一条小路，往上走一小段右边就是沙丘美术馆第二入口，左边再往上走一点就是刚刚缆车会到的地方「鸟取沙丘展望台」。</p>

<p><img src="/assets/aacd5f5cacd1/1*D9v4msXBz0mfsAWzXugtTw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*D9v4msXBz0mfsAWzXugtTw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*N9shdulrUJo5pphjg4lKMw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*N9shdulrUJo5pphjg4lKMw.jpeg" /></p>

<p>先往左边去鸟取沙丘展望台看风景、吃东西，会先到缆车上下车处。</p>

<p><img src="/assets/aacd5f5cacd1/1*mo37aWPygCHfl-dAetnVQg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*mo37aWPygCHfl-dAetnVQg.jpeg" /></p>

<p>可以先到贩卖及旁边这边拿刷子清理鞋子的沙子。(门口工作人员也会提醒)</p>

<p><img src="/assets/aacd5f5cacd1/1*gTZJLV-MjOhVf3kxsPHwmg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*gTZJLV-MjOhVf3kxsPHwmg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*lQX5yEbrhiEqUxf6ekViVw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*lQX5yEbrhiEqUxf6ekViVw.jpeg" /></p>

<p>最后也在这边等公车回鸟取。</p>

<p><img src="/assets/aacd5f5cacd1/1*Re9IYuYqgtJre9oHgws_aA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*Re9IYuYqgtJre9oHgws_aA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*GLQ1-BDnEqB25ZBp2X3BAA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*GLQ1-BDnEqB25ZBp2X3BAA.jpeg" /></p>

<p>展望台一二楼都是卖伴手礼跟有一个小餐厅，三楼可以上去眺望鸟取沙丘(虽然看不到什么东西)。</p>

<p><img src="/assets/aacd5f5cacd1/1*fyEhTboh7RX-ZXqz9-FCPw.webp" alt="" loading="lazy" decoding="async" width="1200" height="868" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*fyEhTboh7RX-ZXqz9-FCPw.png" /></p>

<p>里面吃的选择也不太多，要先去旁边自动贩卖机投币买对应的套餐票券，直接入场找位子坐再把券交给工作人员即可。</p>

<p>随便吃了个牡蛎套餐。</p>

<p><img src="/assets/aacd5f5cacd1/1*bN0RPnkejfCFjKjmcGwNCw.webp" alt="" loading="lazy" decoding="async" width="1071" height="873" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDcxIiBoZWlnaHQ9Ijg3MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*bN0RPnkejfCFjKjmcGwNCw.png" /></p>

<p>也在这边买了一些鸟取伴手礼。</p>

<h4 id="1330-沙丘美术馆">13:30 沙丘美术馆</h4>

<p><img src="/assets/aacd5f5cacd1/1*30_-rtFKE2Az1z6ikKIOSg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*30_-rtFKE2Az1z6ikKIOSg.jpeg" /></p>

<p>吃饱往下走从二号入口往下逛沙丘美术馆。(同样用 <a href="https://www.kkday.com/zh-tw/product/20307-jr-sanin-okayama-area-pass?cid=19365" target="_blank"><strong>周游3日券</strong></a> <strong>免费入场</strong> )</p>

<p><img src="/assets/aacd5f5cacd1/1*Y_ybpatDG6ffIfa3CDMm8g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*Y_ybpatDG6ffIfa3CDMm8g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*OvdkGmr4yDdAyhW9XwMMaQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*OvdkGmr4yDdAyhW9XwMMaQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*BBkrd9MBZZdcAEwYz8gYxw.webp" alt="" loading="lazy" decoding="async" width="1400" height="984" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*BBkrd9MBZZdcAEwYz8gYxw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*NALOYc1jrxf6O7nYgweBvg.webp" alt="" loading="lazy" decoding="async" width="1200" height="1015" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjEwMTUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*NALOYc1jrxf6O7nYgweBvg.png" /></p>

<p>从二号入口开始参观是从外面的沙雕开始参观再一路从 3 楼 2 楼往下走，实际馆内只有 2 楼有沙雕作品，场馆不大、如果不是免费的话我可能不会进来。</p>

<p><img src="/assets/aacd5f5cacd1/1*bRQIVt04vcixxfHrHh2_yg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*bRQIVt04vcixxfHrHh2_yg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*W01cTTu7FAgiW_zJRAeo-g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*W01cTTu7FAgiW_zJRAeo-g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*WZLGVTQPbJoyEK5-cZG7NQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*WZLGVTQPbJoyEK5-cZG7NQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*LiBlPyu3seaWbMkGm0eBnw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*LiBlPyu3seaWbMkGm0eBnw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*SnJ5-b_QTJ19ATurPLHEpw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*SnJ5-b_QTJ19ATurPLHEpw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*rubP2uOF0-o0QdJsoBzSWg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*rubP2uOF0-o0QdJsoBzSWg.jpeg" /></p>

<p>虽然场地小但是每个沙雕作品的细节都很精致。</p>

<p><img src="/assets/aacd5f5cacd1/1*GRvwUBqcwGumVvkL8utiJw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*GRvwUBqcwGumVvkL8utiJw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*lB74w9zvrdIiJBqpIIIT7g.webp" alt="" loading="lazy" decoding="async" width="686" height="881" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2ODYiIGhlaWdodD0iODgxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*lB74w9zvrdIiJBqpIIIT7g.png" /></p>

<p>还有一个沙雕的沙丘美术馆的 QR Code 可以扫描。</p>

<p><img src="/assets/aacd5f5cacd1/1*uH_T1z2iVu4fs6XPKwCstg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*uH_T1z2iVu4fs6XPKwCstg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*K7XJXE5cRDMV7MYzrVybIQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*K7XJXE5cRDMV7MYzrVybIQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*lZu_yUKJOB44L4wuG04uRA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*lZu_yUKJOB44L4wuG04uRA.jpeg" /></p>

<p>逛完一圈又往上走回到刚刚的鸟取沙丘展望台，东晃西晃吃个鸟取梨冰淇淋大约 14:20 在站牌这边等车，等 14:42 往鸟取站的公车。</p>

<blockquote>
  <p><em>这站回鸟取的公车来的时候就已经接近满人了，勉强挤上车，如果有时间可能会找一下从上一站上车会比较好。</em></p>
</blockquote>

<h4 id="202501-update">2025/01 Update</h4>

<p>回来才看到鸟取因为交通比较不方便，所以有提供计程车包车一日游， <a href="https://chugoku.letsgojp.com/archives/661034" target="_blank">详情请参考游客中心或此网站</a> 。</p>

<h4 id="1510-回到鸟取站">15:10 回到鸟取站</h4>

<p><img src="/assets/aacd5f5cacd1/1*zD1KRkIAiYp-wtxk48AogA.webp" alt="" loading="lazy" decoding="async" width="704" height="1176" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDQiIGhlaWdodD0iMTE3NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*zD1KRkIAiYp-wtxk48AogA.png" /></p>

<p>大约 15:10 回到鸟取站，此时开始下雨。</p>

<p><img src="/assets/aacd5f5cacd1/1*7Ex8903aKslRQc4IpfH6GA.webp" alt="" loading="lazy" decoding="async" width="949" height="1189" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDkiIGhlaWdodD0iMTE4OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*7Ex8903aKslRQc4IpfH6GA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*cfJLhRhuQjLhQqWfzVqgFA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*cfJLhRhuQjLhQqWfzVqgFA.jpeg" /></p>

<p>在车站的商店乱晃，这边的伴手礼店也有卖沙丘布丁！</p>

<p><img src="/assets/aacd5f5cacd1/1*HyBzvP9I1y2YC4KbxyLr0w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*HyBzvP9I1y2YC4KbxyLr0w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*-Q6nYvGZP-PBIgMdW6Lk2A.webp" alt="" loading="lazy" decoding="async" width="637" height="432" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MzciIGhlaWdodD0iNDMyIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*-Q6nYvGZP-PBIgMdW6Lk2A.jpeg" /></p>

<p>本来想去鸟取当地有名的 すなば珈琲（砂场咖啡），但下午三点多他们已经休息，就在车站内找了家 nana’s green tea 点个甜点＋咖啡休息充电(人跟手机都要充电)。</p>

<p><img src="/assets/aacd5f5cacd1/1*a6nZx2RTbeZAsTfxOvTPKw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*a6nZx2RTbeZAsTfxOvTPKw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*UrMfxX9LNlDIR7suza8tCQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*UrMfxX9LNlDIR7suza8tCQ.jpeg" /></p>

<p>店内舒适没什么人。</p>

<p><img src="/assets/aacd5f5cacd1/1*5os6rpDnUSjttVgCpigSRA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*5os6rpDnUSjttVgCpigSRA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*4RdqbhEiL0vrRwrMKnIXLw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*4RdqbhEiL0vrRwrMKnIXLw.jpeg" /></p>

<p>蕨饼＋冰淇淋＋热咖啡，很满足。</p>

<h4 id="1615-回饭店拿行李再回车站等车">16:15 回饭店拿行李再回车站等车</h4>

<p><img src="/assets/aacd5f5cacd1/1*UHCBHtR1kg15a4alJuXYlw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*UHCBHtR1kg15a4alJuXYlw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*i5dxFrKSOdkjH9186Q9nQA.webp" alt="" loading="lazy" decoding="async" width="939" height="1210" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzkiIGhlaWdodD0iMTIxMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*i5dxFrKSOdkjH9186Q9nQA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*zlhp1-kuQp679hHmnFJE-g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*zlhp1-kuQp679hHmnFJE-g.jpeg" /></p>

<p>时间还很早，我们要搭 16:55 的特急超级白兔前往姬路。</p>

<p><img src="/assets/aacd5f5cacd1/1*8UmhqEYZA-9f5gzPNnhsiQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*8UmhqEYZA-9f5gzPNnhsiQ.jpeg" /></p>

<p>等车期间有看到柯南列车。</p>

<h4 id="1655-上车前往姬路">16:55 上车前往姬路</h4>

<blockquote>
  <p><strong><em>再见山阴。</em></strong></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*-Xupoj1iDwTdGF6ofS94Dw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*-Xupoj1iDwTdGF6ofS94Dw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*yVwbXNEx2C4NV80hjdj3uA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*yVwbXNEx2C4NV80hjdj3uA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*j3SvEKoIHa7lEXyq5_jcxA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*j3SvEKoIHa7lEXyq5_jcxA.jpeg" /></p>

<p>划到 Green Car 第一排座位，很舒适。</p>

<blockquote>
  <p><strong><em>行李的话因为车比较晃不敢放到上面，索性走到最后一排座位，横放在最后一排座位的后面。</em></strong></p>
</blockquote>

<h4 id="1827-抵达姬路站">18:27 抵达姬路站</h4>

<p><img src="/assets/aacd5f5cacd1/1*3jfwcI6yLbuWuWzDM4mC8A.webp" alt="" loading="lazy" decoding="async" width="708" height="1190" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDgiIGhlaWdodD0iMTE5MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*3jfwcI6yLbuWuWzDM4mC8A.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*OdglmUjNMHHemWGLuppg3g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*OdglmUjNMHHemWGLuppg3g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*XbSKEhcwPLxItxqUXd6CVg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*XbSKEhcwPLxItxqUXd6CVg.jpeg" /></p>

<p>刚好遇到他们的议员选举，站外有议员在造势演讲，人很多。</p>

<p><img src="/assets/aacd5f5cacd1/1*9HmKh497akO8a6922Z7kLA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*9HmKh497akO8a6922Z7kLA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*uBit7SVmrOOBDLSPv9IEGw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*uBit7SVmrOOBDLSPv9IEGw.jpeg" /></p>

<p>出站后直接去饭店 <a href="https://www.toyoko-inn.com/china/search/detail/00317/" target="_blank"><strong>东横INN 姬路站新干线北口</strong></a> ，最后三晚都住在这里，北口这边的东横 INN 比较热闹；地图上看很近，实际走起来体感有点距离，大约要 10 分钟左右。</p>

<p><img src="/assets/aacd5f5cacd1/1*VT_z6TemLvMX-ujCfUewiQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*VT_z6TemLvMX-ujCfUewiQ.jpeg" /></p>

<p>分配到 14 楼顶楼的房间，窗外视野很好。</p>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/fAnO4AoRX-Q" title="东横INN 姬路站新干线北口" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<iframe class="embed-video" loading="lazy" src="https://www.youtube.com/embed/xl9eOyv4A-I" title="东横INN 姬路站新干线北口 14 楼窗外铁路景观" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>可以直接从窗外回头看姬路站铁路，火车经过也会有轻微的轨道声，但还好晚上之后就没火车了。</p>

<h4 id="1900-出去乱晃觅食">19:00 出去乱晃觅食</h4>

<p>一出来看到姬路城夜景觉得很美，不知道发什么神经想走到姬路城拍夜景，太接近反而不好取景没拍什么照片就走，一路又冷又饿，应该直接去吃饭的。</p>

<p><img src="/assets/aacd5f5cacd1/1*dy69JBLXC40kKDIYB3adGw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*dy69JBLXC40kKDIYB3adGw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*dyjiO-KVxTv99UskMZs9Ag.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*dyjiO-KVxTv99UskMZs9Ag.jpeg" /></p>

<p>姬路城距离车站约 1 公里，来回走了快 30 分钟。</p>

<p><img src="/assets/aacd5f5cacd1/1*hEbq2RVL18Yscc-y9ozE8g.webp" alt="&lt;https://himeji-kyoukasuigetsu.com/en/&gt;" loading="lazy" decoding="async" width="1400" height="1040" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*hEbq2RVL18Yscc-y9ozE8g.png" /></p>

<p><a href="https://himeji-kyoukasuigetsu.com/en/" target="_blank">https://himeji-kyoukasuigetsu.com/en/</a></p>

<p><img src="/assets/aacd5f5cacd1/1*KLFCGcyq_F3ZVnM4w_GK2w.webp" alt="&lt;https://himeji-kyoukasuigetsu.com/en/&gt;" loading="lazy" decoding="async" width="1042" height="1059" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDQyIiBoZWlnaHQ9IjEwNTkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*KLFCGcyq_F3ZVnM4w_GK2w.png" /></p>

<p><a href="https://himeji-kyoukasuigetsu.com/en/" target="_blank">https://himeji-kyoukasuigetsu.com/en/</a></p>

<blockquote>
  <p><strong><em>可惜这次错过了姬路城冬季点灯活动，感觉很漂亮浪漫，之后有机会再来一次吧。</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>活动时间 2024年11月22日（五）才开始，一路到 2025年2月23日（日）。</em></strong></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*tnvYT7YGcklotJdPdfpY8w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*tnvYT7YGcklotJdPdfpY8w.jpeg" /></p>

<p>最后发现车站北口二楼这个看台拍姬路城就是最佳位子。</p>

<p><img src="/assets/aacd5f5cacd1/1*dRxfkrBM2x_gMgusOlnZ5A.webp" alt="" loading="lazy" decoding="async" width="1036" height="861" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDM2IiBoZWlnaHQ9Ijg2MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*dRxfkrBM2x_gMgusOlnZ5A.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*zCHRn2ZG88rg_a7WnfXz1g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*zCHRn2ZG88rg_a7WnfXz1g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Pqy-Rk3t-bA36QHoaNrTPg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*Pqy-Rk3t-bA36QHoaNrTPg.jpeg" /></p>

<p>买晚餐前先在姬路站的百货公司 <a href="https://www.jrw-urban.co.jp/piole-himeji/tw" target="_blank">Piole Himeji</a> 稍微逛了一下跟扭扭蛋。</p>

<h4 id="2000-买晚餐回去">~=20:00 买晚餐回去</h4>

<p><img src="/assets/aacd5f5cacd1/1*8hgCoDK6cgGQJT4re9WRAA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*8hgCoDK6cgGQJT4re9WRAA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*piFnI5vcIs2l8lG5gQZRdg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*piFnI5vcIs2l8lG5gQZRdg.jpeg" /></p>

<p>从二楼空桥一路走到隔壁的 TERASSO 找到一家还没关门的烧肉店外带烧肉便当回饭店吃。</p>

<p><img src="/assets/aacd5f5cacd1/1*PfaI0llzUMpwdqEzyz5iPg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*PfaI0llzUMpwdqEzyz5iPg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*vGLx0HKICVp2XggRVuXvQQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*vGLx0HKICVp2XggRVuXvQQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*V_AQ9WNRUuMFogArfhYn_g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*V_AQ9WNRUuMFogArfhYn_g.jpeg" /></p>

<p>途经超商同样买了些吃的喝的。</p>

<p><img src="/assets/aacd5f5cacd1/1*VfGo_hbbLnLFXz2wdnLF4A.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*VfGo_hbbLnLFXz2wdnLF4A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*x3_zZ9A0QkjHdWDNkjuQqg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*x3_zZ9A0QkjHdWDNkjuQqg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*1nvfzK3jA2eVr-tTRIAUBw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*1nvfzK3jA2eVr-tTRIAUBw.jpeg" /></p>

<p>吃饱喝足洗完澡下楼洗个衣服，这次知道东横要自备洗剂，先投币买洗衣粉连同衣服投入洗衣机；这间的烘衣机很新很高级，还可以选温度。</p>

<p><img src="/assets/aacd5f5cacd1/1*1b9IFBlF0z6jwwChXs1zPg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*1b9IFBlF0z6jwwChXs1zPg.jpeg" /></p>

<blockquote>
  <p><strong><em>晚安姬路。</em></strong></p>
</blockquote>

<h3 id="day-5-1116-周六-书写山圆教寺姬路城姬路周边逛街">Day 5 (11/16 周六) 书写山圆教寺、姬路城、姬路周边逛街</h3>

<p><img src="/assets/aacd5f5cacd1/1*EqvQAU91nnYsl8w7vT7CTg.webp" alt="" loading="lazy" decoding="async" width="1400" height="993" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*EqvQAU91nnYsl8w7vT7CTg.png" /></p>

<p>每家东横 INN 都有提供免费早餐，但我都为了赶行程早上几乎都自己随便吃个前一晚买的超商面包跟咖啡就出门了。</p>

<h4 id="0845-出门">08:45 出门</h4>

<p><img src="/assets/aacd5f5cacd1/1*HIa6B4yuh-MjFWMeBs97IQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*HIa6B4yuh-MjFWMeBs97IQ.jpeg" /></p>

<p>早上 8:45 出饭店穿过空无一人的商店街前往车站。</p>

<h4 id="0855-搭公车前往书写山圆教寺">08:55 搭公车前往书写山圆教寺</h4>

<p><img src="/assets/aacd5f5cacd1/1*Z3_zOdcbly3jEyXyN8RKWA.webp" alt="" loading="lazy" decoding="async" width="920" height="1203" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjAiIGhlaWdodD0iMTIwMyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Z3_zOdcbly3jEyXyN8RKWA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*3KNztIIzy_Yw85kEm5ai-Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*3KNztIIzy_Yw85kEm5ai-Q.jpeg" /></p>

<p>姬路车站有好几个月台，Google Map 没写在哪个月台跟搭几号公车，只能现场看指标，在 10 号月台搭乘 10 号 日 姫路駅北〜书写山ロープウェイ 公车。</p>

<blockquote>
  <p><em>书写山圆教寺是电影末代武士的取景地点：</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*ElCz1QpeR3XaKMbYyPvuPQ.webp" alt="&lt;https://visit-himeji.com/zh-hant/trip-ideas/featured-in-the-last-samurai-shoshazan-engyoji-temple-in-himeji/&gt;" loading="lazy" decoding="async" width="1069" height="973" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDY5IiBoZWlnaHQ9Ijk3MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ElCz1QpeR3XaKMbYyPvuPQ.png" /></p>

<p><a href="https://visit-himeji.com/zh-hant/trip-ideas/featured-in-the-last-samurai-shoshazan-engyoji-temple-in-himeji/" target="_blank">https://visit-himeji.com/zh-hant/trip-ideas/featured-in-the-last-samurai-shoshazan-engyoji-temple-in-himeji/</a></p>

<h4 id="0920-抵达书写山缆车搭乘处">~=09:20 抵达书写山缆车搭乘处</h4>

<p><img src="/assets/aacd5f5cacd1/1*a7E1GJ36evNeg3HIpTajiA.webp" alt="" loading="lazy" decoding="async" width="1395" height="1049" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzk1IiBoZWlnaHQ9IjEwNDkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*a7E1GJ36evNeg3HIpTajiA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*deyU47Fxzh-iOMa3Cm6RMg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*deyU47Fxzh-iOMa3Cm6RMg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*d-BdwUp1HRFSSl_Zu16cDQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*d-BdwUp1HRFSSl_Zu16cDQ.jpeg" /></p>

<p>下车后就是缆车搭乘处，在自动售票机买完来回票就能排队等缆车了。(15 分钟一班)</p>

<p><img src="/assets/aacd5f5cacd1/1*Q96ZZxOE04V57QXJcsL2iA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Q96ZZxOE04V57QXJcsL2iA.jpeg" /></p>

<p>书写山这边 11/15–17 有夜间特别开放活动，开到晚上 20:00，缆车时间也延长到 20:30。</p>

<h4 id="0930-搭乘缆车上山">09:30 搭乘缆车上山</h4>

<p><img src="/assets/aacd5f5cacd1/1*-t6iFYeu1txyQ6-B9pZdCQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*-t6iFYeu1txyQ6-B9pZdCQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*2MnYBWj9005tN57I3IRrXQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*2MnYBWj9005tN57I3IRrXQ.jpeg" /></p>

<h4 id="0935-抵达书写山圆教寺入口">09:35 抵达书写山圆教寺入口</h4>

<p><img src="/assets/aacd5f5cacd1/1*4AYY1gP1Kdb589JwBHaFuw.webp" alt="" loading="lazy" decoding="async" width="1200" height="866" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*4AYY1gP1Kdb589JwBHaFuw.png" /></p>

<p>需要买门票入场，那时候没仔细看只买了 <strong>一般的入山志纳金，无法乘坐来回交通车，要用走的上山</strong> 。⚠️⚠️⚠️</p>

<blockquote>
  <p><em>坐车约：5 分钟</em></p>
</blockquote>

<blockquote>
  <p><em>爬山约：20 分钟 (1 KM)</em></p>
</blockquote>

<blockquote>
  <p><strong><em>让我再选的话我选择多 500 日圆节省时间体力。</em></strong></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*p4QIb3vPtJivhpdoDQ6GAQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*p4QIb3vPtJivhpdoDQ6GAQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*7e4WBDn1nRnJYdz5B_hYOA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*7e4WBDn1nRnJYdz5B_hYOA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ewt3SGQwn6WyhRV7Am0_MA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ewt3SGQwn6WyhRV7Am0_MA.jpeg" /></p>

<p>不过还好是一大早体力精神还很充沛，坡度平缓就一路走走赏枫上山了。</p>

<p><img src="/assets/aacd5f5cacd1/1*AS55vHl96nZYuwqjRa93ZA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*AS55vHl96nZYuwqjRa93ZA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*T8xwRPwgXPqr5nZ5LXUq2w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*T8xwRPwgXPqr5nZ5LXUq2w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*W-yWWLLv0UJlQ2QU10Q3Vg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*W-yWWLLv0UJlQ2QU10Q3Vg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*fcCW8202ZiA2OcPgUm-gKw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*fcCW8202ZiA2OcPgUm-gKw.jpeg" /></p>

<p>穿过仁王门大概还有 400 公尺。</p>

<h4 id="0955-抵达摩尼殿">09:55 抵达摩尼殿</h4>

<p><img src="/assets/aacd5f5cacd1/1*ceS4fQCizXrx1avWg9Y3yw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ceS4fQCizXrx1avWg9Y3yw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*80TxXA5vgZrLaPnSGHQVlQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*80TxXA5vgZrLaPnSGHQVlQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*6m7mDkJHyCYezj5AlTKznA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*6m7mDkJHyCYezj5AlTKznA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*fLzPG1W3E1eJ4_pEYPKepQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*fLzPG1W3E1eJ4_pEYPKepQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*AxTqVqv_JomxzIlBE_HbSA.webp" alt="" loading="lazy" decoding="async" width="965" height="1232" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjUiIGhlaWdodD0iMTIzMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*AxTqVqv_JomxzIlBE_HbSA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*5nc-fnNgZHhIwlJhTcYKjg.webp" alt="" loading="lazy" decoding="async" width="1400" height="899" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijg5OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*5nc-fnNgZHhIwlJhTcYKjg.png" /></p>

<p>书写山圆教寺幅员辽阔，全部走完我觉得至少要 2 小时起跳。</p>

<p><img src="/assets/aacd5f5cacd1/1*U4wMNwdurbeaNEOqUKkC9Q.webp" alt="" loading="lazy" decoding="async" width="1200" height="453" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjQ1MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*U4wMNwdurbeaNEOqUKkC9Q.png" /></p>

<p>我只参拜了摩尼殿跟大讲堂就折返下山了。</p>

<p><img src="/assets/aacd5f5cacd1/1*h70I3V6EU2UIea8JaVs_jw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*h70I3V6EU2UIea8JaVs_jw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*cQEiVSO01SrHGYuhQb8Y6A.webp" alt="" loading="lazy" decoding="async" width="946" height="1234" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NDYiIGhlaWdodD0iMTIzNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*cQEiVSO01SrHGYuhQb8Y6A.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*IyDpkfR-0QmrIiNwGg0aJA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*IyDpkfR-0QmrIiNwGg0aJA.jpeg" /></p>

<p>摩尼殿可以脱鞋走进去参拜，也可以从这边鸟瞰枫叶。</p>

<p><img src="/assets/aacd5f5cacd1/1*BbDp9dGeoep-40MgJeDiOQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*BbDp9dGeoep-40MgJeDiOQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*fImTadRZFNlut58qayxvhQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*fImTadRZFNlut58qayxvhQ.jpeg" /></p>

<p>很清幽安静，但今年的枫叶较晚只有零星几株转红。</p>

<p><img src="/assets/aacd5f5cacd1/1*mVNbxhCrjF5jWx5MXgRNWA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*mVNbxhCrjF5jWx5MXgRNWA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*9j_zrDZmNITjHHmA56PmCQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*9j_zrDZmNITjHHmA56PmCQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*mbYDfRbjjG6Z5_w8mI--EQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*mbYDfRbjjG6Z5_w8mI--EQ.jpeg" /></p>

<p>从殿后小路往前走前往大讲堂。</p>

<p><img src="/assets/aacd5f5cacd1/1*hsCWaBEKnGp5QMX_YaF4Gw.webp" alt="" loading="lazy" decoding="async" width="1200" height="870" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg3MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*hsCWaBEKnGp5QMX_YaF4Gw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*0yUCPUF_oEy4manAS8kJ0A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*0yUCPUF_oEy4manAS8kJ0A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*gjTjoLDLZC6EeAP3Gcnbdw.webp" alt="" loading="lazy" decoding="async" width="926" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MjYiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*gjTjoLDLZC6EeAP3Gcnbdw.png" /></p>

<p>大讲堂有一个 <a href="https://x.com/kugikumo" target="_blank">圆教寺 x 隈研吾</a> 装置艺术，展出到 12/1。</p>

<p><img src="/assets/aacd5f5cacd1/1*4m561KwGCbbgXnrrYERkJw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*4m561KwGCbbgXnrrYERkJw.jpeg" /></p>

<p>大讲堂旁的枫叶很红。</p>

<blockquote>
  <p><em>到大讲堂的时候刚好在诵经，也可以脱鞋入内参拜，日本的僧侣诵经方式跟台湾也不太一样，会把经文整本拉开然后边咏诵最后再合起来拍一下。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*V_0ogPmKoPiQ9-nuUfxvlw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*V_0ogPmKoPiQ9-nuUfxvlw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*NKB_Hzykps-3rC3HHrxHIg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*NKB_Hzykps-3rC3HHrxHIg.jpeg" /></p>

<p>旁边的食堂也能进去参观，有很多历史文物陈列。</p>

<p>所有建筑都是古迹(建于1282 年)，走在上面有一种穿越历史的感觉，整体建筑保存维护的很好。</p>

<p><img src="/assets/aacd5f5cacd1/1*T4ybcdOD3Fr9qJPRvKyjvA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*T4ybcdOD3Fr9qJPRvKyjvA.jpeg" /></p>

<p>从食堂二楼看大讲堂。</p>

<p><img src="/assets/aacd5f5cacd1/1*kwc7TD6kOkAMUEGCyQZyHw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*kwc7TD6kOkAMUEGCyQZyHw.jpeg" /></p>

<p>参观完大讲堂后折返回摩尼殿，在摩尼殿外的商店买了一个现烤红豆麻糬补充体力。(现烤的好吃，皮脆脆)</p>

<p><img src="/assets/aacd5f5cacd1/1*3vuyM_hvr2vqmMigtjrJfQ.webp" alt="Have a safe trip home." loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*3vuyM_hvr2vqmMigtjrJfQ.jpeg" /></p>

<p>Have a safe trip home.</p>

<p>吃完后就再花 20 分钟走路下山回到志纳所入口。</p>

<h4 id="1055-搭乘缆车下山">~=10:55 搭乘缆车下山</h4>

<p><img src="/assets/aacd5f5cacd1/1*HYi218ukiOp87of9sIPW7g.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*HYi218ukiOp87of9sIPW7g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*MxZa66WDA3XJLESJ6bTAHA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*MxZa66WDA3XJLESJ6bTAHA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*CPsPU2ed-0Dr7Xk1yyszAw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*CPsPU2ed-0Dr7Xk1yyszAw.jpeg" /></p>

<h4 id="1110-回姬路市区">11:10 回姬路市区</h4>

<p><img src="/assets/aacd5f5cacd1/1*--Rj51jGDSdIKsruPXX5OQ.webp" alt="" loading="lazy" decoding="async" width="938" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzgiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*--Rj51jGDSdIKsruPXX5OQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*mLKgafi4UWM-lqsxIxnTHg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*mLKgafi4UWM-lqsxIxnTHg.jpeg" /></p>

<p>下山走回来的时候的公车站，大约 11:05，等 11:10 公车回姬路市区。</p>

<h4 id="-1135-抵达-姬路城">~= 11:35 抵达 姬路城</h4>

<p><img src="/assets/aacd5f5cacd1/1*rVlB-YbFKOoCB_4vUzk50w.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*rVlB-YbFKOoCB_4vUzk50w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*kxFG8jVc9-4cfH5uTVpbsQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*kxFG8jVc9-4cfH5uTVpbsQ.jpeg" /></p>

<p>公车下车后往前走一点就是姬路城游船，不过天气阴阴快下雨就没去了。</p>

<p><img src="/assets/aacd5f5cacd1/1*ReisZ-PRti3sK13ozeceDA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ReisZ-PRti3sK13ozeceDA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*OwoTR1-C35HhJiv-rq8o2w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*OwoTR1-C35HhJiv-rq8o2w.jpeg" /></p>

<p>走进姬路城，门口这个桥景很好拍照！</p>

<p><img src="/assets/aacd5f5cacd1/1*KmgaWgD9UXFA3R6UGw8QoQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*KmgaWgD9UXFA3R6UGw8QoQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*NISOgxwwrowWgi9jHz_qWw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*NISOgxwwrowWgi9jHz_qWw.jpeg" /></p>

<p>姬路城前的三之丸广场很大，从这边还要再走 5 分钟才会到城入口。</p>

<p><img src="/assets/aacd5f5cacd1/1*TczWjw__6r_H15vgUwkcUQ.webp" alt="" loading="lazy" decoding="async" width="726" height="660" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MjYiIGhlaWdodD0iNjYwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*TczWjw__6r_H15vgUwkcUQ.png" /></p>

<p>想说先去找昨天路人推荐的姬路城拍摄点，拍摄点在跟入城口相反的方向，在右边的「姬路市动物园」里面。</p>

<p><img src="/assets/aacd5f5cacd1/1*NAGnOqG4plLpo1AVEtwCgg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*NAGnOqG4plLpo1AVEtwCgg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*UzJF2eGGGmIhgK_a3xANAA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*UzJF2eGGGmIhgK_a3xANAA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Ms3Z4aqqUSa2RWA35dGc1g.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*Ms3Z4aqqUSa2RWA35dGc1g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*GmIPAY57WWuEBRXl6tmcBw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*GmIPAY57WWuEBRXl6tmcBw.jpeg" /></p>

<p>看宣传进入右手边有卡皮巴拉，但可能因为太冷没出来；进去后直接直走过桥看到摩天轮后右转，在他后面有一块空地就是拍摄点。</p>

<p><img src="/assets/aacd5f5cacd1/1*Rupw705abK9nx8m8x0MPdw.webp" alt="&lt;https://youtube.com/shorts/XDquPOanhpQ&gt;" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*Rupw705abK9nx8m8x0MPdw.jpeg" /></p>

<p><a href="https://youtube.com/shorts/XDquPOanhpQ" target="_blank">https://youtube.com/shorts/XDquPOanhpQ</a></p>

<p>这个拍摄点的取景很好，可惜没有樱花或枫叶陪衬。</p>

<p><img src="/assets/aacd5f5cacd1/1*84kPNVhjXpUqyGMCbSgE1Q.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*84kPNVhjXpUqyGMCbSgE1Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*JPyc8SBiGKtcrh9r31l3iQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*JPyc8SBiGKtcrh9r31l3iQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*xUkRrlHFLbKJWKjnVAw59A.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*xUkRrlHFLbKJWKjnVAw59A.jpeg" /></p>

<blockquote>
  <p><em>拍完后大概绕了一下这个动物园，设施非常老旧(游乐设施另外付费)，动物空间狭小、 <strong>很多看起来都很忧郁、出现刻板行为，不忍直视</strong> ，逛一下就离开了。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*Ua__vVJVs-uFK2f4yD6erA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*Ua__vVJVs-uFK2f4yD6erA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*pNyzUtrYYyKahNitfuhxBg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*pNyzUtrYYyKahNitfuhxBg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*KEQvJI90xEVXc4r4GQ0wew.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*KEQvJI90xEVXc4r4GQ0wew.jpeg" /></p>

<p>拍完姬路城走回左侧城入口参观城内。</p>

<p><img src="/assets/aacd5f5cacd1/1*NDwQbWnS0PRC8k90t6MIcw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*NDwQbWnS0PRC8k90t6MIcw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*h0xLPH3EGTMSljU26o5GLw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*h0xLPH3EGTMSljU26o5GLw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*wVG-5blJurZ0maq8rx5IDg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*wVG-5blJurZ0maq8rx5IDg.jpeg" /></p>

<p>买完票顺著参观路线一路进到城内。</p>

<p><img src="/assets/aacd5f5cacd1/1*j-yJn4Drf_XR8nZn9aO19w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*j-yJn4Drf_XR8nZn9aO19w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*6NcZZitF85yrZIt8J6kSmw.webp" alt="" loading="lazy" decoding="async" width="1194" height="1544" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTk0IiBoZWlnaHQ9IjE1NDQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*6NcZZitF85yrZIt8J6kSmw.png" /></p>

<p>进入室内后同样要脱鞋，会发一个塑胶袋装鞋子。</p>

<p><img src="/assets/aacd5f5cacd1/1*LD55vnyY6e_RUQpxAhenDg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*LD55vnyY6e_RUQpxAhenDg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*dRqPqCQhSezJ5wsttSJeVg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*dRqPqCQhSezJ5wsttSJeVg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*zl-BV1uAW_u3qxG-KR4wLQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*zl-BV1uAW_u3qxG-KR4wLQ.jpeg" /></p>

<p>从二阶往回看姬路站，一共有六阶越往上越小、楼梯越陡峭，要排队上楼。</p>

<blockquote>
  <p><em>此时已接近中午 12:30，饥肠辘辘加上今天出门忘了带行动电源，手机已快没电加上排队人潮众多，就没再继续往上爬了，在二阶这里折返出城。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*yjWyIFXF4Adh-MEwmBLpsA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*yjWyIFXF4Adh-MEwmBLpsA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*zcaGTdjsKLn3hEBR92zb4g.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*zcaGTdjsKLn3hEBR92zb4g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Zohjzd5XZTXDuf-IkRpI8Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*Zohjzd5XZTXDuf-IkRpI8Q.jpeg" /></p>

<p>出城后一路走回三之丸广场然后走出来外面。</p>

<p><img src="/assets/aacd5f5cacd1/1*Q-BpgNDNoWH4qo3mxZFA5A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Q-BpgNDNoWH4qo3mxZFA5A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*JmXBE3gSYq898CG_1y-rLA.webp" alt="Kushiyaki Kobe beef" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*JmXBE3gSYq898CG_1y-rLA.jpeg" /></p>

<p><a href="https://maps.app.goo.gl/3ANcmi6uR1wnDgqYA" target="_blank">Kushiyaki Kobe beef</a></p>

<p>在姬路城外面商店街找了一家有卖神户牛的店，外带了神户牛丼饭跟串烧回饭店休息充电。</p>

<h4 id="1320-回饭店休息">13:20 回饭店休息</h4>

<p>天候不佳＋早上爬山＋手机没电＝回饭店休息。</p>

<p><img src="/assets/aacd5f5cacd1/1*Sp_2bL6TiDs-FTIT1hf4cg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*Sp_2bL6TiDs-FTIT1hf4cg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*0BxN4BJO9GZ3jCHQr7_qpg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*0BxN4BJO9GZ3jCHQr7_qpg.jpeg" /></p>

<p>除了份量有点小之外，这家的神户牛味道还不错。</p>

<h4 id="1530-姬路站附近逛街">15:30 姬路站附近逛街</h4>

<p>大约休息到 15:30 又重新出门。</p>

<p><img src="/assets/aacd5f5cacd1/1*VoC5czZ4ep3Pej07BaIl8g.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*VoC5czZ4ep3Pej07BaIl8g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*bU2RJeIL3HZ-eIE5aGQ0-A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*bU2RJeIL3HZ-eIE5aGQ0-A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*1yvJy0uUoWXpna40MC5ZTg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*1yvJy0uUoWXpna40MC5ZTg.jpeg" /></p>

<p>姬路站这边意外的没什么好逛的，只有车站这边的 Piole 跟 SANYO 山阳电车那栋的百货公司、周围一条商店街，没有唐吉诃德、麦当劳，Lawson 也只有一家、药妆店也只有一家松本清。</p>

<p><img src="/assets/aacd5f5cacd1/1*EtwTImtOX4SlPrRo6CKBYg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*EtwTImtOX4SlPrRo6CKBYg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*H_cAfQPJP8QXU_7MPgzYyA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*H_cAfQPJP8QXU_7MPgzYyA.jpeg" /></p>

<p>Piole 三楼的 Kiddy Land 有一些吉伊卡哇、这里没什么人也不用排队，带了三只宝宝回家，乌萨奇没有买到睡衣版本的QQ。</p>

<p><img src="/assets/aacd5f5cacd1/1*kG_MA7MnFH9QHo2YPKbofw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*kG_MA7MnFH9QHo2YPKbofw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*DZIjEJdNFvBHGIdphvJ8Kw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*DZIjEJdNFvBHGIdphvJ8Kw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*AGyjVuNTXv_gO9DfdSKAIg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*AGyjVuNTXv_gO9DfdSKAIg.jpeg" /></p>

<p>商店街乱逛，找扭蛋行程。</p>

<p><img src="/assets/aacd5f5cacd1/1*61f9uD9NUYRW1QumaFpNLA.webp" alt="" loading="lazy" decoding="async" width="1400" height="961" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk2MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*61f9uD9NUYRW1QumaFpNLA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*wxoORyKqaWXDmUt9lk9vRg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1016" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMTYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*wxoORyKqaWXDmUt9lk9vRg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*YtH0na_odN_spz7_I1o6cQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*YtH0na_odN_spz7_I1o6cQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*yNe-JTCDJuloVlg7xdtGwA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*yNe-JTCDJuloVlg7xdtGwA.jpeg" /></p>

<p>虽然刚说没什么好逛，但至少扭蛋店还是有也有安利美特。</p>

<p><img src="/assets/aacd5f5cacd1/1*o5h-XaDa6kZ6kjXjPAq7Rw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*o5h-XaDa6kZ6kjXjPAq7Rw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*9u7HGC1YdSWWcS_1_iqMzw.webp" alt="" loading="lazy" decoding="async" width="896" height="1546" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4OTYiIGhlaWdodD0iMTU0NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*9u7HGC1YdSWWcS_1_iqMzw.png" /></p>

<p>接近傍晚时分开始下大雨，还好今天本来就无特别行程安排。</p>

<h4 id="1800-吃晚餐">~=18:00 吃晚餐</h4>

<p><img src="/assets/aacd5f5cacd1/1*UJqc0DWngnbESTHo_PybYw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*UJqc0DWngnbESTHo_PybYw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*IJ8XIPnSJdaAx-6OkmCoJg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*IJ8XIPnSJdaAx-6OkmCoJg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*66Zxcn9rbOdkL3GqjV_cNA.webp" alt="おだしとワインとお料理と。motto" loading="lazy" decoding="async" width="553" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*66Zxcn9rbOdkL3GqjV_cNA.jpeg" /></p>

<p><a href="https://maps.app.goo.gl/arsJs8CYEW3kAdg46" target="_blank">おだしとワインとお料理と。motto</a></p>

<p>在商店街随便找了一家有神户牛的店当晚餐。</p>

<p><img src="/assets/aacd5f5cacd1/1*5Cc0K6Xd5p0FMJbxhB4gOg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*5Cc0K6Xd5p0FMJbxhB4gOg.jpeg" /></p>

<p>这家的特色是有一个前菜招财猫甜点，不会太甜还不错。</p>

<p><img src="/assets/aacd5f5cacd1/1*1b3oeJs9c2rjOL-TaleOQg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*1b3oeJs9c2rjOL-TaleOQg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*6ijkG1uNzojnZlIkRc2fMA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*6ijkG1uNzojnZlIkRc2fMA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*i_EvfGqTY-fQQdXlK7aBjA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*i_EvfGqTY-fQQdXlK7aBjA.jpeg" /></p>

<p>点了神户牛排跟茶泡饭还有生啤。</p>

<p>这家的神户牛排我觉得普普通通，不太好咬也吃不太出神户牛的味道，茶泡饭倒是蛮好吃的。</p>

<p><img src="/assets/aacd5f5cacd1/1*Z0oLUni88-W6TPpVm2gF6g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Z0oLUni88-W6TPpVm2gF6g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*q_ek8sUX3nM5xCBTPkXa6Q.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*q_ek8sUX3nM5xCBTPkXa6Q.jpeg" /></p>

<p>吃饱再乱逛一下，雨后的姬路。</p>

<h4 id="2000-回饭店休息看台日大战">~=20:00 回饭店休息＆看台日大战</h4>

<p><img src="/assets/aacd5f5cacd1/1*j17lqXN-p1caPqDaC6z-rA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*j17lqXN-p1caPqDaC6z-rA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*oBZH4_-Pb7difuUCdwvSBw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*oBZH4_-Pb7difuUCdwvSBw.jpeg" /></p>

<p>日本视角、转播内容完全听不懂，但日本的转播资讯很完整，左边还有棒球知识补充，右边有完整的球路分析。</p>

<p><img src="/assets/aacd5f5cacd1/1*4wJ-WWxbgYAeGgcf-KPtyQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*4wJ-WWxbgYAeGgcf-KPtyQ.jpeg" /></p>

<p>最后这场是日本胜。</p>

<blockquote>
  <p><em>晚安姬路。</em></p>
</blockquote>

<h3 id="day-6-1117周日-大阪神户">Day 6 (11/17周日) 大阪、神户</h3>

<p>本来想冲 鸣门旋涡、明石海峡大桥 但是天候依然不佳，所以改去大阪神户逛街。</p>

<h4 id="-0845-搭乘新干线自由座前往新大阪">~= 08:45 搭乘新干线自由座前往新大阪</h4>

<p><img src="/assets/aacd5f5cacd1/1*T5blo2Kdt0KsYaItd6H5dA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*T5blo2Kdt0KsYaItd6H5dA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*RvSje4c8thVxGXJpBZwnTA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*RvSje4c8thVxGXJpBZwnTA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*gGkwpzey7E9tlg0gbbV35g.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*gGkwpzey7E9tlg0gbbV35g.jpeg" /></p>

<p>搭乘新干线到新大阪(25 分钟)再转乘御堂筋线到大阪的时间跟搭一般的直接到大阪差不多、新干线的班次很多，所以选择搭比较舒适又可以充电的新干线。</p>

<h4 id="917-抵达新大阪">9:17 抵达新大阪</h4>

<p><img src="/assets/aacd5f5cacd1/1*apUd_VYqJJ_mM_Kr_R3YnQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="893" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijg5MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*apUd_VYqJJ_mM_Kr_R3YnQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*6ptZt3XbRNnIK1Ph62j9eg.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*6ptZt3XbRNnIK1Ph62j9eg.jpeg" /></p>

<p>到新大阪后还要走一下到御堂筋线。</p>

<p>先去 <a href="/posts/z-度旅行遊記/京阪神自由行攻略-京都大阪神户8日游全纪录与实用交通住宿指南-76d66c2e34af/">去年来京阪神</a> 没去到的难波八阪神社。</p>

<p><img src="/assets/aacd5f5cacd1/1*vWqBuGY0nf4NQY1pw5Pb7w.webp" alt="" loading="lazy" decoding="async" width="882" height="1095" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4ODIiIGhlaWdodD0iMTA5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*vWqBuGY0nf4NQY1pw5Pb7w.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*uCKGMuqTmPVL61gvJU_AKg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*uCKGMuqTmPVL61gvJU_AKg.jpeg" /></p>

<p>搭到难波站出来再走一小段在某个巷子内就是神社。</p>

<blockquote>
  <p><em>才发现大阪也在测试人脸辨识进出站了。</em></p>
</blockquote>

<h4 id="950-抵达难波八阪神社">~=9:50 抵达难波八阪神社</h4>

<p><img src="/assets/aacd5f5cacd1/1*DCyi2vXA6WzEvhxJ9Qx6Uw.webp" alt="" loading="lazy" decoding="async" width="866" height="1107" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjYiIGhlaWdodD0iMTEwNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*DCyi2vXA6WzEvhxJ9Qx6Uw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*qu1yc41lJWfbKvt2iiI8Og.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*qu1yc41lJWfbKvt2iiI8Og.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*eENL5QrW5I0g_Bb3Iqlc6Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1018" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMTgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*eENL5QrW5I0g_Bb3Iqlc6Q.png" /></p>

<p>神社不大，观光客很多，到此一游拍几张照片就离开了。</p>

<p><img src="/assets/aacd5f5cacd1/1*Ms6lilqCGKSJEQY-2Ad_NQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Ms6lilqCGKSJEQY-2Ad_NQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*1YnEjMoc8KV-OaV08XrMcA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*1YnEjMoc8KV-OaV08XrMcA.jpeg" /></p>

<p>离开后继续走到下一站「大国町」搭一站到「动物园前」下车，前往通天阁。</p>

<p><img src="/assets/aacd5f5cacd1/1*bxBxGhqonhPE-kNU7jl5DA.webp" alt="" loading="lazy" decoding="async" width="877" height="1071" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzciIGhlaWdodD0iMTA3MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*bxBxGhqonhPE-kNU7jl5DA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*_ZGMWno1bnS5VIsevjVuGw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*_ZGMWno1bnS5VIsevjVuGw.jpeg" /></p>

<p>出站穿过地下道、商店街继续往前走就会看到通天阁塔。</p>

<blockquote>
  <p><em>这边感觉治安蛮乱的，一出站过地下道有很多游民，还有游民在吵架很大声，有点可怕。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*WOzCL0xA6hirl6Ru3iYxlg.webp" alt="" loading="lazy" decoding="async" width="859" height="1130" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NTkiIGhlaWdodD0iMTEzMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*WOzCL0xA6hirl6Ru3iYxlg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*xWz0KkdvI5042L31ritmjw.webp" alt="" loading="lazy" decoding="async" width="1400" height="994" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*xWz0KkdvI5042L31ritmjw.png" /></p>

<p>商店街巷子狭窄左右都有吃的，有几家感觉是排队名店、很多人。</p>

<p><img src="/assets/aacd5f5cacd1/1*-cCMXQtTVn7ExtRxRLyOcA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*-cCMXQtTVn7ExtRxRLyOcA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*89McCOa7Itm_L97WibLASw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*89McCOa7Itm_L97WibLASw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*GiVI9kQjjJLKp5E0BYq__Q.webp" alt="" loading="lazy" decoding="async" width="875" height="1093" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzUiIGhlaWdodD0iMTA5MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*GiVI9kQjjJLKp5E0BYq__Q.png" /></p>

<p>约 10:30 抵达通天阁下，准备上去的人大排长龙，我直接放弃。</p>

<p><img src="/assets/aacd5f5cacd1/1*oRVH7x_G3Ga19FD04YQCIg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*oRVH7x_G3Ga19FD04YQCIg.jpeg" /></p>

<p>走回地铁站回大阪。</p>

<h4 id="1100-回到大阪梅田">~=11:00 回到大阪梅田</h4>

<p><img src="/assets/aacd5f5cacd1/1*A97lYcYLqPya_YJp3UFQxw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*A97lYcYLqPya_YJp3UFQxw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*kbWzjvQnQicbyGhGx7qLAw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*kbWzjvQnQicbyGhGx7qLAw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*i-1TYGeHu_AxlzRaluBkGw.webp" alt="" loading="lazy" decoding="async" width="874" height="1099" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzQiIGhlaWdodD0iMTA5OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*i-1TYGeHu_AxlzRaluBkGw.png" /></p>

<p>出站先去 LINKS 百货，五楼可以直通 Yodobashi 扭蛋玩具区。</p>

<p><img src="/assets/aacd5f5cacd1/1*LHUFlm9UQQto7rkwZ4oJ6A.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*LHUFlm9UQQto7rkwZ4oJ6A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*4BeiVIybWx9ixjgSA3Kp6A.webp" alt="" loading="lazy" decoding="async" width="1400" height="977" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk3NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*4BeiVIybWx9ixjgSA3Kp6A.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*RafKwlM7JvNBLvYwtTFhrA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*RafKwlM7JvNBLvYwtTFhrA.jpeg" /></p>

<p>逛完 LINKS 穿过大阪车站、楼上的时空广场，直达大阪大丸百货。</p>

<p><img src="/assets/aacd5f5cacd1/1*a02vHVVx_CBehnuTqyh9jA.webp" alt="" loading="lazy" decoding="async" width="1400" height="990" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*a02vHVVx_CBehnuTqyh9jA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Xa_Xd-BwWMKuukRyd5Tz8w.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Xa_Xd-BwWMKuukRyd5Tz8w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*iCYhY01vtTyAvBSsh3NWuw.webp" alt="" loading="lazy" decoding="async" width="1400" height="983" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*iCYhY01vtTyAvBSsh3NWuw.png" /></p>

<p>来到 13 楼这边有宝可梦中心、大阪任天堂、CAPCOM…</p>

<p><img src="/assets/aacd5f5cacd1/1*EJivBHlcWiG1tgWQoVQWQQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*EJivBHlcWiG1tgWQoVQWQQ.jpeg" /></p>

<p>喵了一下萨尔达周边， <a href="/posts/z-度旅行遊記/京阪神自由行攻略-京都大阪神户8日游全纪录与实用交通住宿指南-76d66c2e34af/">上次已经买很多了</a> ，这次什么都没买就离开了。</p>

<p><img src="/assets/aacd5f5cacd1/1*1H-S0fCwZQFmXJNLTMEISQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*1H-S0fCwZQFmXJNLTMEISQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*YxL275thElHiiaMctikMGg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*YxL275thElHiiaMctikMGg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*pNCyg_53IysVfZa5ndJLXg.webp" alt="" loading="lazy" decoding="async" width="1400" height="986" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*pNCyg_53IysVfZa5ndJLXg.png" /></p>

<p>路过阪神虎周边商店。</p>

<p>准备去吃 Shake Shack，七月去曼谷吃过， <a href="https://medium.com/ztravel/%E9%81%8A%E8%A8%98-2024-%E6%B3%B0%E5%9C%8B%E6%9B%BC%E8%B0%B7-bangkok-5-%E6%97%A5%E8%87%AA%E7%94%B1%E8%A1%8C-b7e7c0938985?source=collection_home---4------0-----------------------" target="_blank">意犹未尽</a> ；来大阪回味。</p>

<h4 id="1200-shake-shack">~=12:00 Shake Shack</h4>

<p><img src="/assets/aacd5f5cacd1/1*EV2jpsFyxgjE9lVIg3isgw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*EV2jpsFyxgjE9lVIg3isgw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*w3Nl5TcRSrFT-9ugnIpuug.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*w3Nl5TcRSrFT-9ugnIpuug.jpeg" /></p>

<p><a href="https://maps.app.goo.gl/LfNFo7TJK7gEZrcN6" target="_blank">Shake Shack 阪神梅田店</a> 就在阪神虎商店隔壁。</p>

<p><img src="/assets/aacd5f5cacd1/1*GZ_3ywx9RZuH5BuTp0bseQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*GZ_3ywx9RZuH5BuTp0bseQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*KdW0FlYYw-Iit-2uYclbLQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*KdW0FlYYw-Iit-2uYclbLQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*chnnVelVCqU-6IsNNWHEGg.webp" alt="" loading="lazy" decoding="async" width="873" height="1136" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzMiIGhlaWdodD0iMTEzNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*chnnVelVCqU-6IsNNWHEGg.png" /></p>

<p>直接用自助点餐，这次吃酪梨培根鸡肉堡跟奶昔；这家空间蛮大的、位子也多。</p>

<p><img src="/assets/aacd5f5cacd1/1*Hqk1yAuVB8DpddJFgHrPZg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*Hqk1yAuVB8DpddJFgHrPZg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*-Ud0FELy464hSGqc-6i2mg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*-Ud0FELy464hSGqc-6i2mg.jpeg" /></p>

<h4 id="大阪车站">大阪车站</h4>

<p><img src="/assets/aacd5f5cacd1/1*cBx2n43-tFXz7zHHk9YIBQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*cBx2n43-tFXz7zHHk9YIBQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*fhj864wdmrcC9LyNv0Xl6A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*fhj864wdmrcC9LyNv0Xl6A.jpeg" /></p>

<p>吃饱后再大阪车站附近闲晃，想说去大阪的 Kiddy Land 找找吉伊卡哇。</p>

<p><img src="/assets/aacd5f5cacd1/1*lKUQzWMeXVljaUZvdyKy9Q.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*lKUQzWMeXVljaUZvdyKy9Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*oyvLMv7OPW7GbnylhM072g.webp" alt="" loading="lazy" decoding="async" width="1400" height="999" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*oyvLMv7OPW7GbnylhM072g.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*qyNQwZ0U6ZWvoyVpBq69yA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*qyNQwZ0U6ZWvoyVpBq69yA.jpeg" /></p>

<p>在大阪地下街迷路，走了很久才找到阪急三番街，再走地下联络道从南馆到北馆，美食街上来就是了。</p>

<p><img src="/assets/aacd5f5cacd1/1*EJF9zT0iOWMNlMddrLdCkQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*EJF9zT0iOWMNlMddrLdCkQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*7vqSVT1kVyDJQMFtlcOy_w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*7vqSVT1kVyDJQMFtlcOy_w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*BYv-IJr_v2YuYmD_-FLjoA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*BYv-IJr_v2YuYmD_-FLjoA.jpeg" /></p>

<p>吉伊卡哇自已独立一个柜位在另外一边。</p>

<h4 id="1300-kiddy-land-osaka-chiikawa">13:00 Kiddy Land Osaka Chiikawa</h4>

<p><img src="/assets/aacd5f5cacd1/1*Cct5wKtjkqkFmVhrZSEraw.webp" alt="" loading="lazy" decoding="async" width="1200" height="865" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Cct5wKtjkqkFmVhrZSEraw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*xvhRITM1s26Q9sgxLP5ZWg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*xvhRITM1s26Q9sgxLP5ZWg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*r4v-nQd9yCftkhFxmVafyA.webp" alt="" loading="lazy" decoding="async" width="880" height="1095" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4ODAiIGhlaWdodD0iMTA5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*r4v-nQd9yCftkhFxmVafyA.png" /></p>

<p>排队的人蛮多的，粗估至少要等 40 分钟以上。</p>

<blockquote>
  <p><strong><em>想当然，我没有花时间排队等。</em></strong></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*uJHEegOR7Zr8Vlp-DqbYCA.webp" alt="" loading="lazy" decoding="async" width="1163" height="636" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTYzIiBoZWlnaHQ9IjYzNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*uJHEegOR7Zr8Vlp-DqbYCA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*QYlEBbbuFij9v2_60PQXeg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*QYlEBbbuFij9v2_60PQXeg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*E3rZ-ET_Z8qEO6Eo3QIyeA.webp" alt="" loading="lazy" decoding="async" width="868" height="1102" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjgiIGhlaWdodD0iMTEwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*E3rZ-ET_Z8qEO6Eo3QIyeA.png" /></p>

<p>一楼有 <a href="/posts/z-度旅行遊記/九州自由行攻略-福冈-长崎-熊本10日独旅全纪录与交通住宿实战经验-d78e0b15a08a/">熊本熊</a> 活动。</p>

<p><img src="/assets/aacd5f5cacd1/1*RW5sFcypjE_mj4CVwxKotQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="994" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk5NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*RW5sFcypjE_mj4CVwxKotQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ipoT-8QkWmfXhInjaK3Q2w.webp" alt="" loading="lazy" decoding="async" width="1330" height="2364" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzMwIiBoZWlnaHQ9IjIzNjQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*ipoT-8QkWmfXhInjaK3Q2w.jpeg" /></p>

<p>可能是假日的关系活动比较多，Kiddy Land 外也有卡娜赫拉的合影活动。(另一只 Usagi XD)</p>

<h4 id="1320-前往神户">13:20 前往神户</h4>

<p><img src="/assets/aacd5f5cacd1/1*iuobD0lpLgt6UCJ8Wqk3ag.webp" alt="" loading="lazy" decoding="async" width="1200" height="867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*iuobD0lpLgt6UCJ8Wqk3ag.png" /></p>

<p>在地下街又迷路了一下才找到大阪梅田地铁站，搭阪急神户线前往神户三宫（阪急）。</p>

<h4 id="1350-抵达神户">13:50 抵达神户</h4>

<p>时间还很早，打算先去「 <a href="https://maps.app.goo.gl/fspZDr7MyGMpT24r6" target="_blank">神户动物王国</a> 」找卡皮巴拉。</p>

<p><img src="/assets/aacd5f5cacd1/1*L_861E8BgHXpjDqG7B-ExA.webp" alt="" loading="lazy" decoding="async" width="1400" height="952" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk1MiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*L_861E8BgHXpjDqG7B-ExA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*wkKdFGjiN_C6aGWTNSNxXA.webp" alt="" loading="lazy" decoding="async" width="602" height="1306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDIiIGhlaWdodD0iMTMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*wkKdFGjiN_C6aGWTNSNxXA.jpeg" /></p>

<p>Google Map 要我搭乘「新交通港湾人工岛线」，在地下街绕了老半天找不到对应的指标。(迷路 Day)</p>

<p><img src="/assets/aacd5f5cacd1/1*OAOZe3cdGLU6r_6Nv2QEww.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*OAOZe3cdGLU6r_6Nv2QEww.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Rx_UFhPm-pM6Nxn2DTKx6w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*Rx_UFhPm-pM6Nxn2DTKx6w.jpeg" /></p>

<p>出站才发现就是天上跑的这条，从二楼三宫站入站。</p>

<p><img src="/assets/aacd5f5cacd1/1*yWTsJjuy_Xn01e9Lus8YOw.webp" alt="" loading="lazy" decoding="async" width="1200" height="501" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjUwMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*yWTsJjuy_Xn01e9Lus8YOw.png" /></p>

<p>车站很多人，后来才知道今天刚好是 <a href="https://zh-tw.kobe-marathon.net/2024/global/" target="_blank">神户马拉松</a> 。</p>

<p>迷路 Day…因为车刚好来没仔细看上错车，上到往北埠头的车，悲剧从此刻开始。</p>

<p><img src="/assets/aacd5f5cacd1/1*sURfSLVO2IkE2QPTq3zm7g.webp" alt="" loading="lazy" decoding="async" width="1200" height="271" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjI3MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*sURfSLVO2IkE2QPTq3zm7g.png" /></p>

<blockquote>
  <p><strong><em>往 神户动物王国 要坐往 神户空港 的，往 北埠头 的会在 北埠头 就回头回神户。</em></strong> <em>⚠️⚠️⚠️</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*Yb1jgpn5nKnHA0to0JlBvA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Yb1jgpn5nKnHA0to0JlBvA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*z8eEqxV_DQKM1FGLRxRU7A.webp" alt="" loading="lazy" decoding="async" width="879" height="1096" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzkiIGhlaWdodD0iMTA5NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*z8eEqxV_DQKM1FGLRxRU7A.png" /></p>

<p>神户马拉松有封路跑上高架，这条地铁跟北捷文湖线一样是早期的轮胎捷运。</p>

<h4 id="1420-发现坐错车-在中埠头-跳车">14:20 发现坐错车 在中埠头 跳车</h4>

<p><img src="/assets/aacd5f5cacd1/1*IGsTOnGQ2wiFBthumdIybw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*IGsTOnGQ2wiFBthumdIybw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*_BOkMH5_0AnTJcaZCtwUtg.webp" alt="" loading="lazy" decoding="async" width="553" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*_BOkMH5_0AnTJcaZCtwUtg.jpeg" /></p>

<p>搭到这边苗头不对直接跳车，Google Map 建议我走回市民广场站转搭下一班。</p>

<p><img src="/assets/aacd5f5cacd1/1*wCBuXOfGc6fSMVTM1MLZ_w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*wCBuXOfGc6fSMVTM1MLZ_w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*g8uGboUzgjpperWLcaCe-A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*g8uGboUzgjpperWLcaCe-A.jpeg" /></p>

<p>可能是因为是海埔新生地港口区，这边很荒凉走起来觉得很远。</p>

<p><img src="/assets/aacd5f5cacd1/1*ZyXQTkEYvXAbIv0TVUgCzQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="978" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk3OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ZyXQTkEYvXAbIv0TVUgCzQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*5ZyBkEGQ_NiYON5ofd9faw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1022" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMjIiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*5ZyBkEGQ_NiYON5ofd9faw.png" /></p>

<p>走快到市民广场前站想说怎么那么热闹，原来是神户马拉松的终点活动会场。</p>

<p><img src="/assets/aacd5f5cacd1/1*ULve9yF_dxl_KN_wjREO0g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ULve9yF_dxl_KN_wjREO0g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*YGSebYSQT5maJTHBLgu2xA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*YGSebYSQT5maJTHBLgu2xA.jpeg" /></p>

<blockquote>
  <p><em>悲剧 2 因为人太多所以这站不给进了，要再往前走到南公园站。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*2Gq2LpscnF2cQqBST6ueyA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*2Gq2LpscnF2cQqBST6ueyA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*gW7yF6pDt4RDQIzLnd-f0A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*gW7yF6pDt4RDQIzLnd-f0A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*HoUGLVRBxl2s45E40BMLGQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*HoUGLVRBxl2s45E40BMLGQ.jpeg" /></p>

<p>走到南公园站再一站就到了，就懒得搭捷运直接走去神户动物王国…</p>

<p>同前述，因为太荒凉走起来感觉很远，确实也很远，从中埠头走来 2 公里(约 30 分钟)。</p>

<h4 id="1450-抵达神户动物王国">14:50 抵达神户动物王国</h4>

<p><img src="/assets/aacd5f5cacd1/1*HzgFgMtmQ3Sw6piVC4Mblg.webp" alt="" loading="lazy" decoding="async" width="1400" height="977" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk3NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*HzgFgMtmQ3Sw6piVC4Mblg.png" /></p>

<p>门票：2,200 日圆</p>

<p><img src="/assets/aacd5f5cacd1/1*bwUP-L5-s7kjH5O2TAcf6g.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*bwUP-L5-s7kjH5O2TAcf6g.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*jqf3mJy-K5HtBDnG0lcThA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*jqf3mJy-K5HtBDnG0lcThA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*PYEx2kx73xmpbMrGZNTcqg.webp" alt="鲸头鹳、兔狲、小熊猫" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*PYEx2kx73xmpbMrGZNTcqg.jpeg" /></p>

<p>鲸头鹳、兔狲、小熊猫</p>

<p>神户动物王国虽然是半室内半室外，但里面的动线规划蛮好的，各种飞禽走兽都有，而且多半可以近距离接触，很适合亲子花个半天来这里玩；动物的状况相较姬路市立动物园好很多、环境也很干净。</p>

<h4 id="卡皮巴拉">卡皮巴拉</h4>

<p><img src="/assets/aacd5f5cacd1/1*DK2DEH8iPJmiTyDHldeqHQ.webp" alt="" loading="lazy" decoding="async" width="876" height="1087" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzYiIGhlaWdodD0iMTA4NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*DK2DEH8iPJmiTyDHldeqHQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*CqjDL7S99NtLuamD8V3A0w.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*CqjDL7S99NtLuamD8V3A0w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*XtvMffuoulVGOt0AK88BbQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*XtvMffuoulVGOt0AK88BbQ.jpeg" /></p>

<p>来这边的目的达成，来摸卡皮巴拉，好肥、毛摸起来好粗糙很像扫把。</p>

<p><img src="/assets/aacd5f5cacd1/1*AoazZpBcYuh-LpiZLCk6fw.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*AoazZpBcYuh-LpiZLCk6fw.jpeg" /></p>

<p>每只都一脸慵懒，不用上班真好！</p>

<p><img src="/assets/aacd5f5cacd1/1*Dui-4l3rOZkGVjVuEAjqZw.webp" alt="" loading="lazy" decoding="async" width="569" height="764" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NjkiIGhlaWdodD0iNzY0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*Dui-4l3rOZkGVjVuEAjqZw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*a0JZ_DEQph3dAI-Mlzhxvw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*a0JZ_DEQph3dAI-Mlzhxvw.jpeg" /></p>

<p>可能因为太胖，现在不贩卖食物在场内喂食、不能喂场外食物或放东西在他头上。</p>

<p>另一区还有袋鼠、羊近距离互动。</p>

<p><img src="/assets/aacd5f5cacd1/1*D4K3htSuQ7vwCDGqizRLrg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*D4K3htSuQ7vwCDGqizRLrg.jpeg" /></p>

<p>摸前、摸完都要记得洗个手。</p>

<p><img src="/assets/aacd5f5cacd1/1*A540bEA8Z1WvYv2BZZB6XQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*A540bEA8Z1WvYv2BZZB6XQ.jpeg" /></p>

<p>还有一只海豹，但看起来场地太小他一直在绕圈圈QQ</p>

<p><img src="/assets/aacd5f5cacd1/1*V3fEMjXiFUrjBW01U3hWOw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*V3fEMjXiFUrjBW01U3hWOw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*3YjSHmLP5S50YO2yFl6aBg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*3YjSHmLP5S50YO2yFl6aBg.jpeg" /></p>

<p>企鹅喂食（需要排整理券）。</p>

<p><img src="/assets/aacd5f5cacd1/1*N2xebJcxnHYGn8e1rTojCw.webp" alt="" loading="lazy" decoding="async" width="1330" height="2364" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzMwIiBoZWlnaHQ9IjIzNjQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*N2xebJcxnHYGn8e1rTojCw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*a_o37TUg0JELGpeHIlmrZQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*a_o37TUg0JELGpeHIlmrZQ.jpeg" /></p>

<p>可爱的小爪水獭家族，一直嘤嘤叫。</p>

<p><img src="/assets/aacd5f5cacd1/1*CuP3tdfDMluPWnxc-9Wq1A.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*CuP3tdfDMluPWnxc-9Wq1A.jpeg" /></p>

<p>水獭这边有一只马来貘，但是没什么理他 QQ</p>

<p><img src="/assets/aacd5f5cacd1/1*JNkNZEh__ouaMUnwCCIdNg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*JNkNZEh__ouaMUnwCCIdNg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*xniRR-ET-l2adsy9Yd30Mw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*xniRR-ET-l2adsy9Yd30Mw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*aW3oScEuZgY3pgBar7RWrA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*aW3oScEuZgY3pgBar7RWrA.jpeg" /></p>

<p>巨嘴鸟跟枭，还有脚边会出现的雉鸡。(走路要小心不要踩到⚠️)</p>

<p><img src="/assets/aacd5f5cacd1/1*yEYyShOUZxvFBGvis-Vrow.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*yEYyShOUZxvFBGvis-Vrow.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*cgKffBX23EMZtHYSuLmf9w.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*cgKffBX23EMZtHYSuLmf9w.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*7Ic9m_24xoIpTB-TS_o_wg.webp" alt="朱利安国王跟会吃同事的鹈鹕、也有夜行馆猫头鹰" loading="lazy" decoding="async" width="1330" height="2364" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzMwIiBoZWlnaHQ9IjIzNjQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*7Ic9m_24xoIpTB-TS_o_wg.jpeg" /></p>

<p>朱利安国王跟会吃同事的鹈鹕、也有夜行馆猫头鹰</p>

<p><img src="/assets/aacd5f5cacd1/1*zUgtU9kQCKScJsprv1NTQQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="964" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk2NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*zUgtU9kQCKScJsprv1NTQQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*pM5AvtCSA_REaZKTOYODgA.webp" alt="" loading="lazy" decoding="async" width="860" height="1091" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjAiIGhlaWdodD0iMTA5MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*pM5AvtCSA_REaZKTOYODgA.png" /></p>

<p>室内还有兔兔猫猫狗狗互动区（要排整理券）、饮食、纪念品店…等等</p>

<p>整体来说体验蛮好的！</p>

<h4 id="1550-离开准备返回神户">15:50 离开，准备返回神户</h4>

<p>主要是来摸卡皮巴拉，加上时间不太够所以没有停留太久。</p>

<p><img src="/assets/aacd5f5cacd1/1*yfpUfEWTujRfFn1SLBi8aQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*yfpUfEWTujRfFn1SLBi8aQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*42N4yOOTADXSR3TnaE0foA.webp" alt="" loading="lazy" decoding="async" width="1400" height="983" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk4MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*42N4yOOTADXSR3TnaE0foA.png" /></p>

<h4 id="-1605-抵达神户三宫站">~= 16:05 抵达(神户)三宫站</h4>

<p><img src="/assets/aacd5f5cacd1/1*oNUQVDNJXP_zpuS0vPWIWA.webp" alt="" loading="lazy" decoding="async" width="872" height="1098" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzIiIGhlaWdodD0iMTA5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*oNUQVDNJXP_zpuS0vPWIWA.png" /></p>

<p>因为神户马拉松的缘故，出站的人很多。</p>

<p><img src="/assets/aacd5f5cacd1/1*92IdBTMJ1Z1AyzHdCQVNHA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*92IdBTMJ1Z1AyzHdCQVNHA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*g-zbhehAAcO3tmvdJ6Dotw.webp" alt="" loading="lazy" decoding="async" width="858" height="1081" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NTgiIGhlaWdodD0iMTA4MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*g-zbhehAAcO3tmvdJ6Dotw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*4kvY1I-JyKoMbo6Xo3Mg6A.webp" alt="" loading="lazy" decoding="async" width="877" height="1079" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzciIGhlaWdodD0iMTA3OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*4kvY1I-JyKoMbo6Xo3Mg6A.png" /></p>

<p>离吃饭时间还有一个多小时，先在神户三宫附近逛逛，一样去找扭蛋跟 Kiddy Land。</p>

<p><img src="/assets/aacd5f5cacd1/1*LAu0vz0PiOzK3QC8xQbeJg.webp" alt="" loading="lazy" decoding="async" width="872" height="1076" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzIiIGhlaWdodD0iMTA3NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*LAu0vz0PiOzK3QC8xQbeJg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*eDM9G1Lrm5nQLnusWKD7uA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*eDM9G1Lrm5nQLnusWKD7uA.jpeg" /></p>

<p>神户的 Kiddy Land 没什么人但是吉伊卡哇的商品很少，没找到我要的睡衣乌萨奇。</p>

<p><img src="/assets/aacd5f5cacd1/1*Cmt7wQ4UV4cYAaTNzxvgHA.webp" alt="" loading="lazy" decoding="async" width="878" height="1102" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzgiIGhlaWdodD0iMTEwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Cmt7wQ4UV4cYAaTNzxvgHA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*q7C947BYHvNxBDhPSGG6uQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="819" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgxOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*q7C947BYHvNxBDhPSGG6uQ.png" /></p>

<p>Center Plaza 这边有点年代但是有很多商店可逛。</p>

<p><img src="/assets/aacd5f5cacd1/1*8vFujFuXpB65kosAzXrtkw.webp" alt="" loading="lazy" decoding="async" width="1200" height="845" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg0NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*8vFujFuXpB65kosAzXrtkw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*XD7jraHi5_yQZfB7YAkv9Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="959" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk1OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*XD7jraHi5_yQZfB7YAkv9Q.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*WlCIdUIpqTHUN4jwg1x_Hg.webp" alt="" loading="lazy" decoding="async" width="820" height="1122" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MjAiIGhlaWdodD0iMTEyMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*WlCIdUIpqTHUN4jwg1x_Hg.png" /></p>

<p>去二楼找扭蛋也去二手商店看看有没有我要的乌萨奇。</p>

<p><img src="/assets/aacd5f5cacd1/1*3AtESgoEYKHf6RFMBy7a4A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*3AtESgoEYKHf6RFMBy7a4A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*DhlS3byoBALyjqUNQNZlqw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*DhlS3byoBALyjqUNQNZlqw.jpeg" /></p>

<p>有一家信长书店，可以买御守送朋友，嘻嘻。</p>

<h4 id="1700-神戸牛-吉祥吉">~=17:00 <a href="https://maps.app.goo.gl/8UcmAfUDGpH8F1PX8" target="_blank">神戸牛 吉祥吉</a></h4>

<p><img src="/assets/aacd5f5cacd1/1*_kTtTzMcYzgucSSbZBpOMg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*_kTtTzMcYzgucSSbZBpOMg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*YeGNnRYe3W2AId3Ey5Xoxg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*YeGNnRYe3W2AId3Ey5Xoxg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*AF8Ium09DuuXVdb6wgirtQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*AF8Ium09DuuXVdb6wgirtQ.jpeg" /></p>

<p>B1 就有一家 神戸牛 吉祥吉，差不多快五点就先来吃晚餐了。</p>

<p>时间还很早，没什么人；老板听到我是台湾来的很热情，这餐也是来神户的目的， <strong>吃一餐好的 — 神户牛</strong> ，不然来的几天几乎都乱吃。</p>

<p><img src="/assets/aacd5f5cacd1/1*TplkGy7shiHlWAHyLf9-KQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="961" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk2MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*TplkGy7shiHlWAHyLf9-KQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*0ufGhslTqU6l0UUlsFCOCg.webp" alt="" loading="lazy" decoding="async" width="822" height="626" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MjIiIGhlaWdodD0iNjI2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*0ufGhslTqU6l0UUlsFCOCg.png" /></p>

<p>我点「神户牛赤身肉牛排 220g」7,700 日圆 (未税价⚠️，结帐要含税)加购套餐(生菜、饭、汤)跟生啤。</p>

<p><img src="/assets/aacd5f5cacd1/1*794jNjGugkDnsJOPEdOJZw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*794jNjGugkDnsJOPEdOJZw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*xSB_UvOX-MwvXzzmDx-KoQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*xSB_UvOX-MwvXzzmDx-KoQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*H55tOkGS36r6WTGAqT560w.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*H55tOkGS36r6WTGAqT560w.jpeg" /></p>

<p>生菜清爽，汤是牛肉汤，很好喝。</p>

<p><img src="/assets/aacd5f5cacd1/1*MJLdfXQZoH_4vUy0KUOq5w.webp" alt="" loading="lazy" decoding="async" width="1200" height="859" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg1OSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*MJLdfXQZoH_4vUy0KUOq5w.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*MUe5xLDpu4wLU2OCnrddTw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*MUe5xLDpu4wLU2OCnrddTw.jpeg" /></p>

<p>肉很嫩、汁多、肉味足，相较昨天吃的神户牛，这才是神户牛的滋味。</p>

<blockquote>
  <p><em>不过真要说我还是比较喜欢铁板的，更胜洋食。</em></p>
</blockquote>

<p>最后实刷： <code class="language-plaintext highlighter-rouge">$2,158 台币</code> 。</p>

<h4 id="1740-吃饱离开前往神户塔">17:40 吃饱离开，前往神户塔</h4>

<p>吃完走到海岸线的旧居留地、大丸前站，搭一站后再步行前往神户塔。</p>

<p><img src="/assets/aacd5f5cacd1/1*ynQiJ9mgKhOxFdSUESJFnQ.webp" alt="" loading="lazy" decoding="async" width="873" height="1095" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzMiIGhlaWdodD0iMTA5NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ynQiJ9mgKhOxFdSUESJFnQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*_BKRsKmQrLdl9fLPgOrFaQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*_BKRsKmQrLdl9fLPgOrFaQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*4l2DyckNmvx97IuF256JUg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*4l2DyckNmvx97IuF256JUg.jpeg" /></p>

<p>神户这边好热闹(相较姬路)，有好多百货可以逛。</p>

<p>搭乘往 新长田，在下一站 港元町 下车。</p>

<h4 id="1805-抵达神户塔周边">18:05 抵达神户塔周边</h4>

<p><img src="/assets/aacd5f5cacd1/1*441FBjZsUDMXDMQxz8XCmg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*441FBjZsUDMXDMQxz8XCmg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*wH_baSj-1o9q5GyFZ97-xg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*wH_baSj-1o9q5GyFZ97-xg.jpeg" /></p>

<p><a href="/posts/z-度旅行遊記/京阪神自由行攻略-京都大阪神户8日游全纪录与实用交通住宿指南-76d66c2e34af/">去年来的时候在维修</a> ，目前已完全开放了。</p>

<p><img src="/assets/aacd5f5cacd1/1*NdyL8AiQtaLIkZfb54dFVA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*NdyL8AiQtaLIkZfb54dFVA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*cD32qAyEg7AOlZJg04FM_w.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*cD32qAyEg7AOlZJg04FM_w.jpeg" /></p>

<p>神户港这边蛮有港湾小镇的感觉，有机会的话会考虑在神户这边住一晚。</p>

<p>这次来走马看花一下就走了。</p>

<h4 id="1830-回神户中华街">18:30 回神户中华街</h4>

<p>回神户站的路上先去中华街买 <a href="https://frantz.co.jp/en/" target="_blank">Kobe Frantz 巧克力伴手礼</a> 。</p>

<p><img src="/assets/aacd5f5cacd1/1*XjaKzeVqxVLXk_MQFlABzw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*XjaKzeVqxVLXk_MQFlABzw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*D2ge3h9VtwH0vCO8-rT6kQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*D2ge3h9VtwH0vCO8-rT6kQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*usONmjglsnKER-HS5DS2yQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*usONmjglsnKER-HS5DS2yQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Y_VKoWARSlj-ZuQHwEYbCQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Y_VKoWARSlj-ZuQHwEYbCQ.jpeg" /></p>

<h4 id="回到-jr-元町站">回到 JR 元町站</h4>

<p><img src="/assets/aacd5f5cacd1/1*HFFt6e3ORaTBS_A2xfk_Mw.webp" alt="" loading="lazy" decoding="async" width="1200" height="791" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc5MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*HFFt6e3ORaTBS_A2xfk_Mw.png" /></p>

<p>请注意是 JR 元町站不要跑去阪神电车元町站。</p>

<h4 id="1853-搭乘-快速-姬路方面网干-前往神户兵库">18:53 搭乘 快速 姬路方面网干 前往神户(兵库)</h4>

<p><img src="/assets/aacd5f5cacd1/1*kQMXFTC_jkFXbQrLjTKawA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*kQMXFTC_jkFXbQrLjTKawA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*CIaO_bZsDuNIThM4GNUXqA.webp" alt="" loading="lazy" decoding="async" width="384" height="351" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzODQiIGhlaWdodD0iMzUxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*CIaO_bZsDuNIThM4GNUXqA.png" /></p>

<h4 id="1857-同月台另一侧-换乘-新快速-湖西线经由网干">18:57 同月台另一侧 换乘 新快速 湖西线经由网干</h4>

<blockquote>
  <p><strong><em>换乘快 20 分钟抵达</em></strong> <em>，还好有换成才赶在姬路唯一一家药妆店松本清免税时间结束前抵达。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*LL8pEAjsoOyIBY7Zng5EOg.webp" alt="" loading="lazy" decoding="async" width="873" height="1100" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzMiIGhlaWdodD0iMTEwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*LL8pEAjsoOyIBY7Zng5EOg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*GNDjeJjhEgixMjH69bSMuQ.webp" alt="" loading="lazy" decoding="async" width="872" height="1106" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzIiIGhlaWdodD0iMTEwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*GNDjeJjhEgixMjH69bSMuQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*zEh8247pPwlJJShPWXRhNg.webp" alt="" loading="lazy" decoding="async" width="867" height="1096" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjciIGhlaWdodD0iMTA5NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*zEh8247pPwlJJShPWXRhNg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*kNw192v7znWE0utpE0cVGA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*kNw192v7znWE0utpE0cVGA.jpeg" /></p>

<p>这列车车型也是要按旁边开门按钮才会开门的、车厢彼此是分开的。</p>

<h4 id="1934-抵达姬路">19:34 抵达姬路</h4>

<p><img src="/assets/aacd5f5cacd1/1*JGEsWM6ZsBJhQ9MDEFgjyg.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*JGEsWM6ZsBJhQ9MDEFgjyg.jpeg" /></p>

<h4 id="1945-抵达姬路-piole-松本清采购药妆">19:45 抵达姬路 Piole 松本清采购药妆</h4>

<p><img src="/assets/aacd5f5cacd1/1*1yNFLnhhhRjr32KRjndzZQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*1yNFLnhhhRjr32KRjndzZQ.jpeg" /></p>

<blockquote>
  <p><em>请注意虽然他营业时间写到 21:00 但是 <strong>免税时间只到 20:30</strong> 。⚠️⚠️⚠️</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*gEwopdiZt9hWS18pwDmbog.webp" alt="买了一个超迷你 Cup Noodle" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*gEwopdiZt9hWS18pwDmbog.jpeg" /></p>

<p>买了一个超迷你 Cup Noodle</p>

<p><img src="/assets/aacd5f5cacd1/1*XIL4YdSSE1aSMvOCfo_Eog.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*XIL4YdSSE1aSMvOCfo_Eog.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*1UO4_sG-Z1vARToCEpeSGQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*1UO4_sG-Z1vARToCEpeSGQ.jpeg" /></p>

<p>在日本的最后一晚，在饭店吃吃吃喝喝宵夜、啤酒。(这丸子是松软口感…)</p>

<blockquote>
  <p><strong><em>晚安姬路。</em></strong></p>
</blockquote>

<h3 id="day-7-1118-周一-冈山回程">Day 7 (11/18 周一) 冈山、回程</h3>

<h4 id="0830-早安姬路">08:30 早安姬路</h4>

<p><img src="/assets/aacd5f5cacd1/1*gIylwTEdczfgkIyCgRg-PQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*gIylwTEdczfgkIyCgRg-PQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*ZfhXzMRapc-5g77Nrk7GCQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*ZfhXzMRapc-5g77Nrk7GCQ.jpeg" /></p>

<p>最后看一眼姬路的早晨。</p>

<p><img src="/assets/aacd5f5cacd1/1*KR95SMQ2Nrdf6lK0wxqEcg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*KR95SMQ2Nrdf6lK0wxqEcg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*u1yIgbMQGfGFLOJ4fsFBbA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*u1yIgbMQGfGFLOJ4fsFBbA.jpeg" /></p>

<p>到新干线站准备搭乘 08:52 的新干线前往冈山。</p>

<h4 id="搭乘-0852-的新干线自由座前往冈山">搭乘 08:52 的新干线自由座前往冈山</h4>

<p><img src="/assets/aacd5f5cacd1/1*WzQVvLKiQSx-5LXpw75O3w.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*WzQVvLKiQSx-5LXpw75O3w.jpeg" /></p>

<h4 id="0913-抵达冈山车站">09:13 抵达冈山车站</h4>

<p>搭乘新干线大约 21 分钟就会到冈山车站了，可惜这次时间不够无法 <a href="https://medium.com/ztravel/%E9%81%8A%E8%A8%98-2023-%E5%BB%A3%E5%B3%B6%E5%B2%A1%E5%B1%B1-6-%E6%97%A5%E9%81%8A-31b9b3a63abc?source=collection_home---4------2-----------------------" target="_blank">再访广岛</a> 。</p>

<p><img src="/assets/aacd5f5cacd1/1*PgFJG7RNh8w5f4pK5Dv6Eg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*PgFJG7RNh8w5f4pK5Dv6Eg.jpeg" /></p>

<p>跟上次一样直接到冈山车站西口搭乘往机场巴士的地方，这里就有置物柜寄放行李、也有厕所(这时间百货还没开厕所很少)。</p>

<h4 id="0930-冈山车站麦当劳吃这阵子台湾很红的松饼汉堡">09:30 冈山车站麦当劳吃这阵子台湾很红的「松饼汉堡」</h4>

<p><img src="/assets/aacd5f5cacd1/1*1O8uNrClegWyQoAJE12e5g.webp" alt="" loading="lazy" decoding="async" width="838" height="809" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MzgiIGhlaWdodD0iODA5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*1O8uNrClegWyQoAJE12e5g.png" /></p>

<p>看不懂日文差点选错，要选这个「マックグリドル」才是松饼系列。</p>

<blockquote>
  <p><em>日本麦当劳早餐时段到 10:30。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*OOoRAGeCSlq2AhtBBs3ZaA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*OOoRAGeCSlq2AhtBBs3ZaA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*tuExEIAQs1IIAede34Odqg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*tuExEIAQs1IIAede34Odqg.jpeg" /></p>

<p>吃完大约 10:00 没有特别想去的地点。</p>

<p><img src="/assets/aacd5f5cacd1/1*17imSbehBjflWDXLWBedlQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*17imSbehBjflWDXLWBedlQ.jpeg" /></p>

<p><a href="/posts/z-度旅行遊記/山阳地区广岛冈山自由行攻略-6日行程-交通-住宿全解析-31b9b3a63abc/">上次已经去过冈山城跟吉备津神社了</a> ，最后时间就去逛逛冈山 AEON 永旺梦乐城。</p>

<p><img src="/assets/aacd5f5cacd1/1*j6NZ7W08WVWsntCa7qvN6A.webp" alt="冈山艺术季" loading="lazy" decoding="async" width="682" height="506" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2ODIiIGhlaWdodD0iNTA2Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*j6NZ7W08WVWsntCa7qvN6A.png" /></p>

<p><a href="https://forestartfest-okayama.jp/" target="_blank">冈山艺术季</a></p>

<p>今年冈山有 <a href="https://forestartfest-okayama.jp/" target="_blank">艺术季活动</a> 。</p>

<p><img src="/assets/aacd5f5cacd1/1*dhgBrvzJrFsPimXmsJb_QQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*dhgBrvzJrFsPimXmsJb_QQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*YEmu3f0rStKaWXCl890OSQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*YEmu3f0rStKaWXCl890OSQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*HaQeBv92EgDp2qdq3EHFvQ.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*HaQeBv92EgDp2qdq3EHFvQ.jpeg" /></p>

<p>施工中的冈山站跟暂时被移到车站旁的桃太郎。</p>

<p><img src="/assets/aacd5f5cacd1/1*_aly6JVMgGDzW4BogUg9Wg.webp" alt="" loading="lazy" decoding="async" width="878" height="1101" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzgiIGhlaWdodD0iMTEwMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*_aly6JVMgGDzW4BogUg9Wg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*6bKTUuYl1MMeXhkb2JKOLg.webp" alt="" loading="lazy" decoding="async" width="882" height="1097" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4ODIiIGhlaWdodD0iMTA5NyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*6bKTUuYl1MMeXhkb2JKOLg.png" /></p>

<p>从地下街过马路到 AEON MALL B2，这边也有一家麦当劳。</p>

<p><img src="/assets/aacd5f5cacd1/1*I7cFknifEeInNlJfK7UYSw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*I7cFknifEeInNlJfK7UYSw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*h_77ECXhHjNHSl7Lr8L7-Q.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*h_77ECXhHjNHSl7Lr8L7-Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*nvJY17geWnC69iCT0kQHrg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*nvJY17geWnC69iCT0kQHrg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*BlcO-BaPAFCkd_q9L30Etw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*BlcO-BaPAFCkd_q9L30Etw.jpeg" /></p>

<p>这边很大很好逛，几乎所有品牌都有。</p>

<p><img src="/assets/aacd5f5cacd1/1*vjssm5svEoPfePGcNgElCg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*vjssm5svEoPfePGcNgElCg.jpeg" /></p>

<p>要吃东西、买伴手礼 (B1-B2) 也都有。</p>

<p><img src="/assets/aacd5f5cacd1/1*8oOH2Pe4c_SbgDzwoR21Yg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*8oOH2Pe4c_SbgDzwoR21Yg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*NapTm7rBZ4qVZ7EpNqr7xg.webp" alt="" loading="lazy" decoding="async" width="1200" height="866" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijg2NiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*NapTm7rBZ4qVZ7EpNqr7xg.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*YClpxnjnyZQuS_ZNi6ZvvQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1008" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwMDgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*YClpxnjnyZQuS_ZNi6ZvvQ.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*HJ4J2jAs8mruW6BZYvyWcA.webp" alt="" loading="lazy" decoding="async" width="553" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTMiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*HJ4J2jAs8mruW6BZYvyWcA.jpeg" /></p>

<p>继续找扭蛋，但都没找到我要的电车按钮扭蛋，放弃…应该是没再出了。</p>

<p><img src="/assets/aacd5f5cacd1/1*HdWGWOOs9agTb9qWYaiqiQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*HdWGWOOs9agTb9qWYaiqiQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*hK5tJ8UD4aNoz9LNTYBWyA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*hK5tJ8UD4aNoz9LNTYBWyA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*MQnwEbWs96IBpBEKW7IB4w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*MQnwEbWs96IBpBEKW7IB4w.jpeg" /></p>

<p>也有几家店有卖吉伊卡哇。</p>

<h4 id="1100-准备吃午餐">~=11:00 准备吃午餐</h4>

<blockquote>
  <p><strong><em>虽然没有很饿但是为了备战下午候机跟虎航没供餐，所以还是要吃。</em></strong> <em>⚠️⚠️⚠️</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*s8axzlQR2pkJASqoyiPjQg.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*s8axzlQR2pkJASqoyiPjQg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*3JEFC2MwRYJbT7WR4kb2Sg.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*3JEFC2MwRYJbT7WR4kb2Sg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*uxodtgWIX2tokvA8GANlBQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*uxodtgWIX2tokvA8GANlBQ.jpeg" /></p>

<p>楼上这边吃的选择很多。</p>

<p><img src="/assets/aacd5f5cacd1/1*8OX9V42Q-S0S7W-1Ve7n6A.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*8OX9V42Q-S0S7W-1Ve7n6A.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*mIUREsw2cy1DfnAuxi9lWg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*mIUREsw2cy1DfnAuxi9lWg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*vAiLB635e_VNF1BrY7U3ZA.webp" alt="**豚ステーキ専门店 B 冈山店**" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*vAiLB635e_VNF1BrY7U3ZA.jpeg" /></p>

<p><a href="https://tabelog.com/okayama/A3301/A330101/33018608/" target="_blank"><strong>豚ステーキ専门店 B 冈山店</strong></a></p>

<p>选了一家主打铁板猪排的店。</p>

<p><img src="/assets/aacd5f5cacd1/1*f9-cymGYzbWqmSgVSwht8Q.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*f9-cymGYzbWqmSgVSwht8Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*-8Sx-7tZ5l-DPua6GOunTA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*-8Sx-7tZ5l-DPua6GOunTA.jpeg" /></p>

<p>点了一份铁板猪排定食(200g)跟生啤。最后付 <code class="language-plaintext highlighter-rouge">2,178 日圆</code></p>

<p><img src="/assets/aacd5f5cacd1/1*rT1vHotHA_BsYMp5BFadUQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*rT1vHotHA_BsYMp5BFadUQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*weW08CNKF-sFY48mz-Qw7g.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*weW08CNKF-sFY48mz-Qw7g.jpeg" /></p>

<p>比较讶异的是猪排上来的时候没有全熟，大约 7 分熟；查了一下评价跟介绍好像就是这家的特色，不过我还是趁铁板热的时候把能用熟的肉块都用熟了。</p>

<blockquote>
  <p><em>吃起来是真的好吃，很 Juice、肉香味足、不会咬不烂；私心觉得不输昨天的神户牛(我可能没富贵命)。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*4SkncSHSzMb-s7cnwrAqFQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*4SkncSHSzMb-s7cnwrAqFQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*E44bH_Sc3tK3PS-gSzr3jQ.webp" alt="小废物行李箱(大约跟 Airpods Pro 一样大)跟娃包" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*E44bH_Sc3tK3PS-gSzr3jQ.jpeg" /></p>

<p>小废物行李箱(大约跟 Airpods Pro 一样大)跟娃包</p>

<p>最后在一楼无印良品买了些东西大约 12:15 就离开了。</p>

<h4 id="1230-回到冈山站">~=12:30 回到冈山站</h4>

<p>准备搭乘 13:00 的交通车去冈山机场。</p>

<p><img src="/assets/aacd5f5cacd1/1*g0faLCzFGCjUq6xndxPXCA.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*g0faLCzFGCjUq6xndxPXCA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*wp34SWl53PM47RyotD7_7A.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*wp34SWl53PM47RyotD7_7A.jpeg" /></p>

<p>最后再看一眼冈山。</p>

<h4 id="1300-搭乘交通车前往冈山机场">~=13:00 搭乘交通车前往冈山机场</h4>

<p><img src="/assets/aacd5f5cacd1/1*WQPyQGy5C0nZLfJ-3GIZcA.webp" alt="" loading="lazy" decoding="async" width="869" height="1101" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjkiIGhlaWdodD0iMTEwMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*WQPyQGy5C0nZLfJ-3GIZcA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*YD-OAt75d1s69u6qZpWrsw.webp" alt="" loading="lazy" decoding="async" width="872" height="1102" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzIiIGhlaWdodD0iMTEwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*YD-OAt75d1s69u6qZpWrsw.png" /></p>

<p>在 21 月台这边排队候车，不用担心搭不上，只要是 13:00 前来排队的都会送你到机场(满了会再加开交通车)。</p>

<p>可以直接刷交通卡上下车(Suica) 或是去候车亭里面投币买票。</p>

<p><img src="/assets/aacd5f5cacd1/1*wZz-iSrK6orko9_30h31gw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*wZz-iSrK6orko9_30h31gw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*2Ey3Ma7iGU0aZcvM-5-KuA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*2Ey3Ma7iGU0aZcvM-5-KuA.jpeg" /></p>

<p>因为满员提早 12:45 就发车了。</p>

<h4 id="1320-抵达冈山桃太郎机场">~=13:20 抵达冈山桃太郎机场</h4>

<p><img src="/assets/aacd5f5cacd1/1*7gnnl4V4uwpVHg9wq9sliw.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*7gnnl4V4uwpVHg9wq9sliw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*Zev8bJycwEj6HruuaPqWyA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Zev8bJycwEj6HruuaPqWyA.jpeg" /></p>

<p>时间还非常早，今年搭的是 17:30 起飞的航班、去年是搭 15:25 的这个时间来刚刚好，17:30 起飞的现在来要干等快 4 个小时。</p>

<p><img src="/assets/aacd5f5cacd1/1*EL5tuKai1e95lToFw7agNQ.webp" alt="&lt;https://www.okayama-airport.org/tw/access/bus&gt;" loading="lazy" decoding="async" width="367" height="600" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNjciIGhlaWdodD0iNjAwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*EL5tuKai1e95lToFw7agNQ.png" /></p>

<p><a href="https://www.okayama-airport.org/tw/access/bus" target="_blank">https://www.okayama-airport.org/tw/access/bus</a></p>

<blockquote>
  <p><em>但是目前没办法，因为 <strong>下一班是 15:55，到机场 16:25</strong> ；虽然机场很小同时间航班也只有一班出境算快，但怕塞车之类的因素，很难保证 16:25 会到，像我来的时候遇到塞车整整多了快 30 分钟车程。</em></p>
</blockquote>

<blockquote>
  <p><em>就看之后冈山机场会不多开交通车班次了，或是去 <a href="https://www.facebook.com/groups/207266832755595" target="_blank"><strong>日本自由行讨论区</strong></a> 社团找人拼计程车。</em></p>
</blockquote>

<blockquote>
  <p><em>看别人分享冈山车站到机场计程车大约 7,000 日圆上下。</em></p>
</blockquote>

<p><img src="/assets/aacd5f5cacd1/1*BAf8ZKtaE0PZp3CSqHp5oQ.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*BAf8ZKtaE0PZp3CSqHp5oQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*KulgQh4uI3M8GHBzX3_hSw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*KulgQh4uI3M8GHBzX3_hSw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*VrbZuTSIDQztMYoFgjVMOA.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*VrbZuTSIDQztMYoFgjVMOA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*WloJT1lwu9sE7K1YY2Lmfg.webp" alt="" loading="lazy" decoding="async" width="900" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*WloJT1lwu9sE7K1YY2Lmfg.jpeg" /></p>

<p>在机场附近乱晃，机场外有一个缩小版的冈山后乐园还有很红的枫叶。</p>

<p><img src="/assets/aacd5f5cacd1/1*DFOrcpULEpM1ZAaCsxVbDQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*DFOrcpULEpM1ZAaCsxVbDQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*OO1rTCEh9kw5aQMfaPk_wQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*OO1rTCEh9kw5aQMfaPk_wQ.jpeg" /></p>

<p>车站外也有一尊桃太郎，另外机场温馨提醒要买保险， <strong>我这次就真的就差点被自行车撞。⚠️</strong></p>

<p><img src="/assets/aacd5f5cacd1/1*oMmge-1kLe8YMumlz4I-dw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1050" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEwNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*oMmge-1kLe8YMumlz4I-dw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*BRsrPzntiPcckzgHSzFOaw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*BRsrPzntiPcckzgHSzFOaw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*JZnvFBhhDjBVHdeEqPDYHw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*JZnvFBhhDjBVHdeEqPDYHw.jpeg" /></p>

<p>国内线这边有蛮多位子可以坐著休息。</p>

<p>一楼只有有一家伴手礼店其他什么都没有， <a href="/posts/z-度旅行遊記/山阳地区广岛冈山自由行攻略-6日行程-交通-住宿全解析-31b9b3a63abc/">跟去年一样</a> 买了一个冰桃麻糬吃。</p>

<p><img src="/assets/aacd5f5cacd1/1*PQ1GM0STjbTPYN0p6_S_aA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*PQ1GM0STjbTPYN0p6_S_aA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*dRHe9n0Rpk7sXzbOplk9NA.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*dRHe9n0Rpk7sXzbOplk9NA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*PQ1GM0STjbTPYN0p6_S_aA.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*PQ1GM0STjbTPYN0p6_S_aA.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*MZVip0FtjrMIxj3t3ppxPg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*MZVip0FtjrMIxj3t3ppxPg.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*1vlNWZvaNY8I47Qydyd9cw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*1vlNWZvaNY8I47Qydyd9cw.jpeg" /></p>

<p>二楼在整修只剩部分店有开， <a href="/posts/z-度旅行遊記/山阳地区广岛冈山自由行攻略-6日行程-交通-住宿全解析-31b9b3a63abc/">去年能去的观景平台</a> 好像也没开放了；但至少还有一家伴手礼店跟几家吃的。</p>

<h4 id="1500-开始办理登机手续">~=15:00 开始办理登机手续</h4>

<p><img src="/assets/aacd5f5cacd1/1*lGDYdJexHQY6XkiyPZJOhw.webp" alt="" loading="lazy" decoding="async" width="882" height="1102" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4ODIiIGhlaWdodD0iMTEwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*lGDYdJexHQY6XkiyPZJOhw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*1oLSBw-IwqMJh4-RA81Apg.webp" alt="" loading="lazy" decoding="async" width="1400" height="965" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk2NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*1oLSBw-IwqMJh4-RA81Apg.png" /></p>

<p>桃太郎机场太小，跟其他机场报到＋托运的流程不一样。</p>

<blockquote>
  <p><strong><em>这边是统一排队，要托运的行李过 X 光＋会贴封条贴纸、没要托运的就不用(出境前的安全检查会扫描其他的)，无托运行李的也要跟著排</em></strong> <em>，排到就跟机场人员说没要托运直接过、如果贴完贴纸又打开行李箱就要重新扫描＋贴贴纸。⚠️⚠️⚠️</em></p>
</blockquote>

<blockquote>
  <p><em>机场人员会讲中文…很厉害</em></p>
</blockquote>

<h4 id="1515-报到托运完毕">~=15:15 报到＋托运完毕</h4>

<p><img src="/assets/aacd5f5cacd1/1*k2WrB1ooYpRa8zSD8A2Dlw.webp" alt="" loading="lazy" decoding="async" width="651" height="1104" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NTEiIGhlaWdodD0iMTEwNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*k2WrB1ooYpRa8zSD8A2Dlw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*MNH21H-7oPaOq-GP_uKUpA.webp" alt="" loading="lazy" decoding="async" width="879" height="1102" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzkiIGhlaWdodD0iMTEwMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*MNH21H-7oPaOq-GP_uKUpA.png" /></p>

<p>这次没买什么、没买酒就 17 kg 了…但是我几乎没手提行李，全塞进去了。</p>

<h4 id="1620-开始排安检出境">~=16:20 开始排安检、出境</h4>

<p><img src="/assets/aacd5f5cacd1/1*Wjgk2cV8hkiBkIjxjke6AA.webp" alt="" loading="lazy" decoding="async" width="876" height="1091" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzYiIGhlaWdodD0iMTA5MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*Wjgk2cV8hkiBkIjxjke6AA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*iezQ2KMlAUzJrKjqlHzyLw.webp" alt="" loading="lazy" decoding="async" width="1200" height="900" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*iezQ2KMlAUzJrKjqlHzyLw.jpeg" /></p>

<p>机场整修中. .但依然有扭蛋。</p>

<p><img src="/assets/aacd5f5cacd1/1*di7LhsC-MYyRIVwYRWVU-Q.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*di7LhsC-MYyRIVwYRWVU-Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*AHTIPdSzU7TJrq1hVeKACg.webp" alt="" loading="lazy" decoding="async" width="774" height="931" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NzQiIGhlaWdodD0iOTMxIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/aacd5f5cacd1/1*AHTIPdSzU7TJrq1hVeKACg.png" /></p>

<p>虽然只有一个航班但是因为机场小、工作人员少、只有一条线、检查的也很细，所以排安检出境就大概花了快 20–30 分钟。</p>

<p>倒水跟丢弃物品的地方也就只是个箱子。</p>

<blockquote>
  <p><em>感觉如果赶 15:55 冈山出发，到机场 16:25 的交通车，如果能准时抵达，基本上报到托运那边已经全空了可以直接办理，然后再上来直接排出境安检应该是来得及的。</em></p>
</blockquote>

<blockquote>
  <p><em>只有我们这一航班，所以应该会等到所有已报到的人安检完才会起飞，早来机场晚排安检的人也没比较快。</em></p>
</blockquote>

<h4 id="1642-开始候机">~=16:42 开始候机</h4>

<p><img src="/assets/aacd5f5cacd1/1*dZLP9y156IaL2ZYxefWyAQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*dZLP9y156IaL2ZYxefWyAQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*vb73mCN99CDryoSCqdo_Dw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*vb73mCN99CDryoSCqdo_Dw.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*0-fhLcrfopTMrx9rvE0nYg.webp" alt="" loading="lazy" decoding="async" width="1200" height="827" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgyNyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*0-fhLcrfopTMrx9rvE0nYg.png" /></p>

<p>候机室不大，只有一家免税店，有卖一些伴手礼、烟酒品相不多。</p>

<p><img src="/assets/aacd5f5cacd1/1*SAM-saIjWrap5wL4dAxENQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*SAM-saIjWrap5wL4dAxENQ.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*QCxhYYWHW2RLvZsTgWQ0Sw.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*QCxhYYWHW2RLvZsTgWQ0Sw.jpeg" /></p>

<p>想投几罐桃子水带回台湾，全卖完了；只好投一罐红茶花伝，回来后发现很好喝、不会太甜，后悔没多投几罐。</p>

<h4 id="1810-起飞-延误-40-分钟">~=18:10 起飞 (延误 40 分钟)</h4>

<p><img src="/assets/aacd5f5cacd1/1*f3Yqp6letQnKZI8spjNn-Q.webp" alt="" loading="lazy" decoding="async" width="1024" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDI0IiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*f3Yqp6letQnKZI8spjNn-Q.jpeg" /></p>

<p><img src="/assets/aacd5f5cacd1/1*PSlGa7hB3SwG6zFHnEVFLQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1867" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjE4NjciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/aacd5f5cacd1/1*PSlGa7hB3SwG6zFHnEVFLQ.jpeg" /></p>

<blockquote>
  <p><strong><em>再见冈山、再见日本。</em></strong></p>
</blockquote>

<p>在机上隔壁坐一位 Youtuber 大哥「 <a href="https://www.youtube.com/@lw.chill2022" target="_blank"><strong>跟著我们一起Chill with us</strong></a> 」人很 Nice，他这次是去四国的，互相交流了一下景点推荐，有机会也想去四国。</p>

<h4 id="1945-抵达台湾-延误-10-分钟">19:45 抵达台湾 (延误 10 分钟)</h4>

<p>还好只影响 10 分钟，速速提领完行李飞奔巴士站。</p>

<h4 id="2020-前往台北的大有巴士">20:20 前往台北的大有巴士</h4>

<p><img src="/assets/aacd5f5cacd1/1*EDhpsb6FiVOOwKoDslj3nA.webp" alt="" loading="lazy" decoding="async" width="879" height="1085" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzkiIGhlaWdodD0iMTA4NSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*EDhpsb6FiVOOwKoDslj3nA.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*63kNa-lLfoQ6uKfjEy9BVw.webp" alt="" loading="lazy" decoding="async" width="875" height="1094" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzUiIGhlaWdodD0iMTA5NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*63kNa-lLfoQ6uKfjEy9BVw.png" /></p>

<p><img src="/assets/aacd5f5cacd1/1*uRb-Shzk65f1cuiiBxd6SQ.webp" alt="" loading="lazy" decoding="async" width="768" height="1024" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NjgiIGhlaWdodD0iMTAyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/aacd5f5cacd1/1*uRb-Shzk65f1cuiiBxd6SQ.jpeg" /></p>

<p>依照地点不同可以搭不同的车回家，之前是搭国光直接回台北，这次我要搭大有巴士 11 月台回新北。</p>

<blockquote>
  <p><em>好巧不巧悠游卡余额不够刷不过，又飞奔去柜台用现金买票(还好前一天把台币带在身上)，最终有赶上客运。</em></p>
</blockquote>

<h4 id="旅程结束">旅程结束。</h4>

<h3 id="心得总结">心得总结</h3>

<p>这次的行程安排太紧凑，很多地方都走马看花，尤其前三天因为移动距离较长加上停留时间太短，没有好好慢慢享受岛根出云、松江的美丽景色；如果有机会会想再去一次，看夕阳、看枫叶、看神迎神在祭典。</p>

<p>如果想了解历史再去出云可参考兰爸爸的影片：</p>
<ol>
  <li><a href="https://www.youtube.com/watch?v=cnp9H--KPyY" target="_blank">日本这片土地是怎么诞生的？竟然是被生出来的！！\|日本神话\|日本的诞生\|天地开辟\|国产み\|神产み\|大八岛囯\|伊邪那岐\|伊邪那美\|兰爸爸说故事</a></li>
  <li><a href="https://www.youtube.com/watch?v=W8SjLltb3U4" target="_blank">日本最调皮的神，与自己的姐姐生下了日本皇室的直系祖先！斩杀八岐大蛇，迎娶美丽的妻子，堪称神仙界的“神生赢家”！日本最初的和歌竟然出自他口？！\|日本神话\|须佐之男\|岩户隐\|八岐大蛇\|稻田姬\|兰爸爸说故事</a></li>
  <li><a href="https://www.youtube.com/watch?v=HbxBcKkfCnk" target="_blank">一只兔子为何要招惹一群鲨鱼？经历过两次的死而复生，他竟然迎娶了自己祖先的女儿！大国主神话\|大国主\|因幡之白兔\|根之囯\|日本神话\|兰爸爸说故事</a>
<strong>有介绍到天照大神、大国主神(出云神社)、因幡之白兔的故事。</strong></li>
</ol>

<h4 id="山阳-冈山广岛地区游记">山阳 冈山广岛地区游记</h4>

<ul>
  <li><a href="/posts/z-度旅行遊記/山阳地区广岛冈山自由行攻略-6日行程-交通-住宿全解析-31b9b3a63abc/"><strong>[游记] 2023 山阳地区 广岛冈山 6 日自由行</strong></a></li>
</ul>

<p>可以一起参考山阳地区游记，有时间的话可以山阳＋山阴一起玩。</p>

<h4 id="kkday-推广--1">KKday 推广 🛒</h4>

<ul>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/153331" target="_blank">日本 JR PASS\|鸟取・松江区域周游券\|eMCO 电子票</a>
(如果只去松江、鸟取松江地区可考虑)</p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/20307-jr-sanin-okayama-area-pass?cid=19365" target="_blank"><strong>关西&amp;山阴地区铁路周游券 JRPass</strong></a>
(冈山机场进出最佳选择)</p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/137689-japan-high-speed-daily-unlimited-data-japanese-esim?cid=19365" target="_blank"><strong>日本eSIM卡｜每日高速、总量、无限流量吃到饱方案</strong></a></p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/20315-jr-sanyo-sanin-area-pass?cid=19365" target="_blank">日本 JR PASS｜山阳＆山阴地区铁路周游券｜eMCO 电子票</a>
(一口气玩遍山阳山阴地区)</p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/184144?cid=19365" target="_blank">鸟取沙丘 \| 日本唯一的惊险滑沙体验</a></p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/11463-osaka-bus-tour-tottori-sand-dunes-uratomi-coast-cruise-sand-museum-japan?cid=19365" target="_blank">【鸟取巴士一日游】鸟取砂丘、浦富海岸巡航、砂之美术馆、采梨子体验｜含特色午餐（大阪出发）</a></p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/262558?cid=19365" target="_blank">游览鸟取沙丘和著名的出云大社 2 日巴士之旅（大阪出发）</a></p>
  </li>
  <li>
    <p><a href="https://www.kkday.com/zh-tw/product/185589?cid=19365" target="_blank">新年参观！出云大社停留3小时【广岛出发】</a></p>
  </li>
</ul>

<blockquote>
  <p><a href="https://www.kkday.com/zh-tw?cid=19365" target="_blank">如果这篇文章对您有帮助，欢迎使用我的 推广连结 选购 KKday 商品、行程，我将获得部分收益，持续更多旅游创作，谢谢。</a></p>
</blockquote>

<h3 id="更多游记">更多游记</h3>

<ul>
  <li>
    <p><a href="https://blog.zhgchg.li/%E9%81%8A%E8%A8%98-2025-%E9%9F%93%E5%9C%8B%E9%87%9C%E5%B1%B1-8-%E5%A4%A9-7-%E5%A4%9C%E8%87%AA%E7%94%B1%E8%A1%8C-8ace34a1a3d8?source=collection_home_page----96927b78a281-----0-----------------------------------" target="_blank">[游记] 2025 韩国釜山 8 天 7 夜自由行</a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/九州自由行攻略-福冈-长崎-熊本10日独旅全纪录与交通住宿实战经验-d78e0b15a08a/">[游记] 2023 九州 10 日自由行独旅</a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/山阳地区广岛冈山自由行攻略-6日行程-交通-住宿全解析-31b9b3a63abc/"><strong>[游记] 2023 山阳地区 广岛冈山 6 日自由行</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/z-度旅行遊記/名古屋一日快闪自由行-乐桃航空红眼班机省钱攻略与行程规划-7b8a0563c157/">[游记] 9/11 名古屋一日快闪</a></p>
  </li>
  <li>
    <p>[游记] <a href="/posts/z-度旅行遊記/东京自由行攻略-5-天食住行全记录与必访景点推荐-9da2c51fa4f2/">2023 东京 5 日自由行</a></p>
  </li>
  <li>
    <p>[游记] <a href="/posts/z-度旅行遊記/京阪神自由行攻略-京都大阪神户8日游全纪录与实用交通住宿指南-76d66c2e34af/">2023 京阪神 8 日自由行</a></p>
  </li>
</ul>]]></content>
  </entry><entry>
    <title type="html">GitHub Pages 免费快速建置个人 LinkTree 连结页面｜linkyee 开源模板教学</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/github-pages-%E5%85%8D%E8%B4%B9%E5%BF%AB%E9%80%9F%E5%BB%BA%E7%BD%AE%E4%B8%AA%E4%BA%BA-linktree-%E8%BF%9E%E7%BB%93%E9%A1%B5%E9%9D%A2-linkyee-%E5%BC%80%E6%BA%90%E6%A8%A1%E6%9D%BF%E6%95%99%E5%AD%A6-70aeddb1fd9b/" rel="alternate" type="text/html" title="GitHub Pages 免费快速建置个人 LinkTree 连结页面｜linkyee 开源模板教学" />
    <published>2024-10-27T13:36:34+08:00</published>
    <updated>2024-10-27T21:57:18+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/70aeddb1fd9b</id><summary type="html">透过 linkyee 范本在 GitHub Pages 免费部署专属连结页，支援自订网域与动态追踪数据，免广告且可客制化样式，几步骤完成快速上线，提升个人品牌曝光与连结管理效率。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Robotic Process Automation" /><category term="simplified-chinese" /><category term="linktree" /><category term="github-pages" /><category term="automation" /><category term="ruby" /><category term="jekyll" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/70aeddb1fd9b/1*CbiCUtVY5CV4wRXBaZBoyw.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/github-pages-%E5%85%8D%E8%B4%B9%E5%BF%AB%E9%80%9F%E5%BB%BA%E7%BD%AE%E4%B8%AA%E4%BA%BA-linktree-%E8%BF%9E%E7%BB%93%E9%A1%B5%E9%9D%A2-linkyee-%E5%BC%80%E6%BA%90%E6%A8%A1%E6%9D%BF%E6%95%99%E5%AD%A6-70aeddb1fd9b/"><![CDATA[<h3 id="linkyee--使用-github-pages-快速免费建立个人类-linktree-连结页面">linkyee — 使用 GitHub Pages 快速免费建立个人类 LinkTree 连结页面</h3>

<p>使用 GitHub Pages 快速建立自己的连结页面，100% 免费、客制化并支援自订义网域</p>

<h3 id="成果">成果</h3>

<p><img src="/assets/70aeddb1fd9b/1*EtG_srpR0i0BRE1dziNDXg.webp" alt="&lt;https://link.zhgchg.li&gt;" loading="lazy" decoding="async" width="1400" height="948" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijk0OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/70aeddb1fd9b/1*EtG_srpR0i0BRE1dziNDXg.png" /></p>

<p><a href="https://link.zhgchg.li" target="_blank">https://link.zhgchg.li</a></p>

<blockquote>
  <p><strong><em>我以把成果开源并打包成 Template Repo (linkyee)，有需要的朋友可以直接 Fork 快速部署使用。</em></strong></p>
</blockquote>

<h3 id="linkyee--your-own-link-pages">linkyee — Your Own Link Pages</h3>

<p><a href="https://github.com/ZhgChgLi/linkyee" target="_blank"><img src="https://repository-images.githubusercontent.com/877945203/b2d2ec07-9a56-400c-b24c-db0b180f7d3e" alt="" /></a></p>

<h4 id="优点">优点：</h4>

<ul>
  <li>
    <p>直接部署在 Github Pages 稳定、免费</p>
  </li>
  <li>
    <p>掌握 HTML 原始档案，可随意修改排版、样式、移除广告、版权宣告； <em>(预设样式就是我用 GenAI ChatGPT 建立的)</em></p>
  </li>
  <li>
    <p>支援自订域名</p>
  </li>
  <li>
    <p><strong>支援动态变数，例如我预设建了 Medium 追踪者、Github Repo 星星数变数，可自动带入、更新追踪者数量在页面上。</strong> 🚀🚀🚀</p>
  </li>
  <li>
    <p>页面载入快速</p>
  </li>
  <li>
    <p>照本文简单几步就能完成设定部署</p>
  </li>
</ul>

<h3 id="github-pages">Github Pages</h3>

<p>Github Pages 是由 Github 提供的免费静态页面寄存服务，所有 Github Free 帐号只要是 Public Repo 都能直接使用，如果是 Private Repo 则须先付费升级 Github 帐号。</p>

<h4 id="限制">限制</h4>

<ul>
  <li>
    <p><strong>只能寄存静态档案资源：</strong> HTML, CSS, JavaScript, 字体档案, 图片档案, PDF, 音讯档案, 文字档案…等等</p>
  </li>
  <li>
    <p><strong>网站(Repo)大小不得超过：</strong> 1 GB 这猜测也是软限制，因为我的 Github Pages Jekyll Repo 已经快 5 GB 了。</p>
  </li>
  <li>
    <p><strong>部署工作时间最长：</strong> 10 分钟</p>
  </li>
  <li>
    <p><strong>每小时最多部署：</strong> 10 次 (软限制)</p>
  </li>
  <li>
    <p><strong>每月流量限制</strong> ：100 GB (软限制)</p>
  </li>
  <li>
    <p>请求过于频繁可能会响应 HTTP 429</p>
  </li>
</ul>

<h4 id="其他-github-pages-应用文章">其他 Github Pages 应用文章</h4>

<ul>
  <li>
    <p><a href="/posts/zrealm-dev/无痛转移-medium-文章到自架-jekyll-静态网站-快速部署与自动同步教学-a0c08d579ab1/">我使用 Github Pages 部署的 Jekyll Blog</a> ➡️ <a href="https://zhgchg.li/" target="_blank"><strong>ZhgChgLi</strong></a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/无痛转移-medium-文章到自架-jekyll-静态网站-快速部署与自动同步教学-a0c08d579ab1/">无痛转移 Medium 到 Github Pages</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/github-pages-自订网域教学-namecheap-购域设定完整流程与部署指引-483af5d93297/"><strong>Github Pages 自订网域教学</strong></a></p>
  </li>
</ul>

<h3 id="开始使用--部署在-github-pages">开始使用 — 部署在 GitHub Pages</h3>

<h4 id="步骤-1-点击-linkyee-范本库右上角的use-this-template按钮--create-a-new-repository">步骤 1. 点击 linkyee 范本库右上角的「Use this template」按钮 -&gt;「Create a new repository」：</h4>

<p><img src="/assets/70aeddb1fd9b/1*G6pU845OnIyEdl-Os0EnwQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1159" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjExNTkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/70aeddb1fd9b/1*G6pU845OnIyEdl-Os0EnwQ.png" /></p>

<h4 id="步骤-2-勾选include-all-branches输入您想要的-github-pages-仓库名称完成后点击create-repository">步骤 2. 勾选「Include all branches」，输入您想要的 GitHub Pages 仓库名称，完成后点击「Create repository」：</h4>

<p><img src="/assets/70aeddb1fd9b/1*PN9zygdxqJmFtUz9Pq35cQ.webp" alt="" loading="lazy" decoding="async" width="1400" height="1159" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjExNTkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/70aeddb1fd9b/1*PN9zygdxqJmFtUz9Pq35cQ.png" /></p>

<blockquote>
  <p><em>GitHub Pages Repo 名称就会是访问网址。</em></p>
</blockquote>

<blockquote>
  <p><em>如果将 Repo 名称输入为 <code class="language-plaintext highlighter-rouge">your-username.github.io</code> ，那么这将成为您的 GitHub Pages 网站的直接访问网址。</em></p>
</blockquote>

<blockquote>
  <p><em>如果您已有 <code class="language-plaintext highlighter-rouge">your-username.github.io</code> Repo，那么 GitHub Pages 网址将会是 <code class="language-plaintext highlighter-rouge">your-username.github.io/Repo-Name</code> 。</em></p>
</blockquote>

<h4 id="等待-fork-完成初次建立时可能会遇到部署错误这是由于-fork-仓库的权限问题接下来我们按照步骤进行调整">等待 Fork 完成。初次建立时可能会遇到部署错误，这是由于 Fork 仓库的权限问题。接下来我们按照步骤进行调整。</h4>

<p><img src="/assets/70aeddb1fd9b/1*EYXix1zABfKXboAxkn_-yw.webp" alt="" loading="lazy" decoding="async" width="374" height="74" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNzQiIGhlaWdodD0iNzQiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/70aeddb1fd9b/1*EYXix1zABfKXboAxkn_-yw.png" /></p>

<h4 id="步骤-4-前往-settings---actions---general确保选择以下选项">步骤 4. 前往 Settings -&gt; Actions -&gt; General，确保选择以下选项：</h4>

<p><img src="/assets/70aeddb1fd9b/1*5c4TZm0ZjolIPPalwEbJMA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1159" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjExNTkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/70aeddb1fd9b/1*5c4TZm0ZjolIPPalwEbJMA.png" /></p>

<ul>
  <li>
    <p>Actions permissions: Allow all actions and reusable workflows</p>
  </li>
  <li>
    <p>Workflow permissions: Read and write permissions</p>
  </li>
</ul>

<p><strong>选择完毕后，点击 Save 按钮储存变更。</strong></p>

<h4 id="步骤-5-前往-settings---pages确认-github-pages-的分支设定为gh-pages">步骤 5. 前往 Settings -&gt; Pages，确认 GitHub Pages 的分支设定为「gh-pages」：</h4>

<p><img src="/assets/70aeddb1fd9b/1*2mmeneQOLEuhRqZIovSh9A.webp" alt="" loading="lazy" decoding="async" width="1200" height="993" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk5MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/70aeddb1fd9b/1*2mmeneQOLEuhRqZIovSh9A.png" /></p>

<blockquote>
  <p><em>「Your site is live at: XXXX」讯息即为您的 GitHub Pages 公开访问网址。</em></p>
</blockquote>

<h4 id="步骤-6-前往-settings---actions等待第一次部署完成">步骤 6. 前往 Settings -&gt; Actions，等待第一次部署完成：</h4>

<p><img src="/assets/70aeddb1fd9b/1*mFQmtcTZr-OjBhqtHwebEw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1159" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjExNTkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/70aeddb1fd9b/1*mFQmtcTZr-OjBhqtHwebEw.png" /></p>

<h4 id="步骤-7-访问-github-pages-网址确认-fork-是否成功">步骤 7. 访问 GitHub Pages 网址，确认 Fork 是否成功：</h4>

<p><img src="/assets/70aeddb1fd9b/1*1vaJpnwjZtsWEjBvKcGjVw.webp" alt="" loading="lazy" decoding="async" width="1200" height="993" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk5MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/70aeddb1fd9b/1*1vaJpnwjZtsWEjBvKcGjVw.png" /></p>

<blockquote>
  <p>恭喜！部署成功，现在您可以修改设定档案，将其替换为您的资料。🎉🎉🎉</p>
</blockquote>

<h3 id="设定">设定</h3>

<h4 id="设定档案">设定档案</h4>

<p>编辑位于根目录中的 config.yml 文件。</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 网站配置  </span>

<span class="c1"># 主题名称，对应至目录：./theme/xxxx  </span>
<span class="na">theme</span><span class="pi">:</span> <span class="s">default</span>  

<span class="c1"># HTML 语言设定  </span>
<span class="na">lang</span><span class="pi">:</span> <span class="s2">"</span><span class="s">en"</span>  

<span class="c1"># 插件（实作于 ./plugins/PLUGIN_NAME）  </span>
<span class="c1"># 在下方设定中使用 {{ vars.PLUGIN_NAME }}  </span>

<span class="c1"># 插件的输出结果可在下方使用，例如：{{vars.MediumFollowersCountPlugin}}  </span>
<span class="na">plugins</span><span class="pi">:</span>  
  <span class="c1"># 自动获取 Medium 的追踪者数量  </span>
  <span class="pi">-</span> <span class="na">MediumFollowersCountPlugin</span><span class="pi">:</span>  
      <span class="na">username</span><span class="pi">:</span> <span class="s">zhgchgli</span>  
  <span class="c1"># 自动获取 GitHub 仓库的星标数量  </span>
  <span class="pi">-</span> <span class="na">GithubRepoStarsCountPlugin</span><span class="pi">:</span>  
      <span class="pi">-</span> <span class="s">ZhgChgLi/ZMarkupParser</span>  
      <span class="pi">-</span> <span class="s">ZhgChgLi/ZReviewTender</span>  
      <span class="pi">-</span> <span class="s">ZhgChgLi/ZMediumToMarkdown</span>  
      <span class="pi">-</span> <span class="s">ZhgChgLi/linkyee</span>  

<span class="c1"># Google Analytics 追踪 ID  </span>
<span class="na">google_analytics_id</span><span class="pi">:</span>  

<span class="c1"># HTML 标题  </span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的连结集"</span>  

<span class="c1"># 头像图片路径  </span>
<span class="na">avatar</span><span class="pi">:</span> <span class="s2">"</span><span class="s">./images/profile.jpeg"</span>  

<span class="c1"># 名称区块文字  </span>
<span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">@zhgchgli"</span>  

<span class="c1"># 标语区块文字  </span>
<span class="na">tagline</span><span class="pi">:</span> <span class="pi">&gt;-</span>  
    <span class="s">一位来自台湾的 iOS、网页与自动化开发者，热爱分享、旅行与写作。  </span>

<span class="c1"># 连结列表  </span>
<span class="c1"># icon：使用 Font Awesome 图示 (https://fontawesome.com/search?o=r&amp;m=free)  </span>
<span class="c1"># text：显示在连结上的文字  </span>
<span class="c1"># title：连结的标题  </span>
<span class="c1"># url：连结的网址  </span>
<span class="c1"># alt：替代文字（无障碍使用）  </span>
<span class="c1"># target：`_blank` 在新页签打开，`_self` 在同页面打开  </span>
<span class="na">links</span><span class="pi">:</span>  
  <span class="pi">-</span> <span class="na">link</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-brands</span><span class="nv"> </span><span class="s">fa-medium"</span>  
      <span class="na">text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">技术部落格</span><span class="nv"> </span><span class="s">&lt;span</span><span class="nv"> </span><span class="s">class='link-button-text'&gt;({{vars.MediumFollowersCountPlugin}}</span><span class="nv"> </span><span class="s">Followers)&lt;/span&gt;"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://blog.zhgchg.li"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的技术部落格"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的技术部落格"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  
  <span class="pi">-</span> <span class="na">link</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-brands</span><span class="nv"> </span><span class="s">fa-medium"</span>  
      <span class="na">text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">旅行日志</span><span class="nv"> </span><span class="s">&lt;span</span><span class="nv"> </span><span class="s">class='link-button-text'&gt;({{vars.MediumFollowersCountPlugin}}</span><span class="nv"> </span><span class="s">Followers)&lt;/span&gt;"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://medium.com/ztravel"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的旅行日志"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的旅行日志"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  
  <span class="pi">-</span> <span class="na">link</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-solid</span><span class="nv"> </span><span class="s">fa-rss"</span>  
      <span class="na">text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">个人网站"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://zhgchg.li/"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的网站"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的网站"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  
  <span class="pi">-</span> <span class="na">link</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-brands</span><span class="nv"> </span><span class="s">fa-swift"</span>  
      <span class="na">text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZMarkupParser</span><span class="nv"> </span><span class="s">&lt;span</span><span class="nv"> </span><span class="s">class='link-button-text'&gt;({{vars.GithubRepoStarsCountPlugin['ZhgChgLi/ZMarkupParser']}}</span><span class="nv"> </span><span class="s">Stars)&lt;/span&gt;"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://github.com/ZhgChgLi/ZMarkupParser"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZMarkupParser</span><span class="nv"> </span><span class="s">是一个纯</span><span class="nv"> </span><span class="s">Swift</span><span class="nv"> </span><span class="s">库，用于将</span><span class="nv"> </span><span class="s">HTML</span><span class="nv"> </span><span class="s">字串转换为具自订样式的</span><span class="nv"> </span><span class="s">NSAttributedString。"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZMarkupParser</span><span class="nv"> </span><span class="s">是一个纯</span><span class="nv"> </span><span class="s">Swift</span><span class="nv"> </span><span class="s">库，用于将</span><span class="nv"> </span><span class="s">HTML</span><span class="nv"> </span><span class="s">字串转换为具自订样式的</span><span class="nv"> </span><span class="s">NSAttributedString。"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  
  <span class="pi">-</span> <span class="na">link</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-brands</span><span class="nv"> </span><span class="s">fa-app-store-ios"</span>  
      <span class="na">text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZReviewTender</span><span class="nv"> </span><span class="s">&lt;span</span><span class="nv"> </span><span class="s">class='link-button-text'&gt;({{vars.GithubRepoStarsCountPlugin['ZhgChgLi/ZReviewTender']}}</span><span class="nv"> </span><span class="s">Stars)&lt;/span&gt;"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://github.com/ZhgChgLi/ZReviewTender"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZReviewTender</span><span class="nv"> </span><span class="s">是一个从</span><span class="nv"> </span><span class="s">App</span><span class="nv"> </span><span class="s">Store</span><span class="nv"> </span><span class="s">和</span><span class="nv"> </span><span class="s">Google</span><span class="nv"> </span><span class="s">Play</span><span class="nv"> </span><span class="s">Console</span><span class="nv"> </span><span class="s">获取应用评论并整合至工作流程的工具。"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZReviewTender</span><span class="nv"> </span><span class="s">是一个从</span><span class="nv"> </span><span class="s">App</span><span class="nv"> </span><span class="s">Store</span><span class="nv"> </span><span class="s">和</span><span class="nv"> </span><span class="s">Google</span><span class="nv"> </span><span class="s">Play</span><span class="nv"> </span><span class="s">Console</span><span class="nv"> </span><span class="s">获取应用评论并整合至工作流程的工具。"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  
  <span class="pi">-</span> <span class="na">link</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-brands</span><span class="nv"> </span><span class="s">fa-markdown"</span>  
      <span class="na">text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZMediumToMarkdown</span><span class="nv"> </span><span class="s">&lt;span</span><span class="nv"> </span><span class="s">class='link-button-text'&gt;({{vars.GithubRepoStarsCountPlugin['ZhgChgLi/ZMediumToMarkdown']}}</span><span class="nv"> </span><span class="s">Stars)&lt;/span&gt;"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://github.com/ZhgChgLi/ZMediumToMarkdown"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZMediumToMarkdown</span><span class="nv"> </span><span class="s">是一个强大的工具，可轻松下载并将</span><span class="nv"> </span><span class="s">Medium</span><span class="nv"> </span><span class="s">文章转换为</span><span class="nv"> </span><span class="s">Markdown</span><span class="nv"> </span><span class="s">格式。"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZMediumToMarkdown</span><span class="nv"> </span><span class="s">是一个强大的工具，可轻松下载并将</span><span class="nv"> </span><span class="s">Medium</span><span class="nv"> </span><span class="s">文章转换为</span><span class="nv"> </span><span class="s">Markdown</span><span class="nv"> </span><span class="s">格式。"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  
  <span class="pi">-</span> <span class="na">link</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-brands</span><span class="nv"> </span><span class="s">fa-github"</span>  
      <span class="na">text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">linkyee</span><span class="nv"> </span><span class="s">&lt;span</span><span class="nv"> </span><span class="s">class='link-button-text'&gt;({{vars.GithubRepoStarsCountPlugin['ZhgChgLi/linkyee']}}</span><span class="nv"> </span><span class="s">Stars)&lt;/span&gt;"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://github.com/ZhgChgLi/linkyee"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">linkyee</span><span class="nv"> </span><span class="s">是一个完全自订且开源的</span><span class="nv"> </span><span class="s">LinkTree</span><span class="nv"> </span><span class="s">替代方案，可直接部署在</span><span class="nv"> </span><span class="s">GitHub</span><span class="nv"> </span><span class="s">Pages</span><span class="nv"> </span><span class="s">上。"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">linkyee</span><span class="nv"> </span><span class="s">是一个完全自订且开源的</span><span class="nv"> </span><span class="s">LinkTree</span><span class="nv"> </span><span class="s">替代方案，可直接部署在</span><span class="nv"> </span><span class="s">GitHub</span><span class="nv"> </span><span class="s">Pages</span><span class="nv"> </span><span class="s">上。"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  

<span class="c1"># 社交媒体连结列表  </span>
<span class="c1"># icon：使用 Font Awesome 图示 (https://fontawesome.com/search?o=r&amp;m=free)  </span>
<span class="c1"># title：连结的标题  </span>
<span class="c1"># url：社交媒体连结的网址  </span>
<span class="c1"># alt：替代文字（无障碍使用）  </span>
<span class="c1"># target：`_blank` 在新页签打开，`_self` 在同页面打开  </span>
<span class="na">socials</span><span class="pi">:</span>  
  <span class="pi">-</span> <span class="na">social</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-brands</span><span class="nv"> </span><span class="s">fa-medium"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://blog.zhgchg.li"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的</span><span class="nv"> </span><span class="s">Medium"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的</span><span class="nv"> </span><span class="s">Medium"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  
  <span class="pi">-</span> <span class="na">social</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-brands</span><span class="nv"> </span><span class="s">fa-github"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://github.com/ZhgChgLi"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的</span><span class="nv"> </span><span class="s">GitHub"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的</span><span class="nv"> </span><span class="s">GitHub"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  
  <span class="pi">-</span> <span class="na">social</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-brands</span><span class="nv"> </span><span class="s">fa-twitter"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://twitter.com/zhgchgli"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的</span><span class="nv"> </span><span class="s">Twitter"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的</span><span class="nv"> </span><span class="s">Twitter"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  
  <span class="pi">-</span> <span class="na">social</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-brands</span><span class="nv"> </span><span class="s">fa-linkedin"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://www.linkedin.com/in/zhgchgli/"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的</span><span class="nv"> </span><span class="s">LinkedIn"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的</span><span class="nv"> </span><span class="s">LinkedIn"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  
  <span class="pi">-</span> <span class="na">social</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-brands</span><span class="nv"> </span><span class="s">fa-instagram"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://www.instagram.com/zhgchgli/"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Instagram"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ZhgChgLi</span><span class="nv"> </span><span class="s">的</span><span class="nv"> </span><span class="s">Instagram"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  
  <span class="pi">-</span> <span class="na">social</span><span class="pi">:</span>  
      <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">fa-solid</span><span class="nv"> </span><span class="s">fa-envelope"</span>  
      <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">zhgchgli@gmail.com"</span>  
      <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Email:</span><span class="nv"> </span><span class="s">zhgchgli@gmail.com"</span>  
      <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">zhgchgli@gmail.com"</span>  
      <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">_blank"</span>  

<span class="c1"># 页尾文字  </span>
<span class="na">footer</span><span class="pi">:</span> <span class="pi">&gt;</span>  
    <span class="s">欢迎来到我的网站！追踪我在 Medium 或 GitHub 上的最新动态，或在 Instagram 和 LinkedIn 上保持联系。  </span>

<span class="c1"># 页尾版权声明  </span>
<span class="c1"># Linkyee 是一个 100% 免费的开源专案—您可以随意修改版权声明。:)  </span>
<span class="na">copyright</span><span class="pi">:</span> <span class="pi">&gt;</span>  
  <span class="s">© 2024 &lt;a href="https://zhgchg.li" target="_blank"&gt;ZhgChgLi&lt;/a&gt;。由 &lt;a href="https://github.com/ZhgChgLi/linkyee" target="_blank"&gt;linkyee&lt;/a&gt; 提供技术支持。  </span>
</code></pre></div></div>

<blockquote>
  <p><strong><em>请注意，每次修改文件后，您需要等待 GitHub Actions 完成自动建置和页面建置与部署任务。</em></strong></p>
</blockquote>

<p><img src="/assets/70aeddb1fd9b/1*56qGAyuECrqDJQMoKbPiOw.webp" alt="" loading="lazy" decoding="async" width="1400" height="1165" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjExNjUiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/70aeddb1fd9b/1*56qGAyuECrqDJQMoKbPiOw.png" /></p>

<blockquote>
  <p><strong><em>重新整理页面以使变更生效。🚀</em></strong></p>
</blockquote>

<p><img src="/assets/70aeddb1fd9b/1*CbiCUtVY5CV4wRXBaZBoyw.webp" alt="" loading="lazy" decoding="async" width="1200" height="809" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwOSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/70aeddb1fd9b/1*CbiCUtVY5CV4wRXBaZBoyw.jpeg" /></p>

<p>成功！！</p>

<h4 id="自订风格样式修改预设主题">自订风格样式、修改预设主题</h4>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">./themes/default/index.html</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">./themes/default/styles.css</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">./themes/default/scripts.js</code></p>
  </li>
</ul>

<h4 id="创建新主题">创建新主题</h4>

<ul>
  <li>
    <p>./themes/ <code class="language-plaintext highlighter-rouge">YOUR_THEME</code></p>
  </li>
  <li>
    <p>在 config.yml 文件中更新为 <code class="language-plaintext highlighter-rouge">theme:YOUR_THEME</code></p>
  </li>
</ul>

<p><strong>没错，您可以使用像 ChatGPT 这样的 GenAI 工具，来帮助您创建自订的连结页面！(预设样式也是我用 ChatGPT 产的)</strong></p>

<h4 id="自动重新部署">自动重新部署</h4>

<p>预设情况下，专案每天会自动重新部署一次，以刷新插件的动态变数值。您可以在 <a href="https://github.com/ZhgChgLi/linkyee/blob/main/.github/workflows/build.yml" target="_blank">Github Action — Automatic build ( .github/workflows/build.yml)</a> 中调整 cron 设定：</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">schedule</span><span class="pi">:</span>
 <span class="pi">-</span> <span class="na">cron</span><span class="pi">:</span> <span class="s1">'</span><span class="s">0</span><span class="nv"> </span><span class="s">0</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*'</span> <span class="c1"># 每日午夜 00:00 (UTC) 执行</span>
</code></pre></div></div>

<p>如果不需要定时重新部署，可以直接删除 <code class="language-plaintext highlighter-rouge">schedule</code> 区块。</p>

<h3 id="自订网域-️️️">自订网域 ❤️❤️❤️</h3>

<p>您可以设置自订的 GitHub Pages 网域， <strong>例如我的： <a href="https://link.zhgchg.li" target="_blank">https://link.zhgchg.li</a> 。</strong></p>

<p>可以找我之前的文章「 <a href="/posts/zrealm-dev/github-pages-自订网域教学-namecheap-购域设定完整流程与部署指引-483af5d93297/"><strong>Github Pages 自订网域教学</strong></a> 」一步一步从购买到绑定网域，也可以通过 <a href="https://namecheap.pxf.io/P0jdZQ" target="_blank"><strong>我的 Namecheap 推广连结购买网域</strong></a> — 我将获得部分分润，这将帮助我继续贡献开源专案。</p>

<h3 id="buy-me-a-coffee-️️️">Buy me a coffee ❤️❤️❤️</h3>

<p><img src="/assets/70aeddb1fd9b/1*QCQqlZr6doDP-cszzpaSpw.webp" alt="&lt;https://www.paypal.com/ncp/payment/CMALMPT8UUTY2&gt;" loading="lazy" decoding="async" width="1090" height="306" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDkwIiBoZWlnaHQ9IjMwNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/70aeddb1fd9b/1*QCQqlZr6doDP-cszzpaSpw.png" /></p>

<p><a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank">https://www.paypal.com/ncp/payment/CMALMPT8UUTY2</a></p>

<p>如果这个专案对您有帮助，请考虑 <a href="https://github.com/ZhgChgLi/linkyee" target="_blank">Star Repo、推荐给朋友</a> ， <strong>或 <a href="https://www.paypal.com/ncp/payment/CMALMPT8UUTY2" target="_blank">赞助我一杯咖啡。感谢您的支持！</a></strong></p>

<p>欢迎提出 Issue，或透过 Pull Request 提交修正或贡献。:)</p>]]></content>
  </entry><entry>
    <title type="html">GA4 自动数据通知机器人｜3 步骤用 Google Apps Script 串接 Telegram Bot</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/ga4-%E8%87%AA%E5%8A%A8%E6%95%B0%E6%8D%AE%E9%80%9A%E7%9F%A5%E6%9C%BA%E5%99%A8%E4%BA%BA-3-%E6%AD%A5%E9%AA%A4%E7%94%A8-google-apps-script-%E4%B8%B2%E6%8E%A5-telegram-bot-1e85b8df2348/" rel="alternate" type="text/html" title="GA4 自动数据通知机器人｜3 步骤用 Google Apps Script 串接 Telegram Bot" />
    <published>2024-10-20T16:19:52+08:00</published>
    <updated>2024-10-20T16:19:52+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/1e85b8df2348</id><summary type="html">针对希望即时掌握网站数据的使用者，教你用 3 步骤打造免费 GA4 自动通知机器人，结合 Google Apps Script 与 Telegram Bot，定时推送近 7 天流量与热门页面，减少人工查询时间，提升数据监控效率。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Robotic Process Automation" /><category term="simplified-chinese" /><category term="automation" /><category term="google-apps-script" /><category term="telegram" /><category term="google-analytics" /><category term="rpa-solutions" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/1e85b8df2348/1*La0AKKSrGNP9EZUV-vrONQ.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/ga4-%E8%87%AA%E5%8A%A8%E6%95%B0%E6%8D%AE%E9%80%9A%E7%9F%A5%E6%9C%BA%E5%99%A8%E4%BA%BA-3-%E6%AD%A5%E9%AA%A4%E7%94%A8-google-apps-script-%E4%B8%B2%E6%8E%A5-telegram-bot-1e85b8df2348/"><![CDATA[<h3 id="简单-3-步骤--打造免费-ga4-自动数据通知机器人">简单 3 步骤 — 打造免费 GA4 自动数据通知机器人</h3>

<p>使用 Google Apps Script 完成 RPA，自行串接 GA4 + Telegram Bot 数据通知机器人</p>

<p><img src="/assets/1e85b8df2348/1*La0AKKSrGNP9EZUV-vrONQ.webp" alt="Photo by BoliviaInteligente" loading="lazy" decoding="async" width="1200" height="750" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijc1MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/1e85b8df2348/1*La0AKKSrGNP9EZUV-vrONQ.jpeg" /></p>

<p>Photo by <a href="https://unsplash.com/@boliviainteligente?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank">BoliviaInteligente</a></p>

<h3 id="前言">前言</h3>

<p>大约从 2020 年开始就自己在摸索使用手边工具实现 RPA，从一开始只是为了自动化个人例行任务，到后来工作也加入了规模更大型的组织，时常会遇到跨团队或仰赖人与人的任务、甚至是重复性任务，才发现 RPA 自动化的效益所在。</p>

<p>举例来说：某个重复任务每个月会发生 10 次，每次需花费 30 分钟处理，有 60 人会遇到，每年团队等于消耗 3,600 小时在这上面，如果能投资 100 小时开发成自动化，后续解放出来的时间，就能投入在更有价值的工作上；实际等于 3,600 浪费的工时＋3,600 更值得投资的产出。</p>

<h4 id="详细可参考我之前的文章"><strong>详细可参考我之前的文章：</strong></h4>

<ul>
  <li>
    <p><a href="/posts/pinkoi-engineering/高效率工程团队大解密-pinkoi-团队协作与自动化实践提升工作效率-11f6c8568154/">2021 Pinkoi Tech Career Talk — 高效率工程团队大解密</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-robotic-process-automation/google-apps-script-打造每日数据报表自动化-rpa-快速串接-google-analytics-与-google-sheet-f6713ba3fee3/">使用 Google Apps Script 实现每日数据报表 RPA 自动化</a></p>
  </li>
</ul>

<h4 id="其他做过的-rpa">其他做过的 RPA：</h4>

<ul>
  <li>
    <p>[GMail to Slack] <a href="/posts/zrealm-dev/google-apps-script-教学-自动转发-gmail-邮件到-slack-channel-客制化通知-d414bdbdb8c9/">运用 Google Apps Script 转发 Gmail 信件到 Slack</a></p>
  </li>
  <li>
    <p>[Google Form x Google Sheet xSlack] <a href="https://medium.com/zrealm-robotic-process-automation/slack-%E6%89%93%E9%80%A0%E5%85%A8%E8%87%AA%E5%8B%95-wfh-%E5%93%A1%E5%B7%A5%E5%81%A5%E5%BA%B7%E7%8B%80%E6%B3%81%E5%9B%9E%E5%A0%B1%E7%B3%BB%E7%B5%B1-d61062833c1a?source=collection_home---6------9-----------------------" target="_blank">Slack 打造全自动 WFH 员工健康状况回报系统</a></p>
  </li>
  <li>
    <p>[Big Query x Slack ] <a href="https://medium.com/zrealm-robotic-process-automation/crashlytics-big-query-%E6%89%93%E9%80%A0%E6%9B%B4%E5%8D%B3%E6%99%82%E4%BE%BF%E5%88%A9%E7%9A%84-crash-%E8%BF%BD%E8%B9%A4%E5%B7%A5%E5%85%B7-e77b80cc6f89?source=collection_home---6------7-----------------------" target="_blank">Crashlytics + Big Query 打造更即时便利的 Crash 追踪工具</a></p>
  </li>
  <li>
    <p>[Google Analytics x Slack] <a href="https://medium.com/zrealm-robotic-process-automation/crashlytics-google-analytics-%E8%87%AA%E5%8B%95%E6%9F%A5%E8%A9%A2-app-crash-free-users-rate-793cb8f89b72?source=collection_home---6------6-----------------------" target="_blank">Crashlytics + Google Analytics 自动查询 App Crash-Free Users Rate</a></p>
  </li>
  <li>
    <p>[Github Webhook x Line Notify] <a href="https://medium.com/zrealm-robotic-process-automation/%E4%BD%BF%E7%94%A8-google-apps-script-%E4%B8%89%E6%AD%A5%E9%A9%9F%E5%85%8D%E8%B2%BB%E5%BB%BA%E7%AB%8B-github-repo-star-notifier-382218e15697?source=collection_home---6------5-----------------------" target="_blank">使用 Google Apps Script 三步骤免费建立 Github Repo Star Notifier</a></p>
  </li>
  <li>
    <p>[Slack x OpenAI (ChatGTP) ] <a href="https://medium.com/zrealm-robotic-process-automation/slack-chatgpt-integration-bd94cc88f9c9?source=collection_home---6------4-----------------------" target="_blank">Slack &amp; ChatGPT Integration</a></p>
  </li>
  <li>
    <p>[Google Analytics x Google Sheet] <a href="https://medium.com/zrealm-robotic-process-automation/%E4%BD%BF%E7%94%A8-google-apps-script-%E5%AF%A6%E7%8F%BE-google-%E6%9C%8D%E5%8B%99-rpa-%E8%87%AA%E5%8B%95%E5%8C%96-f6713ba3fee3?source=collection_home---6------3-----------------------" target="_blank">使用 Google Apps Script 实现每日数据报表 RPA 自动化</a></p>
  </li>
  <li>
    <p>[iOS Shortcut x Line x Reminders] <a href="https://medium.com/zrealm-robotic-process-automation/ios-%E6%8D%B7%E5%BE%91%E8%87%AA%E5%8B%95%E5%8C%96%E6%87%89%E7%94%A8%E5%A0%B4%E6%99%AF-%E8%87%AA%E5%8B%95%E8%BD%89%E7%99%BC%E7%B0%A1%E8%A8%8A%E8%88%87%E8%87%AA%E5%8B%95%E5%BB%BA%E7%AB%8B%E6%8F%90%E9%86%92%E5%BE%85%E8%BE%A6%E4%BA%8B%E9%A0%85-309d0302877b?source=collection_home---6------2-----------------------" target="_blank">iOS 捷径自动化应用场景 — 自动转发简讯与自动建立提醒待办事项</a></p>
  </li>
  <li>
    <p>[Apple Store API x Google Play Console API x Github Action] <a href="https://medium.com/zrealm-robotic-process-automation/quick-start-github-action-x-zreviewtender-%E5%85%8D%E8%B2%BB%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E4%BD%A0%E7%9A%84-app-%E5%95%86%E5%9F%8E%E8%A9%95%E5%83%B9%E7%9B%A3%E6%8E%A7%E6%A9%9F%E5%99%A8%E4%BA%BA-0095528cf875?source=collection_home---6------1-----------------------" target="_blank">Github Action x ZReviewTender 免费快速部署你的 App 商城评价监控机器人</a></p>
  </li>
  <li>
    <p>[Telegram Bot] <a href="https://medium.com/zrealm-robotic-process-automation/10-%E5%88%86%E9%90%98%E5%BF%AB%E9%80%9F%E7%A7%BB%E8%BD%89-line-notify-%E5%88%B0-telegram-bot-%E9%80%9A%E7%9F%A5-6922e90ba90c?source=collection_home---6------0-----------------------" target="_blank">10 分钟快速移转 Line Notify 到 Telegram Bot 通知</a></p>
  </li>
  <li>
    <p>[Medium to Jekyllrb] <a href="/posts/zrealm-dev/无痛转移-medium-文章到自架-jekyll-静态网站-快速部署与自动同步教学-a0c08d579ab1/">无痛转移 Medium 到自架网站</a></p>
  </li>
</ul>

<p>从后台数据看之前蛮多文章有被 ChatGPT 或各种 GenAI 服务收录，间接的帮助了许多非工程背景但也想尝试使用 RPA 解决问题的朋友，因此我仍会持续分享自己生活或工作上遇到的 RPA 场景跟我的解决方案与大家分享 — <a href="/posts/zrealm-dev/google-apps-script-教学-自动转发-gmail-邮件到-slack-channel-客制化通知-d414bdbdb8c9/">ZRealm Robotic Process Automation</a> 。</p>

<h4 id="工商时间">工商时间</h4>

<p>如果您与您的团队有自动化工具、流程串接需求，不论是 Slack App 开发、Notion、Asana、Google Sheet、Google Form、GA 数据，各种串接需求，欢迎与我 <a href="https://zhgchg.li/contact/" target="_blank"><strong>联络开发</strong></a> 。</p>

<h3 id="本篇-google-analytics-4-x-telegram-bot">本篇 Google Analytics 4 x Telegram Bot</h3>

<p>这次要介绍的串接场景是接续上一篇「 <a href="https://medium.com/zrealm-robotic-process-automation/10-%E5%88%86%E9%90%98%E5%BF%AB%E9%80%9F%E7%A7%BB%E8%BD%89-line-notify-%E5%88%B0-telegram-bot-%E9%80%9A%E7%9F%A5-6922e90ba90c?source=collection_home---6------0-----------------------" target="_blank">10 分钟快速移转 Line Notify 到 Telegram Bot 通知</a> 」时想到我的 Medium 备份站「 <a href="https://zhgchg.li/" target="_blank">zhgchg.li</a> 」一直都没有关注他的 GA4 网站数据，想说好像可以多做一个通知机器人，每日传送过去 7 天的网站数据到指定的 Telegram Channel 让我知道。</p>

<p>本篇只是小品，如果要做完整的自动化数据报表请参考之前的文章「 <a href="https://medium.com/zrealm-robotic-process-automation/%E4%BD%BF%E7%94%A8-google-apps-script-%E5%AF%A6%E7%8F%BE-google-%E6%9C%8D%E5%8B%99-rpa-%E8%87%AA%E5%8B%95%E5%8C%96-f6713ba3fee3?source=collection_home---6------3-----------------------" target="_blank">使用 Google Apps Script 实现每日数据报表 RPA 自动化</a> 」另外之前也曾串过 GA4 捞取 App Crash-free rate 可参考此篇文章「 <a href="https://medium.com/zrealm-robotic-process-automation/crashlytics-google-analytics-%E8%87%AA%E5%8B%95%E6%9F%A5%E8%A9%A2-app-crash-free-users-rate-793cb8f89b72?source=collection_home---6------6-----------------------" target="_blank">Crashlytics + Google Analytics 自动查询 App Crash-Free Users Rate</a> 」。</p>

<ul>
  <li>
    <p>Google Apps Script 免费限制、详细使用、部署、功能介绍本篇不会再多介绍，请参考 <a href="https://medium.com/zrealm-robotic-process-automation/%E4%BD%BF%E7%94%A8-google-apps-script-%E5%AF%A6%E7%8F%BE-google-%E6%9C%8D%E5%8B%99-rpa-%E8%87%AA%E5%8B%95%E5%8C%96-f6713ba3fee3?source=collection_home---6------3-----------------------" target="_blank">之前文章</a> 。</p>
  </li>
  <li>
    <p>Telegram Bot 创建、使用本篇也不会再多介绍，同样请参考 <a href="https://medium.com/zrealm-robotic-process-automation/10-%E5%88%86%E9%90%98%E5%BF%AB%E9%80%9F%E7%A7%BB%E8%BD%89-line-notify-%E5%88%B0-telegram-bot-%E9%80%9A%E7%9F%A5-6922e90ba90c?source=collection_home---6------0-----------------------" target="_blank">之前文章</a> 。</p>
  </li>
</ul>

<h4 id="成果">成果</h4>

<p><img src="/assets/1e85b8df2348/1*J7QdgrJRNzVFQJfW5UBBFA.webp" alt="" loading="lazy" decoding="async" width="555" height="460" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NTUiIGhlaWdodD0iNDYwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/1e85b8df2348/1*J7QdgrJRNzVFQJfW5UBBFA.png" /></p>

<p>先上最终效果，Google Apps Script 每日下午 12–13 点之间会自动去捞取我想要的 Google Analytics 4 网站数据并组合成讯息透过 Telegram Bot 传送到我的 Telegram Channel，我可以快速检阅近 7 天网站数据。</p>

<p><strong>我想要观测的数据是：</strong></p>

<ul>
  <li>
    <p>近 7 天 <code class="language-plaintext highlighter-rouge">7daysAgo ~ today</code> 总浏览数 <code class="language-plaintext highlighter-rouge">screenPageViews</code></p>
  </li>
  <li>
    <p>活跃使用者数 <code class="language-plaintext highlighter-rouge">active7DayUsers</code></p>
  </li>
  <li>
    <p>新使用者数 <code class="language-plaintext highlighter-rouge">newUsers</code></p>
  </li>
  <li>
    <p>Top 10 浏览页面 <code class="language-plaintext highlighter-rouge">screenPageViews</code> / <code class="language-plaintext highlighter-rouge">pageTitle</code></p>
  </li>
  <li>
    <p>新使用者最初来源媒介 <code class="language-plaintext highlighter-rouge">newUsers</code> / <code class="language-plaintext highlighter-rouge">firstUserSourceMedium</code></p>
  </li>
</ul>

<blockquote>
  <p><em>实际可依照你自己的需求使用 <a href="https://ga-dev-tools.google/ga4/query-explorer/" target="_blank">GA Dev Tools</a> 产生调整。</em></p>
</blockquote>

<h3 id="step-1-使用-ga4-query-explorer-官方工具-产生数据报表查询参数">Step 1. 使用 <a href="https://ga-dev-tools.google/ga4/query-explorer/" target="_blank">GA4 Query Explorer 官方工具</a> 产生数据报表查询参数</h3>

<p>首先，我们需要使用 <a href="https://ga-dev-tools.google/ga4/query-explorer/" target="_blank">GA4 Query Explorer</a> 官方提供的工具产生我们需要的查询数据报表参数：</p>

<p><img src="/assets/1e85b8df2348/1*4b1S9nYSmO7OmGgDPllxeQ.webp" alt="" loading="lazy" decoding="async" width="1063" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDYzIiBoZWlnaHQ9IjEyMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/1e85b8df2348/1*4b1S9nYSmO7OmGgDPllxeQ.png" /></p>

<ol>
  <li>
    <p>Select Property: 记下你的 <code class="language-plaintext highlighter-rouge">property 编号</code>
<strong>property 编号稍后撰写 Google Apps Script 会使用。</strong></p>
  </li>
  <li>
    <p>start date, end date: 报表开始～结束的日期范围，可使用 <code class="language-plaintext highlighter-rouge">YYYY-MM-DD</code> 或 <code class="language-plaintext highlighter-rouge">yesterday</code> , <code class="language-plaintext highlighter-rouge">today</code> , <code class="language-plaintext highlighter-rouge">NdaysAgo</code> 魔术变数。</p>
  </li>
  <li>
    <p>metrics: 选择你想要查询的指标</p>
  </li>
  <li>
    <p>dimensions: 选择你想要查询的维度</p>
  </li>
  <li>
    <p>metric aggregations: 数据合并计算规则</p>
  </li>
</ol>

<p>这边以我的场景为例：</p>

<ol>
  <li>
    <p>property 编号: <code class="language-plaintext highlighter-rouge">318495208</code></p>
  </li>
  <li>
    <p>start_date: <code class="language-plaintext highlighter-rouge">7daysAgo</code></p>
  </li>
  <li>
    <p>end_date: <code class="language-plaintext highlighter-rouge">yesterday</code>
因 GA 数据报表会延迟，查询前一天～七天最准确。</p>
  </li>
  <li>
    <p>metric aggregations: <code class="language-plaintext highlighter-rouge">total</code></p>
  </li>
</ol>

<p><strong>其他 filter, limit 可依照自己需求设定：</strong></p>

<p><img src="/assets/1e85b8df2348/1*g2psNn3gMZWs4OFRx7phWQ.webp" alt="" loading="lazy" decoding="async" width="832" height="694" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MzIiIGhlaWdodD0iNjk0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/1e85b8df2348/1*g2psNn3gMZWs4OFRx7phWQ.png" /></p>

<p>filter 我用不到留空；limit 我输入 10，因为我只想知道 Top 10。</p>

<h4 id="点击make-request产生对应的数据报表查询参数及结果"><strong>点击「MAKE REQUEST」产生对应的数据报表查询参数及结果：</strong></h4>

<p><img src="/assets/1e85b8df2348/1*Rj1kMTyZiEYGvAztEEngIQ.webp" alt="" loading="lazy" decoding="async" width="808" height="693" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MDgiIGhlaWdodD0iNjkzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/1e85b8df2348/1*Rj1kMTyZiEYGvAztEEngIQ.png" /></p>

<h4 id="记下以下请求参数稍后撰写-google-apps-script-会使用"><strong>记下以下请求参数，稍后撰写 Google Apps Script 会使用：</strong></h4>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"dimensions"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pageTitle"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"metrics"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"screenPageViews"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"dateRanges"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"startDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"7daysAgo"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"endDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"yesterday"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"limit"</span><span class="p">:</span><span class="w"> </span><span class="s2">"10"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"metricAggregations"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="s2">"TOTAL"</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h4 id="结果"><strong>结果：</strong></h4>

<p><img src="/assets/1e85b8df2348/1*ivAXeRTVB8Y7zbP-Gq2I2A.webp" alt="" loading="lazy" decoding="async" width="801" height="903" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MDEiIGhlaWdodD0iOTAzIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/1e85b8df2348/1*ivAXeRTVB8Y7zbP-Gq2I2A.png" /></p>

<p><img src="/assets/1e85b8df2348/1*FFThyuptIYrGsfddHcjupQ.webp" alt="" loading="lazy" decoding="async" width="1179" height="2556" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTc5IiBoZWlnaHQ9IjI1NTYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/1e85b8df2348/1*FFThyuptIYrGsfddHcjupQ.jpeg" /></p>

<ul>
  <li>与 GA 上的数据比较是否正确，正确相符 ✅✅✅</li>
</ul>

<h3 id="step-2-建立-google-apps-script--使用-google-analytics-data-api-查询资料">Step 2. 建立 Google Apps Script &amp; 使用 Google Analytics Data API 查询资料</h3>

<ul>
  <li>
    <p>前往 <a href="https://script.google.com/home" target="_blank">https://script.google.com/home</a></p>
  </li>
  <li>
    <p>建立新专案，命名专案名称</p>
  </li>
  <li>
    <p>点击「服务」-&gt;「+」新增服务</p>
  </li>
  <li>
    <p>选择「Google Analytics Data API」</p>
  </li>
  <li>
    <p>点击「新增」</p>
  </li>
</ul>

<p><img src="/assets/1e85b8df2348/1*gcMDDQTXd-Gos5AdGUXIOw.webp" alt="" loading="lazy" decoding="async" width="1200" height="963" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk2MyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/1e85b8df2348/1*gcMDDQTXd-Gos5AdGUXIOw.png" /></p>

<p><strong>贴上 Google Analytics Data API 查询程式码并组合：</strong></p>

<p>将前面步骤产生的报表查询数据参数：</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"dimensions"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pageTitle"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"metrics"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"screenPageViews"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"dateRanges"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"startDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"7daysAgo"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"endDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"yesterday"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"limit"</span><span class="p">:</span><span class="w"> </span><span class="s2">"10"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"metricAggregations"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="s2">"TOTAL"</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p><strong>转换成程式：</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">execute</span><span class="p">()</span> <span class="p">{</span>
  <span class="nx">Logger</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nf">fetchScreenPageViews</span><span class="p">(</span><span class="dl">"</span><span class="s2">318495208</span><span class="dl">"</span><span class="p">)));</span>
<span class="p">}</span>

<span class="c1">// 拆成独立方法，方便日后重复使用...</span>
<span class="c1">// 预设 startDate=7daysAgo, endDate=yesterday</span>
<span class="c1">// 其他用法：</span>
<span class="c1">// e.g. fetchScreenPageViews("1111". "3daysAgo", "yesterday")</span>
<span class="c1">// e.g. fetchScreenPageViews("2222". "yesterday", "today")</span>
<span class="kd">function</span> <span class="nf">fetchScreenPageViews</span><span class="p">(</span><span class="nx">propertyId</span><span class="p">,</span> <span class="nx">startDate</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">7daysAgo</span><span class="dl">"</span><span class="p">,</span> <span class="nx">endDate</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">yesterday</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">screenPageViewsMetric</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newMetric</span><span class="p">();</span>
  <span class="nx">screenPageViewsMetric</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">screenPageViews</span><span class="dl">"</span><span class="p">;</span>

  <span class="kd">const</span> <span class="nx">dateRange</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newDateRange</span><span class="p">();</span>
  <span class="nx">dateRange</span><span class="p">.</span><span class="nx">startDate</span> <span class="o">=</span> <span class="nx">startDate</span><span class="p">;</span>
  <span class="nx">dateRange</span><span class="p">.</span><span class="nx">endDate</span> <span class="o">=</span> <span class="nx">endDate</span><span class="p">;</span>

  <span class="kd">const</span> <span class="nx">pageTitleDimension</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newDimension</span><span class="p">();</span>
  <span class="nx">pageTitleDimension</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">pageTitle</span><span class="dl">"</span><span class="p">;</span>

  <span class="kd">const</span> <span class="nx">request</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newRunReportRequest</span><span class="p">();</span>
  <span class="nx">request</span><span class="p">.</span><span class="nx">dimensions</span> <span class="o">=</span> <span class="p">[</span><span class="nx">pageTitleDimension</span><span class="p">];</span>
  <span class="nx">request</span><span class="p">.</span><span class="nx">metrics</span> <span class="o">=</span> <span class="p">[</span><span class="nx">screenPageViewsMetric</span><span class="p">];</span>
  <span class="nx">request</span><span class="p">.</span><span class="nx">dateRanges</span> <span class="o">=</span> <span class="nx">dateRange</span><span class="p">;</span>

  <span class="nx">request</span><span class="p">.</span><span class="nx">limit</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
  <span class="nx">request</span><span class="p">.</span><span class="nx">metricAggregations</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">TOTAL</span><span class="dl">"</span><span class="p">;</span>

  <span class="k">return</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nx">Properties</span><span class="p">.</span><span class="nf">runReport</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="dl">"</span><span class="s2">properties/</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">propertyId</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>程式码解析：</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// metric 指标，可以是多个，请分开宣告...</span>
<span class="kd">const</span> <span class="nx">screenPageViewsMetric</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newMetric</span><span class="p">();</span>
<span class="nx">screenPageViewsMetric</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">screenPageViews</span><span class="dl">"</span><span class="p">;</span>

<span class="c1">// 例如另一个 active1DayUsers：</span>
<span class="kd">const</span> <span class="nx">active1DayUsersMetric</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newMetric</span><span class="p">();</span>
<span class="nx">active1DayUsersMetric</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">active1DayUsers</span><span class="dl">"</span><span class="p">;</span>

<span class="c1">// 宣告日期范围</span>
<span class="kd">const</span> <span class="nx">dateRange</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newDateRange</span><span class="p">();</span>
<span class="nx">dateRange</span><span class="p">.</span><span class="nx">startDate</span> <span class="o">=</span> <span class="nx">startDate</span><span class="p">;</span>
<span class="nx">dateRange</span><span class="p">.</span><span class="nx">endDate</span> <span class="o">=</span> <span class="nx">endDate</span><span class="p">;</span>

<span class="c1">// dimension 维度，可以是多个，请分开宣告...</span>
<span class="kd">const</span> <span class="nx">pageTitleDimension</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newDimension</span><span class="p">();</span>
<span class="nx">pageTitleDimension</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">pageTitle</span><span class="dl">"</span><span class="p">;</span>

<span class="c1">// 例如另一个 dimension：</span>
<span class="kd">const</span> <span class="nx">firstUserSourceMediumDimension</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newDimension</span><span class="p">();</span>
<span class="nx">firstUserSourceMediumDimension</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">firstUserSourceMedium</span><span class="dl">"</span><span class="p">;</span>

<span class="c1">//</span>

<span class="c1">// 产生 Request 物件</span>
<span class="kd">const</span> <span class="nx">request</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newRunReportRequest</span><span class="p">();</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">metrics</span> <span class="o">=</span> <span class="p">[</span><span class="nx">active1DayUsersMetric</span><span class="p">,</span> <span class="nx">active1DayUsersMetric</span><span class="p">];</span> <span class="c1">// 多个就都带入...</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">dimensions</span> <span class="o">=</span> <span class="p">[</span><span class="nx">pageTitleDimension</span><span class="p">,</span> <span class="nx">firstUserSourceMediumDimension</span><span class="p">];</span> <span class="c1">// 多个就都带入...</span>

<span class="nx">request</span><span class="p">.</span><span class="nx">dateRanges</span> <span class="o">=</span> <span class="nx">dateRange</span><span class="p">;</span>

<span class="c1">// 只需要前 10 笔资料 (Top 10)</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">limit</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// 设定数据合并计算逻辑：Total (SUM)</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">metricAggregations</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">TOTAL</span><span class="dl">"</span><span class="p">;</span>

<span class="c1">// 产生查询结果</span>
<span class="k">return</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nx">Properties</span><span class="p">.</span><span class="nf">runReport</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="dl">"</span><span class="s2">properties/</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">propertyId</span><span class="p">).</span><span class="nx">rows</span><span class="p">;</span>
</code></pre></div></div>

<p><strong>第一次执行，会需要授权(日后若程式码有新增需要的权限也会要重新认证一次)：</strong></p>

<blockquote>
  <p><em>实际上就是授权 Google Apps Script 日后使用你的帐号身份执行这些程式，所以需要确保你选择的帐号身份有对应的 GA 报表存取权限。</em></p>
</blockquote>

<p><img src="/assets/1e85b8df2348/1*_z-P8a4PZCozhtgssH82lA.webp" alt="" loading="lazy" decoding="async" width="579" height="477" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NzkiIGhlaWdodD0iNDc3Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/1e85b8df2348/1*_z-P8a4PZCozhtgssH82lA.png" /></p>

<ul>
  <li>撰写好程式码后，点击「侦错」-&gt; 点击「审查权限」</li>
</ul>

<p><img src="/assets/1e85b8df2348/1*ehox-4AjKv3Ddf1jJ_VmTQ.webp" alt="" loading="lazy" decoding="async" width="1200" height="954" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk1NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/1e85b8df2348/1*ehox-4AjKv3Ddf1jJ_VmTQ.png" /></p>

<ul>
  <li>选择要执行的身份帐户，通常等于当前 Google Apps Script 帐户</li>
</ul>

<p><img src="/assets/1e85b8df2348/1*onR-n1sI4-G9KhD_fhef3Q.webp" alt="" loading="lazy" decoding="async" width="1265" height="1006" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjY1IiBoZWlnaHQ9IjEwMDYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/1e85b8df2348/1*onR-n1sI4-G9KhD_fhef3Q.png" /></p>

<ul>
  <li>选择「进阶」展开 -&gt; 点击「前往 XXX」
这是我们自己写给自己用的应用程式，不需经过 Google 验证。</li>
</ul>

<p><img src="/assets/1e85b8df2348/1*73fQnaB__qKhO7NndQ0GyQ.webp" alt="" loading="lazy" decoding="async" width="1265" height="1006" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjY1IiBoZWlnaHQ9IjEwMDYiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/1e85b8df2348/1*73fQnaB__qKhO7NndQ0GyQ.png" /></p>

<ul>
  <li>点击「允许」</li>
</ul>

<p><strong>允许之后再点「侦错」或「执行」就能执行程式：</strong></p>

<p><img src="/assets/1e85b8df2348/1*DbcQnfp8xdJCFnrDc778tw.webp" alt="" loading="lazy" decoding="async" width="1200" height="954" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk1NCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/1e85b8df2348/1*DbcQnfp8xdJCFnrDc778tw.png" /></p>

<p>这边我们先使用 <code class="language-plaintext highlighter-rouge">Logger.log(JSON.stringify())</code> 取得输出结果：</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"kind"</span><span class="p">:</span><span class="w"> </span><span class="s2">"analyticsData#runReport"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"dimensionHeaders"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pageTitle"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"rowCount"</span><span class="p">:</span><span class="w"> </span><span class="mi">71</span><span class="p">,</span><span class="w">
  </span><span class="nl">"metadata"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"currencyCode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"TWD"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"timeZone"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Asia/Taipei"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"rows"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"dimensionValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ZhgChgLi"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"metricValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"166"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"metricValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"109"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"dimensionValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Apple Watch 原厂不锈钢米兰表带开箱 </span><span class="se">\\</span><span class="s2">| ZhgChgLi"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"dimensionValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"iOS ≥ 13.1 使用「捷径」自动化功能搭配米家智慧家居 </span><span class="se">\\</span><span class="s2">| ZhgChgLi"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"metricValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"101"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"dimensionValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Medium Partner Program 终于对全球(包含台湾)写作者开放啦！ </span><span class="se">\\</span><span class="s2">| ZhgChgLi"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"metricValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"85"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"metricValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"77"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"dimensionValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"iOS 捷径自动化应用场景 — 自动转发简讯与自动建立提醒待办事项 </span><span class="se">\\</span><span class="s2">| ZhgChgLi"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"metricValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"51"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"dimensionValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"游记 9/11 名古屋一日快闪自由行 </span><span class="se">\\</span><span class="s2">| ZhgChgLi"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"metricValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"42"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"dimensionValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"iOS 隐私与便利的前世今生 </span><span class="se">\\</span><span class="s2">| ZhgChgLi"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"dimensionValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"iOS Vision framework x WWDC 24 Discover Swift enhancements in the Vision framework Session </span><span class="se">\\</span><span class="s2">| ZhgChgLi"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"metricValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"34"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"dimensionValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"iOS ≥ 18 NSAttributedString attributes Range 合并的一个行为改变 </span><span class="se">\\</span><span class="s2">| ZhgChgLi"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"metricValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"30"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"metricValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"30"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"dimensionValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"手工打造 HTML 解析器的那些事 </span><span class="se">\\</span><span class="s2">| ZhgChgLi"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"metricHeaders"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"TYPE_INTEGER"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"screenPageViews"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"totals"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"dimensionValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"RESERVED_TOTAL"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"metricValues"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1229"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<ul>
  <li><strong>Google Apps Script 请求 GA 数据成功！🎉🎉🎉</strong></li>
</ul>

<h3 id="step-3-组合起来google-apps-script--ga4--telegram-bot">Step 3. 组合起来！Google Apps Script + GA4 + Telegram Bot</h3>

<p>依照上篇文章「 <a href="https://medium.com/zrealm-robotic-process-automation/10-%E5%88%86%E9%90%98%E5%BF%AB%E9%80%9F%E7%A7%BB%E8%BD%89-line-notify-%E5%88%B0-telegram-bot-%E9%80%9A%E7%9F%A5-6922e90ba90c?source=collection_home---6------0-----------------------" target="_blank">10 分钟快速移转 Line Notify 到 Telegram Bot 通知</a> 」建立你的 Telegram Bot 取得 <code class="language-plaintext highlighter-rouge">Bot Token</code> &amp; 想要传送到的 <code class="language-plaintext highlighter-rouge">Channel Chat ID</code> 。</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">telegramToken</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">XXXX</span><span class="dl">"</span> <span class="c1">// 带入你的 Telegram Bot Token</span>
<span class="c1">//</span>

<span class="kd">function</span> <span class="nf">execute</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">screenPageViewsReport</span> <span class="o">=</span> <span class="nf">fetchScreenPageViews</span><span class="p">(</span><span class="dl">"</span><span class="s2">318495208</span><span class="dl">"</span><span class="p">);</span>
  
  <span class="c1">//</span>
  <span class="kd">const</span> <span class="nx">total</span> <span class="o">=</span> <span class="nf">parseInt</span><span class="p">(</span><span class="nx">screenPageViewsReport</span><span class="p">.</span><span class="nx">totals</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">metricValues</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">value</span><span class="p">);</span>
  <span class="kd">var</span> <span class="nx">message</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">总浏览数：</span><span class="dl">"</span><span class="o">+</span><span class="nx">total</span><span class="p">.</span><span class="nf">toLocaleString</span><span class="p">()</span><span class="o">+</span><span class="dl">"</span><span class="se">\n</span><span class="dl">"</span><span class="p">;</span>

  <span class="nx">screenPageViewsReport</span><span class="p">.</span><span class="nx">rows</span><span class="p">.</span><span class="nf">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">element</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">pageTitle</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">dimensionValues</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">value</span><span class="p">;</span>
    <span class="kd">const</span> <span class="nx">value</span> <span class="o">=</span> <span class="nf">parseInt</span><span class="p">(</span><span class="nx">element</span><span class="p">.</span><span class="nx">metricValues</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">value</span><span class="p">);</span>

    <span class="nx">message</span> <span class="o">+=</span> <span class="dl">"</span><span class="s2">[Top </span><span class="dl">"</span><span class="o">+</span><span class="p">(</span><span class="nx">index</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span><span class="o">+</span><span class="dl">"</span><span class="s2">] </span><span class="dl">"</span><span class="o">+</span><span class="nx">pageTitle</span><span class="o">+</span><span class="dl">"</span><span class="s2">: </span><span class="dl">"</span><span class="o">+</span><span class="nx">value</span><span class="p">.</span><span class="nf">toLocaleString</span><span class="p">()</span><span class="o">+</span><span class="dl">"</span><span class="se">\n</span><span class="dl">"</span><span class="p">;</span>
  <span class="p">});</span>

  <span class="nf">sendNotifyMessage</span><span class="p">(</span><span class="nx">message</span><span class="p">,</span> <span class="o">-</span><span class="nx">xxxx</span><span class="p">);</span> <span class="c1">// 带入你的 Channel Chat ID</span>
<span class="p">}</span>


<span class="c1">// 发送讯息到 Telegram 指定 Channel Chat ID</span>
<span class="kd">function</span> <span class="nf">sendNotifyMessage</span><span class="p">(</span><span class="nx">message</span><span class="p">,</span> <span class="nx">chatId</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">var</span> <span class="nx">url</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">https://api.telegram.org/bot</span><span class="dl">"</span><span class="o">+</span><span class="nx">telegramToken</span><span class="o">+</span><span class="dl">"</span><span class="s2">/sendMessage</span><span class="dl">"</span><span class="p">;</span>
  
  <span class="kd">const</span> <span class="nx">payload</span> <span class="o">=</span> <span class="p">{</span>
    <span class="dl">"</span><span class="s2">chat_id</span><span class="dl">"</span><span class="p">:</span> <span class="nx">chatId</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">text</span><span class="dl">"</span><span class="p">:</span> <span class="nx">message</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">disable_web_page_preview</span><span class="dl">"</span><span class="p">:</span> <span class="kc">true</span>
  <span class="p">}</span> 
  <span class="kd">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
    <span class="dl">'</span><span class="s1">method</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">post</span><span class="dl">'</span><span class="p">,</span>
    <span class="dl">'</span><span class="s1">contentType</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">application/json</span><span class="dl">'</span><span class="p">,</span>
    <span class="dl">'</span><span class="s1">muteHttpExceptions</span><span class="dl">'</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
    <span class="dl">'</span><span class="s1">payload</span><span class="dl">'</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">payload</span><span class="p">)</span>
  <span class="p">};</span>

  <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
  <span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>

  <span class="k">if </span><span class="p">(</span><span class="nx">data</span><span class="p">[</span><span class="dl">"</span><span class="s2">ok</span><span class="dl">"</span><span class="p">]</span> <span class="o">==</span> <span class="kc">undefined</span> <span class="err">\\</span><span class="o">|</span><span class="err">\\</span><span class="o">|</span> <span class="nx">data</span><span class="p">[</span><span class="dl">"</span><span class="s2">ok</span><span class="dl">"</span><span class="p">]</span> <span class="o">!=</span> <span class="kc">true</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">data</span><span class="p">[</span><span class="dl">"</span><span class="s2">error_code</span><span class="dl">"</span><span class="p">]</span> <span class="o">!=</span> <span class="kc">undefined</span> <span class="o">&amp;&amp;</span> <span class="nx">data</span><span class="p">[</span><span class="dl">"</span><span class="s2">error_code</span><span class="dl">"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">429</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">Utilities</span><span class="p">.</span><span class="nf">sleep</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
      <span class="nf">sendNotifyMessage</span><span class="p">(</span><span class="nx">message</span><span class="p">,</span> <span class="nx">chatId</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">fetchScreenPageViews</span><span class="p">(</span><span class="nx">propertyId</span><span class="p">,</span> <span class="nx">startDate</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">7daysAgo</span><span class="dl">"</span><span class="p">,</span> <span class="nx">endDate</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">yesterday</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">screenPageViewsMetric</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newMetric</span><span class="p">();</span>
  <span class="nx">screenPageViewsMetric</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">screenPageViews</span><span class="dl">"</span><span class="p">;</span>

  <span class="kd">const</span> <span class="nx">dateRange</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newDateRange</span><span class="p">();</span>
  <span class="nx">dateRange</span><span class="p">.</span><span class="nx">startDate</span> <span class="o">=</span> <span class="nx">startDate</span><span class="p">;</span>
  <span class="nx">dateRange</span><span class="p">.</span><span class="nx">endDate</span> <span class="o">=</span> <span class="nx">endDate</span><span class="p">;</span>

  <span class="kd">const</span> <span class="nx">pageTitleDimension</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newDimension</span><span class="p">();</span>
  <span class="nx">pageTitleDimension</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">pageTitle</span><span class="dl">"</span><span class="p">;</span>

  <span class="kd">const</span> <span class="nx">request</span> <span class="o">=</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nf">newRunReportRequest</span><span class="p">();</span>
  <span class="nx">request</span><span class="p">.</span><span class="nx">dimensions</span> <span class="o">=</span> <span class="p">[</span><span class="nx">pageTitleDimension</span><span class="p">];</span>
  <span class="nx">request</span><span class="p">.</span><span class="nx">metrics</span> <span class="o">=</span> <span class="p">[</span><span class="nx">screenPageViewsMetric</span><span class="p">];</span>
  <span class="nx">request</span><span class="p">.</span><span class="nx">dateRanges</span> <span class="o">=</span> <span class="nx">dateRange</span><span class="p">;</span>

  <span class="nx">request</span><span class="p">.</span><span class="nx">limit</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
  <span class="nx">request</span><span class="p">.</span><span class="nx">metricAggregations</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">TOTAL</span><span class="dl">"</span><span class="p">;</span>

  <span class="k">return</span> <span class="nx">AnalyticsData</span><span class="p">.</span><span class="nx">Properties</span><span class="p">.</span><span class="nf">runReport</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="dl">"</span><span class="s2">properties/</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">propertyId</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>程式码解析：</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//...</span>
  <span class="c1">// 依照报表回传的 json 找到 total 位置，parseInt 将字串转成 INT 数字格式</span>
  <span class="c1">// .toLocaleString() -&gt; 格式化数字，123456 -&gt; 123,456</span>
  <span class="kd">const</span> <span class="nx">total</span> <span class="o">=</span> <span class="nf">parseInt</span><span class="p">(</span><span class="nx">screenPageViewsReport</span><span class="p">.</span><span class="nx">totals</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">metricValues</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">value</span><span class="p">);</span>
  <span class="kd">var</span> <span class="nx">message</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">总浏览数：</span><span class="dl">"</span><span class="o">+</span><span class="nx">total</span><span class="p">.</span><span class="nf">toLocaleString</span><span class="p">()</span><span class="o">+</span><span class="dl">"</span><span class="se">\n</span><span class="dl">"</span><span class="p">;</span>

  <span class="c1">// 依照报表回传的 json 遍历资料，组合成讯息</span>
  <span class="nx">screenPageViewsReport</span><span class="p">.</span><span class="nx">rows</span><span class="p">.</span><span class="nf">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">element</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">pageTitle</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">dimensionValues</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">value</span><span class="p">;</span>
    <span class="kd">const</span> <span class="nx">value</span> <span class="o">=</span> <span class="nf">parseInt</span><span class="p">(</span><span class="nx">element</span><span class="p">.</span><span class="nx">metricValues</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">value</span><span class="p">);</span>

    <span class="nx">message</span> <span class="o">+=</span> <span class="dl">"</span><span class="s2">[Top </span><span class="dl">"</span><span class="o">+</span><span class="p">(</span><span class="nx">index</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span><span class="o">+</span><span class="dl">"</span><span class="s2">] </span><span class="dl">"</span><span class="o">+</span><span class="nx">pageTitle</span><span class="o">+</span><span class="dl">"</span><span class="s2">: </span><span class="dl">"</span><span class="o">+</span><span class="nx">value</span><span class="p">.</span><span class="nf">toLocaleString</span><span class="p">()</span><span class="o">+</span><span class="dl">"</span><span class="se">\n</span><span class="dl">"</span><span class="p">;</span>
  <span class="p">});</span>
<span class="c1">//...</span>
</code></pre></div></div>

<h4 id="执行点击上方执行或侦错并确定方法名称是选择-execute-"><strong>执行：点击上方「执行」或「侦错」并确定方法名称是选择「 <code class="language-plaintext highlighter-rouge">execute</code> 」：</strong></h4>

<p><img src="/assets/1e85b8df2348/1*R7uVMGODJR2Z_GAYnyMYXA.webp" alt="" loading="lazy" decoding="async" width="512" height="109" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTIiIGhlaWdodD0iMTA5Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/1e85b8df2348/1*R7uVMGODJR2Z_GAYnyMYXA.png" /></p>

<p><img src="/assets/1e85b8df2348/1*Pl2v19Ed8COUwCc1deTYFw.webp" alt="" loading="lazy" decoding="async" width="643" height="274" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NDMiIGhlaWdodD0iMjc0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/1e85b8df2348/1*Pl2v19Ed8COUwCc1deTYFw.png" /></p>

<ul>
  <li><strong>成功！🎉🎉🎉</strong></li>
</ul>

<h4 id="设定排程定时自动执行">设定排程定时自动执行</h4>

<p>最后一步是我们希望报表机器人能定时自动执行，从左侧选单前往「触发条件」：</p>

<p><img src="/assets/1e85b8df2348/1*SY1YKLwTvDtP1hQTRqj50w.webp" alt="" loading="lazy" decoding="async" width="866" height="805" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NjYiIGhlaWdodD0iODA1Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/1e85b8df2348/1*SY1YKLwTvDtP1hQTRqj50w.png" /></p>

<ul>
  <li>选择右下角「新增触发条件」按钮</li>
</ul>

<p><img src="/assets/1e85b8df2348/1*wYOwwQBTEtns8nN_7bmvNQ.webp" alt="" loading="lazy" decoding="async" width="875" height="874" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzUiIGhlaWdodD0iODc0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/1e85b8df2348/1*wYOwwQBTEtns8nN_7bmvNQ.png" /></p>

<ol>
  <li>
    <p>选择镡要执行的功能：选择 「 <code class="language-plaintext highlighter-rouge">execute</code> 」方法名称</p>
  </li>
  <li>
    <p>选择执行的部署作业：选择「 <code class="language-plaintext highlighter-rouge">上端</code> 」</p>
  </li>
  <li>
    <p>选取活动来源：选择「 <code class="language-plaintext highlighter-rouge">时间驱动</code> 」</p>
  </li>
  <li>
    <p>选取时间型触发条件类型：选择你想要的触发频率</p>
  </li>
  <li>
    <p>选取时段：选择你想要每日自动触发的时间</p>
  </li>
  <li>
    <p>如果执行失败…通知信件的频率设定</p>
  </li>
  <li>
    <p>储存</p>
  </li>
</ol>

<blockquote>
  <p><strong><em>完成！这样时间到就会自动执行啰。</em></strong> 🎉🎉🎉</p>
</blockquote>

<h3 id="延伸作业">延伸作业</h3>

<p>其他数据如 新使用者数、来源媒介等，同样使用前面程式码就能达成，这边就不在重复赘述，就当成给大家的回家作业啰。</p>]]></content>
  </entry><entry>
    <title type="html">Line Notify 快速移转 Telegram Bot｜10 分钟完成个人通知服务切换</title>
    <link href="https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/line-notify-%E5%BF%AB%E9%80%9F%E7%A7%BB%E8%BD%AC-telegram-bot-10-%E5%88%86%E9%92%9F%E5%AE%8C%E6%88%90%E4%B8%AA%E4%BA%BA%E9%80%9A%E7%9F%A5%E6%9C%8D%E5%8A%A1%E5%88%87%E6%8D%A2-6922e90ba90c/" rel="alternate" type="text/html" title="Line Notify 快速移转 Telegram Bot｜10 分钟完成个人通知服务切换" />
    <published>2024-10-12T21:10:46+08:00</published>
    <updated>2024-10-20T16:57:41+08:00</updated>
    <id>https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/6922e90ba90c</id><summary type="html">面对 Line Notify 即将终止服务，教你用 10 分钟快速将通知系统切换到免费且功能更强大的 Telegram Bot，实现多群组分类、丰富讯息格式与互动指令，提升通知管理效率与使用体验。</summary><author>
      <name>ZhgChgLi</name>
    </author><category term="ZRealm Robotic Process Automation" /><category term="simplified-chinese" /><category term="ios-app-development" /><category term="line" /><category term="telegram" /><category term="google-apps-script" /><category term="automation" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://zh-hans.zhgchg.li/assets/6922e90ba90c/1*r59nJAx__InU09hYMenePg.webp" /><content type="html" xml:base="https://zh-hans.zhgchg.li/posts/zrealm-robotic-process-automation/line-notify-%E5%BF%AB%E9%80%9F%E7%A7%BB%E8%BD%AC-telegram-bot-10-%E5%88%86%E9%92%9F%E5%AE%8C%E6%88%90%E4%B8%AA%E4%BA%BA%E9%80%9A%E7%9F%A5%E6%9C%8D%E5%8A%A1%E5%88%87%E6%8D%A2-6922e90ba90c/"><![CDATA[<h3 id="10-分钟快速移转-line-notify-到-telegram-bot-通知">10 分钟快速移转 Line Notify 到 Telegram Bot 通知</h3>

<p>手把手将 Line Notify 个人通知服务迁移至同样免费、更强大的 Telegram Bot</p>

<p><img src="/assets/6922e90ba90c/1*r59nJAx__InU09hYMenePg.webp" alt="Photo by Lana Codes" loading="lazy" decoding="async" width="1200" height="801" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjgwMSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*r59nJAx__InU09hYMenePg.jpeg" /></p>

<p>Photo by <a href="https://unsplash.com/@lanacodes?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank">Lana Codes</a></p>

<h4 id="line-notify结束服务公告"><a href="https://notify-bot.line.me/closing-announce" target="_blank">LINE Notify结束服务公告</a></h4>

<blockquote>
  <p><em>感谢您长期以来使用LINE Notify。</em></p>
</blockquote>

<blockquote>
  <p><em>LINE Notify自2016年9月推出以来，一直致力于为开发者提供服务。为能提供更优质的服务，并将经营资源集中于后续的类似商品服务，我们决定于2025年3月31日结束本服务。对于长期以来支持并使用LINE作为通知连动服务的所有用户，我们深表感谢。</em></p>
</blockquote>

<blockquote>
  <p><em>若您仍需使用LINE向用户传送通知的商品服务，建议可改用功能更丰富的Messaging API。</em></p>
</blockquote>

<p>撷取自 <a href="https://notify-bot.line.me/closing-announce" target="_blank">Line Notify 官网</a> ， Line 于 2024/10/08 发文公告 Line Notify 将于 2025/04/01 完全关闭，如需继续使用 Line 做为讯息通知，只能用付费的 <a href="https://developers.line.biz/en/services/messaging-api/" target="_blank">Message API</a> 。</p>

<p>Line Notify 的优点是非常容易串接，拿来做个人通知机器人非常方便好用，一些 Line Bot 或第三方服务也会使用 Line Notify 进行通知 (例如：路易莎、你订的订单通知功能)；但缺点也蛮多的，例如讯息内容单一、无法分群组(统一都是传送到 Line Notify Bot)、讯息内容长度有限…等等</p>

<p>随著 Line Notify 宣告终止，正好也给我了一个迁移至其他通讯、通知服务的机会：</p>

<ul>
  <li>
    <p>Slack：免费版讯息只保留 30 天、我的通知比较是个人，用 Slack 有点大材小用。(Slack 传送讯息可参考我之前的文章： <a href="/posts/zrealm-dev/slack-app-整合-chatgpt-利用-openai-api-与-google-cloud-functions-自建智能助理-bd94cc88f9c9/">Slack &amp; ChatGPT Integration</a> )</p>
  </li>
  <li>
    <p>Discord：我的通知比较是个人，一样有点大材小用。</p>
  </li>
  <li>
    <p><strong>Telegram：免费、几乎无限使用。</strong></p>
  </li>
</ul>

<p>对我来说 Telegram 的通讯服务比较符合我原本 Line Notify 的使用需求，我需要一个能接收通知的频道，最好是能依照不同需求有不同的频道，可接受的内容、格式越丰富越好、并且能快速简单串接；Telegram 都符合上述需求，还能多实现跟 Bot 的交互功能。</p>

<h4 id="成果">成果</h4>

<p>先上最终效果图(以 <a href="/posts/zrealm-dev/google-apps-script-三步骤打造免费-github-repo-star-通知器-实时获取-star-动态-382218e15697/">Github Star 通知、Repo Stats 通知为例</a> )：</p>

<p><img src="/assets/6922e90ba90c/1*1kHJu5yZMUST-wrna6KqkA.gif" alt="" loading="lazy" decoding="async" width="380" height="550" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzODAiIGhlaWdodD0iNTUwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" /></p>

<ul>
  <li>
    <p>✅ 有人按 Repo 星星时会触发 Webhook -&gt; Google Apps Script -&gt; Telegram Bot 发送通知到 Telegram — Github Stats Group</p>
  </li>
  <li>
    <p>✅ Google Apps Script 每日定时 -&gt; 捞取 Github Repo Stats 状态 -&gt; Telegram Bot 发送通知到 Telegram — Github Stats Group</p>
  </li>
  <li>
    <p>✅ 使用 <code class="language-plaintext highlighter-rouge">/update</code> Telegram Bot Command 触发捞取 Github Repo Stats 状态 -&gt; Telegram Bot 发送通知到 Telegram — Github Stats Group</p>
  </li>
</ul>

<h4 id="对比原本-line-notify">对比原本 Line Notify</h4>

<p><img src="/assets/6922e90ba90c/1*mTycFPe7rPh1qc0BagUXdw.webp" alt="" loading="lazy" decoding="async" width="960" height="1404" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NjAiIGhlaWdodD0iMTQwNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*mTycFPe7rPh1qc0BagUXdw.png" /></p>

<ul>
  <li>
    <p>❌ 所有讯息无法分类、分群组都传到 Line Notify</p>
  </li>
  <li>
    <p>❌ 无法针对个别讯息做特殊设定 (如通知声、静音…)</p>
  </li>
  <li>
    <p>❌ 无法输入讯息互动</p>
  </li>
</ul>

<h4 id="本文目录">本文目录</h4>

<ul>
  <li>
    <p>设定 Telegram Bot</p>
  </li>
  <li>
    <p>移转 Line Notify 发送讯息到 Telegram Bot (Google Apps Script)</p>
  </li>
  <li>
    <p>与 Telegram Bot 交互 (Command) x 使用 Google Apps Script</p>
  </li>
</ul>

<h3 id="12-设定-telegram-bot">(1/2) 设定 Telegram Bot</h3>

<p>Telegram Bot 的申请非常简单，连网页都不需要开，只要跟官方的 <a href="https://t.me/BotFather" target="_blank">BotFather 机器人</a> 互动就可以了。</p>

<h4 id="step-1-申请-telegram-bot">Step 1. 申请 Telegram Bot</h4>

<p><a href="https://telegram.org/" target="_blank">安装、注册好 Telegram 服务</a> 之后，点击加「 <a href="https://t.me/BotFather" target="_blank">BotFather 机器人</a> 」为好友。</p>

<p><img src="/assets/6922e90ba90c/1*-3qluwPXk-HeGRCTOd-EAA.webp" alt="" loading="lazy" decoding="async" width="691" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2OTEiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*-3qluwPXk-HeGRCTOd-EAA.png" /></p>

<p><img src="/assets/6922e90ba90c/1*QfzbJYQ2vVI2CNvvLU7r_w.webp" alt="" loading="lazy" decoding="async" width="595" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1OTUiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*QfzbJYQ2vVI2CNvvLU7r_w.png" /></p>

<ol>
  <li>
    <p>打开、加入 <a href="https://t.me/BotFather" target="_blank">BotFather 机器人</a></p>
  </li>
  <li>
    <p>加入后直接传送讯息「 <code class="language-plaintext highlighter-rouge">/newbot</code> 」建立你的机器人。</p>
  </li>
  <li>
    <p>输入你的机器人名称</p>
  </li>
  <li>
    <p>输入你的机器人帐号 (不可重复、必须以 <code class="language-plaintext highlighter-rouge">bot</code> 为结尾，例如我的 <code class="language-plaintext highlighter-rouge">zhgchgli_bot</code> )</p>
  </li>
  <li>
    <p>你的 Bot 连结，点进进入开始使用 (e.g. t.me/harrytest56_bot)</p>
  </li>
  <li>
    <p>取得 <code class="language-plaintext highlighter-rouge">你的_BOT_API_Token</code> ， <strong>请妥善保存</strong> ⚠️⚠️⚠️</p>
  </li>
</ol>

<p>点击 4. 取得的 Bot 连结，开始使用 Bot：</p>

<p><img src="/assets/6922e90ba90c/1*5q5PE3D9nwQPlYoY8SqCHQ.webp" alt="" loading="lazy" decoding="async" width="896" height="1526" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4OTYiIGhlaWdodD0iMTUyNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*5q5PE3D9nwQPlYoY8SqCHQ.png" /></p>

<p><img src="/assets/6922e90ba90c/1*NKz9GSDlGov9q7xIlHYlCQ.webp" alt="" loading="lazy" decoding="async" width="756" height="1390" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NTYiIGhlaWdodD0iMTM5MCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*NKz9GSDlGov9q7xIlHYlCQ.png" /></p>

<p><img src="/assets/6922e90ba90c/1*VU7EyeZL2BpVnLRHQBNOPQ.webp" alt="" loading="lazy" decoding="async" width="732" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MzIiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*VU7EyeZL2BpVnLRHQBNOPQ.png" /></p>

<p>目前无任何功能，可以点右上角 Info，编辑名称或上传大头贴。</p>

<h4 id="step-2-创建-telegram-通知-group--加入机器人帐号">Step 2. 创建 Telegram 通知 Group &amp; 加入机器人帐号</h4>

<blockquote>
  <p><em>我希望不同的个人通知类型传到不同的 Group，这 <strong>边因为 Demo 只创建一个 My Notify Group</strong> 。</em></p>
</blockquote>

<blockquote>
  <p><em>你可以依据实际需求创建不同的 Group &amp; 依照步骤加入、设定机器人。</em></p>
</blockquote>

<p><img src="/assets/6922e90ba90c/1*geb_lwnJOUXiuLHvguuXjQ.webp" alt="" loading="lazy" decoding="async" width="1040" height="726" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDQwIiBoZWlnaHQ9IjcyNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*geb_lwnJOUXiuLHvguuXjQ.png" /></p>

<p><img src="/assets/6922e90ba90c/1*bfXDTACy4mW3LZlq6ErKzQ.webp" alt="" loading="lazy" decoding="async" width="705" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDUiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*bfXDTACy4mW3LZlq6ErKzQ.png" /></p>

<p><img src="/assets/6922e90ba90c/1*ZmsCLqEZbNN3IS2uoZV8cw.webp" alt="" loading="lazy" decoding="async" width="705" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDUiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*ZmsCLqEZbNN3IS2uoZV8cw.png" /></p>

<ol>
  <li>
    <p>New Group</p>
  </li>
  <li>
    <p>搜寻你的机器人帐号＆点击加入</p>
  </li>
  <li>
    <p>设定 Group 名称、大头贴</p>
  </li>
</ol>

<h4 id="step-3-取得-group-chat-id">Step 3. 取得 Group Chat ID</h4>

<p>Telegram Bot API 没有直接取得 Group 列表、Group Chat ID 的 Endpoint，只能透过 <code class="language-plaintext highlighter-rouge">/getUpdates</code> 取得机器人讯息列表，并从中找到 Group Chat ID：</p>

<p><strong>Request:</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">curl</span> <span class="nv">'https</span><span class="p">:</span><span class="c1">//api.telegram.org/bot你的_BOT_API_Token/getUpdates'</span>
</code></pre></div></div>

<ul>
  <li>
    <p>Telegram API 格式为 <code class="language-plaintext highlighter-rouge">https://api.telegram.org/bot</code> <strong>你的_BOT_API_Token</strong> <code class="language-plaintext highlighter-rouge">/getUpdates</code> ， BOT API Token 字串前要加上 <code class="language-plaintext highlighter-rouge">bot</code> 字串</p>
  </li>
  <li>
    <p>范例： <code class="language-plaintext highlighter-rouge">curl 'https://api.telegram.org/bot7814194578:AAEWpPJvKn06ID7D9FjV65aDKQLkGkz8cc8/getUpdates'</code></p>
  </li>
</ul>

<p><strong>Response:</strong></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"ok"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
    </span><span class="nl">"result"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
            </span><span class="nl">"update_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">706454235</span><span class="p">,</span><span class="w">
            </span><span class="nl">"my_chat_member"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nl">"chat"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">-4532420331</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"My Nofify"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"group"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"all_members_are_administrators"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
                </span><span class="p">},</span><span class="w">
                </span><span class="nl">"from"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">986128250</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"is_bot"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Harry"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"last_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Li"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"zhgchgli"</span><span class="w">
                </span><span class="p">},</span><span class="w">
                </span><span class="nl">"date"</span><span class="p">:</span><span class="w"> </span><span class="mi">1728726861</span><span class="p">,</span><span class="w">
                </span><span class="nl">"old_chat_member"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"user"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                        </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">7814194578</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"is_bot"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Harry Test"</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"harrytest56_bot"</span><span class="w">
                    </span><span class="p">},</span><span class="w">
                    </span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"left"</span><span class="w">
                </span><span class="p">},</span><span class="w">
                </span><span class="nl">"new_chat_member"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"user"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                        </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">7814194578</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"is_bot"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Harry Test"</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"harrytest56_bot"</span><span class="w">
                    </span><span class="p">},</span><span class="w">
                    </span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"member"</span><span class="w">
                </span><span class="p">}</span><span class="w">
            </span><span class="p">}</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="p">{</span><span class="w">
            </span><span class="nl">"update_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">706454236</span><span class="p">,</span><span class="w">
            </span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nl">"message_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
                </span><span class="nl">"from"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">986128250</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"is_bot"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Harry"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"last_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Li"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"zhgchgli"</span><span class="w">
                </span><span class="p">},</span><span class="w">
                </span><span class="nl">"chat"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">-4532420331</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"My Nofify"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"group"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"all_members_are_administrators"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
                </span><span class="p">},</span><span class="w">
                </span><span class="nl">"date"</span><span class="p">:</span><span class="w"> </span><span class="mi">1728726861</span><span class="p">,</span><span class="w">
                </span><span class="nl">"group_chat_created"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
            </span><span class="p">}</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="p">{</span><span class="w">
            </span><span class="nl">"update_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">706454237</span><span class="p">,</span><span class="w">
            </span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nl">"message_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w">
                </span><span class="nl">"from"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">986128250</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"is_bot"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Harry"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"last_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Li"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"zhgchgli"</span><span class="w">
                </span><span class="p">},</span><span class="w">
                </span><span class="nl">"chat"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">-4532420331</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"My Nofify"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"group"</span><span class="p">,</span><span class="w">
                    </span><span class="nl">"all_members_are_administrators"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
                </span><span class="p">},</span><span class="w">
                </span><span class="nl">"date"</span><span class="p">:</span><span class="w"> </span><span class="mi">1728726864</span><span class="p">,</span><span class="w">
                </span><span class="nl">"new_chat_photo"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
                    </span><span class="p">{</span><span class="w">
                        </span><span class="nl">"file_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"AgACAgUAAxkBAAMCZwpHUEaLZSvFFYu8GiO-8qI_jVYAApfAMRu0B1BUJP-4u2wF6scBAAMCAANhAAM2BA"</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"file_unique_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"AQADl8AxG7QHUFQAAQ"</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"file_size"</span><span class="p">:</span><span class="w"> </span><span class="mi">5922</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"width"</span><span class="p">:</span><span class="w"> </span><span class="mi">160</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"height"</span><span class="p">:</span><span class="w"> </span><span class="mi">160</span><span class="w">
                    </span><span class="p">},</span><span class="w">
                    </span><span class="p">{</span><span class="w">
                        </span><span class="nl">"file_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"AgACAgUAAxkBAAMCZwpHUEaLZSvFFYu8GiO-8qI_jVYAApfAMRu0B1BUJP-4u2wF6scBAAMCAANiAAM2BA"</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"file_unique_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"AQADl8AxG7QHUFRn"</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"file_size"</span><span class="p">:</span><span class="w"> </span><span class="mi">15097</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"width"</span><span class="p">:</span><span class="w"> </span><span class="mi">320</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"height"</span><span class="p">:</span><span class="w"> </span><span class="mi">320</span><span class="w">
                    </span><span class="p">},</span><span class="w">
                    </span><span class="p">{</span><span class="w">
                        </span><span class="nl">"file_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"AgACAgUAAxkBAAMCZwpHUEaLZSvFFYu8GiO-8qI_jVYAApfAMRu0B1BUJP-4u2wF6scBAAMCAANjAAM2BA"</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"file_unique_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"AQADl8AxG7QHUFQB"</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"file_size"</span><span class="p">:</span><span class="w"> </span><span class="mi">37988</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"width"</span><span class="p">:</span><span class="w"> </span><span class="mi">640</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"height"</span><span class="p">:</span><span class="w"> </span><span class="mi">640</span><span class="w">
                    </span><span class="p">}</span><span class="w">
                </span><span class="p">]</span><span class="w">
            </span><span class="p">}</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>可以从回应中找到对应 Group Name + type=group 的巢状 JSON 资料，其中的 id 就是 Group Chat ID:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"chat"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">-4532420331</span><span class="p">,</span><span class="w">
  </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"My Nofify"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"group"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"all_members_are_administrators"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Group Chat Id</code> = <code class="language-plaintext highlighter-rouge">-4532420331</code></li>
</ul>

<blockquote>
  <p><strong><em>⚠️⚠️⚠️️</em></strong> <em>如果你的 Response 为空 <code class="language-plaintext highlighter-rouge">{ "ok": true, "result": [] }</code> 请尝试在你的 Group 发送讯息 (e.g. <code class="language-plaintext highlighter-rouge">Hello</code> ) 再重新 Call API 应该就有了。</em></p>
</blockquote>

<h4 id="step-4-发送讯息">Step 4. 发送讯息</h4>

<p>我们可以使用 <code class="language-plaintext highlighter-rouge">/sendMessage</code> 发送讯息到 Group。</p>

<p><strong>Request:</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">curl</span> <span class="nv">'https</span><span class="p">:</span><span class="c1">//api.telegram.org/bot你的_BOT_API_Token/sendMessage' \</span>
<span class="o">--</span><span class="n">form</span> <span class="nv">'chat_id</span><span class="o">=</span><span class="s">"Group Chat Id"</span><span class="err">'</span> <span class="err">\</span>
<span class="o">--</span><span class="n">form</span> <span class="nv">'text</span><span class="o">=</span><span class="s">"讯息内容"</span><span class="err">'</span>
</code></pre></div></div>

<p><strong>范例：</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">curl</span> <span class="nv">'https</span><span class="p">:</span><span class="c1">//api.telegram.org/bot7814194578:AAEWpPJvKn06ID7D9FjV65aDKQLkGkz8cc8/sendMessage' \</span>
<span class="o">--</span><span class="n">form</span> <span class="nv">'chat_id</span><span class="o">=</span><span class="s">"-4532420331"</span><span class="err">'</span> <span class="err">\</span>
<span class="o">--</span><span class="n">form</span> <span class="nv">'text</span><span class="o">=</span><span class="s">"test"</span><span class="err">'</span>
</code></pre></div></div>

<ul>
  <li><a href="https://core.telegram.org/bots/api#sendmessage" target="_blank"><strong>API 参数可参考官方文件</strong></a></li>
</ul>

<p><strong>Response &amp; Result:</strong></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"ok"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
  </span><span class="nl">"result"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"message_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w">
    </span><span class="nl">"from"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">7814194578</span><span class="p">,</span><span class="w">
      </span><span class="nl">"is_bot"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
      </span><span class="nl">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Harry Test"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"harrytest56_bot"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"chat"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">-4532420331</span><span class="p">,</span><span class="w">
      </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"My Nofify"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"group"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"all_members_are_administrators"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"date"</span><span class="p">:</span><span class="w"> </span><span class="mi">1728727847</span><span class="p">,</span><span class="w">
    </span><span class="nl">"text"</span><span class="p">:</span><span class="w"> </span><span class="s2">"test"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<ul>
  <li>发送成功取得以上 Response</li>
</ul>

<p><img src="/assets/6922e90ba90c/1*WG4ngRKKac1cICU4NvoEJA.webp" alt="" loading="lazy" decoding="async" width="984" height="1614" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5ODQiIGhlaWdodD0iMTYxNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*WG4ngRKKac1cICU4NvoEJA.png" /></p>

<ul>
  <li>回 Telegram Group 就会出现刚发送的讯息内容。</li>
</ul>

<h3 id="22-移转-line-notify-发送讯息到-telegram-bot-google-apps-script">(2/2) 移转 Line Notify 发送讯息到 Telegram Bot (Google Apps Script)</h3>

<p>我的个人通知机器人服务是使用 Google Apps Script 达成的，因此以 Google Apps Script 转换为例 (类 JavaScript)。</p>

<h4 id="原始的-line-notify-发送程式码">原始的 Line Notify 发送程式码：</h4>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">lineToken</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">XXXX</span><span class="dl">"</span><span class="p">;</span>

<span class="kd">function</span> <span class="nf">sendLineNotifyMessage</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">var</span> <span class="nx">url</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">https://notify-api.line.me/api/notify</span><span class="dl">'</span><span class="p">;</span>
  
  <span class="kd">var</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">post</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
      <span class="dl">'</span><span class="s1">Authorization</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Bearer </span><span class="dl">'</span><span class="o">+</span><span class="nx">lineToken</span>
    <span class="p">},</span>
    <span class="na">payload</span><span class="p">:</span> <span class="p">{</span>
      <span class="dl">'</span><span class="s1">message</span><span class="dl">'</span><span class="p">:</span> <span class="nx">message</span>
    <span class="p">}</span>
  <span class="p">};</span> 
  <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
  <span class="nx">Logger</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>
<span class="p">}</span>
</code></pre></div></div>

<p>可以看到非常简单方便好用…</p>

<h4 id="移转成-telegram-bot-发送程式码">移转成 Telegram Bot 发送程式码：</h4>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">telegramToken</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">你的_BOT_API_Token</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">TelegramChatId</span> <span class="o">=</span> <span class="p">{</span>
  <span class="na">GA</span><span class="p">:</span> <span class="o">-</span><span class="mi">123456</span><span class="p">,</span>
  <span class="na">GITHUB</span><span class="p">:</span> <span class="o">-</span><span class="mi">123457</span><span class="p">,</span>
  <span class="na">MEDIUM</span><span class="p">:</span> <span class="o">-</span><span class="mi">123458</span>
<span class="p">};</span>

<span class="kd">function</span> <span class="nf">sendNotifyMessage</span><span class="p">(</span><span class="nx">message</span><span class="p">,</span> <span class="nx">chatId</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">var</span> <span class="nx">url</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">https://api.telegram.org/bot</span><span class="dl">"</span><span class="o">+</span><span class="nx">telegramToken</span><span class="o">+</span><span class="dl">"</span><span class="s2">/sendMessage</span><span class="dl">"</span><span class="p">;</span>
  
  <span class="kd">const</span> <span class="nx">payload</span> <span class="o">=</span> <span class="p">{</span>
    <span class="dl">"</span><span class="s2">chat_id</span><span class="dl">"</span><span class="p">:</span> <span class="nx">chatId</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">text</span><span class="dl">"</span><span class="p">:</span> <span class="nx">message</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">parse_mode</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Markdown</span><span class="dl">"</span>
  <span class="p">}</span> 
  <span class="kd">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
    <span class="dl">'</span><span class="s1">method</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">post</span><span class="dl">'</span><span class="p">,</span>
    <span class="dl">'</span><span class="s1">contentType</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">application/json</span><span class="dl">'</span><span class="p">,</span>
    <span class="dl">'</span><span class="s1">muteHttpExceptions</span><span class="dl">'</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
    <span class="dl">'</span><span class="s1">payload</span><span class="dl">'</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">payload</span><span class="p">)</span>
  <span class="p">};</span>

  <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
  <span class="nx">Logger</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>
<span class="p">}</span>
</code></pre></div></div>

<p>照前面 Telegram Bot 设定步骤取得的资讯。</p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">telegramToken</code> = <code class="language-plaintext highlighter-rouge">你的_BOT_API_Token</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">TelegramChatId</code> 这边是我自己多定义的方法，因为实务上我希望不同的通知分别传送到不同的 Group，因此定义了一个结构管理目标 Group 与他的 <code class="language-plaintext highlighter-rouge">Group Chat Id</code> 。</p>
  </li>
</ul>

<p><code class="language-plaintext highlighter-rouge">/sendMessage</code> <a href="https://core.telegram.org/bots/api#sendmessage" target="_blank"><strong>API 参数，更多参数、细节可参考官方文件</strong></a> ，以下是我自己会用到的参数：</p>

<ul>
  <li>
    <p>text: 讯息内容 (必带)</p>
  </li>
  <li>
    <p>chat_id: 目标 Group Chat Id (必带)</p>
  </li>
  <li>
    <p>parse_mode: 讯息内容解析方式，这边我指定 <code class="language-plaintext highlighter-rouge">Markdown</code></p>
  </li>
  <li>
    <p>disable_web_page_preview: 讯息内容的连结是否不要预览，这边设 <code class="language-plaintext highlighter-rouge">true</code> 关闭，可以让讯息显示更简洁。</p>
  </li>
</ul>

<p><strong>使用方式：</strong></p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">sendNotifyMessage</span><span class="o">(</span><span class="s2">"Hello"</span><span class="o">,</span> <span class="nt">TelegramChatId</span><span class="nc">.MEDIUM</span><span class="o">)</span> <span class="o">//</span> <span class="err">发送</span> <span class="nt">Hello</span> <span class="err">讯息到</span> <span class="nt">MEDIUM</span> <span class="nt">Group</span> <span class="nt">Chat</span> <span class="nt">Id</span>
<span class="nt">sendNotifyMessage</span><span class="o">(</span><span class="s2">"Hello"</span><span class="o">,</span> <span class="nt">-1234</span><span class="o">)</span> <span class="o">//</span> <span class="err">发送</span> <span class="nt">Hello</span> <span class="err">讯息到</span> <span class="nt">-1234</span> <span class="nt">Group</span> <span class="nt">Chat</span> <span class="nt">Id</span>
</code></pre></div></div>

<h3 id="成果-1">成果</h3>

<p>以我的 <a href="/posts/zrealm-dev/google-apps-script-三步骤打造免费-github-repo-star-通知器-实时获取-star-动态-382218e15697/">Github Repo Star Notifier 机器人</a> 为例：</p>

<p><img src="/assets/6922e90ba90c/1*yJDcnb7n1fIJAM-AV1Qk6w.webp" alt="" loading="lazy" decoding="async" width="840" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NDAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*yJDcnb7n1fIJAM-AV1Qk6w.png" /></p>

<p><img src="/assets/6922e90ba90c/1*5kBotSkNf9nN8NV-lCwZoQ.webp" alt="" loading="lazy" decoding="async" width="896" height="1236" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4OTYiIGhlaWdodD0iMTIzNiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*5kBotSkNf9nN8NV-lCwZoQ.png" /></p>

<ul>
  <li>
    <p>验证成功！ 当有人按我的 Repo Star 时能正确改发送通知到 Telegram Group！🎉🎉🎉</p>
  </li>
  <li>
    <p>制作方式可参考我之前的文章「 <a href="/posts/zrealm-dev/google-apps-script-三步骤打造免费-github-repo-star-通知器-实时获取-star-动态-382218e15697/">使用 Google Apps Script 三步骤免费建立 Github Repo Star Notifier</a> 」</p>
  </li>
</ul>

<h4 id="设定特殊声音或静音">设定特殊声音或静音</h4>

<p><img src="/assets/6922e90ba90c/1*kQsYkefi0SD7e9t4PerdRA.webp" alt="" loading="lazy" decoding="async" width="1004" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDA0IiBoZWlnaHQ9IjEyMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/6922e90ba90c/1*kQsYkefi0SD7e9t4PerdRA.jpeg" /></p>

<p>比 Line Notify 更棒的事是我们还可以对不同的 Group 设定不同的通知声音或是静音。</p>

<h3 id="与-telegram-bot-交互-command-x-使用-google-apps-script">与 Telegram Bot 交互 (Command) x 使用 Google Apps Script</h3>

<p>除了替代 Notify 功能之外， Telegram Bot 还能轻易地实现与使用者交互的功能 — Telegram Bot Command。</p>

<p>回到我的使用场景，我的机器人会定时或是 Webhook 触发传送通知讯息送给我；但有时候我也想手动触发机器人立刻取得当前结果，以往 Line Notify 没有这个功能，以 Google Apps Script 来说就只能暴力的设定一个网址，只要打开网址就会触发，很不好用。</p>

<p>Telegram Bot Command 就能让我直接输入指令讯息，命令机器人立刻执行我想做的事情。</p>

<blockquote>
  <p><em>本文以 <a href="https://script.google.com/home" target="_blank">Goolge Apps Script</a> 为例，Google Apps Script 详细介绍可参考我之前文章「 <a href="/posts/zrealm-robotic-process-automation/google-apps-script-打造每日数据报表自动化-rpa-快速串接-google-analytics-与-google-sheet-f6713ba3fee3/"><strong>使用 Google Apps Script 实现 Google 服务 RPA 自动化</strong></a> 」。</em></p>
</blockquote>

<h4 id="step-1-使用-google-apps-script-实现-command-处理逻辑">Step 1. 使用 Google Apps Script 实现 Command 处理逻辑</h4>

<ul>
  <li>
    <p>前往 Google Apps Script 首页</p>
  </li>
  <li>
    <p>左上方「建立新专案」</p>
  </li>
  <li>
    <p>点击「未命名专案」输入专案名称 e.g. <code class="language-plaintext highlighter-rouge">Telegram</code></p>
  </li>
  <li>
    <p>贴上基础程式码：</p>
  </li>
</ul>

<p><img src="/assets/6922e90ba90c/1*ZeW4O7Mdgcyj0VsSLDpxeA.webp" alt="" loading="lazy" decoding="async" width="1400" height="1288" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjEyODgiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/6922e90ba90c/1*ZeW4O7Mdgcyj0VsSLDpxeA.png" /></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">telegramToken</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">你的_BOT_API_Token</span><span class="dl">"</span><span class="p">;</span>

<span class="kd">function</span> <span class="nf">doPost</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">postData</span><span class="p">.</span><span class="nx">contents</span><span class="p">);</span>
  <span class="k">if </span><span class="p">(</span><span class="nx">content</span><span class="p">.</span><span class="nx">message</span> <span class="o">&amp;&amp;</span> <span class="nx">content</span><span class="p">.</span><span class="nx">message</span><span class="p">.</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">command</span> <span class="o">=</span> <span class="nx">content</span><span class="p">.</span><span class="nx">message</span><span class="p">.</span><span class="nx">text</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="s1"> </span><span class="dl">'</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span>
    <span class="kd">const</span> <span class="nx">chatId</span> <span class="o">=</span> <span class="nx">content</span><span class="p">.</span><span class="nx">message</span><span class="p">.</span><span class="nx">chat</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>

    <span class="k">if </span><span class="p">(</span><span class="nx">command</span><span class="p">.</span><span class="nf">startsWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">/update</span><span class="dl">"</span><span class="p">))</span> <span class="p">{</span> 
      <span class="c1">// 收到 /update 指令</span>
      <span class="c1">// 在这边处理你想做的事...然后回应...</span>
      <span class="nf">sendNotifyMessage</span><span class="p">(</span><span class="dl">"</span><span class="s2">你好.....</span><span class="se">\n</span><span class="s2">指令:</span><span class="dl">"</span><span class="o">+</span><span class="nx">command</span><span class="p">,</span> <span class="nx">chatId</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="k">return</span> <span class="nx">HtmlService</span><span class="p">.</span><span class="nf">createHtmlOutput</span><span class="p">(</span><span class="dl">"</span><span class="s2">OK!</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">sendNotifyMessage</span><span class="p">(</span><span class="nx">message</span><span class="p">,</span> <span class="nx">chatId</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">var</span> <span class="nx">url</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">https://api.telegram.org/bot</span><span class="dl">"</span><span class="o">+</span><span class="nx">telegramToken</span><span class="o">+</span><span class="dl">"</span><span class="s2">/sendMessage</span><span class="dl">"</span><span class="p">;</span>
  
  <span class="kd">const</span> <span class="nx">payload</span> <span class="o">=</span> <span class="p">{</span>
    <span class="dl">"</span><span class="s2">chat_id</span><span class="dl">"</span><span class="p">:</span> <span class="nx">chatId</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">text</span><span class="dl">"</span><span class="p">:</span> <span class="nx">message</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">disable_web_page_preview</span><span class="dl">"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
    <span class="dl">"</span><span class="s2">parse_mode</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Markdown</span><span class="dl">"</span>
  <span class="p">}</span> 
  <span class="kd">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
    <span class="dl">'</span><span class="s1">method</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">post</span><span class="dl">'</span><span class="p">,</span>
    <span class="dl">'</span><span class="s1">contentType</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">application/json</span><span class="dl">'</span><span class="p">,</span>
    <span class="dl">'</span><span class="s1">muteHttpExceptions</span><span class="dl">'</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
    <span class="dl">'</span><span class="s1">payload</span><span class="dl">'</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">payload</span><span class="p">)</span>
  <span class="p">};</span>

  <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
  <span class="nx">Logger</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">telegramToken</code> = <code class="language-plaintext highlighter-rouge">你的_BOT_API_Token</code></p>
  </li>
  <li>
    <p>上述 Demo 程式我们在收到 Post 请求、Command 参数等于 <code class="language-plaintext highlighter-rouge">/update</code> 时回应 <code class="language-plaintext highlighter-rouge">你好…</code> 模拟收到指令后处理后回应的场景。</p>
  </li>
</ul>

<h4 id="step-2-完成-google-apps-script-web-部署">Step 2. 完成 Google Apps Script Web 部署</h4>

<p><img src="/assets/6922e90ba90c/1*JfJfs4bYsSfsZYGVkApCSg.webp" alt="" loading="lazy" decoding="async" width="1200" height="705" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjcwNSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*JfJfs4bYsSfsZYGVkApCSg.png" /></p>

<p><img src="/assets/6922e90ba90c/1*TwSm45_Xwv4p7z4o9HJz2w.webp" alt="" loading="lazy" decoding="async" width="1400" height="1109" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjExMDkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/6922e90ba90c/1*TwSm45_Xwv4p7z4o9HJz2w.png" /></p>

<p><img src="/assets/6922e90ba90c/1*7RLJXZ3APnEI4V9bKqp3eg.webp" alt="" loading="lazy" decoding="async" width="1200" height="941" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9Ijk0MSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*7RLJXZ3APnEI4V9bKqp3eg.png" /></p>

<ul>
  <li>
    <p>右上角「部署」-&gt; 「新增部署作业」</p>
  </li>
  <li>
    <p>左上角「设定」-&gt;「网页应用程式」</p>
  </li>
  <li>
    <p>谁可以存取选择「所有人」</p>
  </li>
</ul>

<p><img src="/assets/6922e90ba90c/1*aRBaOOnhwBeK05l9e3Yv8g.webp" alt="" loading="lazy" decoding="async" width="568" height="380" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NjgiIGhlaWdodD0iMzgwIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6922e90ba90c/1*aRBaOOnhwBeK05l9e3Yv8g.png" /></p>

<p><img src="/assets/6922e90ba90c/1*FtY8NL36peDbOB4JWdzhDA.webp" alt="" loading="lazy" decoding="async" width="1296" height="932" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjk2IiBoZWlnaHQ9IjkzMiI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*FtY8NL36peDbOB4JWdzhDA.png" /></p>

<p><img src="/assets/6922e90ba90c/1*e2E41TCEf5O7nSOnVzpgbw.webp" alt="" loading="lazy" decoding="async" width="1400" height="768" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9Ijc2OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*e2E41TCEf5O7nSOnVzpgbw.png" /></p>

<ul>
  <li>
    <p>新增部署作业，选择「授予存取权」</p>
  </li>
  <li>
    <p>跳出帐号视窗，选择你的 Google 登入帐号</p>
  </li>
  <li>
    <p>跳出警告视窗，选择「Advanced」-&gt;「Go to <code class="language-plaintext highlighter-rouge">专案名称</code> (unsafe)」</p>
  </li>
  <li>
    <p>选择「Allow」</p>
  </li>
</ul>

<p><img src="/assets/6922e90ba90c/1*n0iO-XSPqifUKUkIgVQUSg.webp" alt="" loading="lazy" decoding="async" width="1400" height="1109" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjExMDkiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNlZGUyY2YiLz48L3N2Zz4=" data-orig="/assets/6922e90ba90c/1*n0iO-XSPqifUKUkIgVQUSg.png" /></p>

<ul>
  <li>网页应用程式网址： <code class="language-plaintext highlighter-rouge">你的 Webhook 网址</code> <strong>。</strong>
复制下来。
e.g. <code class="language-plaintext highlighter-rouge">https://script.google.com/macros/s/AKfycbx2oFv-eB4LezdOk3P3aoEZVhx_PI6n_YnTNP7WVVQSaiRU52di5bKNThsvIZxus3Si/exec</code></li>
</ul>

<blockquote>
  <p><em>Google Apps Script 网页应用程式部署、更新、使用、除错可参考我之前的文章「 <a href="/posts/zrealm-robotic-process-automation/google-apps-script-打造每日数据报表自动化-rpa-快速串接-google-analytics-与-google-sheet-f6713ba3fee3/"><strong>使用 Google Apps Script 实现 Google 服务 RPA 自动化</strong></a> 」。</em></p>
</blockquote>

<blockquote>
  <p><strong><em>⚠️⚠️⚠️ 请注意，如果 Google Apps Script 程式码有变更要点击部署-&gt;管理部署-&gt;选择建立新版本才会生效，细节可参考上述文章。</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>⚠️⚠️⚠️请注意，如果 Google Apps Script 程式码有变更要点击部署-&gt;管理部署-&gt;选择建立新版本才会生效，细节可参考上述文章。</em></strong></p>
</blockquote>

<blockquote>
  <p><strong><em>⚠️⚠️⚠️请注意，如果 Google Apps Script 程式码有变更要点击部署-&gt;管理部署-&gt;选择建立新版本才会生效，细节可参考上述文章。</em></strong></p>
</blockquote>

<h4 id="step-3-注册-webhook">Step 3. 注册 Webhook</h4>

<p>使用 Telegram API <code class="language-plaintext highlighter-rouge">/setWebhook</code> 注册你的 Webhook 网址。</p>

<p><strong>Request:</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">curl</span> <span class="o">--</span><span class="n">location</span> <span class="nv">'https</span><span class="p">:</span><span class="c1">//api.telegram.org/你的_BOT_API_Token/setWebhook' \</span>
<span class="o">--</span><span class="n">form</span> <span class="nv">'url</span><span class="o">=</span><span class="s">"你的 Webhook 网址"</span><span class="err">'</span>
</code></pre></div></div>

<p><strong>Response:</strong></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"ok"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
    </span><span class="nl">"result"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
    </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Webhook was set"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h4 id="测试">测试</h4>

<p><img src="/assets/6922e90ba90c/1*wNhksFLSip5DC0rXqMA_0A.webp" alt="" loading="lazy" decoding="async" width="870" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*wNhksFLSip5DC0rXqMA_0A.png" /></p>

<p><img src="/assets/6922e90ba90c/1*d_B3h3C30vI61p3ALP77yw.webp" alt="" loading="lazy" decoding="async" width="870" height="1200" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NzAiIGhlaWdodD0iMTIwMCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2VkZTJjZiIvPjwvc3ZnPg==" data-orig="/assets/6922e90ba90c/1*d_B3h3C30vI61p3ALP77yw.png" /></p>

<ul>
  <li>
    <p>我们会根据不同的 Chat Id 回应，因此不管是 1:1 对机器人或是有机器人在的 Group 群组都能回应。</p>
  </li>
  <li>
    <p>成功 🎉🎉🎉</p>
  </li>
</ul>

<h3 id="下篇">下篇：</h3>

<ul>
  <li><a href="/posts/zrealm-robotic-process-automation/ga4-自动数据通知机器人-3-步骤用-google-apps-script-串接-telegram-bot-1e85b8df2348/">简单 3 步骤 — 打造免费 GA4 自动数据通知机器人</a></li>
</ul>

<h3 id="其他-google-apps-script-自动化文章">其他 Google Apps Script 自动化文章</h3>

<ul>
  <li>
    <p><a href="/posts/zrealm-robotic-process-automation/google-apps-script-打造每日数据报表自动化-rpa-快速串接-google-analytics-与-google-sheet-f6713ba3fee3/">使用 Google Apps Script 实现 Google 服务 RPA 自动化</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/slack-app-整合-chatgpt-利用-openai-api-与-google-cloud-functions-自建智能助理-bd94cc88f9c9/">Slack &amp; ChatGPT Integration</a></p>
  </li>
  <li>
    <p><a href="/posts/zrealm-dev/google-apps-script-三步骤打造免费-github-repo-star-通知器-实时获取-star-动态-382218e15697/">使用 Google Apps Script 三步骤免费建立 Github Repo Star Notifier</a></p>
  </li>
</ul>

<h4 id="附注">附注</h4>

<p><img src="/assets/6922e90ba90c/1*zOFjvO5SSwbJgFL8kMff0w.webp" alt="" loading="lazy" decoding="async" width="706" height="284" lqip="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDYiIGhlaWdodD0iMjg0Ij48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZWRlMmNmIi8+PC9zdmc+" data-orig="/assets/6922e90ba90c/1*zOFjvO5SSwbJgFL8kMff0w.png" /></p>

<p>本文也是我 Medium 的第 100 篇文章(2018/10 发表 <a href="/posts/zrealm-life/blog经营心路历程-从新手到技术分享-重燃写作动力的秘诀-b7a3fb3d5531/">第一篇</a> ，6 年了)，坚持不懈、继续努力，详细心得跟数据等到破 1000 Followers (2024/10 目前 925) 或是总浏览数破 1,000,000 (2024/10 目前 984,549) 时再来分享。</p>]]></content>
  </entry>
</feed>
