fix(android): patch android config identifier and avoid Java reserved words

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-28 08:36:30 +08:00
parent 3edfe7030f
commit e4a0955a8e
5 changed files with 116 additions and 15 deletions

View File

@@ -18,6 +18,12 @@ if (!jobId || !appName || !appIdentifier) {
const zipPath = path.join(root, "builds", jobId, "site.zip");
const distDir = path.join(root, "template", "dist");
const confPath = path.join(root, "template", "src-tauri", "tauri.conf.json");
const androidConfPath = path.join(
root,
"template",
"src-tauri",
"tauri.android.conf.json",
);
if (!fs.existsSync(zipPath)) {
console.error(`Missing upload: ${zipPath}`);
@@ -36,14 +42,22 @@ if (!fs.existsSync(indexPath)) {
process.exit(1);
}
const conf = JSON.parse(fs.readFileSync(confPath, "utf8"));
conf.productName = appName;
conf.mainBinaryName = appName.replace(/[^\w.-]+/g, "") || "Web2App";
conf.identifier = appIdentifier;
conf.version = "1.0.0";
conf.app.windows = conf.app.windows ?? [{}];
conf.app.windows[0].title = appName;
fs.writeFileSync(confPath, `${JSON.stringify(conf, null, 2)}\n`);
function patchTauriConfig(filePath) {
const conf = JSON.parse(fs.readFileSync(filePath, "utf8"));
conf.productName = appName;
conf.mainBinaryName = appName.replace(/[^\w.-]+/g, "") || "Web2App";
conf.identifier = appIdentifier;
conf.version = "1.0.0";
if (conf.app?.windows?.[0]) {
conf.app.windows[0].title = appName;
}
fs.writeFileSync(filePath, `${JSON.stringify(conf, null, 2)}\n`);
}
patchTauriConfig(confPath);
if (fs.existsSync(androidConfPath)) {
patchTauriConfig(androidConfPath);
}
const iconCandidates = ["icon.png", "favicon.png", "logo.png"];
for (const candidate of iconCandidates) {

View File

@@ -16,7 +16,12 @@ import {
triggerBuildWorkflow,
uploadSiteZip,
} from "../services/github.js";
import { slugifyIdentifier, validateZipBuffer, ZipValidationError } from "../services/zip.js";
import {
normalizeAppIdentifier,
slugifyIdentifier,
validateZipBuffer,
ZipValidationError,
} from "../services/zip.js";
const upload = multer({
storage: multer.memoryStorage(),
@@ -69,9 +74,10 @@ buildsRouter.post("/", upload.single("file"), async (req, res) => {
const { normalizedBuffer } = validateZipBuffer(req.file.buffer, maxUploadBytes);
const jobId = nanoid(10);
const appIdentifier =
identifierInput ||
`com.web2app.${slugifyIdentifier(appName) || jobId.toLowerCase()}`;
const slug = slugifyIdentifier(appName) || jobId.toLowerCase();
const appIdentifier = normalizeAppIdentifier(
identifierInput || `com.web2app.${slug}`,
);
insertBuild({ id: jobId, appName, appIdentifier });

View File

@@ -93,10 +93,91 @@ function addDirectoryToZip(zip: AdmZip, dir: string, prefix: string) {
}
}
const JAVA_RESERVED_SEGMENTS = new Set([
"abstract",
"assert",
"boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
"const",
"continue",
"default",
"do",
"double",
"else",
"enum",
"extends",
"final",
"finally",
"float",
"for",
"goto",
"if",
"implements",
"import",
"instanceof",
"int",
"interface",
"long",
"native",
"new",
"package",
"private",
"protected",
"public",
"return",
"short",
"static",
"strictfp",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
"transient",
"try",
"void",
"volatile",
"while",
]);
function sanitizeSegment(segment: string): string {
let value = segment.toLowerCase().replace(/[^a-z0-9_]/g, "");
if (!value) return "app";
if (/^\d/.test(value)) value = `app${value}`;
if (JAVA_RESERVED_SEGMENTS.has(value)) value = `${value}app`;
return value.slice(0, 48);
}
export function slugifyIdentifier(input: string): string {
return input
.toLowerCase()
.replace(/[^a-z0-9]+/g, ".")
.replace(/^\.+|\.+$/g, "")
.slice(0, 48);
.split(".")
.map(sanitizeSegment)
.filter(Boolean)
.join(".")
.slice(0, 120);
}
export function normalizeAppIdentifier(identifier: string): string {
const parts = identifier
.trim()
.split(".")
.map(sanitizeSegment)
.filter(Boolean);
if (parts.length < 2) {
throw new ZipValidationError(
"Bundle ID 至少需要两段,例如 com.example.myapp",
);
}
return parts.join(".");
}

View File

@@ -2,7 +2,7 @@
"$schema": "https://schema.tauri.app/config/2",
"productName": "Web2App",
"version": "1.0.0",
"identifier": "com.web2app.default",
"identifier": "com.web2app.app",
"app": {
"windows": [
{

View File

@@ -3,7 +3,7 @@
"productName": "Web2App",
"mainBinaryName": "Web2App",
"version": "1.0.0",
"identifier": "com.web2app.default",
"identifier": "com.web2app.app",
"build": {
"beforeDevCommand": "",
"beforeBuildCommand": "",