// Inject the runtime permissions the web UI needs into the Capacitor-generated AndroidManifest.xml.
// Run on Codemagic from the Android workflow:
// node mobile/scripts/android-patch.js mobile/android/app/src/main/AndroidManifest.xml
//
// WHY: mobile/android/ is gitignored (regenerated in CI by `cap add android`, same as iOS ios/). The
// freshly generated manifest only declares INTERNET, so without this the WebRTC calls in the web UI can't
// get camera/mic and Android 13+ never prompts for notifications. This adds the same permissions listed in
// mobile/resources/android-permissions.xml. (When the native-call Android plugin lands, it will contribute
// its own manifest entries via Capacitor manifest-merging; this only covers the app-level WebView perms.)
//
// TOLERANT: exits 0 and no-ops if anything is off, so it can NEVER fail the build. Idempotent (keyed on
// the bzcAndroidPerms marker), so re-runs never duplicate the block.
const fs = require('fs');
const p = process.argv[2];
if (!p || !fs.existsSync(p)) { console.log(' (AndroidManifest.xml not found — permission patch skipped)'); process.exit(0); }
try {
let s = fs.readFileSync(p, 'utf8');
// (1) Native-call FirebaseMessagingService swap. The native-call plugin declares its own MESSAGING_EVENT
// service (BzCallMessagingService) that handles call-wake data messages AND forwards regular push to Capacitor
// via super. Remove @capacitor/push-notifications' own MessagingService here — the APP manifest is the highest
// merge priority, so this reliably guarantees exactly one receiver. Needs the `tools` namespace + an insert
// inside . Keyed on bzcCallSvcRemove so re-runs never duplicate it.
if (!s.includes('bzcCallSvcRemove')) {
// Ensure xmlns:tools is declared on (tools:node="remove" needs it).
if (!/]*xmlns:tools=/.test(s)) {
s = s.replace(/',
' ',
' ',
].join('\n');
const before = s;
s = s.replace(/<\/application>/, removal + '');
if (s !== before) console.log(' Capacitor MessagingService removal injected (native-call takes over MESSAGING_EVENT)');
else console.log(' could not find — MessagingService removal skipped');
fs.writeFileSync(p, s);
} else {
console.log(' Capacitor MessagingService removal already present');
}
// (2) WebView permissions.
if (s.includes('bzcAndroidPerms') || s.includes('android.permission.RECORD_AUDIO')) {
console.log(' Android permissions already present'); process.exit(0);
}
const block = [
'',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
'',
].join('\n');
const orig = s;
// Insert directly before the closing tag.
s = s.replace(/<\/manifest>\s*$/, block + '\n');
if (s === orig) { console.log(' could not find — permission patch skipped'); process.exit(0); }
fs.writeFileSync(p, s);
console.log(' Android permissions injected into ' + p);
} catch (e) {
console.log(' Android permission patch skipped:', e.message);
}
process.exit(0);