diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index b0448b0..454c890 100644 --- a/.github/workflows/android-build.yml +++ b/.github/workflows/android-build.yml @@ -14,7 +14,7 @@ on: - 'nitrogen/generated/android/**' - 'cpp/**' - 'android/**' - - '**/bun.lock' + - '**/yarn.lock' - '**/react-native.config.js' - '**/nitro.json' pull_request: @@ -25,7 +25,7 @@ on: - '**/nitrogen/generated/android/**' - 'cpp/**' - 'android/**' - - '**/bun.lock' + - '**/yarn.lock' - '**/react-native.config.js' - '**/nitro.json' workflow_dispatch: @@ -39,10 +39,15 @@ jobs: name: Build Android Example App runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v5 + + - name: Enable Corepack + run: corepack enable + + - uses: actions/setup-node@v5 with: - node-version: '20' + node-version: '24' + cache: 'yarn' - name: Install dependencies (yarn) run: yarn install --immutable @@ -50,11 +55,11 @@ jobs: - name: Generate Nitro bindings run: yarn codegen - - name: Setup JDK 17 + - name: Setup JDK 21 uses: actions/setup-java@v5 with: distribution: 'zulu' - java-version: '17' + java-version: '21' cache: 'gradle' - name: Cache Gradle diff --git a/.github/workflows/ios-build.yml b/.github/workflows/ios-build.yml index 33ce6ee..72d5a43 100644 --- a/.github/workflows/ios-build.yml +++ b/.github/workflows/ios-build.yml @@ -17,7 +17,7 @@ on: - 'cpp/**' - 'ios/**' - '**/Podfile.lock' - - '**/bun.lock' + - '**/yarn.lock' - '**/*.podspec' - '**/react-native.config.js' - '**/nitro.json' @@ -32,7 +32,7 @@ on: - 'cpp/**' - 'ios/**' - '**/Podfile.lock' - - '**/bun.lock' + - '**/yarn.lock' - '**/*.podspec' - '**/react-native.config.js' - '**/nitro.json' @@ -48,16 +48,21 @@ concurrency: jobs: build: name: Build iOS Example App - runs-on: macOS-15 + runs-on: macos-26 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v5 + + - name: Enable Corepack + run: corepack enable + + - uses: actions/setup-node@v5 with: - node-version: '20' + node-version: '24' + cache: 'yarn' - name: Setup Xcode uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: 16.4 + xcode-version: '26.2' - name: Install dependencies (yarn) run: yarn install --immutable @@ -68,7 +73,7 @@ jobs: - name: Setup Ruby (bundle) uses: ruby/setup-ruby@v1 with: - ruby-version: '3.2' + ruby-version: '3.4' bundler-cache: true working-directory: example/ios diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d081834..a619ec8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,27 +21,25 @@ jobs: id-token: write steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 - - name: Setup Bun.js - uses: oven-sh/setup-bun@v2 - with: - bun-version: latest - - name: Cache bun dependencies - id: bun-cache - uses: actions/cache@v4 + + - name: Enable Corepack + run: corepack enable + + - name: Setup Node.js + uses: actions/setup-node@v5 with: - path: ~/.bun/install/cache - key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }} - restore-keys: | - ${{ runner.os }}-bun- + node-version: '24' + cache: 'yarn' + registry-url: 'https://registry.npmjs.org' - - name: Install npm dependencies (bun) - run: bun install + - name: Install dependencies (yarn) + run: yarn install --immutable - name: Build lib - run: bun run build + run: yarn build - name: Release env: @@ -52,4 +50,4 @@ jobs: GIT_AUTHOR_EMAIL: '${{ github.actor }}@users.noreply.github.com' GIT_COMMITTER_NAME: ${{ github.actor }} GIT_COMMITTER_EMAIL: '${{ github.actor }}@users.noreply.github.com' - run: bun release + run: yarn release diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..9841c7a --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +yarn lint-staged diff --git a/README.md b/README.md index 947f22b..a5e7aa1 100644 --- a/README.md +++ b/README.md @@ -1,324 +1,371 @@ -# react-native-inappbrowser-nitro - -[![npm version](https://img.shields.io/npm/v/react-native-inappbrowser-nitro.svg?style=flat-square)](https://www.npmjs.com/package/react-native-inappbrowser-nitro) -[![npm downloads](https://img.shields.io/npm/dm/react-native-inappbrowser-nitro.svg?style=flat-square)](https://www.npmjs.com/package/react-native-inappbrowser-nitro) -[![license](https://img.shields.io/npm/l/react-native-inappbrowser-nitro.svg?style=flat-square)](LICENSE) +
-Lightning-fast, modern in-app browser for React Native powered by Nitro Modules. Enjoy direct JSI bindings, zero bridge overhead, and polished native browser UX on both iOS and Android. +# react-native-inappbrowser-nitro -
- InAppBrowser Nitro Demo -
+**A modern, native in-app browser for React Native — built on [Nitro Modules](https://nitro.margelo.com/).** -## Contents +[![npm version](https://img.shields.io/npm/v/react-native-inappbrowser-nitro?style=flat-square&color=0a7ea4)](https://www.npmjs.com/package/react-native-inappbrowser-nitro) +[![npm downloads](https://img.shields.io/npm/dm/react-native-inappbrowser-nitro?style=flat-square&color=0a7ea4)](https://www.npmjs.com/package/react-native-inappbrowser-nitro) +[![bundle size](https://img.shields.io/bundlephobia/minzip/react-native-inappbrowser-nitro?style=flat-square&label=min%2Bgzip)](https://bundlephobia.com/package/react-native-inappbrowser-nitro) +[![license](https://img.shields.io/npm/l/react-native-inappbrowser-nitro?style=flat-square&color=0a7ea4)](./LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/mCodex/react-native-inappbrowser-nitro/ios-build.yml?style=flat-square&label=iOS)](https://github.com/mCodex/react-native-inappbrowser-nitro/actions/workflows/ios-build.yml) +[![CI](https://img.shields.io/github/actions/workflow/status/mCodex/react-native-inappbrowser-nitro/android-build.yml?style=flat-square&label=Android)](https://github.com/mCodex/react-native-inappbrowser-nitro/actions/workflows/android-build.yml) -- [Highlights](#highlights) -- [Platform Support](#platform-support) -- [Installation](#installation) -- [Usage](#usage) -- [Migration Guide (pre-Nitro → latest)](#migration-guide-pre-nitro--latest) -- [API Surface](#api-surface) -- [Options Reference](#options-reference) -- [Dynamic Color Palettes](#dynamic-color-palettes) -- [Security & Emulator Notes](#security--emulator-notes) -- [Troubleshooting](#troubleshooting) -- [Contributing](#contributing) -- [License](#license) +[**Installation**](#installation) · +[**Quick start**](#quick-start) · +[**API**](#api) · +[**Options**](#options) · +[**Migration**](#migrating-from-react-native-inappbrowser-reborn) · +[**FAQ**](#faq) -## Highlights +Demo -- TurboModule-first implementation with native-speed execution and zero bridge overhead. -- Fully typed TypeScript API plus ergonomic React hook helpers. -- ✅ **iOS 26 ready**: high-contrast dynamic colors, edge-dismiss control, and UI style overrides. -- ✅ **Android 16 ready**: partial custom tabs, referrer controls, and per-theme palettes. -- Authentication-first design with ephemeral sessions and graceful fallbacks. -- Works great with Hermes, Fabric, and the React Native New Architecture. +
-## Platform Support +--- -| Platform | Minimum | Targeted | Highlights | -|----------|---------|----------|------------| -| iOS | 11.0 | 17 / 26* | SafariViewController + ASWebAuthentication support. | -| Android | API 23 | API 34 / 16* | Chrome Custom Tabs with dynamic theming. | -| React Native | 0.70.0 | Latest | Nitro Modules + TypeScript bindings. | +## Why this library? -\* iOS 26 and Android 16 features are automatically gated behind runtime checks. +| | | +|---|---| +| ⚡ **Native speed** | Direct JSI bindings via Nitro Modules — no JSON bridge, no scheduler hops. | +| 🎯 **Right primitive on each platform** | `SFSafariViewController` on iOS, Chrome **Custom Tabs** on Android — not a `WKWebView` reimplementation. | +| 🔐 **OAuth-ready** | First-class `openAuth` flow with ephemeral sessions and redirect interception. | +| 🪝 **Hook + imperative APIs** | `useInAppBrowser()` for component state, named exports for everything else. | +| 🧩 **Strict TypeScript** | Discriminated result types, dual `as const` + literal-type enums, full JSDoc with examples. | +| 📦 **Small footprint** | `"sideEffects": false`, ESM-first build, lazy-initialized native module. | -> **Expo** is not supported because Nitro modules require native compilation. +--- -## Android Browser Fallback +## Requirements -
-Browser selection logic on Android +| | Minimum | Tested up to | +|---|---|---| +| React Native | `0.75` (New Architecture) | `0.85` | +| iOS | `15.1` | `26.2` | +| Android | API `23` (Android 6) | API `36` (Android 16) | +| `react-native-nitro-modules` | `0.35` | `0.35.4` | -On Android, the library prioritizes Chrome Custom Tabs for the best user experience when Chrome is installed. If Chrome is not available (e.g., on Samsung devices), it falls back to opening the URL in the device's default web browser using the standard `Intent.ACTION_VIEW` mechanism. +> [!IMPORTANT] +> This library requires the **React Native New Architecture** and is **not compatible with Expo Go**. It works in [Expo prebuild / dev clients](https://docs.expo.dev/develop/development-builds/introduction/). -This ensures compatibility across devices while maintaining optimal performance with Chrome when possible. -
+--- ## Installation ```sh -npm install react-native-inappbrowser-nitro react-native-nitro-modules +yarn add react-native-inappbrowser-nitro react-native-nitro-modules ``` -or +
+npm / pnpm / bun ```sh -yarn add react-native-inappbrowser-nitro react-native-nitro-modules +npm install react-native-inappbrowser-nitro react-native-nitro-modules +pnpm add react-native-inappbrowser-nitro react-native-nitro-modules +bun add react-native-inappbrowser-nitro react-native-nitro-modules ``` +
+ ### iOS ```sh -cd ios -pod install +cd ios && pod install ``` ### Android -No additional steps—Gradle autolinking handles everything. +Autolinking handles everything. No manual `MainApplication` edits required. + +--- -## Usage +## Quick start ### Imperative API ```tsx import { isAvailable, open } from 'react-native-inappbrowser-nitro' -async function openDocs() { - if (!(await isAvailable())) { - console.warn('No compatible browser found') - return - } - - const result = await open('https://nitro.margelo.com', { - preferredBarTintColor: { base: '#111827', light: '#1F2933', highContrast: '#000000' }, - preferredControlTintColor: { base: '#F9FAFB', highContrast: '#FFD700' }, // iOS 26+ - toolbarColor: { base: '#2563EB', dark: '#1E3A8A' }, - enablePartialCustomTab: true, // Android 16+ +if (await isAvailable()) { + const result = await open('https://github.com', { + preferredBarTintColor: { light: '#FFFFFF', dark: '#000000' }, // iOS + toolbarColor: { light: '#FFFFFF', dark: '#000000' }, // Android + readerMode: true, }) - console.log(result) + if (result.type === 'success') { + console.log('Opened', result.url) + } } ``` -### React Hook +### React hook ```tsx -import { useInAppBrowser } from 'react-native-inappbrowser-nitro' +import { useInAppBrowser } from 'react-native-inappbrowser-nitro/hooks' -export function LaunchButton() { +function DocsButton() { const { open, isLoading, error } = useInAppBrowser() return ( -