// 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);