fix(android): use login consent instead of native privacy prompt

This commit is contained in:
key
2026-07-29 09:59:41 +08:00
parent f322f2b21b
commit 7f3357c7a1
10 changed files with 181 additions and 131 deletions
+22 -26
View File
@@ -74,43 +74,39 @@ export const validateLegalUrlPair = (termsValue, privacyValue) => {
return { termsUrl, privacyUrl };
};
const extractLinks = (message) =>
[...String(message || '').matchAll(/href="([^"]+)"/g)].map((match) => match[1]);
export const validateAndroidPrivacyDocument = (privacy) => {
if (!privacy || typeof privacy !== 'object') {
throw new Error('androidPrivacy.json must contain a JSON object');
}
if (privacy.prompt !== 'template') {
throw new Error('androidPrivacy.json must use prompt=template');
if (privacy.prompt !== 'none') {
throw new Error('androidPrivacy.json must use prompt=none for the controlled internal App');
}
if (!/^[1-9]\d*$/.test(String(privacy.version || ''))) {
throw new Error('androidPrivacy.json version must be a positive numeric policy version');
throw new Error('androidPrivacy.json version must be a positive numeric configuration version');
}
if (privacy.hrefLoader !== 'system') {
throw new Error('androidPrivacy.json must open legal links with hrefLoader=system');
for (const templateOnlyField of [
'title',
'message',
'buttonAccept',
'buttonRefuse',
'hrefLoader',
'second',
'disagreeMode',
'styles'
]) {
if (Object.hasOwn(privacy, templateOnlyField)) {
throw new Error(`androidPrivacy.json prompt=none must not contain ${templateOnlyField}`);
}
}
const primaryLinks = extractLinks(privacy.message);
const secondaryLinks = extractLinks(privacy.second?.message);
if (primaryLinks.length !== 2 || secondaryLinks.length !== 2) {
throw new Error('androidPrivacy.json must contain two legal links in both prompts');
}
const primary = validateLegalUrlPair(primaryLinks[0], primaryLinks[1]);
const secondary = validateLegalUrlPair(secondaryLinks[0], secondaryLinks[1]);
if (primary.termsUrl !== secondary.termsUrl || primary.privacyUrl !== secondary.privacyUrl) {
throw new Error('androidPrivacy.json primary and secondary prompts must use the same legal links');
}
return primary;
return {
prompt: privacy.prompt,
version: String(privacy.version)
};
};
export const renderAndroidPrivacy = (templateText, termsValue, privacyValue) => {
const { termsUrl, privacyUrl } = validateLegalUrlPair(termsValue, privacyValue);
const rendered = String(templateText)
.replaceAll('__TERMS_URL__', termsUrl)
.replaceAll('__PRIVACY_URL__', privacyUrl);
const privacy = JSON.parse(rendered);
validateLegalUrlPair(termsValue, privacyValue);
const privacy = JSON.parse(String(templateText));
validateAndroidPrivacyDocument(privacy);
return `${JSON.stringify(privacy, null, 2)}\n`;
};