🔑 Google Cloud & Play Console · Setup for Jeff
The remaining configuration, all of it inside Google's consoles. Finish this and the Android pipeline is working end to end — built, signed, uploaded, installed, and signing in. Every step has a verification you can actually run.

First, your question — what is actually verified?

You asked how we can fully test the pipeline when the consoles are not configured. Fair challenge. Here is the precise answer.

Half of the pipelineStateWhy
Build — source to a signed, correctly-versioned packageVERIFIEDRan end to end today from a clean checkout. 5 minutes, 8 of 8 gates, signature and versionCode read back out of the artifacts. This half is genuinely finished and needs nothing from Google.
Deliver — package to a tester's phone, and signing in on itBLOCKED ON YOUNobody can verify this yet, including me. It cannot be faked or simulated — it requires a real Play app and a real OAuth client, both of which need your Google account.
So the honest summary is: the half that was ours is done and proven. The half that needs your account has not been tested by anyone, and this guide is how it gets tested. When you finish it, run the end-to-end test at the bottom — that is the moment the whole pipeline is proven, not before.
One thing you can do today with zero Google setup: a signed APK already exists from this morning's verification build — ~/.hoop/wt-android-verify/app/build/app/outputs/flutter-apk/app-release.apk, versionCode 1, signed with our real upload key. Copy it to an Android phone and install it. Everything works except Google sign-in. That confirms the built package is genuinely good before you spend time in the consoles.

What you are setting up, in order

PartWhereWhat it unblocks
AGoogle Cloud ConsoleGoogle sign-in working on Android
BPlay ConsoleGetting the app to testers
CBothUploads without a human — optional, do it last
DA phoneProving all of it actually works

A and B are independent — either order. C must come after B (the service account is granted access to an app that has to exist first). One step inside A can only be done after B; it is flagged where it appears.

AGoogle Cloud Console — make Google sign-in work

Android sign-in fails today with ApiException: 10 (DEVELOPER_ERROR). Google identifies an Android app by the pair package name + signing certificate SHA-1, and that pair has never been registered. There is no code to change — the app's sign-in code already works on Android.

A1 · Get into the right project

Go to console.cloud.google.com and select project number 584364169898.

Verify you are in the right place: go to APIs & Services → Credentials. You should already see two OAuth 2.0 client IDs — one iOS, one Web. If you do not see them, you are in the wrong project. This matters because a wrong-but-plausible project produces the identical error you are trying to fix.

For reference, the Web client already there is 584364169898-mhmfq7c5…. Our backend validates every Google login against that exact ID, so the Android client must live in the same project.

A2 · OAuth consent screen

It should already be configured — you cannot create OAuth clients without it, and two already exist. Check APIs & Services → OAuth consent screen.

If it says Publishing status: Testing, only accounts on its test-user list can sign in, capped at 100. That is fine for internal testing, but add every tester's Google account to that list or their sign-in will fail for a reason that looks nothing like the real cause. If it says In production, anyone can sign in and there is nothing to do.

A3 · Create the Android OAuth client

APIs & Services → Credentials → + Create Credentials → OAuth client ID → Android.

FieldValue — copy exactly
NameHOOP Android (upload key) — internal label, anything works
Package namecom.hooptech.hoop
SHA-17A:03:8F:8C:9A:FA:D9:26:A5:62:CD:B9:3E:77:29:E2:25:E7:91:CA

Click Create. Nothing needs copying back — no client ID goes into our code. Android finds it by package and fingerprint.

A4 · You will need up to three of these, one per signing key

This is the part that catches people. Re-signing an app changes its SHA-1, so as far as Google is concerned each differently-signed build is a different app.

KeyWhen to add itSHA-1
Upload keyNow (A3 above)7A:03:8F:8C:9A:FA:D9:26:A5:62:CD:B9:3E:77:29:E2:25:E7:91:CA
Covers every package our build produces and installs directly.
Debug keyOnly if testing debug builds89:9C:99:50:3C:2A:D1:77:63:82:11:37:FB:9A:C3:2C:FD:7F:D0:9A
This Mac's debug key. Machine-specific.
Play signing keyAfter part BDoes not exist yet — Google generates it when you enable Play App Signing. Get it from Play Console → Test and release → Setup → App signing, then repeat A3 with that fingerprint.
Miss the third one and you get the most confusing bug in this whole project: sign-in works perfectly when you install the APK yourself, and fails for every single tester who installs from Play. Same code, same version — Play stripped our signature and re-signed with its own key, so the fingerprint Google sees is different. Do A4 again immediately after your first upload.

✅ Verifying part A

There is no "configured" indicator in the console. The only real test is signing in on a phone, with the log open:

~/Library/Android/sdk/platform-tools/adb logcat | grep google_signin
What you seeMeans
Sign-in completes, nothing loggedWorking.
code=sign_in_failed + a DEVELOPER_ERROR linePair still unregistered — wrong project, typo in the fingerprint, or the installed build was signed with a different key than the one you registered.
登录成功但 idToken 为空Different problem, not the Android client. Tell me if you see this.

Allow a few minutes after creating the client, and force-stop the app before retrying.

BPlay Console — get the app to testers

B1 · Create the app

play.google.com/consoleCreate app. Name (what users see in the store), default language, App not Game, and Free.

Free → Paid cannot be changed after publishing. Free is almost certainly right since HOOP monetises inside the app, but make it a decision rather than a default.

B2 · Play App Signing — the one permanent choice

Turn it ON. You are offered this once, during your first upload, and it can never be changed.

With it on there are two keys: yours (the upload key in ~/.hoop-keys/) and Google's (the app signing key, which they hold). You sign, Google verifies, strips your signature and re-signs with theirs.

Why it matters: if the upload key is ever lost or leaked, you can register a replacement and keep shipping. Without it, losing that one file permanently ends the app — Android only accepts updates signed with the original key, there is no appeal, and the only path forward is a new package name with all installs and ratings abandoned.

The cost is that Google holds a key you cannot export. Against permanently losing the app, that is not a close call.

B3 · The declarations Play requires

Under Policy → App content. Internal testing does not require these — you can get a build to testers first. They are required before any public track, and some take review time, so start them early.

ItemNotes
Privacy policy URLReady to paste: https://hoopcomm.com/privacy — confirmed returning HTTP 200 today.
Data safetyWhat the app collects and why. HOOP collects account identifiers, contacts (invite feature), photos and camera, and messages. Answer accurately — it is cross-checked against actual app behaviour and inaccuracy gets apps removed.
Content ratingQuestionnaire; the rating is issued from your answers. Social features and user-generated content are the material part.
Target audienceIncluding children triggers a large extra policy surface. Decide deliberately.
AdsThe app does contain ad code (play-services-ads is a dependency). Declare it.
Store listingDescriptions, icon 512×512, feature graphic 1024×500, ≥2 phone screenshots. Screenshots can come from a sideloaded build.

B4 · Upload to internal testing

Test and release → Testing → Internal testing → Create new release.

Upload the .aab. One already exists from this morning's build:

~/.hoop/wt-android-verify/app/build/app/outputs/bundle/release/app-release.aab
# versionCode 1, signed with our upload key, 531M

Or have NOVA cut a fresh one — either works, the pipeline is the same.

When it finishes processing, write down the download size Play reports. That is the authoritative answer to the size question, and it is a number nobody can compute outside Play — it is calculated after splitting the bundle by CPU, screen density and language. Our file is 531 MB on disk and Play's base-module limit is 500 MB of download size, so the two are not directly comparable. This step settles it.

Then release notes → Save → Review release → Start rollout to Internal testing.

B5 · Add testers

Testers tab → create an email list → add each tester's Google account address (up to 100) → copy the opt-in link Play generates.

Each tester must open that link while signed into the exact account you listed. Signed into a different account they see nothing at all and will report that it is broken. This is the single most common confusion on this track.

B6 · Go back and finish part A

Now that Play App Signing is on, Google has generated its own key. Get its SHA-1 from Test and release → Setup → App signing and repeat A3 with it. Sign-in will fail for everyone installing from Play until you do.

✅ Verifying part B

  • The release shows as Available to internal testers, not stuck in review or draft.
  • Play's App signing page shows both an app signing certificate and an upload certificate — the upload one must match our SHA-1 7A:03:…:91:CA. If it does not, the package was signed with the wrong key.
  • A tester on the list can find and install the app from Play.

CService account — uploads without a human

Optional, and do it last. Nothing above depends on it. It lets the build pipeline push to Play automatically instead of someone dragging a file into a browser.

C1 · Enable the API

Cloud Console, project 584364169898APIs & Services → Library → find Google Play Android Developer APIEnable.

C2 · Create the service account and its key

IAM & Admin → Service Accounts → Create service account. Name it something obvious like hoop-play-publisher. No project roles are needed — the permissions that matter are granted in Play, not here.

Then open it → Keys → Add key → Create new key → JSON. It downloads once.

That JSON file can publish releases as you. Treat it exactly like the keystore:
mv ~/Downloads/<whatever>.json ~/.hoop-keys/play-service-account.json
chmod 600 ~/.hoop-keys/play-service-account.json
Never in the repository, never pasted into chat, never emailed.

C3 · Grant it access in Play

Play Console → Users and permissions → Invite new users → paste the service account's email (it looks like hoop-play-publisher@<project>.iam.gserviceaccount.com, and is the client_email field inside the JSON) → grant release permissions for this app → Invite user.

This is the step most often missed. The credential will authenticate perfectly and then be refused, because authentication and authorisation are different things and only the second one happens here.

✅ Verifying part C — an actual command, not an inspection

Nothing in either console tells you the three pieces fit together. This does:

cd <a checkout of the repo>
python3 tools/tf-build/verify_play_credentials.py \
  ~/.hoop-keys/play-service-account.json com.hooptech.hoop

It uses the credential to open a Play "edit" and then abandons it — the only action that proves genuine release permission, and it changes nothing (an uncommitted edit simply expires). Read-only calls cannot prove this, because read access does not imply publish access.

ResultMeaning
✅ 200All three pieces are correct. You are done.
🛑 401The credential itself was rejected — wrong project, revoked, or expired key.
🛑 403Valid credential, no permission. Either C1 or C3 is missing.
🛑 404No such app on Play. Part B is not done.
Disclosure about this script: its failure paths are tested — missing file, malformed JSON, an OAuth-client JSON given instead of a service-account one, missing arguments. The success path is not, because there is no service account yet to test it with. The first time you run it against a real credential, you are also testing the script. Tell me what it prints either way.

DThe end-to-end test — this is the moment it is proven

Do these in order. Each step depends on the one before, so the first failure tells you exactly which part is wrong.

#DoPass looks like
1Have NOVA build, or reuse this morning's AABLog ends ✅ versionCode N,真钥匙签的
2Upload it to internal testing (B4)Play accepts it and reports a download size
3Check the upload certificate (B, verify)Play shows upload SHA-1 = 7A:03:…:91:CA
4Register the Play signing SHA-1 (B6 → A3)A third Android OAuth client exists
5A tester opts in and installs from PlayApp appears in Play for them and installs
6Open it and sign in with GoogleSign-in succeeds; nothing in adb logcat | grep google_signin
7Use the app — send a message, open a gameNormal behaviour, same as iOS
When step 6 passes, the pipeline is proven end to end — source, build, signing, Play distribution, installation and authentication. That is the claim you have been asking for, and it cannot honestly be made before then.

Step 5 or 6 failing is expected the first time if part A's third fingerprint was skipped. That is the single most likely failure, and A4 is the fix.

Checklist

Done whenCheck
A1In project 584364169898iOS and Web OAuth clients visible
A2Consent screen configuredIf "Testing", every tester is on the test-user list
A3Android client for the upload keySign-in works on a sideloaded build
B1App createdAppears in Play Console
B2Play App Signing ONApp signing page lists two certificates
B4AAB uploadedRelease is live on internal testing; size noted
B5Testers addedA tester can install from Play
B6Android client for the Play signing keySign-in works on a Play-installed build
C1-C3Service account (optional)verify_play_credentials.py prints ✅
DEnd-to-endStep 6 passes

What I verified, and what I did not

Verified on this machine today: both fingerprints, read out of the keystores with keytool. The package name and the Web client ID, cross-checked between build.gradle.kts, google_signin.dart and the backend config. The privacy URL returning 200. The signed AAB and APK referenced here — they exist, at those paths, with those sizes. The failure paths of the verification script.

Not verified — instructions, not observations: every console screen in parts A, B and C. I have no access to either console, so menu names and layouts come from Google's documentation and may have moved. The values to enter are verified from our own code and keys; the clicks are not. Also unverified: the success path of the credential script, whether Play accepts our size, and whether sign-in works once the client exists — that is exactly what part D is for.

If a console screen does not match what is written here, the guide is wrong, not you. Tell me what you actually see and I will correct it.

Companion: the build pipeline (verified working) · the original wireframe.

先回答你那个问题:到底哪一半验过了?

你问:两个控制台都还没配,凭什么说流水线验过了。这个问题问得对,答案是这样的。

流水线的哪一半状态凭什么
出包 —— 从源码到一个签好名、版本号正确的包已验证今天在干净检出上端到端真跑过:5 分钟、八道闸全过、签名和版本号都是从产物里反读的。这一半是真做完了,而且完全不需要 Google。
送达 —— 从包到测试者手机上,并且能登录卡在你这儿现在谁都验不了,包括我。 这件事没法模拟、没法造假 —— 它需要一个真的 Play 应用和一个真的 OAuth 客户端,两样都要你的 Google 账号。
所以老实的说法是:属于我们那一半做完了而且有证据;需要你账号那一半至今没有任何人测过,而这份指南就是去把它测出来的。你配完之后跑一遍最后那个端到端测试 —— 到那一刻整条流水线才算被证明,在那之前都不算。
有一件今天就能做、完全不碰 Google 的事:今早那次验证出的签名包还在 —— ~/.hoop/wt-android-verify/app/build/app/outputs/flutter-apk/app-release.apk,版本号 1,用我们的真上传密钥签的。拷到安卓手机上装起来,除了 Google 登录之外一切都能用。先这么确认包本身是好的,再去花时间配控制台。

你要配的东西,按顺序

部分在哪儿配配完解开什么
AGoogle Cloud Console安卓上的 Google 登录
BPlay Console把包送到测试者手里
C两边都要不用人手也能上传 —— 可选,放最后
D一台手机证明上面这些真的成了

A 和 B 互相独立,先做哪个都行。C 必须在 B 之后(服务账号是被授权去操作一个应用,那个应用得先存在)。A 里面有一步只能等 B 做完才能做,到那儿会点明。

AGoogle Cloud Console —— 让 Google 登录能用

安卓上现在登录会失败,报 ApiException: 10(DEVELOPER_ERROR)。Google 靠包名 + 签名证书 SHA-1 这一对来认一个安卓应用,而这一对从来没登记过。代码一个字都不用改 —— 应用里那段登录代码在安卓上本来就是对的。

A1 · 先进对项目

打开 console.cloud.google.com,选项目编号 584364169898

怎么确认进对了:API 和服务 → 凭据,那儿应该已经有两个 OAuth 2.0 客户端 —— 一个 iOS、一个 Web。看不到就是进错项目了。这一条要专门核,是因为进错一个看起来很像的项目,报的错和你正要修的那个一模一样

作参考:已经在那儿的 Web 客户端是 584364169898-mhmfq7c5…。我们后端验每一次 Google 登录时认的就是这个 ID,所以安卓客户端必须建在同一个项目里。

A2 · OAuth 同意屏幕

它应该早就配好了 —— 没有它就建不出 OAuth 客户端,而那儿已经有两个了。去 API 和服务 → OAuth 同意屏幕 看一眼。

如果显示发布状态:测试中,那么只有测试用户名单里的账号能登录,上限 100 个。内部测试够用,但每个测试者的 Google 账号都要加进那份名单,否则他们登录会失败,而失败的样子和真正的原因一点都不像。如果显示已发布,那就不用管。

A3 · 建安卓 OAuth 客户端

API 和服务 → 凭据 → 创建凭据 → OAuth 客户端 ID → 类型选 Android。

填什么值 —— 原样照抄
名称HOOP Android (upload key) —— 只是给自己看的标签,随便起
包名com.hooptech.hoop
SHA-17A:03:8F:8C:9A:FA:D9:26:A5:62:CD:B9:3E:77:29:E2:25:E7:91:CA

点创建。不用把任何东西抄回来 —— 没有任何客户端 ID 要进我们的代码,安卓是靠包名和指纹自己找到它的。

A4 · 一共要建三个,每把签名密钥一个

这是最容易栽的地方。重新签名会让 SHA-1 变掉,所以在 Google 眼里,签名不同的包就是不同的应用

哪把密钥什么时候加SHA-1
上传密钥现在(就是上面 A3)7A:03:8F:8C:9A:FA:D9:26:A5:62:CD:B9:3E:77:29:E2:25:E7:91:CA
管住我们自己出的、自己装的每一个包。
调试密钥只有要测调试包才加89:9C:99:50:3C:2A:D1:77:63:82:11:37:FB:9A:C3:2C:FD:7F:D0:9A
这台 Mac 的调试密钥,每台机器都不一样。
Play 签名密钥等 B 做完之后现在还不存在 —— 打开 Play 应用签名时 Google 自己生成。之后去 Play Console → 测试和发布 → 设置 → 应用签名 拿到它,再按 A3 建一个。
漏掉第三个,你会撞上这个项目里最绕人的一个 bug:你自己装 APK 登录一切正常,而每一个从 Play 装的测试者都登不了。同样的代码、同样的版本 —— 因为 Play 把我们的签名剥掉、换成它自己的重签了,Google 看到的指纹就不是同一个。第一次上传成功之后,立刻回来把 A4 做完。

✅ 怎么验 A 这一部分

控制台里没有任何地方会显示「配好了」。唯一真的检验就是在手机上登一次,同时开着日志:

~/Library/Android/sdk/platform-tools/adb logcat | grep google_signin
你看到什么说明
登录成功,日志里什么都没有成了。
code=sign_in_failed 加一行 DEVELOPER_ERROR这一对还是没登记上 —— 项目不对、指纹敲错了、或者装的那个包不是你登记的那把密钥签的。
登录成功但 idToken 为空那是另一个问题,不是安卓客户端这儿。看到这个告诉我。

建完客户端等几分钟才生效,重试前先把应用强制停止一次。

BPlay Console —— 把包送到测试者手里

B1 · 建应用

play.google.com/console创建应用。名字(用户在商店里看到的那个)、默认语言、类型选应用不是游戏、选免费

免费改成付费在发布之后就改不了了。 免费几乎肯定是对的(HOOP 靠应用内变现),但这要当成一个决定,别当成默认值随手点过去。

B2 · Play 应用签名 —— 唯一那个永久性选择

一定要打开。 它只在你第一次上传时问一次,而且永远改不了

打开之后有两把密钥:你的(~/.hoop-keys/ 里那把上传密钥)和 Google 的(真正的应用签名密钥,它保管)。你签,Google 验,然后把你的签名剥掉、换成它自己的。

为什么重要:上传密钥万一丢了或者泄露了,你还能申请换一把,继续发版。不打开的话,丢掉那一个文件就是这个应用的终点 —— 安卓只认最初那把密钥签的更新包,没有申诉途径,唯一的出路是换个包名重新上架,已有的安装量和评分全部作废。

代价是 Google 手上有一把你导不出来的密钥。和「永久失去这个应用」比,这根本不用犹豫。

B3 · Play 要你填的那几份表

政策 → 应用内容 底下。内部测试不需要这些 —— 可以先把包发给测试者。但公开发布之前全都要,而且有几份要审核时间,所以早点开始。

哪一份说明
隐私政策地址现成的,直接粘: https://hoopcomm.com/privacy —— 今天核过,返回 200。
数据安全声明应用收集什么、为什么收。HOOP 收账号标识、通讯录(邀请功能)、照片和相机、消息内容。如实填 —— 它会和应用的真实行为对照,填不实会被下架。
内容分级一份问卷,分级是按你的答案自动出的。社交功能和用户生成内容是关键那几题。
目标受众答案里一旦包含儿童,会触发一大片额外的政策要求。这一题要认真想。
广告声明应用里确实有广告代码(依赖里有 play-services-ads),照实声明。
商店页面长短描述、图标 512×512、特色图 1024×500、至少两张手机截图。截图可以拿自己装的包来截。

B4 · 传到内部测试

测试和发布 → 测试 → 内部测试 → 创建新版本。

.aab 传上去。今早那次出包的那个还在:

~/.hoop/wt-android-verify/app/build/app/outputs/bundle/release/app-release.aab
# 版本号 1,我们的上传密钥签的,531M

或者让 NOVA 现出一个新的 —— 都行,走的是同一条流水线。

它处理完之后,把 Play 报出来的「下载体积」记下来。 那才是体积那个问题的权威答案,而且那个数在 Play 之外谁都算不出来 —— 它是把包按 CPU、屏幕密度、语言拆分之后算的。我们的文件在磁盘上是 531 MB,而 Play 对 base module 限的是 500 MB 的下载体积,两者不能直接比。这一步就是去把它问清楚。

然后填更新说明 → 保存 → 检查版本 → 开始向内部测试发布

B5 · 加测试者

测试者那一栏 → 建一份邮箱清单 → 把每个测试者的 Google 账号邮箱加进去(最多 100)→ 复制 Play 生成的那条加入链接。

每个测试者必须用你填进清单的那个账号登录着去打开那条链接。用别的账号登录的话,他们什么都看不到,然后会来报「坏了」。这是这条通道上最常见的一个误会。

B6 · 回去把 A 补完

现在 Play 应用签名开了,Google 已经生成了它自己那把密钥。去 测试和发布 → 设置 → 应用签名 拿到它的 SHA-1,按 A3 再建一个客户端。不做这一步,所有从 Play 装的人都登不了。

✅ 怎么验 B 这一部分

  • 版本状态是「可供内部测试人员使用」,不是卡在审核或草稿。
  • Play 的应用签名页面上两张证书都在 —— 应用签名证书,和上传证书。上传那张必须等于我们的 7A:03:…:91:CA。对不上就说明这个包是用错的密钥签的。
  • 名单里的测试者能在 Play 里找到并装上这个应用。

C服务账号 —— 不用人手也能上传

可选,而且放到最后做。 上面每一步都不依赖它。它的作用是让出包流水线自动把包推上 Play,而不是让人去浏览器里拖一个文件。

C1 · 启用那个 API

Cloud Console,项目 584364169898API 和服务 → 库 → 搜 Google Play Android Developer API启用

C2 · 建服务账号,给它一把密钥

IAM 和管理 → 服务账号 → 创建服务账号。 名字起得一眼能认,比如 hoop-play-publisher不用给它任何项目角色 —— 真正管用的权限是在 Play 那边给的,不是这儿。

建完点进去 → 密钥 → 添加密钥 → 创建新密钥 → JSON。它只会下载这一次。

那个 JSON 文件能以你的名义发布版本。 把它当成和密钥库一样的东西对待:
mv ~/Downloads/<那个文件>.json ~/.hoop-keys/play-service-account.json
chmod 600 ~/.hoop-keys/play-service-account.json
永远不进仓库,永远不粘进聊天,永远不发邮件。

C3 · 在 Play 里给它权限

Play Console → 用户和权限 → 邀请新用户 → 粘那个服务账号的邮箱(长得像 hoop-play-publisher@<项目>.iam.gserviceaccount.com,就是 JSON 里 client_email 那个字段)→ 给它这个应用的发布权限 → 邀请用户

这一步是最常被漏掉的。漏了的话,凭据会认证得好好的然后被拒绝 —— 因为「你是谁」和「你能干什么」是两件事,这一步管的是第二件。

✅ 怎么验 C —— 一条真能跑的命令,不是"看一眼"

两个控制台里都没有任何地方会告诉你这三块拼上了。这条命令会:

cd <仓库的任意一棵检出>
python3 tools/tf-build/verify_play_credentials.py \
  ~/.hoop-keys/play-service-account.json com.hooptech.hoop

它拿这把凭据去开一个 Play 的 edit 然后丢掉 —— 那是唯一能证明「真有发布权限」的动作,而且什么都不会改(不提交的 edit 会自己过期)。只读接口证明不了这件事,因为有读权限不等于能发版。

结果说明
✅ 200三块全对,C 部分完成。
🛑 401凭据本身没被接受 —— 项目不对、被撤销、或者过期了。
🛑 403凭据有效但没权限。C1 或者 C3 漏了一个。
🛑 404Play 上没这个应用 —— B 部分还没做。
关于这个脚本,我要说清楚一件事:它的失败路径我都实测过 —— 文件不在、JSON 不合法、下成了 OAuth 客户端的 JSON 而不是服务账号的、参数不够。但成功那条路(200)我没验过,因为现在根本没有服务账号可以拿来试。你第一次拿真凭据跑它的时候,同时也是在测这个脚本。 不管它打出什么都告诉我。

D端到端测试 —— 到这一步才算被证明

按顺序做。每一步都依赖上一步,所以第一个失败的地方就直接指出是哪一块配错了

#做什么过了长什么样
1让 NOVA 出包,或者直接用今早那个 AAB日志最后一行是 ✅ versionCode N,真钥匙签的
2传到内部测试(B4)Play 收下了,并报出一个下载体积
3核一眼上传证书(B 的验证那节)Play 上显示的上传 SHA-1 = 7A:03:…:91:CA
4登记 Play 签名密钥的 SHA-1(B6 → A3)安卓 OAuth 客户端变成三个
5测试者加入,并从 Play 装他在 Play 里看得到这个应用,并装上了
6打开应用,用 Google 登录登录成功;adb logcat | grep google_signin 里什么都没有
7正常用一下 —— 发条消息、开个游戏和 iOS 上表现一样
第 6 步过了那一刻,整条流水线才算端到端被证明 —— 源码、出包、签名、Play 分发、安装、登录,全串通了。你一直在要的就是这句话,而在那之前它说不出口。

第一次跑,第 5 或第 6 步失败是意料之中的,只要 A 里那第三个指纹没登记。那是最可能的失败,修法就是 A4。

对照清单

什么时候算做完怎么核
A1进了项目 584364169898看得到 iOS 和 Web 两个 OAuth 客户端
A2同意屏幕配好了如果是「测试中」,每个测试者都在测试用户名单里
A3上传密钥的安卓客户端建好了自己装的包上能用 Google 登录
B1应用建好了Play Console 里能看到它
B2Play 应用签名打开了应用签名页面上有两张证书
B4AAB 传上去了内部测试上已发布;下载体积记下来了
B5测试者加好了有人能从 Play 装上
B6Play 签名密钥的安卓客户端也建了从 Play 装的包上能用 Google 登录
C1-C3服务账号(可选)verify_play_credentials.py 打出 ✅
D端到端第 6 步过了

哪些我真验过、哪些没有

今天在这台机器上验过的:两把指纹,都是 keytool 从密钥库里读出来的。包名和 Web 客户端 ID,在 build.gradle.ktsgoogle_signin.dart、后端配置三处互相核过。隐私政策地址返回 200。文中提到的那个签名 AAB 和 APK —— 它们真的在那些路径上,大小也是那些。验证脚本的失败路径。

没验过的 —— 这几段是说明,不是我看到的事实:A、B、C 三部分里的每一个控制台界面。我没有这两个控制台的权限,所以菜单名和位置是按 Google 的文档写的,可能已经挪过地方。要填的值是核过的,怎么点没有。 另外没验的:凭据脚本的成功路径、Play 收不收我们这个体积、以及客户端建好之后登录是不是真的就通了 —— D 部分就是为了验这几件。

控制台界面要是和这儿写的对不上,那是指南错了,不是你错了。把你实际看到的告诉我,我来改。

配套:出包那一半(已验证跑通)· 最早那份线框图