web: recognize Android targets and point users at the CLI

Dropping an .apk/.apks/.xapk package or a .so library reported
"not recognized — will be skipped", which reads as "not protected"
when the real gap is that the Android pipeline (filesystem
orchestration in senbei-io) has no wasm build. These files now get an
explicit android pseudo-kind at staging time: the row explains that
the CLI handles them, and they neither enable the Unpack button nor
error out mid-run.
This commit is contained in:
2026-09-10 09:32:58 +08:00
parent a230c37281
commit 512a627066
2 changed files with 34 additions and 4 deletions
+31 -3
View File
@@ -50,6 +50,22 @@ const KIND_LABEL = {
'native-dll': 'protected native DLL', 'native-dll': 'protected native DLL',
'managed-dll': 'protected managed DLL', 'managed-dll': 'protected managed DLL',
metadata: 'il2cpp metadata', metadata: 'il2cpp metadata',
'android-package':
'Android app package — the web build cannot unpack these yet; use the senbei CLI',
'android-so':
'Android AArch64 library — the web build cannot unpack these yet; use the senbei CLI',
};
// Android targets are recognized by extension so the row can explain the
// situation instead of reporting a protected file as unrecognized: the
// Android pipeline is filesystem orchestration (senbei-io) with no wasm
// build, so these files need the CLI. The pseudo-kinds are labels only —
// they never reach the worker.
const ANDROID_KIND = {
apk: 'android-package',
apks: 'android-package',
xapk: 'android-package',
so: 'android-so',
}; };
const COMPANION_SVG = const COMPANION_SVG =
@@ -91,8 +107,13 @@ async function stageFiles(list) {
// the PE header fields); read a small slice, not the whole file. // the PE header fields); read a small slice, not the whole file.
const head = new Uint8Array(await file.slice(0, 65536).arrayBuffer()); const head = new Uint8Array(await file.slice(0, 65536).arrayBuffer());
// Companions are ciphertext fragments; detect() only makes sense on the // Companions are ciphertext fragments; detect() only makes sense on the
// base module, so skip it for `._` files. // base module, so skip it for `._` files. Android targets short-circuit
const kind = file.name.endsWith('._') ? undefined : detect(head); // detect() as well: an ELF/zip never classifies as a protected PE, and
// the row must carry the android pseudo-kind for its status line.
const ext = file.name.slice(file.name.lastIndexOf('.') + 1).toLowerCase();
const kind = file.name.endsWith('._')
? undefined
: (ANDROID_KIND[ext] ?? detect(head));
const old = files.get(file.name); const old = files.get(file.name);
files.set(file.name, { files.set(file.name, {
file, file,
@@ -284,7 +305,10 @@ function render() {
const unpackable = [...files].some( const unpackable = [...files].some(
([name, e]) => ([name, e]) =>
!name.endsWith('._') && e.kind !== undefined && e.state === 'staged', !name.endsWith('._') &&
e.kind !== undefined &&
!e.kind.startsWith('android-') &&
e.state === 'staged',
); );
unpackBtn.disabled = !unpackable; unpackBtn.disabled = !unpackable;
actions.hidden = files.size === 0; actions.hidden = files.size === 0;
@@ -364,6 +388,10 @@ unpackBtn.addEventListener('click', async () => {
continue; continue;
} }
// Android rows are informational only (no wasm pipeline); their staged
// status line already says to use the CLI.
if (entry.kind.startsWith('android-')) continue;
entry.state = 'working'; entry.state = 'working';
render(); render();
try { try {
+3 -1
View File
@@ -56,7 +56,9 @@
<p class="hint"> <p class="hint">
Protected <code>.exe</code> / <code>.dll</code> modules, optional Protected <code>.exe</code> / <code>.dll</code> modules, optional
<code>._</code> companions, or an il2cpp <code>._</code> companions, or an il2cpp
<code>global-metadata.dat</code>. <code>global-metadata.dat</code>. Android packages
(<code>.apk</code> / <code>.apks</code> / <code>.xapk</code>) and
<code>.so</code> libraries are recognized but need the CLI.
</p> </p>
<input type="file" id="picker" multiple hidden> <input type="file" id="picker" multiple hidden>
</div> </div>