Everything written this session that has not been through the device: rounds 43 to 48 (each patch adversarially verified, 43's transient-notice expectation fixed), a partial round 49, the pipeline scripts, the Android Auto design and the icon comparison mock. Also the two harness changes that were never A/B'd — adaptive waits, which may only shorten a declared wait and never lengthen it, and a ship that runs the mock walk and the deploy at the same time. The A/B and its 255-step baseline are in handoff/tools; main stays at what the phone has actually walked.
117 lines
6.7 KiB
JavaScript
117 lines
6.7 KiB
JavaScript
// Round forty-three: the build nobody has made. Every APK in this port is
|
|
// `assembleArm64Debug`, and the generated project turns R8 on for `release`
|
|
// and only for `release` — while tauri finds a plugin class by string, files
|
|
// every @Command under `commands[method.name]`, and lets Jackson fill every
|
|
// @InvokeArg field by field. Minification breaks exactly that, and it breaks
|
|
// it silently: the app builds, installs, launches, and then a tap answers
|
|
// "No command pickFolder found for plugin ...". So: one consumer-rules.pro
|
|
// per plugin module (registered by one Gradle line each, the shape
|
|
// tauri-android and tauri-plugin-dialog already use here — opener ships the
|
|
// file and never registers it, which is the failure mode), one app-wide
|
|
// file for what belongs to no plugin — the runtime annotation attributes, a
|
|
// -dontwarn pair for the two java.beans classes jackson-databind references
|
|
// and Android has not, and the four @Command methods declared on
|
|
// app.tauri.plugin.Plugin that no rule of tauri's own names — and a
|
|
// `--release` flag on build.sh that is off by default, so the deploy pipeline
|
|
// keeps the path it has run every twenty minutes for a month. No features, no
|
|
// UI, no Rust, no Kotlin, and neither walk is touched: the release build is a
|
|
// hand list, not a walk.
|
|
const fs = require('fs');
|
|
const root = process.env.SS_ROOT || 'F:/Coding/SoulStream/';
|
|
const scratch = 'C:/Users/Kyle/AppData/Local/Temp/claude/F--Coding-SoulStream/5488514a-11e8-482a-b0a0-20cb511ee110/scratchpad/';
|
|
const ins = (name) => fs.readFileSync(scratch + name, 'utf8').replace(/\s+$/, '');
|
|
let p, s;
|
|
const load = (file) => { p = file; s = fs.readFileSync(root + p, 'utf8'); };
|
|
const save = () => fs.writeFileSync(root + p, s);
|
|
const once = (a) => {
|
|
const i = s.indexOf(a);
|
|
if (i < 0) throw new Error('missing in ' + p + ': ' + a.slice(0, 90));
|
|
if (s.indexOf(a, i + 1) >= 0) throw new Error('ambiguous in ' + p + ': ' + a.slice(0, 90));
|
|
return i;
|
|
};
|
|
const rep = (a, b) => { once(a); s = s.replace(a, () => b); };
|
|
const NL = String.fromCharCode(10);
|
|
|
|
/* Five of the writes below are whole new files, which succeed as happily the
|
|
second time as the first, while the Gradle and build.sh `rep`s would throw
|
|
somewhere in the middle and leave half a tree. Refuse a second run here,
|
|
before a byte is touched: the app-wide rules file is what this round
|
|
creates and nothing else in the repo makes it. */
|
|
if (fs.existsSync(root + 'src-tauri/android/proguard-soulstream.pro')) {
|
|
throw new Error('src-tauri/android/proguard-soulstream.pro already exists — round 43 has already run against ' + root);
|
|
}
|
|
|
|
// ── the rules that belong to the app, kept where gen/ cannot lose them ─
|
|
/* first, so the guard above covers a run that dies anywhere below it */
|
|
fs.writeFileSync(root + 'src-tauri/android/proguard-soulstream.pro', ins('ins-r43-proguard-app.txt') + NL);
|
|
|
|
// ── the rules that travel with each plugin ────────────────────────────
|
|
/* A consumer file is handed to whatever app links the module and does
|
|
nothing at all unless that app minifies, so the debug APK is untouched;
|
|
and because it lives in the module rather than in gen/android, a
|
|
regenerated project still has it. One Gradle line each. The anchor is the
|
|
whole `defaultConfig` block rather than its `minSdk` line, so it cannot
|
|
match again once the line is in — a second pass over a half-applied tree
|
|
refuses rather than writing the line twice. */
|
|
const plugins = [
|
|
['storage', 'ins-r43-consumer-storage.txt'],
|
|
['media-session', 'ins-r43-consumer-media.txt'],
|
|
['share', 'ins-r43-consumer-share.txt'],
|
|
['transfer-notice', 'ins-r43-consumer-notice.txt'],
|
|
];
|
|
for (const [name, file] of plugins) {
|
|
const dir = 'crates/tauri-plugin-' + name + '/android/';
|
|
fs.writeFileSync(root + dir + 'consumer-rules.pro', ins(file) + NL);
|
|
load(dir + 'build.gradle.kts');
|
|
rep(` defaultConfig {
|
|
minSdk = 26
|
|
}`,
|
|
` defaultConfig {
|
|
minSdk = 26
|
|
// the plugin's own R8 keep rules, handed to whatever app links this
|
|
// module — inert unless that app minifies, which only the release
|
|
// build type does
|
|
consumerProguardFiles("consumer-rules.pro")
|
|
}`);
|
|
save();
|
|
}
|
|
|
|
// ── build.sh: a release flag, off by default ──────────────────────────
|
|
load('src-tauri/android/build.sh');
|
|
/* the flag block sits between the toolchain and the cargo line, so a sibling
|
|
round appending at the end or editing the cargo line does not meet it */
|
|
rep(`source src-tauri/android/env.sh`,
|
|
`source src-tauri/android/env.sh` + NL + ins('ins-r43-build-flag.txt'));
|
|
/* $CARGO_EXTRA is assigned on BOTH branches, so `set -u` is satisfied, and
|
|
unquoted on purpose: empty expands to no words at all, which makes the
|
|
default cargo line character for character what it is today. */
|
|
rep(`cargo build --lib -p app --target aarch64-linux-android --features tauri/custom-protocol 2>&1`,
|
|
`cargo build --lib -p app --target aarch64-linux-android --features tauri/custom-protocol $CARGO_EXTRA 2>&1`);
|
|
rep(`SO=target/aarch64-linux-android/debug/libapp_lib.so`,
|
|
`SO=target/aarch64-linux-android/$PROFILE/libapp_lib.so`);
|
|
rep(`./gradlew.bat assembleArm64Debug -x rustBuildArm64Debug -q`,
|
|
`./gradlew.bat assemble$VARIANT -x rustBuild$VARIANT -q`);
|
|
rep(`cd /f/Coding/SoulStream
|
|
APK=src-tauri/gen/android/app/build/outputs/apk/arm64/debug/app-arm64-debug.apk
|
|
ls -la "$APK"`, ins('ins-r43-build-tail.txt'));
|
|
save();
|
|
|
|
// ── the doc ───────────────────────────────────────────────────────────
|
|
load('ANDROID.md');
|
|
/* the last sentence of the dev-flavour section, NOT the `## Verifying`
|
|
heading below it: a sibling inserting a section of its own would reach for
|
|
the heading, and this one still lands where it belongs either way */
|
|
rep(`harness and the app see one origin in both flavours.`,
|
|
`harness and the app see one origin in both flavours.` + NL + NL + ins('ins-r43-doc-release.txt'));
|
|
/* the last sentence of the file. Deliberately NOT the `## Not done yet`
|
|
heading and NOT its intro — that sentence carries a ROUND COUNT, which is
|
|
exactly what a sibling round bumps. No count anywhere in this file is
|
|
touched, because this round adds no step to any walk. */
|
|
/* one newline, not two: the bullets in that list sit flush against each
|
|
other, and a blank line between two of them turns the whole list loose */
|
|
rep(`which the tour deliberately refuses.`,
|
|
`which the tour deliberately refuses.` + NL + ins('ins-r43-doc-notdone.txt'));
|
|
save();
|
|
|
|
console.log('round 43 wired');
|