Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c8b4e8c
feat: add native UserButton and UserProfile components for iOS
chriscanin Dec 3, 2025
39fb327
feat(clerk): add getSession and signOut methods to ClerkExpoModule an…
chriscanin Dec 3, 2025
6d393b8
feat(user-button): fetch and display user details in UserButton compo…
chriscanin Dec 3, 2025
96dcbbc
Refactor code structure for improved readability and maintainability
chriscanin Dec 4, 2025
9962fdc
Merge remote-tracking branch 'origin/main' into chris/mobile-342-brid…
chriscanin Jan 7, 2026
82edb61
feat(clerk): integrate Clerk SDK for Android with authentication and …
chriscanin Jan 8, 2026
13f7a46
Merge remote-tracking branch 'origin/main' into chris/mobile-343-brid…
chriscanin Jan 16, 2026
b2b12c2
feat(clerk): enhance error handling and user session management in Cl…
chriscanin Jan 22, 2026
638887d
feat(clerk): iOS bridging is working. Only minor debugging left to do.
chriscanin Jan 23, 2026
aba2c72
refactor: Revamp Clerk bridging integration for improved session hand…
chriscanin Jan 23, 2026
36780e7
feat(clerk): update Android integration with new dependency versions …
chriscanin Jan 23, 2026
1a0b4ee
feat: Update Clerk SDK versions and enhance Android packaging
chriscanin Jan 24, 2026
04ba08f
feat: add AuthView component for native authentication flows
chriscanin Jan 27, 2026
d7d2300
feat(clerk): enable native module support and fix module config
chriscanin Feb 3, 2026
7a295ab
feat(expo): add .md suggestion
chriscanin Feb 3, 2026
d5408eb
fix(react): conditionally load UI scripts to prevent document.createE…
chriscanin Feb 4, 2026
184feae
feat: enhance native module support for core-3 and add hooks for auth…
chriscanin Feb 10, 2026
21945eb
clean up images from maestro testing, should not have been commited.
chriscanin Feb 11, 2026
cfc635d
Fix android build for core-3 components release.
chriscanin Feb 12, 2026
73a0f6d
Continued fixes for android build for core-3 components release.
chriscanin Feb 12, 2026
956cdc9
fix: improve native bridge quality and prevent coroutine leaks in And…
chriscanin Feb 13, 2026
b8127fd
Merge origin/main and resolve conflicts
chriscanin Feb 13, 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
17 changes: 17 additions & 0 deletions .changeset/fix-native-bridge-quality.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@clerk/expo': patch
'@clerk/react': patch
---

Fix code quality issues across native bridge layer

- Fix forEach callback in `isomorphicClerk` to use block statement, avoiding implicit return lint warning
- Emit `'error'` status instead of `'ready'` when `clerk.load()` fails in `isomorphicClerk`
- Add `isMountedRef` guards after every `await` in `syncNativeAuthToJs` to prevent state mutations after unmount
- Only call `onSuccess` after `syncNativeSession` succeeds in `AuthView`; call `onError` on sync failure
- Replace non-null assertion and `as any` cast with null-check and type guard in `syncNativeSession`
- Cancel Recomposer and CoroutineScope in `onDetachedFromWindow` to prevent coroutine leaks (Android)
- Replace direct SharedPreferences access with `Clerk.session?.fetchToken()` public API (Android)
- Return `UIViewController` from inline view factories to preserve SwiftUI lifecycle (iOS)
- Retain `UIHostingController` as child view controller in `ExpoView` subclasses (iOS)
- Handle auth event stream termination and nil `createdSessionId` by invoking completion with failure (iOS)
5 changes: 5 additions & 0 deletions .changeset/modern-hornets-fold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@clerk/react": patch
---

Fix `ReferenceError: Property 'document' doesn't exist` crash in React Native environments by conditionally loading UI scripts only in standard browser contexts.
279 changes: 279 additions & 0 deletions packages/expo/NATIVE_IOS_SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
# Native iOS Setup for @clerk/clerk-expo

This guide explains how to use Clerk's native iOS components in your Expo or React Native application.

## Overview

`@clerk/clerk-expo` supports two implementations:

1. **Native-First (Recommended)**: Uses Clerk's native iOS Swift UI components for the best user experience
2. **React Native**: Cross-platform React Native components that work everywhere

## Feature Comparison

| Feature | Native iOS (Swift UI) | React Native |
| -------------------- | ------------------------------------ | ------------------------------- |
| **UI/UX** | Native iOS design, follows Apple HIG | Cross-platform design |
| **Performance** | Native Swift performance | JavaScript bridge overhead |
| **Bundle Size** | Smaller JS bundle | Larger JS bundle |
| **Customization** | Limited to Clerk iOS theming | Full React Native customization |
| **Platform Support** | iOS only | iOS, Android, Web |
| **Build Method** | Requires native build (EAS/Xcode) | Works with Expo Go |
| **Face ID/Touch ID** | Native biometric integration | Via expo-local-authentication |
| **Passkeys** | Native passkey support | Limited support |
| **OAuth** | Native SFAuthenticationSession | WebBrowser-based |

---

## Setup Instructions

### For Expo Users (Recommended)

#### Prerequisites

- Expo SDK 50 or later
- EAS Build account (native builds required)
- iOS deployment target 15.1+

#### 1. Install the Package

```bash
npx expo install @clerk/clerk-expo
```

#### 2. Add the Expo Config Plugin

In your `app.json` or `app.config.js`:

```json
{
"expo": {
"plugins": [["@clerk/clerk-expo/app.plugin"]]
}
}
```

#### 3. Configure Your App

```tsx
// app/_layout.tsx
import { ClerkProvider } from '@clerk/clerk-expo';

export default function RootLayout() {
return (
<ClerkProvider publishableKey={process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY}>
{/* Your app content */}
</ClerkProvider>
);
}
```

#### 4. Use Native Components

```tsx
// app/(auth)/sign-in.tsx
import { SignIn } from '@clerk/clerk-expo/native';
import { useRouter } from 'expo-router';

export default function SignInScreen() {
const router = useRouter();

return (
<SignIn
mode='signIn'
onSuccess={() => router.replace('/(home)')}
onError={error => console.error('Sign in error:', error)}
/>
);
}
```

#### 5. Build with EAS

The native iOS components require a native build:

```bash
# Development build
eas build --profile development --platform ios

# Install on simulator
eas build:run --profile development --platform ios

# Production build
eas build --profile production --platform ios
```

**Important**: Native iOS components **will not work** with Expo Go. You must create a development build.

---

### For React Native CLI Users

If you're using React Native without Expo, you'll need to manually add the clerk-ios Swift package.

#### Prerequisites

- React Native 0.70 or later
- CocoaPods
- Xcode 14+
- iOS deployment target 15.1+

#### 1. Install the Package

```bash
npm install @clerk/clerk-expo
# or
yarn add @clerk/clerk-expo
```

#### 2. Install iOS Dependencies

```bash
cd ios && pod install && cd ..
```

#### 3. Add clerk-ios Swift Package in Xcode

1. Open your `.xcworkspace` file in Xcode
2. Select your project in the Project Navigator
3. Select your app target
4. Go to the "Package Dependencies" tab
5. Click the "+" button
6. Enter the repository URL: `https://github.com/clerk/clerk-ios.git`
7. Select "Up to Next Major Version" with minimum version `0.68.1`
8. Ensure the "Clerk" product is selected for your target
9. Click "Add Package"

#### 4. Verify Installation

Build your project to ensure the Swift package is properly linked:

```bash
npx react-native run-ios
```

---

## Using React Native Components Instead

If you want to use the cross-platform React Native components (works with Expo Go), import from the main package:

```tsx
import { SignIn } from '@clerk/clerk-expo';
// NOT from '@clerk/clerk-expo/native'
```

### When to Use React Native Components

- Testing in Expo Go
- Need Android support
- Want full UI customization
- Don't need native iOS features (Face ID, Passkeys)

### When to Use Native iOS Components

- Building a production iOS app
- Want the best iOS user experience
- Need native biometric authentication
- Want smaller JavaScript bundle size
- Need passkey support

---

## API Reference

### Native SignIn Component

```tsx
import { SignIn } from '@clerk/clerk-expo/native';

<SignIn
mode="signIn" | "signUp" | "signInOrUp"
isDismissable={boolean}
onSuccess={(data) => void}
onError={(error) => void}
/>
```

**Props:**

- `mode`: Authentication mode (default: `"signInOrUp"`)
- `isDismissable`: Whether the view can be dismissed (default: `true`)
- `onSuccess`: Callback when authentication succeeds
- `onError`: Callback when authentication fails

---

## Troubleshooting

### "Module 'Clerk' not found"

The clerk-ios Swift package isn't installed. Follow the manual setup steps above.

### "Expo Go doesn't show native components"

Native components require a development build. Run `eas build --profile development --platform ios`.

### Plugin doesn't add Swift package

The config plugin only runs during `expo prebuild` or `eas build`. If you're using a bare workflow, you'll need to add the package manually in Xcode.

### Build fails with Swift errors

Ensure your iOS deployment target is at least 15.1 in your `Podfile`:

```ruby
platform :ios, '15.1'
```

---

## Migration Guide

### From React Native Components to Native

1. Change your imports:

```tsx
// Before
import { SignIn } from '@clerk/clerk-expo';

// After
import { SignIn } from '@clerk/clerk-expo/native';
```

2. Create a development build (can't use Expo Go)
3. Test on a physical device or simulator

### From Native to React Native

1. Change your imports back:

```tsx
// Before
import { SignIn } from '@clerk/clerk-expo/native';

// After
import { SignIn } from '@clerk/clerk-expo';
```

2. Can now use Expo Go for testing

---

## Additional Resources

- [Clerk iOS SDK Documentation](https://github.com/clerk/clerk-ios)
- [Expo Config Plugins](https://docs.expo.dev/config-plugins/introduction/)
- [EAS Build Documentation](https://docs.expo.dev/build/introduction/)
- [Clerk Dashboard](https://dashboard.clerk.com/)

---

## Support

For issues related to:

- Native iOS components: [clerk-ios repository](https://github.com/clerk/clerk-ios/issues)
- Expo integration: [clerk-javascript repository](https://github.com/clerk/javascript/issues)
- General Clerk questions: [Clerk Discord](https://clerk.com/discord)
44 changes: 41 additions & 3 deletions packages/expo/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
id 'org.jetbrains.kotlin.plugin.compose' version '2.1.20'
}

group = 'com.clerk.expo'
version = '1.0.0'
Expand All @@ -10,14 +13,19 @@ ext {
credentialsVersion = "1.3.0"
googleIdVersion = "1.1.1"
kotlinxCoroutinesVersion = "1.7.3"
clerkAndroidApiVersion = "0.1.30"
clerkAndroidUiVersion = "0.1.31"
composeVersion = "1.7.0"
activityComposeVersion = "1.9.0"
lifecycleVersion = "2.8.0"
}

def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

android {
namespace "expo.modules.clerk.googlesignin"
namespace "expo.modules.clerk"

compileSdk safeExtGet("compileSdkVersion", 36)

Expand All @@ -43,13 +51,25 @@ android {
jvmTarget = "17"
}

buildFeatures {
compose = true
}

packaging {
resources {
excludes += ['META-INF/versions/9/OSGI-INF/MANIFEST.MF']
}
}

sourceSets {
main {
java.srcDirs = ['src/main/java']
}
}
}

// Note: kotlin-stdlib exclusions are handled in the clerk-android-ui dependency declaration

dependencies {
// Expo modules core
implementation project(':expo-modules-core')
Expand All @@ -61,4 +81,22 @@ dependencies {

// Coroutines for async operations
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinxCoroutinesVersion"

// Clerk Android SDK with prebuilt UI
// Exclude kotlin-stdlib to prevent 2.3.0 from polluting the project
// Exclude okhttp to prevent version conflict with React Native's okhttp
implementation("com.clerk:clerk-android-ui:$clerkAndroidUiVersion") {
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib'
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
exclude group: 'com.squareup.okhttp3', module: 'okhttp-urlconnection'
}

// Jetpack Compose for wrapping Clerk views
implementation "androidx.compose.ui:ui:$composeVersion"
implementation "androidx.compose.material3:material3:1.3.0"
implementation "androidx.activity:activity-compose:$activityComposeVersion"
implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycleVersion"
}
Loading
Loading