Skip to content

fix(cli): apply cleartext to the app module and merge with existing network-security-config - #8671

Merged
alexgerardojacinto merged 5 commits into
nextfrom
fix/RMET-5420-cleartext-app-module
Oct 22, 2026
Merged

alexgerardojacinto merged 5 commits into
nextfrom
fix/RMET-5420-cleartext-app-module

Conversation

@alexgerardojacinto

@alexgerardojacinto alexgerardojacinto commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Description

Follow-up to #8572. Applies cleartext opt-in (server.cleartext, live-reload, Cordova edit-config usesCleartextTraffic) to the app module instead of the generated capacitor-cordova-android-plugins module, and merges into an existing network-security-config.xml instead of competing with it.

  • Cleartext is written to android/app/src/main/res/xml/ and referenced from android/app/src/main/AndroidManifest.xml.
  • If the app has no config, the CLI creates one and the manifest reference. If the app already has one (any name the manifest references), only cleartextTrafficPermitted on <base-config> is changed (the element is added if missing). Trust anchors, pinning and <domain-config> entries are left untouched, so a <domain-config> that blocks cleartext for a host still applies to that host.
  • A <!-- capacitor:cleartext ... --> marker comment in the config file records what the CLI did (created the file, added the manifest reference, original <base-config> value), so turning the trigger off reverts only the CLI's own changes: a created file is deleted, an edited file gets its original value back, and an app-owned file or reference is never deleted.
  • The file written to the plugins module by fix(cli): replace usesCleartextTraffic with network-security-config #8572 is removed on the next sync if it matches what that version generated.
  • cap run --url that fails now reverts the cleartext configuration too (previously only the cap config was reverted).
  • server.cleartext JSDoc updated.

ref: RMET-5420

Change Type

  • Fix
  • Feature
  • Refactor
  • Breaking Change
  • Documentation
  • Other (CI, chores, etc.)

Rationale / Problems Fixed

Since #8572, on Capacitor 9 the plugins module is only linked into the app when it has at least one Cordova plugin:

  1. For Capacitor-only apps server.cleartext=true was a silent no-op.
  2. For apps with their own network-security-config.xml: with the same filename the app's file won the manifest merge (the CLI's value was silently overridden); with a different filename the manifest merger failed on android:networkSecurityConfig, and tools:replace unblocked the build but the app's file still won.

Tests or Reproductions

Unit tests: cli/test/android-cleartext.spec.ts (merge/revert/idempotency, own config with same/different name, legacy file cleanup) and cli/test/run-cleartext-revert.spec.ts (failed cap run --url). Full CLI suite passes (22 suites).

Control, same scratch app built with the CLI before and after this change, server.cleartext=true:

Scenario Before (#8572) After
Capacitor-only app nothing written, no-op app config + manifest reference created, builds
Own config, different name, Cordova plugin linked build fails: manifest merger, Suggestion: add 'tools:replace="android:networkSecurityConfig"' builds, app's reference kept, <base-config> true
Own config, same name, Cordova plugin linked builds, app's file stays cleartextTrafficPermitted="false" builds, <base-config> true, restored on revert

Runtime, on a Pixel 7 (Android 17) and a Pixel 3 XL (Android 12) with the same results on both. A test page fetches http://httpforever.com/ and https://example.com/ through CapacitorHttp:

Scenario HTTP HTTPS
Capacitor-only, server.cleartext=false blocked OK
Capacitor-only, server.cleartext=true allowed OK
Back to false blocked, no config or manifest reference left OK
Own config (<base-config> false), false / true / false blocked / allowed / blocked, file restored byte for byte, manifest untouched OK
Own config with <domain-config httpforever.com cleartext=false>, true still blocked (domain rule wins) -
Own config with a wrong pin on example.com, true / false - blocked both ways (pinning preserved), file restored byte for byte
cap run --url http://localhost:8080 --forwardPorts 8080:8080, server.cleartext=false page loaded over http while running -
After Ctrl+C config and manifest reference removed, manifest identical to the original -

Platforms Affected

  • Android
  • iOS
  • Web

…etwork-security-config

Cleartext opt-in was written to the generated capacitor-cordova-android-plugins
module, which is not linked into Capacitor-only apps and conflicts with an
app-owned network-security-config.xml. Write it to android/app instead,
merging only cleartextTrafficPermitted and tracking CLI changes with a marker
comment so they can be reverted without touching app-owned content.

ref: RMET-5420

@OS-ruimoreiramendes OS-ruimoreiramendes left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested locally with the inappbrowser example app.

  • Capacitor-only app, no NSC: server.cleartext on → NSC + manifest ref created, HTTP loads; off → both removed
  • App with own NSC (same name), with <base-config>=false + trust-anchors + <domain-config> with a pin: only <base-config> flipped, everything else untouched, revert byte-equal to original.
  • App with own NSC under a different name (my_nsc.xml): no parallel file created, manifest untouched, build no longer breaks on the manifest merger
  • cap run : create/revert NSC + manifest.

LGTM 👍

@alexgerardojacinto
alexgerardojacinto merged commit 19567bb into next Oct 22, 2026
6 checks passed
@alexgerardojacinto
alexgerardojacinto deleted the fix/RMET-5420-cleartext-app-module branch October 22, 2026 18:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants