From d91e148f0594c7be0dfafa46524e8c6020980f66 Mon Sep 17 00:00:00 2001 From: Pavel Gric Date: Wed, 25 Feb 2026 09:46:07 +0100 Subject: [PATCH 1/2] feat: add option to specify services in AndroidManifest --- docs/android.serrvices.md | 33 ++++++++++++++++++++++++ packages/app/android/android-manifest.js | 25 ++++++++++++++++++ packages/app/scripts/types.ts | 28 ++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 docs/android.serrvices.md diff --git a/docs/android.serrvices.md b/docs/android.serrvices.md new file mode 100644 index 000000000..429cd2a62 --- /dev/null +++ b/docs/android.serrvices.md @@ -0,0 +1,33 @@ +A name-value pair for an item of additional, arbitrary data that can be supplied to the application. + +Equivalent to +[``](https://developer.android.com/guide/topics/manifest/service-element). + +Example: + +```xml + + + +``` + +becomes + +```json +{ + "android": { + "services": [ + { + "android:name": "com.example.locationService", + "android:exported": true, + "android:foregroundServiceType": "location" + } + ], + } +} +``` + +
diff --git a/packages/app/android/android-manifest.js b/packages/app/android/android-manifest.js index 7bb2014a6..40f08788f 100644 --- a/packages/app/android/android-manifest.js +++ b/packages/app/android/android-manifest.js @@ -109,6 +109,31 @@ function generateAndroidManifest(appManifestPath, manifestOutput, fs = nodefs) { } } + // https://developer.android.com/guide/topics/manifest/service-element + const services = android.services; + if (Array.isArray(services)) { + const names = ["android:name"]; + const attributes = [ + "android:description", + "android:directBootAware", + "android:enabled", + "android:exported", + "android:foregroundServiceType", + "android:icon", + "android:isolatedProcess", + "android:label", + "android:name", + "android:permission", + "android:process", + "android:stopWithTask", + ]; + const entries = toXML(services, names, attributes, attributeNamePrefix); + + if (entries.length > 0) { + manifest.application["service"] = entries; + } + } + const builder = new XMLBuilder(xmlOptions); fs.mkdirSync(path.dirname(manifestOutput), { recursive: true, mode: 0o755 }); fs.writeFileSync(manifestOutput, builder.build(xml)); diff --git a/packages/app/scripts/types.ts b/packages/app/scripts/types.ts index 0ceee097c..766676388 100644 --- a/packages/app/scripts/types.ts +++ b/packages/app/scripts/types.ts @@ -29,6 +29,33 @@ export type AndroidConfig = { "android:name": string; "android:value": string; }[]; + services?: { + "android:name": string; + "android:description": string; + "android:directBootAware": "true" | "false"; + "android:enabled": "true" | "false"; + "android:exported": "true" | "false"; + "android:foregroundServiceType": + | "camera" + | "connectedDevice" + | "dataSync" + | "health" + | "location" + | "mediaPlayback" + | "mediaProjection" + | "microphone" + | "phoneCall" + | "remoteMessaging" + | "shortService" + | "specialUse" + | "systemExempted"; + "android:icon": string; + "android:isolatedProcess": "true" | "false"; + "android:label": string; + "android:permission": string; + "android:process": string; + "android:stopWithTask": "true" | "false"; + }[]; }; }; @@ -37,6 +64,7 @@ export type AndroidManifest = { "uses-permission": Record[]; application: { "meta-data": Record[]; + service: Record[]; }; }; From 48d66c621423b2bbda273ad44a283e0b07147eb2 Mon Sep 17 00:00:00 2001 From: Pavel Gric Date: Wed, 25 Feb 2026 10:25:11 +0100 Subject: [PATCH 2/2] fix: filename typo --- docs/{android.serrvices.md => android.services.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{android.serrvices.md => android.services.md} (100%) diff --git a/docs/android.serrvices.md b/docs/android.services.md similarity index 100% rename from docs/android.serrvices.md rename to docs/android.services.md