Custom Tabs postMessage channel breaks after full-page navigation on Chrome 150 (worked on ≤ 149)
Environment
|
|
| androidx.browser |
<fill in, e.g. 1.8.0> |
| Works on |
Chrome for Android 137, and 149.0.7827.201 |
| Broken on |
Chrome for Android 150.0.7871.x (<fill in exact build>) |
| Repro |
Consistent across devices; confirmed by downgrading Chrome on the same device (150 → 149/137 restores it) |
Summary
We use the Custom Tabs / TWA postMessage bridge (per the official guide and the twa-post-message demo) for two-way native↔web communication.
It worked reliably through Chrome 149. Starting with Chrome 150, the postMessage channel is no longer usable after a full-page navigation / reload in the web content (e.g. logout, which does window.location → full document reload). This breaks all native↔web messaging until the app is restarted.
What works (Chrome ≤ 149, including 149.0.7827.201)
warmup() → newSession() → requestPostMessageChannel(origin, origin, extras).
onRelationshipValidationResult returns result = true.
onMessageChannelReady fires.
session.postMessage(...) returns RESULT_SUCCESS (0).
- Inbound web→native messages arrive in
onPostMessage.
- After a full-page reload (logout), on
NAVIGATION_FINISHED we re-request the channel, it re-entangles, and messaging resumes.
What breaks on Chrome 150
After a full-page reload (fresh document load in the same Custom Tab):
onNavigationEvent(NAVIGATION_FINISHED) fires as before.
requestPostMessageChannel(...) returns true.
onRelationshipValidationResult returns result = true (origin validates).
onMessageChannelReady fires.
- But
session.postMessage(...) returns -3 (RESULT_FAILURE_MESSAGING_ERROR), and no inbound web→native message is ever delivered (onPostMessage is never called for the new document).
- The channel never re-entangles for the reloaded document; it stays dead until the app is restarted.
So on Chrome 150 the API reports success at every step (channel requested → validated → "ready"), yet the actual message port is not usable for the freshly-loaded document.
Digital Asset Links are valid (misconfiguration ruled out)
use_as_origin verifies as linked for our origin via Google's checker:
GET https://digitalassetlinks.googleapis.com/v1/assetlinks:check
?source.web.site=https://<our-origin>
&relation=delegate_permission/common.use_as_origin
&target.android_app.package_name=<our.package>
&target.android_app.certificate.sha256_fingerprint=<our:fingerprint>
→ { "linked": true, "maxAge": "..." }
PostMessageService is declared with android:exported="true".
- Our integration matches the official
twa-post-message demo.
So this is not a manifest / asset-links / integration misconfiguration.
Additional observation on Chrome 150
Calling requestPostMessageChannel(...) appears to re-trigger onRelationshipValidationResult repeatedly, which did not happen on ≤ 149. If an app re-requests the channel from within onRelationshipValidationResult, this now creates a validate → request → validate loop that did not exist before — suggesting the validation/entanglement timing around requestPostMessageChannel changed in Chrome 150.
Expected behavior
After a full-page navigation, re-requesting the channel on NAVIGATION_FINISHED (with onMessageChannelReady firing and validation succeeding) should produce a usable channel — postMessage should return RESULT_SUCCESS and inbound messages should be delivered to onPostMessage, as on Chrome ≤ 149.
Actual behavior
onMessageChannelReady fires, but postMessage returns -3 and no inbound messages are delivered; the channel is never usable for the reloaded document.
Steps to reproduce
- Integrate postMessage per the official guide (bare
scheme://host origin, use_as_origin in assetlinks.json, PostMessageService exported).
- Establish the channel and confirm two-way messaging works.
- In the web content, trigger a full-page reload (e.g.
window.location.href = ..., as logout does).
- On
NAVIGATION_FINISHED, re-request the channel.
- Observe:
requestPostMessageChannel → true, validation → true, onMessageChannelReady fires, but postMessage → -3 and onPostMessage is never called.
- Downgrade Chrome to 149 / 137 → the same code works again.
Question
Was Custom Tabs postMessage / use_as_origin entanglement changed in Chrome 150 (possibly as part of the June 2026 Custom Tabs origin-validation security hardening)?
If so, what is the correct way for an app to re-establish a usable postMessage channel after a full-page navigation on Chrome 150+?
Custom Tabs postMessage channel breaks after full-page navigation on Chrome 150 (worked on ≤ 149)
Environment
<fill in, e.g. 1.8.0><fill in exact build>)Summary
We use the Custom Tabs / TWA postMessage bridge (per the official guide and the
twa-post-messagedemo) for two-way native↔web communication.It worked reliably through Chrome 149. Starting with Chrome 150, the postMessage channel is no longer usable after a full-page navigation / reload in the web content (e.g. logout, which does
window.location→ full document reload). This breaks all native↔web messaging until the app is restarted.What works (Chrome ≤ 149, including 149.0.7827.201)
warmup()→newSession()→requestPostMessageChannel(origin, origin, extras).onRelationshipValidationResultreturnsresult = true.onMessageChannelReadyfires.session.postMessage(...)returnsRESULT_SUCCESS (0).onPostMessage.NAVIGATION_FINISHEDwe re-request the channel, it re-entangles, and messaging resumes.What breaks on Chrome 150
After a full-page reload (fresh document load in the same Custom Tab):
onNavigationEvent(NAVIGATION_FINISHED)fires as before.requestPostMessageChannel(...)returnstrue.onRelationshipValidationResultreturnsresult = true(origin validates).onMessageChannelReadyfires.session.postMessage(...)returns-3(RESULT_FAILURE_MESSAGING_ERROR), and no inbound web→native message is ever delivered (onPostMessageis never called for the new document).So on Chrome 150 the API reports success at every step (channel requested → validated → "ready"), yet the actual message port is not usable for the freshly-loaded document.
Digital Asset Links are valid (misconfiguration ruled out)
use_as_originverifies as linked for our origin via Google's checker:PostMessageServiceis declared withandroid:exported="true".twa-post-messagedemo.So this is not a manifest / asset-links / integration misconfiguration.
Additional observation on Chrome 150
Calling
requestPostMessageChannel(...)appears to re-triggeronRelationshipValidationResultrepeatedly, which did not happen on ≤ 149. If an app re-requests the channel from withinonRelationshipValidationResult, this now creates avalidate → request → validateloop that did not exist before — suggesting the validation/entanglement timing aroundrequestPostMessageChannelchanged in Chrome 150.Expected behavior
After a full-page navigation, re-requesting the channel on
NAVIGATION_FINISHED(withonMessageChannelReadyfiring and validation succeeding) should produce a usable channel —postMessageshould returnRESULT_SUCCESSand inbound messages should be delivered toonPostMessage, as on Chrome ≤ 149.Actual behavior
onMessageChannelReadyfires, butpostMessagereturns-3and no inbound messages are delivered; the channel is never usable for the reloaded document.Steps to reproduce
scheme://hostorigin,use_as_origininassetlinks.json,PostMessageServiceexported).window.location.href = ..., as logout does).NAVIGATION_FINISHED, re-request the channel.requestPostMessageChannel→true, validation →true,onMessageChannelReadyfires, butpostMessage→-3andonPostMessageis never called.Question
Was Custom Tabs postMessage /
use_as_originentanglement changed in Chrome 150 (possibly as part of the June 2026 Custom Tabs origin-validation security hardening)?If so, what is the correct way for an app to re-establish a usable postMessage channel after a full-page navigation on Chrome 150+?