We're sunsetting PodQuest on 2025-07-28. Thank you for your support!
Export Podcast Subscriptions
cover of episode EP90 Podwise App 上线啦!从网页到App,我们都经历了什么?

EP90 Podwise App 上线啦!从网页到App,我们都经历了什么?

2025/1/13
logo of podcast 硬地骇客

硬地骇客

AI Deep Dive AI Insights AI Chapters Transcript
People
S
Sato
一笑
龟龟
Topics
Sato: 我是Sato,参与了Podwise App从网页到App的整个开发过程。最初Podwise定位于桌面端,但考虑到移动端的应用场景,我们采用了响应式设计,这使得我们能够在同一个代码库中同时支持桌面端和移动端。在开发过程中,我们遇到了很多挑战,例如如何平衡桌面端和移动端的不同需求,以及如何选择合适的技术栈。最终,我们选择了Next.js和Capacitor的组合,虽然这个组合也带来了一些额外的挑战,但总体来说,它帮助我们高效地完成了App的开发。 在App Store审核方面,我们也遇到了一些意想不到的困难。审核人员认为我们应用提供的功能并不应该强制用户登录,这让我们不得不重新调整应用的逻辑,并向审核人员解释我们的设计理念。这个过程耗费了大量的时间和精力,但最终我们还是成功地通过了审核。 未来,我们将继续完善Podwise App的功能,并根据用户的反馈不断改进。我们也计划推出安卓版本,并探索更多与设备本身能力集成的可能性,例如Apple的AI能力。 一笑: 我是一笑,主要负责Podwise App的技术选型和开发。在技术选型方面,我们面临着如何平衡成本、性能和跨平台兼容性的问题。最终,我们选择了Web技术栈,并使用Capacitor框架将Web应用封装成App。这个选择使得我们能够最大限度地复用Web端的代码,降低了开发成本。 然而,Next.js和Capacitor的组合也带来了一些挑战。Next.js侧重于服务端渲染,这与Capacitor的纯静态页面要求存在冲突。为了解决这个问题,我们不得不对代码进行大量的修改,并做了两个工程,部分代码有差异。此外,集成原生能力,例如推送通知、支付和文件系统访问,也需要花费大量的时间和精力。 在开发过程中,我们也遇到了很多意想不到的问题,例如跨域问题、WebView的限制等等。这些问题都需要我们自己去寻找解决方案,并进行大量的调试和测试。总的来说,这个过程非常复杂,但最终我们还是成功地完成了Podwise App的开发。 龟龟: 我是龟龟,主要负责Podwise App的设计和用户体验。在设计方面,我们最初是从桌面端开始设计的,然后逐步适配到移动端。然而,移动端的设计比桌面端更复杂,需要更精细的规划和调整。我们花了大量的时间来优化移动端的交互和用户体验,以确保用户能够轻松地找到所需的内容和功能。 响应式设计虽然能够帮助我们同时支持桌面端和移动端,但它也带来了一些挑战。我们需要仔细权衡桌面端和移动端的不同需求,并确保设计能够满足两端的不同使用习惯。在实际开发过程中,我们经常需要反向调整桌面端结构以适应移动端交互。 在App Store审核方面,我们也遇到了一些问题。审核人员认为我们应用提供的功能并不应该强制用户登录,这让我们不得不重新调整应用的逻辑,并向审核人员解释我们的设计理念。这个过程耗费了大量的时间和精力,但最终我们还是成功地通过了审核。

Deep Dive

Key Insights

为什么 Podwise 选择从网页版转向开发独立的移动端 App?

Podwise 选择开发独立移动端 App 主要有两方面原因:一是用户习惯,大多数用户更倾向于在 App Store 中搜索应用;二是技术限制,Web 版无法实现推送通知、离线存储等功能,且无法接入 App Store 的内购系统。

Podwise 在技术选型时为什么选择了 Web 技术栈和 Capacitor?

Podwise 选择 Web 技术栈和 Capacitor 主要是因为团队已经通过响应式设计支持了移动端,沿用 Web 技术栈成本最低且跨平台。虽然 Web 技术栈在性能和体验上不如原生方案,但 Capacitor 提供了完整的生态支持,能够满足大部分需求。

Podwise 在将 Web 应用封装成 App 时遇到了哪些主要挑战?

主要挑战包括将 Next.js 的 SSR(服务端渲染)应用改造成纯静态应用,适配原生能力如推送通知、文件系统和支付系统,以及处理跨平台兼容性问题。此外,由于 Next.js 和 Capacitor 的组合较为罕见,很多问题在网上找不到解决方案,增加了开发难度。

Podwise 如何处理跨平台的支付系统兼容性问题?

Podwise 通过抽象支付流程,分别实现 Apple Pay、Google Pay 和 Stripe 的支付逻辑,并将所有订阅状态统一到自己的订阅记录中。此外,还处理了退款、取消订阅等细节问题,确保用户在不同平台的订阅状态一致。

Podwise 在 App Store 上架审核过程中遇到了哪些问题?

Podwise 在 App Store 上架审核时多次被拒,主要原因是审核人员认为应用不应强制用户登录以收集隐私信息。团队通过解释应用已有大量 Web 版存量用户,并修改部分功能展示逻辑,最终说服审核人员通过审核。

Podwise 未来的移动端规划是什么?

Podwise 的移动端规划主要跟随 Web 版功能更新,如即将上线的中文翻译功能。此外,团队还计划优化动态广告探测能力,并探索与设备原生 AI 能力的集成,以提供更轻量的功能体验。

Podwise 的安卓版本何时上线?

Podwise 的安卓版本已经在开发中,团队目前正在调试 Google Play Store 的订阅系统和真机体验。预计在解决相关问题后,安卓版本将很快上线。

Chapters
本期节目讨论了 Podwise App 从网页到 App 的转变,以及响应式设计的应用。讨论了响应式设计的原则,从桌面端到移动端的适配,以及为什么选择响应式设计。
  • Podwise 最初定位偏向桌面端,但移动端也需要考虑
  • 响应式设计是必然选择,除非有充足的人员
  • 响应式设计原则:从桌面端到移动端适配,移动端设计更复杂

Shownotes Transcript

大家好 欢迎收听尼海克我是 Sato 我是一笑我是龟龟经过不懈的努力 PODOS 终于正式上架了苹果的 App Store 全球的歌曲啊

现在只要在苹果商店搜索 Podwise 都可以找到如果有听众朋友刚好是我们的老用户的话也欢迎大家随时来体验当然如果给我们留个 review 和五星好评那就更好了非常感谢作为一个养成系的播客上架苹果商店也是我们的第一次今天恰好趁这个机会跟大家分享一下我们都碰到了什么问题以及是怎么解决的

大家姑且一听啊或许有用呢那废话不多说开始我们今天的节目吧首先我不知道有多少人知道啊就是其实 Podwise 从一开始网页设计的时候就是 responsive design 的也就是大家常说的小硬式设计我不知道各位这个当时是什么样的考虑一开始就做这样的小硬式设计的对其实我们最初在定位这个 Podwise 的时候是比较偏向桌面端的但是移动端但是也没有说就不要做啊就是因为像 Podwise 的

擅长处理的这种节目

当时定位的这个目标的节目其实都是文字量非常大的嘛那使用场景上我们考虑的也是一个比较专注的使用场景就是比如说学习啊或者说研究这样的场景不同于很多这种听播客的时候的那个娱乐场景就比如说我开车的时候随便找个东西听一听就是娱乐场景但是我们 Photowise 可能会比较偏向于一个专注使用的场景那这种场景其实还是一个大屏来做会比较舒服嘛对吧所以我们就一开始是偏桌面端的

但是它毕竟是个博客 APP 所以我们直接放起移动端也并不太合适而且即使就算是看这种场景对于像公共交通通勤也是一个比较合适的使用的一个时机对吧你坐地铁什么的你靠着东西来看一看也是很常见的一个情况

但要是单独为桌面和移动端去做成两个产品呢就我们这个人员规模属实不太现实而且这还不是一个 H5 和 APP 的跨平台问题因为这俩 H5 和 APP 它们其实在这个产品逻辑上是一样的嘛交互上是一样的那这是一个大屏和小屏其实是需要去去适配不同的这个交互不同的使用流程的一个问题但是

那这样显然就是响应式布局就比较合适了对吧人家天生就是做这个的

所以我觉得这个就算是一个必然的选择了除非说我们本来就是兵多将广对吧然后有专门的 PD 去处理 PC 专门的 PD 去处理 Mobile 那我觉得可以搞一搞否则的话肯定还是响应式的这个思路去做会比较合适一点然后既然我们首先是要做桌面端对吧一开始说我们比较偏桌面端同时实际上我们也需要去快速的做 POC 快速的 MVP 对吧去快速连带

那 Web 肯定也就是首选不太可能去做成一个 native 的 app 那自然就是 Web 加上这个 responsive design 来做这个事情对其实这里我还有一个挺大的疑问我相信可能有很多听众可能跟我有一样的疑问我们在做这种响应式设计的时候到底是应该从 PC 端从桌面端往下精简呢还是说我先做移动端然后再去放大 PC 端的功能这个的设计原则是什么能给大家分享一下吗

设计原则你让我来聊设计原则我觉得就是我不太配啊没有这个资格对在设计这个事情上我就只配谈实践谈不了理论和原则从我个人的实践来说的话毕竟从我们的产品定位上去推研发路径的话其实肯定是从桌面端先设计然后往移动端去适配的因为我们先做的就是桌面端吧

但是你刚说从桌面端往移动端去精简呢就是我觉得这个精简这个说法其实可能不太确切因为功能上的精简是有可能的比如说我这个 PC 上这个功能塞得下但是目标上塞不下对吧所以我不要了但交互上我觉得其实移动端反而是更复杂和更精细的对它不是精简它其实更精细了因为毕竟桌面空间很大嘛你可以随便乱塞

在桌面上你就算把很多不重要的信息也放出来然后布局做的比较随意虽然观感上可能差一点但是使用体验其实不会很难受

你可以随便做比如说左右布局啊然后可以把功能按钮全都频扑出来之类的都没关系但是移动端不行移动端反正就那么大个屏幕嘛所以需要你非常仔细的去规划信息呈现和功能入口保证用户想看的内容都能轻松看到想用的功能都能快速找到所以实际上我在移动端的这个设计上花的时间啊是远比桌面端要多的虽然实际发生的情况

很多时候是我先做的桌面端的这个功能但是结果去调那个移动端的样式的时候会花很多时间然后往往是调着调着觉得这个交互在移动端不合理但是合理的交互呢在响应式好作的这个范围呢很难搞结果我就又回头去调桌面端的结构来反向兼容我理想的这个移动端交互所以虽然是从桌面端出发的但是实际上在我的实践里面其实主导设计的反而还是移动端

所以如果一定要回答应该从桌面到移动还是从移动到桌面我觉得可能是从移动到桌面会更好一些不容易反攻毕竟桌面的设计空间要大得多得多然后像 responsive design 虽然名字上有个 design 但其实

其实我理解它解决的是开发的问题它并不解决设计的问题设计实际上是为了满足这个响应式的原则对原则嘛对响应式设计其实应该算是个原则对就是个设计原则就是你提到的这个那设计实际上为了满足这个响应式的原则是需要花更多心思去让桌面和移动端的这个设计是

相似但又同时符合各自端的这个使用习惯的因为相似你才能用响应式的这个方式比较简单的做出来嘛要是完全两个样子其实你也用不上响应式设计这样的这种这种技术了对吧哪怕你用响应式硬做出来其实最后的可维护性可能也非常差因为你其实就是写了两套代码嘛因为你的交互比较相似你才能用一套代码去把它给做出来

对毕竟因为桌面端其实比较大当我们去做设计的时候其实它的空间它的可操作性其实还是蛮大的但是你如果从移动端上面去考虑的话其实移动端的它的可操作空间是小的然后它对体验的要求是高的所以说先从移动端考虑我觉得这个思路是挺对的我还想问一下你看既然我们移动端本来就可以用只不过是网页版的那为什么还要去发布一个移动端的 APP 呢这个我觉得

两方面的原因吧一方面是用户的使用习惯另一方面则是技术上的限制先说用户习惯吧那手机实际上今天还是 APP 生态为主导的就是大家很多时候在手机上找一个应用第一反应是跑去 APP Store 里面搜对吧哪怕就是 web 有不用安装既开机用的优点

就我个人来说有 APP 我其实也喜欢用 APP 假如说一个应用有 H5 有小程序有 APP 全都齐如果是高频使用的情况下我肯定是会去下个 APP 的

然后包括其实我们自己在推广的过程中也遇到过很多次潜在用户跑来问我们说为啥你们这个东西在 App Store 里搜不到对吧我们遇到过很多其实在我们发布 App 之前也有很多用户把 Podwise 的这个 Web 添加到主频用这种方式来使用这个其实就是 PWA 的方式对吧其实这种方式已经能获得可能大概有 80%的 App 提案但是现实情况是绝大多数用户可能压根都不知道还可以这个样子

很多用户都不知道说我可以在 Safari 里面把这一个网页通过添加到主频的方式把它变成一个类似 APP 的东西然后就是能力限制举几个例子就比如说发送通知那其实在像 iOS 的 Safari 中你就必须把这个 web 添加到主频你才能够去请求一个通知权限不然你都是请求不了的你就不能给用户发通知

然后像比如说如果你的 APP 想去离线存储一些内容虽然 PWA 也可以让你的 APP 向离线使用嘛对吧但是你能存储的空间却是被严格限制的特别是 iOS 其实存不了多少东西像 Photowise 其实我们提供了一个下载节目的转录内容然后去离线阅读的能力嘛

那像 iOS 的 Safari 它的存东西的限制以前限制的是 50 兆后来放宽了放宽到了最大的 500 兆但是很多时候其实也是不够用的所以你就可能用 PWA 你就做不了这种东西然后还有像是什么接应用商店的内购能力对吧就是像 App Store 的那种 IAP 这个 PWA 就完全没法搞了

但这也就不符合一般用户的使用习惯所以还是觉得做一个 APP 会比较好一点我们去做移动端的话是不是自然而然就是选择 web 技术战略因为我们毕竟之前其实做的全部都是 web 然后这样的话其实成本是最低的然后也是跨平台的我想问一下我们当时做技术选型的时候当时是怎么考虑的有没有调研过一些框架比如说什么 Ironic Cordova 等等之类的这些东西做到这个问题

技术选型这个问题我必须要说凡事都得是要取舍确实我们是用了 web 技术站主要也是因为本身已经通过响应式设计去支持了移动端直接沿用显然是成本最低的方案而且

他还跨平台像你说的但是呢 web 技术站在性能和体验上终究还是打不过这种 native 方案包括说这种套了一层壳的 native 方案什么是套了一层壳的 native 方案就像 rec native 或者说 flutterrec native 你别看他看着特别像 web 但实际上他本质上还是跑在一个 native 的这个空间上的对

不像 web 它是完全跑在一个 webview 里面然后呢这里面其实本身我们在这个技术站上面一开始使用的是 next.js 这本身也是一个非常大的限制因为 next.js 它它其实是一个注重 SSR 就是服务端渲染和 RSG 静态页面生成的这个框架所以你用 next.js 做出来的 webapp 其实它不是一个纯的 SPA 应用不是一个纯的 single page 的 application

这一方面就导致很多转场动画就没法做因为你这个转场动画你得是一个 SPA 嘛你也得两个页面同时存在你这个转场动画才好做然后另一方面实际上也给封装成 APP 去带来了很大的麻烦

这个可以后面再讲但是反过来说 Next.js 在我们做 web 版的时候也确实带来了显著的效率提升开始在做 web 版的时候就是很幸福但是再去把它给封装成 app 的时候就不幸福了这个在做 web 的时候带来的效率提升减去包 app 踩过的坑和吐过的血之后还是不是赚的我觉得就不好说了对所以你要说这个

技术选型是怎么考虑的其实我这感觉就是有一种骑虎难下的感觉因为你那个时候说我要去做 APP 了完全为 APP 去重写一套代码不管是现有功能的迁移还是说以后我做了新功能我要去开发维护都是一个不太能接受的成本等到我下了决心就尽量复用代码之后再去找解决方案就会发现 Web 包 APP 的框架几乎只有 Capacitor 是一个可选的其实像你说的 Ionic Cordova 之类的

都是 capacitor 就是它是 capacitor 的前身嘛一脉相承的这都是一个玩意儿对包括你今天去看这个很多 capacitor 的插件你会发现它其实就是 Codewa 的插件 Codewa 的插件可以直接拿到 capacitor 里面去用对也因为就只有这一个可选的所以其实 capacitor 的生态相对来说还是挺完整的比我预想的要完整的多你像比如说我们用到了 Firebase 然后很多人收款会去用 RevenueCat 的

这一类 APP 常用的服务它都会提供 Capacitor 的插件然后包括社区里的各种插件其实也还都挺多的像 Github 上有一个那个 Ogg 就叫 Capacitor Community 它里面就会有很多这种 Capacitor 的插件当然如果我决心足够大的话其实还有另外一个倒反天罡的方案就是把整个 Codebase 用 flat 重写因为 flat 是可以在浏览器里跑的 flat 不是只能在 APP 跑

对这样的话其实你也可以得到一个三端统一的一个方案但是这就要放弃 Next.js 独有的一些特性比如说 Next.js 是前后端同构的这个在你一个人去做开发的时候其实非常方便说真的下次如果确定比如说我们下一个产品确定是要做 Web 加 App 的我想我应该是不会再用今天 PotWise 这个方案了就是这个方案我甚至觉得我可能是第一个吃完这个螃蟹的人就是肯定有人吃过这个螃蟹但是吃到一半没吃下去你知道吧

我觉得我可能是第一个吃完这个螃蟹的人对那我就想问一下你看 PodOS 其实以前是一个很功能完整的一个网站那想把 PodOS 这个网站封装成一个 APP 用刚才你讲的 Capacitor 把它封装成一个 APP 这里面主要还要做哪些工作这个说实话其实远比我预想的要麻烦的多一方面是 Nexus JS 加上 Capacitor 这个组合本身就有点

水土不服啊另一方面就是像我刚刚说的我因为可能是第一个吃完这个螃蟹的人嘛所以遇到的问题几乎在网上找不到解决方案然后对这种网上没有答案的问题啊你就是去问大语言模型也是无济于事的他也不知道所以对非常的麻烦那笼统的来讲第一个要解决的问题也是最大的麻烦是你得先把你的网站改造成纯静态的

这个纯静态不是说没有动态内容而是说你的页面都得是静态资源你不能有那种 SSR 服务端渲染那就是必须都是都是 CSR 的然后不是一定要 SPA 但 SPA 就是纯静态的不巧的是呢刚刚也讲过对吧 SGS 本身是一个侧重 SSR 的框架

虽然 Next.js 也提供了 static export 这样的一个模式就是你可以静态导出成一个纯静态网站但是如果你要用这个 static 导出的模式就会有很多 Next.js 的特性不能用比较典型的比如说 ServeAction 就不行那 SSR 这种肯定显然也是不行的

关于这部分的改造其实我有更新到我们那个 Podwise 的那个小册子里面详细的内容大家可以到小册里面去看这里要讲的话就是太多了比较值得一提的是为了更好的 SEO 的这个目的和用户在 web 上的这个使用体验因为 SSR 有一个相比于 CSR 就有一个非常大的好处是它的手评渲染会更快嘛对吧所以实际上我觉得我们是需要保留一些 SSR 的

那这些 SSR 在 APP 这端其实是留不下来的所以实际上我在改造的时候并不是简单的把整个工程全部去做了静态化而是在附用绝大多数代码的情况下去做了两个工程然后部分代码有差异在 WEB 这边比如说我对于特别重要的一些页面比如说这个节目的详情页我仍然保留了 SSR 但是在这个 APP 这边我就把它做成了纯静态的这个是一个点非常大的一个改造然后第二步

其实是适配一些 native 的能力包括你可能想给你的 app 添加一些额外的 native 的能力比如说最典型的 push notification 对吧推送通知然后还有和这个文件系统相关的然后也包括支付能力那像 podwise 这几部分其实都做了 push notification 我们是通过这个 firebase 去做的然后 firebase 加上 capacitor 的插件是可以做到一套代码去把这个事情都做完的不仅限于说我

iOS 和安卓的这个推送消息也包括你在桌面浏览器端里面的推送消息其实都是一套代码就可以搞定了那支付也一样支付可以用这个 Revenue Cat 来统一多个平台的支付相功能它有这个开拍手的插件但是值得一提的是 Revenue Cat 好像国内是被抢了是吧对 最近好像被抢了是的然后其实 Revenue Cat 还要再多收你一道钱你本身已经被这个 App Store 什么的剥削了一道 Revenue Cat 还要再收你一道钱

但是它收的不贵啊然后呢像文件系统这样的东西你 web 肯定是做不了的就是你单独做成 app 特有能力我们就是做了一个刚刚讲到可以下载这个节目转录内容的功能嘛这个是属于 app 独有 web 没有

然后还有一些小的功能可能需要按需去调整的跟 native 相关的比如说我分享导出在 web 上我可能比如说导出到那个 Obsidian 我是直接搞了一个 Markdown 的文件下载下载然后你拖进去就好了但是在 app 上就可以做成说我直接跳转那个 Obsidian 然后它会弹出一个导入的一个

一个窗口然后就可以直接导进去会更方便一些然后像分享的时候 share 的时候也是因为你的两个系统之间这个 share 的方式不同嘛对所以这些都需要搞一下然后包括像这个 oas 登录这种在 web 上和 app 也不同也是需要去调整适配的因为 web 就是在浏览器里面去 redirect 嘛对吧它就是都在浏览器里面完成但是 app 是需要换起一个内置的浏览器或者说去跳到 web 浏览器之后再跳回 app

这就需要你去搞明白说这个 schemer URL 和 universal URL link 这种东西到底是什么玩意儿然后去做好配置和验证你才能够确保你跳出去之后还能再跳回来所以这些东西就是跟 native 相关的都是要搞的然后你把这两块搞了之后其实就差不多了因为毕竟我们绝大多数的代码都是附用的对 听你讲讲其实还是挺复杂的尤其是登录你要重做然后支付的话

刚才讲说可能也得去重新接等等之类的刚好这里聊到支付啊我其实还想问一下因为我们之前在 Podwise 里边是在用 Strap 在做支付的验证嘛再往以前是 Lemon 反正我们现在既有 Lemon 的也有 Strap 的然后现在我们做了移动端那移动端你在 OS 上面你肯定得接 Apple Pay

对吧然后你在 Google 上肯定要接 Google Pay 对吧那对于 Podwise 的会员来讲的话你不管在哪买了你最终肯定得是一套会员体系嘛不管我是在 Apple 买了还是在 Google 买了还是在哪买了我最终我这个月该是会员就得是会员那这个兼容是怎么做的那给大家分享一下吧嗯对虽然其实前面提到了 Revenue Cat 这个服务啊它就是可以兼容的但我们实际上也没有用是自己做的整合呃

一个是因为 Revenue Cat 要收钱另外一个是因为我做了一半才发现 Revenue Cat 可以在 Capacitor 里面用所以就是结果事实上就是没有用但是没有用正好也可以给大家说一下这里面需要做些什么事情但是有需要的朋友可以去考察一下这个 Revenue Cat 适不适合你的需求因为说句实话虽然说 Stripe 还是比较好接的但是像苹果 App Store 的那个 IAP 就是那个 In-App-A-Purchase 就是内构接起来是要麻烦很多

然后三个你都要接的话要处理的细节其实还是挺多的但实际上呢三个平常的大体流程其实是一致的就是你要做的就是展示产品和价格那为什么你要去专门做一下展示产品和价格因为不同地区的这个用户看到的价格是不一样的 Stripe 可能无所谓但是像苹果的这个 App Review 的这个 Guideline 里面它就会要求你不同的用户看到的产品价格应该是它的 Native 货币

就是你日本的用户应该看到 JPY 嘛对吧所以你需要去从他的这个 App Store 里面去读你的产品的这个价格然后展示出来所以第一步是展示产品价格然后第二步就是用户下单完成支付

然后第三步就是我们的后台去接到回调修改用户状态当然如果你是一个纯的 Classic 的 App 没有后台的话 App Store 之类的也是提供了这种方式的就是它可以在你的 App 内接到一个回调这个就不展开说了但一般我们肯定都是有后台的我们在后台里面接到回调去修改用户状态

然后三个平台其实也都一样支持比如说取消订阅呀恢复订阅呀然后切换这个订阅的计划之类的所以我们只需要把这些动作和步骤抽象一下然后做成三套实现按照平台去 build 不同的代码或者说去调用不同的代码就行了然后你把所有的状态都统一到你自己的一个订阅的一个记录里面就

就可以了当然你额外需要做一些控制逻辑的比如说你不能在 web 上去取消 app store 的订阅你做不到那这个时候你在 web 上就要提示用户说你这个订阅是在这个苹果的 app store 订的那你要去我们的 iOS app 里面去操作才能够取消订阅之类的这种细节就是还挺多的

然后还有比如说像处理退款苹果就有一个退款撤销的回调就是用户申请了退款然后呢可能 App Store 也允许了但是又因为什么原因他把这个退款撤销了所以就是等于说这个退款被 rollback 了像这种回调 stripe 就是没有的

你就是需要去处理好这种问题然后把用户的这个 subscription 重新去 active 因为我现在我们安卓的结果还没接完等回头我把安卓的也弄完了之后我会总结一下发在我们的知识星球里面说这个东西到底该怎么做到时候大家感兴趣可以去看一下然后其实除了接这个事情之外实际上

在营销运营上还是有很多麻烦事的因为接你反正就接一次就好了但是你要比如说你要搞活动的话你又得到三个平台都去配对吧你搞一个新年活动你得三个平台去配优惠然后再得还可能优惠力度都一样之了

之类的然后用户跑过来说我之前已经定了我想想说这个优惠能不能搞啊然后你就要到不同的平台去对吧给他操作说我先给你退款怎么样的反正就这个运营上的麻烦我觉得远比接入要麻烦的多但是好像也没有产品来解决这个问题我不知道

因为我理解这个东西就算你用 revenue cat 也是解决不了对吧嗯对听你讲这个里边真的是满满的细节就是你要把三个平台里边的兼容之类的全部都要做好然后 A 平台订阅的然后在 B 平台里边也不能取消订阅然后这个里边其实逻辑还是蛮复杂的这个要做好真的不容易啊对

因为 Capacitor 是可以帮你封装 App 的嘛它是帮你把 Web 可以封装成一个 App 它其实还提供了很多额外的能力你刚才也有提过就是它可以桥接 Native 嘛比如说什么蓝牙呀什么位置呀等等这些能力嘛那我们现在有集成这部分相关的能力嘛然后就是这个 Capacitor 现在够我们用嘛比如说现在有用户不是说想让我们在耳机上面点一下做一下 highlight 这种东西能做吗嗯

蓝颜和位置我们现在暂时还没有集成前面其实刚刚提到过一部分比如说像 Fire System 之类的这也是集成了的

但这个东西呢够用肯定是够用的因为哪怕在社区里面找不到这个现成的 plugin 你自己去写一点 native 代码然后再桥接到这个 webjess 的这个环境下也是非常简单的就是反正对因为我现在也已经在 podbyte 里面简单做过一些这个跟那个 native 能力的桥接我做了一个说我去判断一下我这个 app 是不是在 testflight 或者说在 sandbox 的环境里面去运作的

然后去做了一些特殊处理对那这个东西其实在那个 Kypesto 官方就没有这样的 plugin 社区我也没找到合适的我就自己写了一下非常快所以倒是不用太担心这部分像你说的蓝牙这个即使社区里面没有那自己去弄一弄然后把比如说耳机按下的这个事件再重新发到这个 WebGames 的那个环境里面就可以了对

OK 你刚才其实也有提过因为我们其实是一个 web 的技术站然后做的显示设计代码肯定是一套那现在要做移动的 app 了你刚才有讲说其实你是删除了部分代码还是怎么样子然后给它做了区分了代码仓库就这部分我们现在是怎么管理工程的这个能给大家介绍一下吗对我现在是两个代码仓库然后我现在的做法是写了一个简单的脚本按需从 web 的代码仓库里面往 app 的代码仓库里面去同步代码

就是因为 web 我们这边是 next.js 所以其实它前后端代码是在一起的那实际上 app 那边肯定显然是不需要后端代码的所以我会选择性的去同步一些代码到这个 app 这边我感觉这个不能算是一个最优的方式但是对我来说已经够用了其实最开始的时候我是想过用一个工程的在 build 的时候想办法通过不同的这个 build 的配置来区分后来发现非常麻烦因为我们用的是 next.js 它这个 build 的动作其实是比较黑盒的

它其实也没有提供多少 Build 的选项给你去调整

包括它比如说没有提供说我忽略哪些文件不够的它没有这个选项然后对也没有提供比如说我同名不同后缀文件的优先级之类的比如我有一个叫 page.tsx 然后我有一个 page.ios.tsx 对吧我希望说我优先选择 ios 这个文件它其实这些配置都是没有的那当然虽然你可以通过比如说我给这个 next config 传入 webpack 的配置因为 next 其实背后用 webpack 嘛

还有用 Turbo 但 Turbo 好像现在还是在 Experiment 然后你可以通过说传入 Webpack 配置或者说去修改 TS Config 因为 TypeScript 它提供了像我刚刚讲的后缀文件优先级之类的你可以去搞这些配置应该是可以做得到的但是我在粗略研究之后决定还是算了感觉真去折腾这个怕是得折腾好久所以我现在就对我现在就通过自己写一个脚本按照两个这个

Blob 语法的一个列表来选择同步哪些文件忽略哪些文件也包括说我解析 package.json 之后把有差异的依赖也同步过来这样的话两个独立工程只附用代码不附用配置最大的好处就是让两边的工具链都用比较标准的方式来运作而不是说我一通魔改之后这个魔改之后我相信还是让它用标准的方式来运作会稳定的多然后这样的话你在处理两个平台之间的差异的时候也会灵活的多

所以我现在就没有选择用一个工程去做这个事情当然这种方式呢我觉得就可能比较适合一人开发的情况你多人协作的时候你分成两个工程去做可能就会麻烦一些会有额外的沟通成本对到时候去同步啊干嘛的其实搞来搞去比如说你在 web 里边在 base 里边改了一些东西然后他在另外一边又改了一些东西对这个其实合并啊同步啊还挺麻烦的对但其实一个人做的话就无所谓了对自己都知道嘛

对那我们现在事后看的话 web 的技术战相比其他的跨平台技术比如说你刚才也有提到做 real native 或者做 flutter 有没有什么优劣势那最大的优势肯定就是代码服用了嘛对特别是你先做了 webapp 的情况下然后呢生态比较丰富也比较成熟啊

再要说的话有时就是看开发者本身是不是更熟悉 web 技术战吧你本身本身要熟悉的话那开发效率比较高但劣势的话其实也挺明显的比较显著的就是他的性能一般然后动画也不好做因为我始终觉得 app 的这个

体验其实是很重要的就是你能够做的怎么说呢比如说动画流畅使用起来舒服的话其实对于 App 的这个使用体验会好很多然后呢还有一个劣势就是 Native 能力的适配相对比较费劲那虽然像那个 React Native 和 Flutter 其实也存在和 Native 适配的问题但是它们终究底层是跑在一个环境里面的但是像 Capacitor 它这样基于 WebView 的

这个方案其实是会有一些 WebView 带来的特有的问题需要去解决的典型的就是那些浏览器的限制在 WebView 里面一样存在比如说跨域问题那跨域问题当然也可以解决啊因为你毕竟已经是一个 APP 了嘛但是就会有额外的麻烦事需要去处理然后有些麻烦事是非常麻烦的比如说我们在这个 Web 里面去播放音乐的时候对吧我们去拉取一个音频的时候

浏览器本身是对于音频这种拉曲是做了额外的处理的比如它会发一些额外的这个 security 的 header 告诉服务端然后服务端就知道你是浏览器在跟我拉音频所以我不会跨域我不会阻止你但是你直接用 Fitch API 你用 Programmatic 的方式去拉音频它就会跨域那这种问题其实在 App 里面是不存在的但是在 WebView 里面就会存在但是你要说我自己想办法去拉音频

然后再塞给这个 Audio 元素那就是一个非常麻烦的事情本来它就是完全自动的一个事情对所以这些就是比较麻烦的地方对我们之前已经有 Web 了嘛那我们在 PodWise 在做这个移动端这个开发的过程从开发到上线

就最终大概经历了多少时间然后这个里面有没有什么是巨坑呢嗯其实拖了非常长时间对因为实际上我在最初做出一版可以跑的 APP 之后搁置了挺长一段时间然后又回头去做一些 web 上的功能然后做了 web 上的功能又要再搬到 APP 上期间还花了不少时间就在让这个 APP

没有那么重的 web 改这个事情上去调来调去调样式调动画给我看了一下我这个 app 的工程其实我们现在已经是一月份了对去年三月份就创建文件夹了去年三月份就新建文件夹了然后第一版能跑的实际上四月份就有了

所以到现在都大半年了然后接下来绝大多数的 commit message 我去看了我这个仓库的这个提交记录绝大多数的 commit message 都是从 web site 同步代码从 web site 同步代码从 web site 同步代码就全都是这种

然后夹杂着很多 APP 独有的问题的处理提交比如说 Universal Link 比如说支付相关的所以时间跨度非常大但你要说实际花的时间其实也不算很多就必须承认这中间还是有很大的为难情绪和拖延的成分在因为这个技术选情毕竟没摸过经常说你要去做的时候就会觉得很麻烦就会不想做然后就会拖着好多东西

对然后可参考的资料又少得可怜所以经常都是 web 那边有事情做呢就会给自己一个理由说那我先把 web 这边做的吧 app 这边就先放放

然后就会越拖越久所以最后就是下了决心说不行我一定要把它给搞完才给它搞完所以最大的坑你说除了那些这个技术选型上本身别人没有遇到过的坑对吧我全都趟了一遍之外可能最大的坑就是自己的这个为难情绪在最大的坑是自己是吧对对对是的

因为我知道就移动端其实大家在用的过程里面很多人其实比较大的影响体验的点除了你刚才讲的那些流畅性等等的其实还有 crash 用着用着然后就挂了对吧闪退了对闪退了对闪退的是种我知道很多移动端的 app 它其实都有这样的监控策略我不知道我们自己有没有在用类似这样的监控策略去监控闪退就是能保证大家的使用体验的类似于这样的方案可以给大家分享一下

对我现在接入的是这个 Firebase 的一个服务 Firebase 有一个服务是 Crashlytics 那 Firebase 本身是收费的但是其中有一些部分是免费的像这个 Crashlytics 就是免费的然后像它的那个 message 就是 push notification 也是免费的然后这些东西也都有 Capacitor 插线所以其实接下来也挺方便的当然有一点值得一提的是因为你用 Capacitor 去包的话其实大部分时候你的 APP 是不会 Crash

就从 app 级别它是不会闪退的只是 webview 里的页面挂了而已所以需要注意的一点是这种错误你需要自己采集然后通过你用的 crash 监控的服务的 API 发过去才能被监控到否则的话你可能接了之后会发现你这个 crash 率非常非常低因为本身 webview 它不会 crash

了解,确实可能需要自己去把页面挂掉的信息然后发给 Firebase 然后让他再推给我们自己这个逻辑还是挺好的然后因为你刚才讲说其实我们 4 月份的时候已经有一个现能跑的版本了但是后来其实我们还是先发了 TestFlat 发了 TestFlat 的过程里面有没有什么令你印象深刻的客户提供过来的就是我们的用户提供过来的反馈

让我印象比较深刻的到没有功能上的反馈因为毕竟在用我们 TestFlight 的绝大多数都是我们的存量用户但印象比较深的是推特上有一个朋友拿 Podwise 作为 PWA 开发的案例来讲还有不止一个朋友来问过我你这个到底是用什么技术站做的也有知道说我在用这个 Capacity 搞的来问我说你这东西靠不靠谱这个技术站靠不靠谱他也打算用这个我就

我记得有位朋友在我们的 TestFlight 大概两三周没更新版本的时候就是在我打退场股的时候对吧忍不住跑来问我说是不是用 Capacitor 遇到问题做不下去了因为他们公司内也有个项目打算上 Capacitor 看我们不更新的有点慌不过来问能不能用 Capacitor 的一般其实我都会适当的劝退一下我说如果你用 Next.js 你最好不要用 Capacitor 也不要用这个组合

改版社本身还是可以用的虽然说实话社区也不是很活跃特别是很多插件的文档完善录都比较一般对自己摸索的去使用但是整体使用下来倒是没有发现什么跨不过去的坎倒是主要的问题还是出在这个 Next.js 和改版社这个组合上花了非常多的时间

所以令人印象的用户反馈就是有很多人过来问你说这个东西靠不靠谱然后你给人家给劝退了是吧对对对蛮多人来问这个技术选型的对那从 Testflat 到上架就看起来就一步啊苹果不是上架的时候会审核吗之前我们就经常在 X 上看到很多人说这个审核又被拒了或者说这个审核都提交一个多礼拜了根本就没反应那我们这个上架过程里面有碰到什么有意思的事情吗

对这个上架过程啊确实挺有意思的因为我感觉是相当的不顺利比我预想的一样难得多得多对其实一开始的时候我也确实担心过审核被拒啊但是我担心的原因是说我们这样的这个 web 包壳技术战是不是会有影响啊结果确实被拒了但理由和这个没有关系而且是是个让人异常头大的理由啊我们被被拒绝的理由是什么呢他还不是拒了一次啊反复拒绝

主要理由是审核人员认为我们应用提供的功能并不应该强需求用户登录然后我们不应该强需求用户登录所以我们就不应该要求用户注册然后去收集用户的隐私信息它其实这个背后最关键的点就是收集用户隐私信息邮箱地址但有的听众朋友可能会想说如果你不让用户注册一个账户你怎么去

去存下来用户的订阅计划怎么知道这个用户是 standard 的还是 free 的用户包括他当前的 token 的余量是什么实际上确实是可以不用的我一开始也觉得说这个怎么搞呢后来研究了一下发现确实可以不用的因为对于 iOS 设备来说用户的 Apple ID 其实就是用户的一个账户然后因为你购买的所有东西都是通过 Apple ID 在 App Store 里面买

所以实际上苹果那边是有这个 Apple ID 和你的所有这个订阅关系的这个关系的 Apple Store 其实帮你管理了这个订阅关系虽然这个具体的 Apple ID 背后的邮箱是什么苹果是不会告诉你的但是它确实有这个订阅关系所以很多 App 确实是

不需要就是有一个服务端去存用户的这些订阅关系的然后比如说我们换了一个新手机很多人应该都体验过就我们换了一个新手机然后打开一个我们曾经付费过的 APP 会发现这个付费状态没有了然后这个时候呢这个 APP 一般会提供一个功能叫恢复购买然后你点一下它

它其实就会向 App Store 去请求这个用户的购买历史和订阅关系然后 App Store 会返回给他之后他就会重新存下来然后这时候你的订阅关系会员又重新就有了所以实际上是一个这样的逻辑

那这么做确实是可以不需要用户去注册的对吧那你可能会向适合人员解释说那你看我这个 APP 是有多端多设备数据同步的对吧我这个用户在 iOS 这边用了我在 web 上也要能看到这些数据啊用户不注册一个账号我怎么给他同步数据呢那这个事苹果的这个 review 的 guideline 里面也帮你想到了他会说你可以尽量推迟用户的注册时机对吧因为用户他不是一定会在多端多设备去用的

那只有他真的在多端多设备同时使用的时候你才提示他去注册那这样的话我就可以尽量推后对这个用户的这个隐私地信息的收集的时机然后用户也可以选择说我不要多端多统统我就可以不给你这个邮箱地址了是吧那这个怎么说呢听起来还挺有道理的但是实际上你真的要去开发实现的话就非常麻烦你要去做非常多的事情比如说你要先把他的这些数据在本地都存好然后他真的去

去注册了一个用户之后你再去一步的去把这些数据重新同步到云端什么的因为你要去做很多这种逻辑就在我看来简直他就是在刁难人所以非常头大对那这个时候如果你真的说傻乎乎的开始按照审核的意见去改

你就上当了因为实际上这个审核判断的空间是很大的因为你随便用几个 APP 你就会发现大量的 APP 都是上来就要求你注册登录不然你啥也干不了像我们的这个竞品 Snapped 就是这样的然后包括像小宇宙也是这样的你上来就得登录注册那你说我听个播客节目为什么一定要登录没有道理嘛对吧但是其实人家就是这么干的可见这个不是一个死标准所以你

完全可以尝试尝试什么呢说服他说服这个审核人员我当时也在网上找了找大家是怎么处理的因为很多人碰到这个问题这个审核理由然后有网友提到说一个 APP 正常背后都是同一个人在审所以你说我啥也不改然后我再提交一遍看看能不能碰运气碰到一个标准宽松一点的审核人员这不太现实的因为一定是同一个人在审你

但你也别想着说我去改个这个 APP 的这个 bundle ID 改个新的名字当成一个新 APP 去申请上架换个审核人员行不行

最好不要做这个事情因为 Apple 会做二进制比对它会发现你重复提交同样的 App 然后就可能给你的开发者账号封了然后你这个应用没上去 99 刀的这个开发者账号还丢了浪费 99 刀对所以最后我的策略就是向这个审核员去解释然后做了一些象征性的修改意思是我有在努力配合

然后最后还确实审核通过了但总结一下的话我感觉起作用的解释和修改是什么呢是解释是我向这个审核员说我们这个 APP 已经有 web 版有很多存量用户了那这些存量用户需要一个 APP 然后他们是一定需要登录才能得到完整的使用体验的因为他们在 web 里面也就很多存量数据了嘛

对吧然后包括我们已经有很多复分用户如果用户在多端发生重复订阅的情况其实对用户体验来说是非常糟糕的这个是解释的地方其实我觉得比较有用的在于说我强调我们已经存在一个 web 版然后存在很多存在用户了

然后修改的地方呢是主要把一些之前访问会直接跳转到登录的这个链接改造成了我会先展示一个功能说明然后引导用户去点击登录比如说跳转到这个用户的 library 的时候以前点下去它就直接跳了嘛那现在我会告诉他说这个是你的 library 如果你需要获取你的这种浏览历史之类的你就要去登录中间展示一下就比较柔和一点然后还有一个就是把内构的页面改为在未登录状态下也能完整展示

把订阅你能获得的这个 features 都列清楚之前这个页面也是需要登录才能看到的因为之前我的逻辑就很简单嘛你只有登录了你才能够去订阅所以我就会先要求用户登录才能看到这个内构的页面反正把这个东西改了之后大概来回改了有个三四次然后加上解释最后是审过了但是搞了有接近一个月的时间对

对我觉得你的解释还是挺合理的我觉得于情于理也都应该给你过对那接下来的功能上面就是在移动端我们未来的规划是什么其实我们做的中文的翻译很久了对其实中文翻译我们其实最近也要去接了对那在移动端上面未来会有什么别的规划吗移动端主要的 roadmap 肯定还是会跟着 web 走 web 上什么 app 就会上什么

毕竟我们是一个技术站嘛对吧前面折腾那么久就是为了这个事情对所以就像你说的比如说正在做的这个翻译功能那肯定是 Web 上了之后稍微稳定一点就会给它搞到 App 上这也是 App 比较麻烦的一个地方对吧你不能随意的更新版本然后还得考虑上前兼容的事情 Web 的话无所谓你随便更新包括不兼容也没关系反正你就给用户一个提示让他强刷一下就好了

还有一些是 APP 能做但是 web 做不了的优化可能会抽空搞一搞比如说我们现在这个 DAI 也就是说这个动态广告探测的能力 web 因为受限于这个浏览器跨域保护的问题现在探测效率其实不太高也不是特别稳定但是 APP 是有能力无视跨域问题的有机会优化一下但是这里面也会有很大的坑就是像我刚刚说的那个对吧它这个 audio 的这个获取的跨域处理什么的

因为你在 webview 里面反正就比较麻烦要去搞一下另外后续我觉得可以长期可以看的是说怎么和设备本身的能力去做进一步的集成比如说 Apple 的这个 AI 对吧 Apple Intelligence 这个有没有机会集成一下将设备端的这个 AI 能力对用起来去提供一些轻量的诸如问答之类的这个 future 可以不占用服务端的资源对吧这个我觉得也是一个挺好的思路对

对 我觉得你最后讲的这个 Apple Intelligence 这个确实是啊因为它苹果现在 OS16 等等未来的它其实都提供了类似这样的能力嘛那如果说我们能去调用它的 Apple Intelligence 就是用户的隐私还得到了保障还利用了它自己手机本身的能力我也我觉得这个逻辑还挺好的我觉得未来真的苹果自己的 iOS 的 App 里边应该会有很多人会用到这个里边的能力吧我猜对 是的

那最后可以再期待一下因为我们知道说现在有很多安卓的用户也在催就问我们说你们这个安卓版到底啥时候上线那既然我们已经是 Capacitor 做的封装技术站了是不是这个安卓的版本其实也会很快的到来对 这个本身没什么难度其实我们现在在安卓模拟器里面一直都是跑得好好的之前最大的问题是我没有安卓设备所以我就没办法去调试像 Play Store 的订阅之类的

然后可能有一些真机上的体验也不太确定是怎么样的所以就一直没放前段时间我买了一台二手的 Pixel 8 所以这个问题就算是解决了那把手头的事情弄得完我就会去着手把这个 Google Play Store 的适配和调试做了然后

应该就可以去上架了但是这中间肯定还会有很多问题是我们因为就像我们去上 Apple 的 App Store 一样我们也是第一次去上 Google 的 Play Store 不知道这里面会有什么问题等着我们去体验啊到时候可能也会需要搞一搞对

对反正到时候如果再有任何问题的话我们再开一期博客然后再跟大家来分享毕竟我们是养成系博客对毕竟我们是养成系博客可以跟大家持续不断的去更新我们自己碰到的问题等等之类的对彩坑日记对好的

好的那我们今天的分享就先到这里吧如果大家对于我们产品上架还有别的任何疑问的话也欢迎大家在下方留言跟我们讨论最后也非常欢迎大家来 App Store 然后下载并体验我们的产品 PodOS 如果能再给个推荐语跟五星好评那就更好了再次感谢大家那我们本期节目就先到这里吧我们下期再见拜拜好拜拜

以上就是我们本期播客的全部内容感谢大家收听也欢迎大家踊跃留言如果你喜欢我们欢迎点赞并分享给感兴趣的朋友如果你在用苹果播客收听也希望你花几秒钟给我们一个好评这会让更多的人了解到我们要是能再点击一下订阅那就再好不过了我们下周见