Skip to content

com.oculus.browser does not implement CustomTabsService — Platform SDK JS bridge blocked #25

@textoo

Description

@textoo

Summary

It is currently impossible to expose the Meta Horizon Platform SDK to a PWA's
JavaScript context from a Bubblewrap-packaged app running on Meta Quest, because
com.oculus.browser does not implement CustomTabsService.

Device & environment

  • Device: Meta Quest 3
  • HorizonOS: Android 14
  • Bubblewrap: meta-quest fork (latest)
  • com.oculus.browser: system browser

What we tried

We investigated every available mechanism to bridge the Platform SDK
(android-platform-sdk:77) to JavaScript running inside the TWA:

1. postMessage via CustomTabsSession — blocked

The TWA postMessage API (requestPostMessageChannel) requires CustomTabsService,
which is not implemented by com.oculus.browser:

W ActivityManager: Unable to start service Intent {
  act=android.support.customtabs.action.CustomTabsService
  pkg=com.oculus.browser
} U=0: not found

bindCustomTabsService() returns null, the channel never opens,
and no JS can be injected into the page.

2. JavascriptInterface — blocked

TWAs delegate rendering to the system browser. There is no WebView instance
in the Android view hierarchy to call addJavascriptInterface() on.

3. ExtraCommandHandler / TrustedWebActivityCallbackRemote — JS side not exposed

DelegationService.onExtraCommand() works on the native side, but
com.oculus.browser does not expose any corresponding JS API
(navigator.sendExtraCommand is undefined, no window.trustedWebActivity
or similar object is injected into the page).

4. WebViewFallbackActivity — never triggered

Quest's TWA implementation does not fall back to WebViewFallbackActivity
even when fallbackType = "webview" is set in the manifest. The app always
launches through LauncherActivity using the system browser.

Impact

This blocks the entire Platform SDK surface from being accessible in PWAs:

  • Users.getLoggedInUser() — user identity / alias
  • Leaderboards.getEntries() / writeEntry() — leaderboards
  • Achievements.unlock() — achievements
  • IAP.getViewerPurchases() — in-app purchases

These are core social and monetisation features that native apps access trivially.
PWAs on Quest have no equivalent path today.

What would fix this

Any one of the following would unblock the JS bridge:

  1. com.oculus.browser implements CustomTabsService — the postMessage
    channel would open and the bridge would work immediately with no changes
    to Bubblewrap.

  2. An official JS API injected by the browser — similar to how Chrome injects
    APIs in TWA contexts, Quest's browser could expose a window.HorizonPlatform
    or navigator.sendExtraCommand surface backed by the Platform SDK.

  3. A documented WebView-based packaging mode — an officially supported
    alternative to TWA for Quest that gives the app direct WebView access,
    while remaining Store-compliant.

Question for the Meta browser / Bubblewrap team

Is support for CustomTabsService in com.oculus.browser on the roadmap?
Is there an alternative approach we may have missed?

We are happy to contribute a Bubblewrap implementation the moment a supported
mechanism is available.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions