Context
@comapeo/core-react-native is published as an Expo module. The
library currently declares android:dataExtractionRules and
android:fullBackupContent on its <application> element to exclude
the rootkey-bearing SharedPreferences from cloud backup and
device-to-device transfer (see android/src/main/AndroidManifest.xml,
PR #36, comment thread on backup-rules merge conflict).
Host apps that already declare these attributes get a manifest-merger
conflict and must manually:
- Merge the library's exclusions into their own backup-rules XML.
- Add
tools:replace="android:dataExtractionRules,android:fullBackupContent" to their <application> tag.
This is documented in README.md > Configure for Android > Backup-rules merge conflict but it's still a friction point at integration time
and easy to forget when iterating.
Proposal
An Expo config plugin that runs at expo prebuild time and:
- Adds the library's backup-rules XML files to the host app's
res/xml/ directory (or makes them resolvable via the library
AAR — they're already there, but the plugin can verify).
- Reads the host app's existing backup-rules XML if any.
- Default Expo template apps don't set these → plugin sets the
attributes on the host's <application> and copies our XML files
in. No conflict because the host had no prior declaration.
- Host already has rules → plugin parses the host's XML, merges our
<exclude domain="sharedpref" path="comapeo-core.xml" /> entries
into the right sections (<cloud-backup>, <device-transfer>,
<full-backup-content>), writes the merged XML back, and ensures
the <application> attributes still point at it.
- Removes the attributes from the library's own
AndroidManifest.xml so there's never a merge conflict —
responsibility shifts entirely to the host manifest, which the
plugin owns at prebuild time.
For non-Expo (bare-RN-without-Expo) consumers, the README path stays
the canonical fix.
Why this is worth doing
- Eliminates a build-time integration step for the largest class of
consumers (managed-Expo apps).
- Removes the manifest-merger conflict for any consumer that has its
own backup rules — friction point disappears entirely.
- Keeps secure-by-default: forgetting to register the plugin is the
only way to lose the exclusion, and that's discoverable via a
smoke test (the encrypted SharedPreferences ends up in backups).
Cost
Roughly 100–150 LOC of plugin code plus tests:
withDangerousMod for the XML file copy / merge step.
withAndroidManifest for the <application> attribute add /
tools:replace handling.
- An XML-merge helper that's safe against repeated invocations
(expo prebuild runs are idempotent in the rest of the toolchain;
this plugin should be too).
- A test fixture covering: (a) host with no rules, (b) host with
rules that already have our exclusions, (c) host with rules that
conflict.
Acceptance
Open questions
- Should the plugin be opt-in (consumer adds it to their
app.json
plugins array) or auto-registered (via expo-module.config.json)?
Auto is friendlier; opt-in is more explicit.
- What should the plugin do if it detects an existing
tools:replace="android:dataExtractionRules" on the host? Mostly:
nothing, because the host has explicitly opted out of merging.
Log a warning suggesting they include our exclusions.
- How do bare-RN consumers (no Expo) interact with this? They
continue to follow the README path; the plugin doesn't apply.
Context
@comapeo/core-react-nativeis published as an Expo module. Thelibrary currently declares
android:dataExtractionRulesandandroid:fullBackupContenton its<application>element to excludethe rootkey-bearing SharedPreferences from cloud backup and
device-to-device transfer (see
android/src/main/AndroidManifest.xml,PR #36, comment thread on backup-rules merge conflict).
Host apps that already declare these attributes get a manifest-merger
conflict and must manually:
tools:replace="android:dataExtractionRules,android:fullBackupContent"to their<application>tag.This is documented in
README.md > Configure for Android > Backup-rules merge conflictbut it's still a friction point at integration timeand easy to forget when iterating.
Proposal
An Expo config plugin that runs at
expo prebuildtime and:res/xml/directory (or makes them resolvable via the libraryAAR — they're already there, but the plugin can verify).
attributes on the host's
<application>and copies our XML filesin. No conflict because the host had no prior declaration.
<exclude domain="sharedpref" path="comapeo-core.xml" />entriesinto the right sections (
<cloud-backup>,<device-transfer>,<full-backup-content>), writes the merged XML back, and ensuresthe
<application>attributes still point at it.AndroidManifest.xml so there's never a merge conflict —
responsibility shifts entirely to the host manifest, which the
plugin owns at prebuild time.
For non-Expo (bare-RN-without-Expo) consumers, the README path stays
the canonical fix.
Why this is worth doing
consumers (managed-Expo apps).
own backup rules — friction point disappears entirely.
only way to lose the exclusion, and that's discoverable via a
smoke test (the encrypted SharedPreferences ends up in backups).
Cost
Roughly 100–150 LOC of plugin code plus tests:
withDangerousModfor the XML file copy / merge step.withAndroidManifestfor the<application>attribute add /tools:replacehandling.(
expo prebuildruns are idempotent in the rest of the toolchain;this plugin should be too).
rules that already have our exclusions, (c) host with rules that
conflict.
Acceptance
plugins/(or wherever published Expo pluginsgo in this repo) and is auto-registered when the package is
installed.
expo prebuild --cleanon a fresh Expo template + this moduleproduces a host manifest with our exclusions, no conflicts.
expo prebuild --cleanon an Expo template that ALREADY hasbackup rules merges our exclusions in non-destructively.
<exclude>entries, no toggling
tools:replace.AndroidManifest.xmlno longer declares thebackup attributes once the plugin path is verified end-to-end.
README.md > Configure for Androidupdates to reflect thatExpo consumers need do nothing; bare-RN consumers follow the
manual path.
Open questions
app.jsonplugins array) or auto-registered (via
expo-module.config.json)?Auto is friendlier; opt-in is more explicit.
tools:replace="android:dataExtractionRules"on the host? Mostly:nothing, because the host has explicitly opted out of merging.
Log a warning suggesting they include our exclusions.
continue to follow the README path; the plugin doesn't apply.