Skip to content

Commit 9266ecc

Browse files
committed
Remove browser warmup functionality from all platforms
Eliminates the warmup API, implementation, and documentation for both Android and iOS. Removes related code, hooks, and references, including the CustomTabsConnection and BrowserWarmupCoordinator classes. Updates the README and example app to reflect the removal of warmup, focusing on streamlined browser session management and improved code clarity.
1 parent da58143 commit 9266ecc

15 files changed

Lines changed: 171 additions & 224 deletions

README.md

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ Lightning-fast, modern in-app browser for React Native powered by Nitro Modules.
3232
- Fully typed TypeScript API plus ergonomic React hook helpers.
3333
-**iOS 26 ready**: high-contrast dynamic colors, edge-dismiss control, and UI style overrides.
3434
-**Android 16 ready**: partial custom tabs, referrer controls, and per-theme palettes.
35-
- Authentication-first design with ephemeral sessions, warmup, and graceful fallbacks.
35+
- Authentication-first design with ephemeral sessions and graceful fallbacks.
3636
- Works great with Hermes, Fabric, and the React Native New Architecture.
3737

3838
## Platform Support
3939

4040
| Platform | Minimum | Targeted | Highlights |
4141
|----------|---------|----------|------------|
4242
| iOS | 11.0 | 17 / 26* | SafariViewController + ASWebAuthentication support. |
43-
| Android | API 23 | API 34 / 16* | Chrome Custom Tabs with warmup and dynamic theming. |
43+
| Android | API 23 | API 34 / 16* | Chrome Custom Tabs with dynamic theming. |
4444
| React Native | 0.70.0 | Latest | Nitro Modules + TypeScript bindings. |
4545

4646
\* iOS 26 and Android 16 features are automatically gated behind runtime checks.
@@ -113,22 +113,6 @@ export function LaunchButton() {
113113
}
114114
```
115115

116-
### Warmup & Prefetch
117-
118-
```tsx
119-
import { useEffect } from 'react'
120-
import { InAppBrowser } from 'react-native-inappbrowser-nitro'
121-
122-
export function useBrowserWarmup() {
123-
useEffect(() => {
124-
InAppBrowser.warmup({
125-
toolbarColor: { base: '#0EA5E9' },
126-
includeReferrer: true,
127-
}).catch(console.warn)
128-
}, [])
129-
}
130-
```
131-
132116
### Authentication Flow (OAuth / SSO)
133117

134118
```tsx
@@ -177,17 +161,7 @@ If you depended on awaiting dismissal, refactor to handle completion via deep li
177161
+InAppBrowser.open(url, { toolbarColor: { base: '#6200EE', dark: '#3700B3' } })
178162
```
179163

180-
### 3. Use `warmup()` instead of manual Custom Tabs priming
181-
182-
Chrome warmup is wrapped in a cross-platform helper. Call it during app boot or screen focus:
183-
184-
```tsx
185-
useEffect(() => {
186-
InAppBrowser.warmup({ toolbarColor: { base: '#0EA5E9' } }).catch(console.warn)
187-
}, [])
188-
```
189-
190-
### 4. Prefer the hook for loading/error handling
164+
### 3. Prefer the hook for loading/error handling
191165

192166
`useInAppBrowser` wraps the imperative API with loading state and error capture, aligning with the new async semantics.
193167

@@ -197,7 +171,7 @@ useEffect(() => {
197171
+const handleOpen = () => open(url)
198172
```
199173

200-
### 5. Regenerate bindings after upgrading
174+
### 4. Regenerate bindings after upgrading
201175

202176
Run `yarn codegen && yarn build` (or your project script) to regenerate Nitro bindings so the new enums and options are available on both platforms.
203177

@@ -210,7 +184,6 @@ Run `yarn codegen && yarn build` (or your project script) to regenerate Nitro bi
210184
| `openAuth(url, redirectUrl, options?)` | Open an OAuth/SSO flow that resolves once the redirect URL is reached. |
211185
| `close()` | Programmatically dismiss an open browser session. |
212186
| `closeAuth()` | Abort an authentication session. |
213-
| `warmup(options?)` | Pre-initialize native resources to improve first paint. |
214187

215188
All functions return Promises and are fully typed. See `src/core/InAppBrowser.ts` for the higher-level wrapper implementation.
216189

android/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ dependencies {
137137

138138
// Add a dependency on NitroModules
139139
implementation project(":react-native-nitro-modules")
140+
141+
implementation "androidx.browser:browser:1.7.0"
142+
implementation "androidx.core:core-ktx:1.13.1"
140143
}
141144

142145
if (isNewArchitectureEnabled()) {
Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,109 @@
11
package com.inappbrowsernitro
22

3+
import android.app.Activity
4+
import android.content.ActivityNotFoundException
5+
import android.content.Context
6+
import android.content.Intent
7+
import android.net.Uri
8+
import androidx.browser.customtabs.CustomTabsIntent
9+
import com.inappbrowsernitro.browser.BrowserFallback
10+
import com.inappbrowsernitro.browser.CustomTabsIntentFactory
11+
import com.inappbrowsernitro.browser.CustomTabsPackageHelper
12+
import com.margelo.nitro.NitroModules
13+
import com.margelo.nitro.core.Promise
14+
import com.margelo.nitro.inappbrowsernitro.BrowserResultType
315
import com.margelo.nitro.inappbrowsernitro.HybridInappbrowserNitroSpec
16+
import com.margelo.nitro.inappbrowsernitro.InAppBrowserAuthResult
17+
import com.margelo.nitro.inappbrowsernitro.InAppBrowserOptions
18+
import com.margelo.nitro.inappbrowsernitro.InAppBrowserResult
19+
import kotlinx.coroutines.Dispatchers
20+
import kotlinx.coroutines.withContext
421

5-
class HybridInappbrowserNitro: HybridInappbrowserNitroSpec() {
6-
override fun sum(num1: Double, num2: Double): Double {
7-
return num1 + num2
22+
class HybridInappbrowserNitro : HybridInappbrowserNitroSpec() {
23+
private val reactContext get() = NitroModules.applicationContext
24+
private val applicationContext: Context?
25+
get() = reactContext ?: NitroModules.applicationContext
26+
27+
override fun isAvailable(): Promise<Boolean> {
28+
val context = applicationContext ?: return Promise.resolved(false)
29+
val customTabsPackage = CustomTabsPackageHelper.resolvePackage(context, null)
30+
if (customTabsPackage != null) {
31+
return Promise.resolved(true)
32+
}
33+
34+
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(SCHEME_CHECK_URL))
35+
val canHandle = intent.resolveActivity(context.packageManager) != null
36+
return Promise.resolved(canHandle)
37+
}
38+
39+
override fun open(url: String, options: InAppBrowserOptions?): Promise<InAppBrowserResult> {
40+
return Promise.async {
41+
openInternal(url, options)
42+
}
43+
}
44+
45+
override fun openAuth(url: String, redirectUrl: String, options: InAppBrowserOptions?): Promise<InAppBrowserAuthResult> {
46+
return Promise.async {
47+
val result = openInternal(url, options)
48+
InAppBrowserAuthResult(result.type, result.url, result.message)
49+
}
50+
}
51+
52+
override fun close(): Promise<Unit> {
53+
return Promise.resolved(Unit)
54+
}
55+
56+
override fun closeAuth(): Promise<Unit> {
57+
return Promise.resolved(Unit)
58+
}
59+
60+
private suspend fun openInternal(url: String, options: InAppBrowserOptions?): InAppBrowserResult {
61+
val context = applicationContext ?: return dismiss("React context unavailable")
62+
val parsedUri = runCatching { Uri.parse(url) }.getOrNull()
63+
?: return dismiss("Invalid URL: $url")
64+
65+
val intent = CustomTabsIntentFactory(context, null).create(options)
66+
val launchContext = reactContext?.currentActivity ?: context
67+
val launched = launchCustomTab(intent, launchContext, parsedUri)
68+
69+
if (launched) {
70+
return InAppBrowserResult(BrowserResultType.SUCCESS, parsedUri.toString(), null)
71+
}
72+
73+
val fallbackLaunched = (launchContext as? Activity)?.let { launchFallback(it, url) } ?: false
74+
return if (fallbackLaunched) {
75+
InAppBrowserResult(BrowserResultType.SUCCESS, parsedUri.toString(), null)
76+
} else {
77+
dismiss("No browser available to handle $url")
78+
}
79+
}
80+
81+
private suspend fun launchCustomTab(intent: CustomTabsIntent, context: Context, uri: Uri): Boolean {
82+
return withContext(Dispatchers.Main) {
83+
try {
84+
if (context !is Activity) {
85+
intent.intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
86+
}
87+
intent.launchUrl(context, uri)
88+
true
89+
} catch (_: ActivityNotFoundException) {
90+
false
91+
}
92+
}
93+
}
94+
95+
private fun launchFallback(activity: Activity, url: String): Boolean {
96+
val fallback = BrowserFallback(activity)
97+
if (fallback.openSystemBrowser(url)) return true
98+
if (fallback.openChooser(url)) return true
99+
return fallback.redirectToStore()
100+
}
101+
102+
private fun dismiss(message: String): InAppBrowserResult {
103+
return InAppBrowserResult(BrowserResultType.DISMISS, null, message)
104+
}
105+
106+
private companion object {
107+
private const val SCHEME_CHECK_URL = "https://example.com"
8108
}
9109
}

android/src/main/java/com/inappbrowsernitro/browser/CustomTabsConnection.kt

Lines changed: 0 additions & 87 deletions
This file was deleted.
Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package com.inappbrowsernitro.browser
22

33
import android.content.Context
4-
import android.content.Intent
5-
import android.net.Uri
64
import androidx.browser.customtabs.CustomTabsClient
75

86
internal object CustomTabsPackageHelper {
@@ -11,10 +9,6 @@ internal object CustomTabsPackageHelper {
119
return preferred
1210
}
1311

14-
return CustomTabsClient.getPackageName(context, buildIntent())
15-
}
16-
17-
private fun buildIntent(): Intent {
18-
return Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"))
12+
return CustomTabsClient.getPackageName(context, null)
1913
}
2014
}

android/src/main/java/com/inappbrowsernitro/browser/DynamicColorResolver.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package com.inappbrowsernitro.browser
22

33
import android.content.Context
44
import android.graphics.Color
5-
import android.os.Build
65
import android.view.accessibility.AccessibilityManager
76
import androidx.core.content.getSystemService
87
import com.margelo.nitro.inappbrowsernitro.DynamicColor
@@ -12,7 +11,12 @@ internal object DynamicColorResolver {
1211
dynamicColor ?: return null
1312

1413
val accessibilityManager = context.getSystemService<AccessibilityManager>()
15-
val isHighContrast = accessibilityManager?.isHighTextContrastEnabled == true
14+
val isHighContrast = accessibilityManager?.let { manager ->
15+
runCatching {
16+
val method = AccessibilityManager::class.java.getMethod("isHighTextContrastEnabled")
17+
(method.invoke(manager) as? Boolean) == true
18+
}.getOrDefault(false)
19+
} == true
1620

1721
val isDark = (context.resources.configuration.uiMode and android.content.res.Configuration.UI_MODE_NIGHT_MASK) == android.content.res.Configuration.UI_MODE_NIGHT_YES
1822

0 commit comments

Comments
 (0)