Skip to main content

游牧周记第37期

· 11 min read
Suhe
This site owner

美剧

安道尔2

第一季就很好看,个人觉得是星战宇宙中超过曼达洛人的存在,其实也就这2部我看得下去。 这一季开局一般,到了后半截开始起飞,非常有后劲。

异形.地球

看了2集,蛮好的。 太空船和外星生物这次没有掉到纽约或西方主流大城市,轮到泰国了(新暹罗,应该指曼谷吧)。

星期三2

这调调还在。 说实话前段时间看了些演技极差的烂片后,发现这部片子不管怎么扯,所有演员的演技在线。

听小机 Listen Bot

没错,这就是我花了1周开发上架的App。 我的app网站 8月13日凌晨终于审核完成。 主体开发就2天,然后第三天进入IOS发布审核。 play市场1天完成。 appStore审核了4天,所以总计7天。

一周上架一个可以赚钱的app?

  1. idea酝酿时间不能算在内,其中最主要的不是核心功能思路,而是落实有没有成熟的同类产品。
  2. 从动手写第一个代码开始算起,这时候遇到第一个问题,包名怎么取?虽然是个英文名,甚至是简写而已,但影响到写代码过程中的思路和体验,最好基本确定,不要coding过程中一直想改,影响心情。
  3. 名称用了4个钟头才定下来,其中90%都是在开启上网功能的ChatGpt上查重和想点子,最后出门溜达一圈自己想出了一个,回家用AI落实没啥太成熟的同行应用,还被夸了一道,就定了。中英文一起。
  4. 这是一个和语音识别有关的应用,AI从我描述的核心功能出发,设计了技术栈总结,结果发现ChatGPT建议的好多是第三方包和服务,反而是国产Kimi推荐了一个靠设备自身识别功能的,非常令人兴奋。
  5. 这时已经是晚上,用新的包名在macbook上建了一个expo最新版(sdk都54+了),就累不动睡了。
  6. 第二天坐公交去五华区图书馆,从10点干到13点,终于把核心的语音识别功能调试成功,高高兴兴回家去,准备开着大屏幕接着写。
  7. 然后就是轻车熟路的AI LLM服务接入,唯一问题是什么时候切入,发现是个非常细节的问题,调试到自己一头雾水的时候,已经凌晨了,还是睡了。
  8. 已经算第三天了,想着继续降低一点体验感要求,就图个能尽快提交市场。首先简化了AI介入为手动,然后UI部分完全套用之前用熟了的自创useStyle框架(各位看我教程都明白),快速搞了个基本能用的版本。
  9. 这时候想到必须今晚提交,那还得有logo(icon)啊,开启免费版ChatGPT,说了想法,结果生成一个还不错的小人,就是手有点怪,让他改,改更怪了,运气好在5张的今日免费额度用完前搞定了。
  10. 基本文案也用AI弄了,当然自己加工时间也不短,差不多耗了2个小时。中英日文版,没错,及时如此紧张的时间,我还是用了多语言。先写简体中文的json,然后在IDE中AI生成其他版本。顺便说一句,这次IDE用回了VSCode,Cursor把人整郁闷了这次放弃。总之AI没有花一分钱。
  11. 然后截图,准备上线。这时候才发现问题来了,Eas网络抽风,死活都没法在线打包,本地也卡得要死,有时试上十多次才能进入正常运行环节,等到地老天荒才能打成一个包。这个过程中也没闲着继续调试App功能,不断发现bug和可以优化的地方,同时请AI检查逻辑错误。就这么边调试边打包,都第n个build了,发现天已经黑了。
  12. 说明一下,现在还没试过任何android的命令,不是说要完全放弃安卓,而是以苹果为目标,抓住快速变现人群才是关键,iOS版上线成功,才有做其他市场的心情。
  13. 这天真累啊,RevenueCat的配置也快速搞定了,虽然只是iOS,这可是我最关心的功能,虽然做了无数次,还是有点担心它抽风。事实证明还好,集成得很快。
  14. App store上架资料准备期间,国内ICP备案的申请也在进行,这时候发现已经是周五凌晨,我理论上已经到第4天了。3天完成的计划被打破。ICP备案如果不加入安卓,以后要补充可能麻烦,于是在基本没调试过android版的情况下,先打包apk,这个漫长的调试啊,整完已经3点am了。累死,睡了。
  15. 第4天,基本都在折腾打包和上架提交,这期间解锁了GitHub Action对接Eas的新技能,打包效率大幅提升,直到Eas鸡贼的免费额度用完,不过iOS版也基本可用了,终于提交了AppStore,发现第一次提交不需要ICP备案也没问题,及时后面出了问题只影响国内市场发布,等等也无所谓。秉承来都来了的原则,把Google Play市场的资料也整了。第一次运行了android版,算是意外的顺利,这次开发过程中比较幸运的一件事,没花多少时间修改安卓UI就ok了。看来安卓要先上线,唯一的问题是我考虑安卓打包签名用本地文件,不想依赖云服务,于是也只能本地打包,那个速度不比eas的ios本地打包快多少。过程中不断发现bug和优化点,打了n个包以后提交测试,然后推进正式版,居然实现了android先上线。这时候又到子夜了,今天结束。
  16. 第5天周末,发现iOS还在待审核状态,ICP备案阿里云方面的工作和工信部那边完成了,管局还没开工,估计要等周一了。今天状态稍微放松点了,不断测试调试,iOS等审核不敢发新版,android连续提交2个版本,包括RevenueCat的集成,Google这边挺折腾的。今晚不用熬夜了,下午同学通知聚会吃菌子,然后就骑单车出门了,算是锻炼一把。
  17. 截至目前iOS还在待审核状态,我个人的经验证明3天上架不太可能,除非只是Google Play,加上iOS的话4-5天算是极限了。至于国内市场,本人可不敢想,作为个人开发者基本放弃了。整个过程中代码时间大约只占一半,Eas打包意外的烦人,大约浪费了我1/4的时间,还有1/4的时间是文案、图片和国内ICP备案等琐事,包括想名字等。

下次看是否出一个审核过程的要点说明。

Expo开发

一个新app从开发到上架,再次归纳

  1. ideas
  2. AI确认名称和技术栈
  3. coding和测试,包括GitHub的代码管理
  4. 集成RevenueCat,如果有其他第三方服务包括广告等,继续
  5. 真机测试,先集中力量搞iOS,毕竟是付费主力
  6. Eas打包测试,配置GitHub Actions触发打包,这一步也可以更靠前到3
  7. AppStore id和证书的申请
  8. AppStore新建App,AI辅助完善多语言文字、icon,搞点截图(注意大小,还有iPad13寸版本)
  9. 这时候如果有国内市场,就要考虑ICP认证了,这件事涉及到Android最好一起做
  10. 不管Android版本测试与否,先打包apk,为了ICP
  11. 阿里云去申请ICP备案,前面一些工作是为了提取信息
  12. 备案要几天,这时候继续提交AppStore,先testFlight,但也不要太细,差不多就提交
  13. 测试Android,差不多了就打包提交GooglePlay,先申请,截图和文字可以先用iOS的
  14. 第一次aab打包,之前建立新的keystore文件签名(下方有详细介绍)
  15. 提交GooglePlay,也是测试一下,发布正式版

新android项目的本地签名

云端的选择有两个,在GooglePlay或Eas服务中设置。

不想依赖云服务,所以最终选择了自己建立keystore文件。 这里发现以前项目的keystore不能复用,不然GooglePlay不批准,也就是说一个app要对应一个不同的签名。

macOs上这样做:

# 确认安装了keytool
keytool -version

# 如果没有,安装java,没错,这玩意是java自带的
brew install openjdk

然后生成keystore文件:

keytool -genkeypair \
-v \
-storetype JKS \
-keystore my-release-key.keystore \
-alias my-key-alias \
-keyalg RSA \
-keysize 2048 \
-validity 10000

参数含义
-keystorekeystore 文件名(会生成在当前目录)
-alias你给密钥取的别名(之后构建要用)
-keyalg加密算法(Android 推荐 RSA)
-keysize密钥长度(2048 够用)
-validity有效期(单位天,10000 天≈27 年)
执行上面命令后,会提示你输入:
  • keystore 密码(必须记住)
  • 姓名、组织、城市、省份、国家代码
  • key 密码(建议和 keystore 密码相同,方便记忆)

生成后可以验证一下:

keytool -list -v -keystore my-release-key.keystore

会提示输入密码,然后显示:

  • SHA1 / SHA256 证书指纹
  • 证书有效期

比较容易犯的错误之一是把alias搞错了,可以这样找回:

keytool -list -v -keystore path/to/my-release-key.keystore

然后你的expo项目中eas.json:

 
{
"build": {
"apk": {
"android": {
"buildType": "apk"
},
"credentialsSource": "local"
}
}
}

local就是指本地的加密配置文件: 建立 credentials.json(不要传到 Git,前面的key store文件也是)

{
"android": {
"keystore": {
"keystorePath": "./my-release-key.keystore",
"keystorePassword": "你的_keystore_密码",
"keyAlias": "my-key-alias",
"keyPassword": "你的_key_密码"
}
}
}

最后打包:

eas build --platform android --profile apk

tailwindcss v4+的theme怎么搞?

查遍全网,只有这个靠谱!AI全部懵了

tailwindcss中global.css的三个层次概念

我遇到的问题:

@layer base {
a {
text-decoration: none;
}
}

这段代码无效,但把内容从@layer base中提到最外层,就ok了。

AI解读原因:

Tailwind CSS 在编译时会@layer base 里的样式权重降到低于 base 层之外的普通 CSS,而浏览器对 <a> 的 UA 样式(text-decoration: underline)又属于「user-agent stylesheet」,权重很低,所以放在最外层能覆盖,放进 @layer base 反而被 UA 样式顶掉。

这里涉及一个Tailwind 的三层概念。 ──────────────

  1. base
    浏览器 UA 样式 + 你的 @layer base {} 代码 → 权重最低(0-0-0)。
    典型用途:重置 <a><h1> 等标签默认样式。

  2. components
    @layer components {} → 权重 0-0-1。
    典型用途:你写的 .btn.card 等工具类。

  3. utilities
    .text-red-500 等原子类 → 权重 0-1-0,足够高,不会被 base/components 顶掉

──────────────

为什么放在 @layer base 里有时“无效”?

• 浏览器 UA 对 <a>text-decoration: underline 权重也是 0-0-0,
但「后出现的规则」会覆盖「先出现的规则」。
• Tailwind 把 base 层放在 最前面,所以
base → UA → 你的最外层 CSS,最终 UA 样式反而在最后生效。
• 因此需要:

  • 把样式写在 Tailwind 之后(最外层),或

  • !important / :where() 提升/降低权重。

什么时候该用 @layer base

• 想整理所有「全局标签重置」到一处,而不是散落各处。
• 不介意权重 0-0-0,或愿意配合 !important / :where()
• 方便 Tailwind 在 PurgeCSS 时知道「这段代码属于 base 层,不要误删」。

简记
@layer base ≠ 高权重,只是一个「分组 + 排序」指令。

那最初的问题这样做,定义就生效了:

@layer base {
a {
text-decoration: none !important;
}
}