Skip to content

fix: separate local storage between WebView processes#54

Open
ItsChaceD wants to merge 6 commits intomainfrom
fix/RMET-4918/isolate-local-storage
Open

fix: separate local storage between WebView processes#54
ItsChaceD wants to merge 6 commits intomainfrom
fix/RMET-4918/isolate-local-storage

Conversation

@ItsChaceD
Copy link
Copy Markdown
Contributor

@ItsChaceD ItsChaceD commented Jan 19, 2026

Description

This PR implements localStorage isolation on Android API 28+ via setDataDirectorySuffix, bringing it into alignment with iOS behavior.

Due to Android system limitations, isolation can only be achieved by running the WebView in a separate :OSInAppBrowser process with a dedicated data directory suffix. This requires events to be propagated between the processes via broadcast receivers. To avoid a breaking change, we keep the class signatures the same and add a custom @RequiresEventBridgeRegistration annotation to proactively warn native library users of the new registration requirement.

Context

https://outsystemsrd.atlassian.net/browse/RMET-4918?atlOrigin=eyJpIjoiOWI4NWVmMDIwZDhhNDRmMGJhMTljMWFlNTQxYmFkZjIiLCJwIjoiaiJ9

Type of changes

  • Fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Refactor (cosmetic changes)
  • Breaking change (change that would cause existing functionality to not work as expected)

Platforms affected

  • Android
  • iOS
  • JavaScript

Comment thread src/main/AndroidManifest.xml
@OS-pedrogustavobilro
Copy link
Copy Markdown
Collaborator

OS-pedrogustavobilro commented Feb 3, 2026

Also @ItsChaceD FYI one of the tests is broken with your PR, it passes in main branch.

test_handleOpen_withValidURL_launchesWebView_when_browserPageNavigationCompleted_then_browserPageNavigationCompletedTriggered

It's hard to tell on the CI logs because of SonarCloud integration is broken. We should take a look at SonarCloud soon, it's been broken for too long now...

Copy link
Copy Markdown
Collaborator

@OS-pedrogustavobilro OS-pedrogustavobilro left a comment

Choose a reason for hiding this comment

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

Overall checked the code and tested and LGTM.

We'll still need to address #54 (comment) in the coming days, but yeah I'll re-review if changes are made because of that.

@SerializedName("pauseMedia") val pauseMedia: Boolean = true,
@SerializedName("customUserAgent") val customUserAgent: String? = null
@SerializedName("customUserAgent") val customUserAgent: String? = null,
@SerializedName("isIsolated") val isIsolated: Boolean = true
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just to confirm here: By default the plugin will set "isIsolated" to true, meaning this will be a breaking change in the plugin as discussed some time ago?

The reason why we are using default of true is because there are potential security concerns implicated? Because otherwise if we think there aren't security concerns, we can leave it at false to maintain backwards compatibility.

Comment on lines +156 to +165
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try {
val processName = Application.getProcessName()
if (processName.endsWith(":OSInAppBrowser")) {
WebView.setDataDirectorySuffix("OSInAppBrowser")
}
} catch (e: Exception) {
Log.d(LOG_TAG, "Suffix already set or error: ${e.message}")
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What happens on versions below Android 9 (not applicable to OutSystems, applicable to Capacitor)?

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.

3 participants