Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
c8dac0c
refactor(sdk): return visitor data as an object from native modules
TheUnderScorer Jul 23, 2026
5df5374
refactor: access native module through codegen turbomodule spec
TheUnderScorer Jul 23, 2026
63b1edc
feat(android): migrate native module to turbomodule (backward compati…
TheUnderScorer Jul 23, 2026
65097ef
feat(ios): migrate native module to turbomodule (backward compatible)
TheUnderScorer Jul 24, 2026
a565e98
feat(e2e-app): add architecture info component
TheUnderScorer Jul 24, 2026
d35f521
fix(sdk): exclude build artifacts from pod source files
TheUnderScorer Jul 24, 2026
1659c3e
chore: add temporary new/old arch logs
TheUnderScorer Jul 24, 2026
504b63e
chore(e2e-tests): remove react-native pinning step
TheUnderScorer Jul 24, 2026
5dbc29c
chore(android): update gradle config for architecture compatibility
TheUnderScorer Jul 24, 2026
a993f0b
chore(e2e-tests): pin react-native version and hoist deps
TheUnderScorer Jul 29, 2026
5d8c1cf
chore(e2e-tests): add dependency inspection and pod install steps
TheUnderScorer Jul 29, 2026
8d0ddd8
chore(e2e-tests): remove shameful hoisting and pod install steps
TheUnderScorer Jul 29, 2026
a97dde4
chore(e2e-app): update pnpm config to re-enable shameful hoisting
TheUnderScorer Jul 29, 2026
217f6d3
chore(e2e-tests): add missing working-directory in steps
TheUnderScorer Jul 29, 2026
d2bf275
feat(e2e-app): add getData performance tracking logic
TheUnderScorer Jul 31, 2026
0be97a8
feat(e2e-app): add UI Manager info to benchmark logs
TheUnderScorer Jul 31, 2026
90a2f4e
refactor(e2e-app): adjust UI Manager text structure
TheUnderScorer Aug 3, 2026
fdf6bf8
feat(e2e-app): add retry logic for detox build steps
TheUnderScorer Aug 3, 2026
aac6cee
chore(android): add comments for new architecture enablement
TheUnderScorer Aug 3, 2026
e446eef
refactor: remove temporary logs for architecture verification
TheUnderScorer Aug 3, 2026
e44322b
chore(e2e-tests): add retry logic for detox test steps
TheUnderScorer Aug 3, 2026
217c43f
chore: remove benchmark logic
TheUnderScorer Aug 3, 2026
e83c165
feat(react-native): add TurboModule support for new architecture
TheUnderScorer Aug 3, 2026
9081de5
refactor(e2e-app): ensure boolean casting for global variables
TheUnderScorer Aug 3, 2026
a12776c
chore(e2e-tests): update retry wait duration
TheUnderScorer Aug 4, 2026
336691a
chore: apply copilot suggestions
TheUnderScorer Aug 3, 2026
18a4159
test(e2e-tests): add matrix support for architecture testing
TheUnderScorer Aug 4, 2026
c7a441c
refactor: unify method signatures and simplify logic
TheUnderScorer Aug 4, 2026
23f53cd
refactor: enforce non-null timeout with sentinel values
TheUnderScorer Aug 5, 2026
5efd0ef
refactor: remove legacy architecture support and dependencies
TheUnderScorer Aug 5, 2026
d1406f2
chore: enter pre-release mode
TheUnderScorer Aug 5, 2026
64a3b35
Merge remote-tracking branch 'origin/main' into feature/INTER-970-new…
TheUnderScorer Aug 10, 2026
62e7bc6
chore: resolve merge conflict in sdk/README.md
Copilot Aug 11, 2026
9195690
refactor(ci): remove retry-cmd script and update workflows
TheUnderScorer Sep 15, 2026
3c5913b
docs: restore comment
TheUnderScorer Sep 15, 2026
6e64a6b
refactor(android): remove unused method withAndroidBuildProperties
TheUnderScorer Sep 15, 2026
59208e4
test(e2e): add architecture verification test
TheUnderScorer Sep 15, 2026
7145613
fix(e2e): update global type definitions
TheUnderScorer Sep 15, 2026
505e400
fix(e2e): update testIds import path
TheUnderScorer Sep 15, 2026
fd2b23b
chore: revert retry-cmd script
TheUnderScorer Sep 16, 2026
ba3217d
fix(e2e): use env variable for apiKey in arch test
TheUnderScorer Sep 17, 2026
9c41461
Merge branch 'main' into feature/INTER-970-new-arch
TheUnderScorer Sep 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/new-architecture-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@fingerprintjs/fingerprintjs-pro-react-native': major
---

Dropped React Native Old Architecture support. The native module is now a TurboModule (New Architecture only) exposed via a Codegen spec.

This is a breaking change: the SDK now requires React Native >= 0.79 (Expo SDK >= 53) with the [New Architecture](https://reactnative.dev/architecture/landing-page) enabled.
8 changes: 8 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mode": "pre",
"tag": "rc",
"initialVersions": {
"@fingerprintjs/fingerprintjs-pro-react-native": "3.17.0"
},
"changesets": []
}
17 changes: 12 additions & 5 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
steps:
- id: set-matrix
run: |
echo "matrix=['local', '0.73', '0.74', '0.75', '0.76', '0.77', '0.79', '0.81', '0.83', '0.85']" >> $GITHUB_OUTPUT
echo "matrix=['local', '0.79', '0.81', '0.83', '0.85']" >> $GITHUB_OUTPUT

build-android:
strategy:
Expand Down Expand Up @@ -81,11 +81,14 @@ jobs:
run: rm -rf node_modules && pnpm install --frozen-lockfile
working-directory: e2e-app

- run: pnpm why react-native
working-directory: e2e-app

- name: Prebuild
run: pnpm prebuild
working-directory: e2e-app

- run: pnpm exec detox build --configuration android.emu.release
- run: node scripts/retry-cmd.mjs --retries=3 "pnpm exec detox build --configuration android.emu.release"
working-directory: e2e-app

- name: Upload artifacts
Expand Down Expand Up @@ -191,8 +194,9 @@ jobs:
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
arch: x86_64
working-directory: e2e-app
avd-name: ${{ steps.device.outputs.AVD_NAME }}
script: cd e2e-app && pnpm exec detox test --configuration android.emu.release --headless --record-logs all --record-videos failing
script: node scripts/retry-cmd.mjs --retries=3 "pnpm exec detox test --configuration android.emu.release --headless --record-logs all --record-videos failing"

- name: Upload artifacts
if: always()
Expand Down Expand Up @@ -277,11 +281,14 @@ jobs:
run: rm -rf node_modules && pnpm install --frozen-lockfile
working-directory: e2e-app

- run: pnpm why react-native
working-directory: e2e-app

- name: Prebuild
run: pnpm prebuild
working-directory: e2e-app

- run: pnpm exec detox build --configuration ios.sim.release
- run: node scripts/retry-cmd.mjs --retries=3 "pnpm exec detox build --configuration ios.sim.release"
working-directory: e2e-app

- name: Upload artifacts
Expand Down Expand Up @@ -355,7 +362,7 @@ jobs:
if: github.event_name != 'release'
working-directory: e2e-app

- run: pnpm exec detox test --configuration ios.sim.release --cleanup --headless --record-logs all --record-videos failing
- run: node scripts/retry-cmd.mjs --retries=3 "pnpm exec detox test --configuration ios.sim.release --cleanup --headless --record-logs all --record-videos failing"
working-directory: e2e-app
env:
MINIMUM_US_DEFAULT_PUBLIC_KEY: ${{ secrets.MINIMUM_US_DEFAULT_PUBLIC_KEY }}
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ application to call the native Fingerprint Pro libraries (Android and iOS) and i

## Requirements and limitations

- React Native versions 0.73 through 0.86 are supported
- Expo 51.0.0 or higher is supported
- React Native 0.79 or higher is supported (New Architecture only)
- Expo 53.0.0 or higher is supported
- Android 6.0 (API level 23+) or higher
- iOS 13+/tvOS 15+, Swift 5.9 or higher (stable releases)

Expand Down
39 changes: 25 additions & 14 deletions e2e-app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
// SafeAreaView is deprecated in newer RN versions, react-native-safe-area-context is recommended
// but it doesn't work nicely with older RN versions that we also run tests against, so keep SafeAreaView import from react-native for now
/* eslint-disable @typescript-eslint/no-deprecated */
import { Pressable, SafeAreaView, Text, View } from 'react-native'
import { FingerprintJsProProvider, useVisitorData } from '@fingerprintjs/fingerprintjs-pro-react-native'
import { testIds } from '@/e2e/ids'
import { useEffect } from 'react'
import { testTags } from '@/e2e/tags'
import config from '@/src/config'
import { ArchInfo } from '@/src/components/ArchInfo'

function InnerApp() {
const { isLoading, error, data, getData } = useVisitorData()

const doGetData = async () => {
const tags = config.useTags ? testTags : undefined

await getData(tags, config.linkedId)
}

useEffect(() => {
if (error) {
console.error(error)
Expand All @@ -18,7 +26,6 @@ function InnerApp() {

return (
<View style={{ flex: 1 }}>
{/* eslint-disable-next-line @typescript-eslint/no-deprecated */}
<SafeAreaView
style={{
padding: 24,
Expand All @@ -27,6 +34,7 @@ function InnerApp() {
flex: 1,
}}
>
<ArchInfo />
{isLoading ? <Text testID={testIds.loading}>Loading...</Text> : null}
{error ? (
<View>
Expand All @@ -37,20 +45,23 @@ function InnerApp() {
</View>
) : null}
{data ? <Text testID={testIds.data}>{JSON.stringify(data)}</Text> : null}
<Pressable
testID={testIds.getData}
onPress={async () => {
const tags = config.useTags ? testTags : undefined

await getData(tags, config.linkedId)
}}
style={{
paddingBottom: 48,
paddingLeft: 24,
}}
>
<Text>Get data</Text>
</Pressable>
<View style={{ marginTop: 24, marginBottom: 24, alignItems: 'center' }}>
<Pressable
testID={testIds.getData}
onPress={doGetData}
style={{
padding: 12,
backgroundColor: '#2196F3',
borderRadius: 8,
marginBottom: 12,
minWidth: 200,
alignItems: 'center',
}}
>
<Text style={{ color: '#ffffff', fontWeight: 'bold' }}>Get data</Text>
</Pressable>
</View>
</SafeAreaView>
</View>
)
Expand Down
18 changes: 0 additions & 18 deletions e2e-app/app-config-tools/android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,6 @@ const androidBuildProperties: AndroidBuildProperties = {
enableBundleCompression: false,
}

export function withAndroidBuildProperties(props: Partial<AndroidBuildProperties>) {
return () => {
Object.assign(androidBuildProperties, props)
}
}

export function setCompileSdkVersion(version: number) {
return withAndroidBuildProperties({
compileSdkVersion: version,
})
}

export function stripAndroidExtraBuildProperties() {
delete androidBuildProperties.compileSdkVersion
delete androidBuildProperties.targetSdkVersion
delete androidBuildProperties.buildToolsVersion
}

export function getAndroidBuildProperties() {
return { ...androidBuildProperties }
}
9 changes: 0 additions & 9 deletions e2e-app/app-config-tools/arch.ts

This file was deleted.

20 changes: 0 additions & 20 deletions e2e-app/app-config-tools/expoConfigPatchers.ts

This file was deleted.

30 changes: 4 additions & 26 deletions e2e-app/app-config-tools/reactNativeMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import { disableNewArch } from './arch'
import { setCompileSdkVersion, stripAndroidExtraBuildProperties } from './android'
import { withFingerprintMavenRepo, withNewArchFlag, withSplashscreen } from './expoConfigPatchers'

// config is typed as any, as different expo version have different types for the config object
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ExpoConfigPatcher = (config: any) => void
Expand All @@ -19,29 +15,11 @@ type ReactNativeMetadata = {
* - The key represents the version of React Native.
* - The value is an object containing:
* - `callbacks`: An array of functions to execute in the context of the respective React Native version.
*
* The SDK supports React Native >= 0.79 (New Architecture only), so no version currently needs
* version-specific handling. New entries can be added here if a future version requires it.
*/
const reactNativeMetadata: Record<string, ReactNativeMetadata | undefined> = {
0.73: {
callbacks: [disableNewArch, stripAndroidExtraBuildProperties, setCompileSdkVersion(34)],
patchExpoConfig: [withNewArchFlag, withSplashscreen, withFingerprintMavenRepo],
},
0.74: {
callbacks: [disableNewArch, stripAndroidExtraBuildProperties, setCompileSdkVersion(34)],
patchExpoConfig: [withNewArchFlag, withSplashscreen],
},
0.75: {
callbacks: [disableNewArch, stripAndroidExtraBuildProperties, setCompileSdkVersion(34)],
patchExpoConfig: [withNewArchFlag, withSplashscreen],
},
0.76: {
callbacks: [stripAndroidExtraBuildProperties, setCompileSdkVersion(35)],
patchExpoConfig: [withNewArchFlag, withSplashscreen],
},
0.77: {
callbacks: [stripAndroidExtraBuildProperties, setCompileSdkVersion(35)],
patchExpoConfig: [withNewArchFlag, withSplashscreen],
},
}
const reactNativeMetadata: Record<string, ReactNativeMetadata | undefined> = {}

export function handleReactNativeVersion(rnVersion: string) {
if (reactNativeMetadata[rnVersion]?.callbacks?.length) {
Expand Down
4 changes: 4 additions & 0 deletions e2e-app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@ const config: ExpoConfig = {
],
}

// The SDK supports the New Architecture only (React Native >= 0.79), so always enable it.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
;(config as any).newArchEnabled = true

export default patchExpoConfig(rnVersionStr, config)
39 changes: 39 additions & 0 deletions e2e-app/e2e/arch.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { by, device, element, waitFor } from 'detox'
import { beforeAll, describe, expect, it, jest } from '@jest/globals'
import { DeviceLaunchAppConfig } from 'detox/detox'
import { wait } from './wait'
import { Config } from '@/src/config.types'
import { testIds } from './ids'
import { getElementText } from './getElementText'

async function launchApp(params?: DeviceLaunchAppConfig) {
await device.launchApp(params)

await wait(4000)
}

jest.retryTimes(3, {
waitBeforeRetry: 1000,
logErrorsBeforeRetry: false,
})

describe('React Native architecture', () => {
beforeAll(async () => {
await launchApp({
newInstance: true,
launchArgs: {
apiKey: process.env.MINIMUM_US_DEFAULT_PUBLIC_KEY,
region: 'us',
} as Config,
})
})

it('runs on fabric', async () => {
await waitFor(element(by.id(testIds.uiManager)))
.toExist()
.withTimeout(10_000)

const uiManager = await getElementText(element(by.id(testIds.uiManager)))
expect(uiManager.toLowerCase()).toEqual('fabric')
})
})
2 changes: 1 addition & 1 deletion e2e-app/e2e/identification.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ async function launchApp(params?: DeviceLaunchAppConfig) {
}

jest.retryTimes(3, {
waitBeforeRetry: 10_000,
waitBeforeRetry: 1000,
logErrorsBeforeRetry: false,
})

Expand Down
1 change: 1 addition & 0 deletions e2e-app/e2e/ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export const testIds = {
errorCause: 'error-cause',
data: 'data',
getData: 'get-data',
uiManager: 'ui-manager',
Comment thread
kevinmia marked this conversation as resolved.
}
36 changes: 0 additions & 36 deletions e2e-app/plugins/withAndroidMavenRepo.js

This file was deleted.

2 changes: 2 additions & 0 deletions e2e-app/pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ allowBuilds:
detox: true
dtrace-provider: true
esbuild: true

shamefullyHoist: true
Loading
Loading