Skip to content

Commit 7de6fd6

Browse files
authored
Merge pull request #90 from mCodex/refactor/src-dry-kiss-srp-nitro-035
Refactor/src dry kiss srp nitro 035
2 parents 388038b + f6f6577 commit 7de6fd6

49 files changed

Lines changed: 3871 additions & 5617 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/FUNDING.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# These are supported funding model platforms
2+
3+
github: [mcodex]
4+
patreon: # Replace with a single Patreon username
5+
open_collective: # Replace with a single Open Collective username
6+
ko_fi: # Replace with a single Ko-fi username
7+
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8+
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9+
liberapay: # Replace with a single Liberapay username
10+
issuehunt: # Replace with a single IssueHunt username
11+
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12+
polar: # Replace with a single Polar username
13+
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14+
thanks_dev: # Replace with a single thanks.dev username
15+
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

.github/workflows/ios-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,6 @@ jobs:
9999
-scheme InappbrowserNitroExample \
100100
-sdk iphonesimulator \
101101
-configuration Debug \
102-
-destination 'platform=iOS Simulator,name=iPhone 16' \
102+
-destination 'generic/platform=iOS Simulator' \
103103
build \
104104
CODE_SIGNING_ALLOWED=NO | xcpretty

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,10 @@ android/keystores/debug.keystore
7676
lib/
7777
tsconfig.tsbuildinfo
7878

79+
# stray tsc output in sources (should never be committed)
80+
src/**/*.js
81+
src/**/*.js.map
82+
src/**/*.d.ts
83+
src/**/*.d.ts.map
84+
7985
nitrogen/

README.md

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,15 @@ No additional steps—Gradle autolinking handles everything.
8484
### Imperative API
8585

8686
```tsx
87-
import { InAppBrowser } from 'react-native-inappbrowser-nitro'
87+
import { isAvailable, open } from 'react-native-inappbrowser-nitro'
8888

8989
async function openDocs() {
90-
if (!(await InAppBrowser.isAvailable())) {
90+
if (!(await isAvailable())) {
9191
console.warn('No compatible browser found')
9292
return
9393
}
9494

95-
const result = await InAppBrowser.open('https://nitro.margelo.com', {
95+
const result = await open('https://nitro.margelo.com', {
9696
preferredBarTintColor: { base: '#111827', light: '#1F2933', highContrast: '#000000' },
9797
preferredControlTintColor: { base: '#F9FAFB', highContrast: '#FFD700' }, // iOS 26+
9898
toolbarColor: { base: '#2563EB', dark: '#1E3A8A' },
@@ -125,7 +125,9 @@ export function LaunchButton() {
125125
### Authentication Flow (OAuth / SSO)
126126

127127
```tsx
128-
const result = await InAppBrowser.openAuth(
128+
import { openAuth } from 'react-native-inappbrowser-nitro'
129+
130+
const result = await openAuth(
129131
'https://provider.com/oauth/authorize?client_id=abc',
130132
'myapp://oauth/callback',
131133
{
@@ -144,6 +146,34 @@ if (result.type === 'success' && result.url) {
144146

145147
Migrating from earlier `react-native-inappbrowser-nitro` versions? Note these key changes when adopting the Nitro rewrite:
146148

149+
### Migrating to v3 (named exports)
150+
151+
The `InAppBrowser` static class has been replaced with individual named exports for better tree shaking. Update your imports:
152+
153+
```diff
154+
-import { InAppBrowser } from 'react-native-inappbrowser-nitro'
155+
+import { open, openAuth, close, closeAuth, isAvailable } from 'react-native-inappbrowser-nitro'
156+
157+
-InAppBrowser.open(url, options)
158+
+open(url, options)
159+
160+
-InAppBrowser.openAuth(url, redirectUrl, options)
161+
+openAuth(url, redirectUrl, options)
162+
163+
-InAppBrowser.close()
164+
+close()
165+
166+
-InAppBrowser.closeAuth()
167+
+closeAuth()
168+
169+
-InAppBrowser.isAvailable()
170+
+isAvailable()
171+
```
172+
173+
The hook import is unchanged: `import { useInAppBrowser } from 'react-native-inappbrowser-nitro'`
174+
175+
---
176+
147177
### 1. `open()` resolves on presentation
148178

149179
Older releases resolved the promise when the browser closed. The new implementation resolves as soon as Safari/Custom Tabs is shown (mirroring Android behavior), and dismissal status is delivered asynchronously.
@@ -194,7 +224,7 @@ Run `yarn codegen && yarn build` (or your project script) to regenerate Nitro bi
194224
| `close()` | Programmatically dismiss an open browser session. |
195225
| `closeAuth()` | Abort an authentication session. |
196226

197-
All functions return Promises and are fully typed. See `src/core/InAppBrowser.ts` for the higher-level wrapper implementation.
227+
All functions return Promises and are fully typed. See `src/core/native.ts` for the native module wrapper implementation.
198228

199229
## Options Reference
200230

android/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ dependencies {
139139
implementation project(":react-native-nitro-modules")
140140

141141
implementation "androidx.browser:browser:1.7.0"
142+
implementation "androidx.core:core:1.13.1"
142143
implementation "androidx.core:core-ktx:1.13.1"
143144
}
144145

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#include <jni.h>
2+
#include <fbjni/fbjni.h>
23
#include "InappbrowserNitroOnLoad.hpp"
34

45
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
5-
return margelo::nitro::inappbrowsernitro::initialize(vm);
6+
return facebook::jni::initialize(vm, [] {
7+
margelo::nitro::inappbrowsernitro::registerAllNatives();
8+
});
69
}

android/src/main/java/com/inappbrowsernitro/HybridInappbrowserNitro.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ import kotlinx.coroutines.Dispatchers
2020
import kotlinx.coroutines.withContext
2121

2222
class HybridInappbrowserNitro : HybridInappbrowserNitroSpec() {
23-
private val reactContext get() = NitroModules.applicationContext
24-
private val applicationContext: Context?
25-
get() = reactContext ?: NitroModules.applicationContext
23+
private val applicationContext get() = NitroModules.applicationContext
2624

2725
override fun isAvailable(): Promise<Boolean> {
2826
val context = applicationContext ?: return Promise.resolved(false)
@@ -50,10 +48,12 @@ class HybridInappbrowserNitro : HybridInappbrowserNitroSpec() {
5048
}
5149

5250
override fun close(): Promise<Unit> {
51+
// Custom Tabs runs in a separate Activity; close is handled by the user navigating back.
5352
return Promise.resolved(Unit)
5453
}
5554

5655
override fun closeAuth(): Promise<Unit> {
56+
// Custom Tabs runs in a separate Activity; close is handled by the user navigating back.
5757
return Promise.resolved(Unit)
5858
}
5959

@@ -63,9 +63,9 @@ class HybridInappbrowserNitro : HybridInappbrowserNitroSpec() {
6363
?: return dismiss("Invalid URL: $url")
6464

6565
val customTabsPackage = CustomTabsPackageHelper.resolvePackage(context, null)
66-
val launchContext = reactContext?.currentActivity ?: context
66+
val launchContext = applicationContext?.currentActivity ?: context
6767

68-
if (customTabsPackage == "com.android.chrome") {
68+
if (customTabsPackage != null) {
6969
val intent = CustomTabsIntentFactory(context, null).create(options)
7070
intent.intent.setPackage(customTabsPackage)
7171
val launched = launchCustomTab(intent, launchContext, parsedUri)

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@ internal object CustomTabsPackageHelper {
1818
return CustomTabsClient.getPackageName(context, null)
1919
}
2020

21+
@Suppress("DEPRECATION")
2122
private fun isPackageInstalled(context: Context, packageName: String): Boolean {
2223
return try {
2324
context.packageManager.getPackageInfo(packageName, 0)
2425
true
25-
} catch (e: PackageManager.NameNotFoundException) {
26+
} catch (_: PackageManager.NameNotFoundException) {
27+
false
28+
} catch (_: Exception) {
2629
false
2730
}
2831
}

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

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

33
import android.content.Context
44
import android.graphics.Color
5+
import android.os.Build
56
import android.view.accessibility.AccessibilityManager
67
import androidx.core.content.getSystemService
78
import com.margelo.nitro.inappbrowsernitro.DynamicColor
@@ -11,14 +12,15 @@ internal object DynamicColorResolver {
1112
dynamicColor ?: return null
1213

1314
val accessibilityManager = context.getSystemService<AccessibilityManager>()
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
15+
val isHighContrast = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
16+
isHighTextContrastEnabledSafe(accessibilityManager)
17+
} else {
18+
false
19+
}
2020

21-
val isDark = (context.resources.configuration.uiMode and android.content.res.Configuration.UI_MODE_NIGHT_MASK) == android.content.res.Configuration.UI_MODE_NIGHT_YES
21+
val isDark = (context.resources.configuration.uiMode and
22+
android.content.res.Configuration.UI_MODE_NIGHT_MASK) ==
23+
android.content.res.Configuration.UI_MODE_NIGHT_YES
2224

2325
val candidate = when {
2426
isHighContrast && dynamicColor.highContrast != null -> dynamicColor.highContrast
@@ -49,5 +51,18 @@ internal object DynamicColorResolver {
4951
}
5052
}
5153

54+
// `AccessibilityManager.isHighTextContrastEnabled()` is an @hide API on
55+
// Android; it is not exposed through the public SDK. Access it via
56+
// reflection and fall back to `false` if unavailable.
57+
private fun isHighTextContrastEnabledSafe(manager: AccessibilityManager?): Boolean {
58+
manager ?: return false
59+
return try {
60+
val method = AccessibilityManager::class.java.getMethod("isHighTextContrastEnabled")
61+
method.invoke(manager) as? Boolean ?: false
62+
} catch (_: Throwable) {
63+
false
64+
}
65+
}
66+
5267
enum class DynamicScheme { SYSTEM, LIGHT, DARK }
5368
}

biome.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"$schema": "https://biomejs.dev/schemas/2.4.12/schema.json",
3+
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
4+
"files": {
5+
"includes": [
6+
"**",
7+
"!**/node_modules",
8+
"!**/lib",
9+
"!**/build",
10+
"!**/dist",
11+
"!**/nitrogen/generated",
12+
"!**/android",
13+
"!**/ios",
14+
"!example/vendor",
15+
"!**/*.min.js",
16+
"!**/*.bundle.js"
17+
]
18+
},
19+
"formatter": {
20+
"enabled": true,
21+
"indentStyle": "space",
22+
"indentWidth": 2,
23+
"lineWidth": 80
24+
},
25+
"linter": {
26+
"enabled": true,
27+
"rules": { "recommended": true }
28+
},
29+
"javascript": {
30+
"formatter": {
31+
"quoteStyle": "single",
32+
"semicolons": "asNeeded",
33+
"trailingCommas": "es5",
34+
"quoteProperties": "preserve"
35+
}
36+
},
37+
"assist": {
38+
"enabled": true,
39+
"actions": { "source": { "organizeImports": "on" } }
40+
}
41+
}

0 commit comments

Comments
 (0)