apple iap-submit: DEVELOPER_REJECTED IAP / subscription / group versions (left by a canceled submission) are submitted as they are, plan says 'add (developer rejected, re-submitted as is)', --new-version only for APPROVED / REJECTED, empty draft reused; fake ASC models cancel and re-add. play build / check: warn before Gradle when defaultConfig does not read -PversionCode / -PversionName, with the exact Groovy / Kotlin line (built with AGP 8.13); android.injected.version.code does not override bundleRelease; post-build versionCode mismatch is a hard stop. play-production-release plan: 'Do you want to restart your review?' dialog, Restart review is never-press. Pitfalls 31-33
This commit is contained in:
parent
41d2ffcc24
commit
0b1451800c
18 changed files with 399 additions and 26 deletions
|
|
@ -10,6 +10,9 @@
|
|||
// .storebound/credentials.json (ANDROID_KEYSTORE, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, ANDROID_KEY_PASSWORD)
|
||||
// goes to Gradle as injected signing properties through the environment, never on the command line; without it the
|
||||
// project's own signingConfig signs. Local only: Play is only read (version codes).
|
||||
// Before Gradle runs, the app module's build file must read -PversionCode / -PversionName in defaultConfig (a literal
|
||||
// or an env var keeps the AAB at that value; android.injected.version.* does not override it for bundleRelease): a
|
||||
// warning with the exact line to use. After the build, an AAB whose versionCode is not the planned one is a hard stop.
|
||||
import { copyFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
||||
import { join, relative } from 'node:path';
|
||||
import { androidSigning } from '../lib/credentials';
|
||||
|
|
@ -17,7 +20,7 @@ import type { Ctx } from '../lib/ctx';
|
|||
import { need } from '../lib/ctx';
|
||||
import { done, log, printJson, warn } from '../lib/log';
|
||||
import { pump } from '../lib/runner';
|
||||
import { aabInfo, findBundles, gradleArgs, pickGradle, signingEnv } from '../lib/gradle';
|
||||
import { aabInfo, appBuildFile, findBundles, gradleArgs, pickGradle, signingEnv, versionSourceIssues, versionSourceMessage } from '../lib/gradle';
|
||||
import { nextVersionCode } from '../lib/release';
|
||||
import { capacitorProject, webStep } from '../lib/web-assets';
|
||||
import { androidSdk, androidSdkEnv, androidSdkMissing } from '../lib/tools';
|
||||
|
|
@ -61,9 +64,12 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
// the SDK as Android Studio finds it (ANDROID_HOME is often unset in non-interactive shells and local.properties is
|
||||
// gitignored): handed to Gradle through the environment, local.properties is never written
|
||||
const sdk = androidSdk([t.dir]);
|
||||
// the build file must read -PversionCode / -PversionName (Flutter passes --build-number / --build-name instead)
|
||||
const buildFile = t.framework === 'flutter' ? null : appBuildFile(t);
|
||||
const versionWarnings = buildFile ? versionSourceIssues(buildFile).map(i => versionSourceMessage(i, relative(root, buildFile), t.framework)) : [];
|
||||
const plan = { framework: t.framework, dir: relative(root, t.dir) || '.', module: t.module, task: t.framework === 'flutter' ? 'flutter build appbundle' : t.task,
|
||||
versionCode: code || null, versionName: versionName ?? null, signing: signing ? `upload key from ${process.env.ANDROID_KEYSTORE ? 'env' : '.storebound/credentials.json'} (alias ${signing.keyAlias})` : 'the project\'s own signingConfig',
|
||||
androidSdk: sdk.path ? `${sdk.path} (${sdk.source})` : null, command: argv.join(' '), out: relative(root, out) || '.', notes: t.notes };
|
||||
androidSdk: sdk.path ? `${sdk.path} (${sdk.source})` : null, command: argv.join(' '), out: relative(root, out) || '.', notes: t.notes, versionWarnings };
|
||||
const webOpts = { config, root, cap, store: 'play' as const, tag: TAG, noPrebuild: a.has('no-prebuild'), allowStale: a.has('allow-stale-web') };
|
||||
if (dry) {
|
||||
const web = await webStep({ ...webOpts, dry: true, quiet: json });
|
||||
|
|
@ -72,6 +78,7 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
log(TAG, `signing: ${plan.signing}`);
|
||||
if (sdk.path) log(TAG, `Android SDK: ${sdk.path} (from ${sdk.source})`); else warn(TAG, androidSdkMissing(sdk));
|
||||
for (const n of t.notes) log(TAG, n);
|
||||
for (const w of versionWarnings) warn(TAG, w);
|
||||
log(TAG, `would run (in ${relative(root, cwd) || '.'}): ${plan.command}`);
|
||||
done(TAG, 'build planned (dry run)');
|
||||
return;
|
||||
|
|
@ -82,6 +89,7 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
if (signing && !existsSync(signing.storeFile)) throw new Error('ANDROID_KEYSTORE: the keystore file does not exist');
|
||||
if (!signing) warn(TAG, 'no ANDROID_KEYSTORE: the project\'s own release signingConfig must sign, else Play refuses the bundle');
|
||||
for (const n of t.notes) log(TAG, n);
|
||||
for (const w of versionWarnings) warn(TAG, w);
|
||||
log(TAG, `$ ${plan.command}`);
|
||||
const started = Date.now();
|
||||
mkdirSync(out, { recursive: true });
|
||||
|
|
@ -100,7 +108,11 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
if (!aab) throw new Error(`build finished but no new .aab under ${relative(root, t.dir)}/${t.module}/build/outputs/bundle`);
|
||||
const info = aabInfo(aab);
|
||||
if (info.packageName !== pkg) warn(TAG, `the AAB's package is ${info.packageName}, the config says ${pkg}`);
|
||||
if (code && info.versionCode !== code) warn(TAG, `the AAB has versionCode ${info.versionCode}, not ${code}: the build file sets it itself; read -PversionCode there or pass that number to play upload knowingly`);
|
||||
// the hard stop: an AAB with another versionCode than planned is never copied to the output folder
|
||||
if (code && info.versionCode !== code) {
|
||||
const fix = buildFile ? versionSourceIssues(buildFile).filter(i => i.field === 'versionCode').map(i => ` Use in defaultConfig of ${relative(root, buildFile)}: ${i.fix}`).join('') : '';
|
||||
throw new Error(`the AAB has versionCode ${info.versionCode}, not ${code}: the build file sets it itself and ignores -PversionCode (android.injected.version.code does not override it).${fix || ' Read -PversionCode in defaultConfig.'} Then build again. (Built: ${relative(root, aab)}, not copied.)`);
|
||||
}
|
||||
const dest = join(out, `${info.packageName}-${info.versionCode}.aab`);
|
||||
copyFileSync(aab, dest);
|
||||
const result = { aab: dest, packageName: info.packageName, versionCode: info.versionCode, versionName: info.versionName ?? null, web: web.bundle };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue