Skip to content

feat(android): opt-in Partial Custom Tab via androidCustomTabPartialHeightFraction#1119

Open
omeratt wants to merge 2 commits into
FormidableLabs:mainfrom
omeratt:feat/android-partial-custom-tabs
Open

feat(android): opt-in Partial Custom Tab via androidCustomTabPartialHeightFraction#1119
omeratt wants to merge 2 commits into
FormidableLabs:mainfrom
omeratt:feat/android-partial-custom-tabs

Conversation

@omeratt
Copy link
Copy Markdown

@omeratt omeratt commented May 22, 2026

Fixes #1118

Description

Adds an opt-in androidCustomTabPartialHeightFraction AuthConfiguration
field that, on Chrome 107+, renders the authorization Chrome Custom Tab as
a user-resizable bottom sheet at the caller-specified fraction of the
screen height — matching the modal feel of iOS's
ASWebAuthenticationSession. See #1118 for the UX motivation and
side-by-side screenshots.

The feature is gracefully degrading and zero-regression:

  • Unset (default) → no behavior change. Chrome renders the full-screen
    Custom Tab as today.
  • Set to a number in (0, 1] → between
    authService.createCustomTabsIntentBuilder() and .build(), the
    library calls
    setInitialActivityHeightPx(displayHeight * fraction, CustomTabsIntent.ACTIVITY_HEIGHT_ADJUSTABLE).
    Older Chrome silently ignores the extra and falls back to the
    full-screen Custom Tab — no crash, no warning, no behavior surprise.
  • Skipped when androidTrustedWebActivity is true (TWAs intentionally
    render full-screen).

What changed

File Change
packages/react-native-app-auth/index.d.ts New optional androidCustomTabPartialHeightFraction?: number on AuthConfiguration.
packages/react-native-app-auth/index.js Validation (must be a number in (0, 1], otherwise invariant throws); Android-only positional argument to the native bridge. iOS path is untouched (Platform.OS === 'android' guard).
packages/react-native-app-auth/android/build.gradle Bumps androidx.browser:browser 1.4.0 → 1.5.0 for the setInitialActivityHeightPx API.
packages/react-native-app-auth/android/src/main/java/com/rnappauth/RNAppAuthModule.java Threads the fraction through authorize and authorizeWithConfiguration; conditionally calls setInitialActivityHeightPx between builder creation and .build().
packages/react-native-app-auth/index.spec.js 5 new tests on the Android-specific describe block (valid fraction passthrough; default null; throw on non-number; throw on ≤ 0; throw on > 1). Updates the existing 5 native-bridge assertions to include the new positional arg.
docs/docs/usage/config.md Documents the new option, the Chrome 107+ floor, and the prefetchConfiguration warmup recommendation needed for the bottom sheet to render on the first invocation.
.changeset/android-partial-custom-tabs.md Minor bump changeset (additive, opt-in, backward compatible).

Usage

import { authorize, prefetchConfiguration } from 'react-native-app-auth';

const config = {
  issuer: 'https://accounts.google.com',
  clientId: '<YOUR_CLIENT_ID>',
  redirectUrl: '<YOUR_REDIRECT_URL>',
  scopes: ['openid', 'email'],
  androidCustomTabPartialHeightFraction: 0.85, // 85% of screen height on Chrome 107+
};

// On the screen that will invoke authorize(), call prefetchConfiguration on
// mount so the bottom sheet renders on the first tap (otherwise Chrome's
// first launch falls back to full-screen; subsequent launches get the sheet).
useEffect(() => {
  prefetchConfiguration({ warmAndPrefetchChrome: true, ...config });
}, []);

// Later, on user tap:
const result = await authorize(config);

Steps to verify

  1. yarn install at the repo root, then in packages/react-native-app-auth/:
    • yarn lint → passes (no new warnings introduced by this PR).
    • yarn test → 78 tests pass, including 5 new tests for
      androidCustomTabPartialHeightFraction validation + native-bridge
      passthrough.
  2. Build the example app on an Android emulator running Chrome 107+ (the
    repo's CI emulator at API 35 ships Chrome 147, which works). Add
    androidCustomTabPartialHeightFraction: 0.85 to the example config and
    call prefetchConfiguration on screen mount, then tap the authorize
    button → the Chrome Custom Tab renders as a bottom sheet at ~85% of the
    screen height; the host activity is visible behind it; the user can
    drag the sheet up to full-screen via the handle. Cancel via the X
    button → returns to the host app.
  3. Smoke the fallback path: with androidCustomTabPartialHeightFraction
    unset, the flow renders full-screen exactly as before this PR.
  4. Smoke a Trusted Web Activity flow with the option set → the option is
    ignored (TWA renders full-screen as before).
  5. TypeScript: import { AuthConfiguration } and try
    { androidCustomTabPartialHeightFraction: 0.85 } satisfies AuthConfiguration
    → typechecks; { androidCustomTabPartialHeightFraction: 'half' }
    type error. Confirms the index.d.ts change is correct.

Tests, README, and TypeScript definitions are updated.

…eightFraction

Adds an optional fraction-based config that renders the Chrome Custom Tab as
a user-resizable bottom sheet on Chrome 107+, matching the modal feel of
iOS's ASWebAuthenticationSession. When omitted, behavior is unchanged.

- index.d.ts: new optional `androidCustomTabPartialHeightFraction: number`
- index.js: validation (must be a number in (0, 1]) + Android-only bridge arg
- RNAppAuthModule.java: threads the fraction through `authorize` and
  `authorizeWithConfiguration`; between `createCustomTabsIntentBuilder()` and
  `build()`, calls `setInitialActivityHeightPx(displayHeight * fraction,
  ACTIVITY_HEIGHT_ADJUSTABLE)` when the fraction is non-null and the request
  is not a Trusted Web Activity
- android/build.gradle: bump androidx.browser:browser 1.4.0 -> 1.5.0 for the
  setInitialActivityHeightPx API
- docs/usage/config.md: documents the new option, the Chrome 107+ floor,
  and the prefetchConfiguration warmup recommendation for first-launch
- index.spec.js: 5 new tests for the option (valid fraction passthrough,
  default null, invalid type, fraction <= 0, fraction > 1) + updates the
  existing 5 native-bridge assertions to include the new positional arg
- changeset: minor bump (additive, opt-in, backward compatible)
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 22, 2026

🦋 Changeset detected

Latest commit: 14239ab

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
react-native-app-auth Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown

vercel Bot commented May 22, 2026

@omeratt is attempting to deploy a commit to the formidable-labs Team on Vercel.

A member of the Team first needs to authorize it.

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.

Android: opt-in Partial Custom Tab (bottom-sheet) for the authorization flow

1 participant