Google Play 开始运行你的私人 Vibe-coded 应用,不需要开发者账号

·11 分钟阅读·Evergreen Tools Team

Google 在 2026 年 10 月 13 日的 Play 更新里有一句话,比其余内容都重要:你可以用 AI Studio 做一个自定义 Android 应用,然后用普通 Google 账号、不需要开发者账号,通过 Google Play 把它装到自己的设备上。私人应用保持私有、与公开目录隔离;先在包括美国在内的部分市场上线,面向 18 岁以上用户;「分享给亲友」会在未来几个月推出;将来要公开给所有人用,则转为专业开发者账号,届时应用要过和其他开发者一样的信任与安全审核和质量标准。它读起来像个消费者功能。但对写软件的人来说,这是一个没有审核闸门的新分发层——这正是值得认真想一想的地方。

手持 Android 手机,屏幕上显示应用图标

私人应用不进公开目录,于是「谁来评审」的答案变成了:你自己。

这个「私人层」到底拿掉了什么

公开上架一个应用,会附带审核流程、数据安全声明、开发者身份和一堆政策义务。私人应用这条路把大部分脚手架都拿掉了,而这正是重点:摩擦才是大多数人从没把自己想要的小工具做出来的原因。这个交换很直接,值得说清楚:你换到速度和隐私,交出的是那个曾经帮你抓到明显错误的外部评审者。

那位评审者从来不是你的安全体系,但它是一道兜底。它最常抓到的不是恶意软件,而是权限申请过多和数据处理随意——而这恰好是生成式应用最容易引入的一类问题,因为权限清单没有经过人手写。

所以第一个有用的重构是:私人层并没有取消工作,它只是把工作挪了位置。以前商店替你查的东西,现在归你,而且归你的时刻,恰恰是你最不想做这件事的时刻——应用已经能在你手机上跑了。

# A personal app still needs a real build. Keep it reproducible, or you will be
# the only person who can ever rebuild it, including future you.

./gradlew :app:assembleRelease \
  -PversionCode=7 \
  -PversionName=1.4.0 \
  --no-daemon

# Sign with a keystore you have backed up OUTSIDE the device that runs the app.
# Losing the key means you cannot ship an update that keeps app data.
keytool -genkeypair -v \
  -keystore ~/keys/personal-app.jks \
  -alias personal \
  -keyalg RSA -keysize 4096 -validity 10000 \
  -storetype PKCS12

# Verify the artifact before you install it anywhere:
apksigner verify --print-certs app/build/outputs/apk/release/app-release.apk

# Rule: the signed APK plus the keystore plus the version tag are the release.
# If any of the three lives only on one phone, you do not have a release.

构建必须可复现,否则它不是应用,是一个artifact

生成式应用有一个特定的失败模式:唯一能跑的构建只存在于那台设备上,keystore 建过一次就没备份,产生代码的提示词躺在一个早就滚过去的聊天窗口里。六周后系统更新弄坏了什么,你没法重建同一个应用去修它。

最低标准其实很小:项目进版本控制、发布包由脚本产出、keystore 存在运行它的手机之外、归档产物里带上 versionCode 和 versionName。这不是企业流程,这是「你能维护的应用」和「你不敢碰的二进制」之间的差别。

签名值得单独说一句,因为它是不可逆的那部分。签名密钥丢了,你就无法发布一个保留原有数据的更新;你只能发一个新应用,用户从头开始。对有你真正在乎的数据的私人应用,把密钥备份到设备之外。

# The most common way a personal app leaks is a key pasted into source. Keep
# secrets out of the repo, inject at build time, and fail the build when one slips.

# local.properties (never committed)
#   AI_API_KEY=...
#   MAPS_KEY=...

# app/build.gradle.kts
android {
    buildFeatures { buildConfig = true }
    defaultConfig {
        val props = java.util.Properties().apply {
            val f = rootProject.file("local.properties")
            if (f.exists()) f.inputStream().use { load(it) }
        }
        buildConfigField("String", "AI_API_KEY",
            "\"" + (props.getProperty("AI_API_KEY") ?: "") + "\"")
    }
}

# CI guard: refuse to build if a key-shaped string is committed
! git grep -nE '(sk-[A-Za-z0-9]{20,}|AIza[0-9A-Za-z_-]{35})' -- '*.kt' '*.java' '*.xml' \
  || { echo "secret in source"; exit 1; }

# This is not paranoia. A personal app is still an app other people can pull
# apart with apktool, and a leaked key is a bill with your name on it.

密钥是那种真的会花钱的失误

调用模型或地图服务的 vibe-coded 应用需要凭据,而阻力最小的做法就是把它粘进源码。在 APK 没离开你手里之前都没事——而公告已经明确预告了「未来几个月分享给亲友」,也就是说 APK 会离开你手里。

APK 不是不透明的。任何人解压就能读字符串、反编译字节码,几分钟就能把你的密钥捞出来。缓解办法不是混淆,而是不要把密钥发出去:构建时从未被跟踪的 properties 文件注入;需要特权调用时,把密钥留在你自己控制的服务器上;再加一条 CI grep,源码里出现密钥形态的字符串就拒绝构建。

最后这条只要十行,却能在它变成账单之前抓住错误。如果这篇文章只能带走一件事,就带走它——因为这是唯一一个以发票而不是 bug 报告形式出现的失误。

#!/usr/bin/env bash
# Small tools rot silently. Record what you shipped, where it came from, and what
# it can reach — a 20-line manifest beats remembering in three months.

set -euo pipefail
OUT="releases/$(date +%Y-%m-%d)"
mkdir -p "$OUT"

{
  echo "commit: $(git rev-parse --short HEAD)"
  echo "built:  $(date -Iseconds)"
  echo "version: $(grep -m1 versionName app/build.gradle.kts | cut -d'"' -f2)"
  echo "prompt-notes:"
  sed -n '1,20p' prompts/feature-notes.md 2>/dev/null || echo "  (none recorded)"
} > "$OUT/manifest.txt"

# What does this app actually touch on the phone?
aapt dump permissions app/build/outputs/apk/release/app-release.apk \
  > "$OUT/permissions.txt" 2>/dev/null || echo "aapt missing" > "$OUT/permissions.txt"

cp app/build/outputs/apk/release/app-release.apk "$OUT/"
echo "release recorded in $OUT"
# Re-run this every time you regenerate the app. Generated code changes fast.
显示器上一行行源代码

生成的代码最终仍然编译成一个人人可反编译的 APK。

审一下生成的应用到底能碰到什么

生成的代码继承了模型认为合理的权限,而模型对权限一向很大方。一个记事本应用申请通讯录和位置,不是恶意,只是没人看过。在一部同时装着邮箱、日历和银行应用的手机上,「没人看过」就是错误的默认值。

三个检查能覆盖大部分风险,而且都是 shell 命令而不是流程。导出权限清单,凡是不能用一句话解释的都删掉。确认没开明文流量,因为不做 TLS 的应用在公共网络上什么都没有。再看备份规则,因为一个缓存了 token、备份设置又是默认的私人应用,会把那个 token 导出到备份目标去。

每次发布都把权限清单归档。它给你版本之间的 diff,而 diff 才能把「这应用怎么突然能访问我照片了」变成一次可以回滚的提交。

# Before installing a generated app on the phone that holds your mail, calendar and
# banking apps, check three things. All three are cheap and all three are skipped.

# 1. Permissions the app requests vs permissions the feature needs
aapt dump permissions app-release.apk | sed 's/^/  /'

# 2. Cleartext traffic: an app that talks HTTP has nothing to protect it on Wi-Fi
grep -r "usesCleartextTraffic" app/src/main/AndroidManifest.xml || echo "cleartext: not set"

# 3. Backup rules: does app data (including any cached tokens) leave the device?
grep -A5 "dataExtractionRules\|fullBackupContent" app/src/main/AndroidManifest.xml \
  || echo "backup rules: default"

# Default is not a decision. For a personal app holding a credential, the answer
# should be: no cleartext, explicit backup rules, and permission list you can
# explain item by item. If you cannot explain a permission, remove it and rebuild.

「毕业」到公开,是另一个产品

Google 的公告写得很清楚:公开意味着转到专业开发者账号,届时应用要过平台上每个开发者都要过的信任与安全审核和质量标准。这条边界是合理的,也是一个好时机去承认:你为自己做的应用,不是陌生人会用的应用。

具体来说,四件事同时变:身份、政策、数据处理和支持。包名事实上变成永久标识,因为之后再改会丢掉安装量和数据。数据安全声明必须与应用真实行为一致,也就是说你得真的知道。每个权限都需要一句你能说出口的理由。而且出问题时要有人能被找到——这是承诺,不是勾选框。

下面这份清单,是我会在开始走这条路之前跑的,而不是在提交审核请求之后。它同时也是「让私人层保持私人」的一个不错的论据:当你把公开分发的要求写下来,私人应用的范围往往会缩回到你真正需要的那个大小。

#!/usr/bin/env bash
# The graduation path. Google's post says that if you want to share an app with the
# world you move to a professional developer account, and the app then goes through
# the same Trust & Safety reviews and quality standards as any other developer.
# Prepare for that transition before you need it.

set -euo pipefail
cat <<'EOF'
[ ] package name is final (changing it later loses installs and data)
[ ] signing key backed up off-device, with a second copy in a password manager
[ ] versionCode increases monotonically; versionName is human-readable
[ ] privacy policy drafted: what data the app stores, where, and for how long
[ ] every permission has a one-line justification you could say out loud
[ ] targetSdk current; no deprecated APIs flagged by lint
[ ] data safety form answers match what the app actually does
[ ] crash reporting + a way to reach users, before strangers install it
[ ] account for review time in the launch plan, not after
EOF

# A private app that becomes public is a different product, not a bigger version of
# the same one. The checklist is where that difference gets acknowledged.
开着代码编辑器与终端的工作站

可复现的构建加上备份好的签名密钥,就是「玩具」和「工具」的全部差别。

📌 常见问题 FAQ

这需要开发者账号吗?

不需要。Google 说你可以用 Google AI Studio 做自定义 Android 应用,并用普通 Google 账号通过 Google Play 装到自己的设备上,不需要开发者账号。只有当你之后想公开分发时,才需要专业开发者账号。

现在谁能用?

按 Google 的公告,先在包括美国在内的部分市场推出,面向 18 岁以上用户。其他市场没有被描述为同步开放,请以你所在地区 Play 商店里的实际状态为准。

私人应用会出现在公开商店里吗?

Google 说明私人应用保持私有、安全,并与公开商店目录隔离。公司同时表示「未来几个月」会支持分享给亲友,所以这条隐私边界预期是略微放宽,而不是消失。

以后想公开上架怎么办?

Google 说 Play 会帮你「毕业」到专业开发者账号,届时应用要过与其他开发者相同的信任与安全审核和质量标准。请把它当成一套新的发布流程,而不是一个开关,并预期身份、政策和数据处理方面的要求都会生效。

在 vibe-coded 应用里放 API 密钥安全吗?

不安全。APK 可以被解包、字符串可以被读取,所以编译进应用的密钥,在应用离开你设备的那一刻就应视为公开。构建时从未跟踪的文件注入密钥,把特权调用放到你自己控制的服务器后面,并加一条 CI 检查:源码里出现密钥形态字符串就让构建失败。