Overview
whisper.rn works with Expo through the prebuild workflow. Since whisper.rn includes native code, you cannot use it in Expo Go. You must create a development build.
whisper.rn requires native modules and cannot be used with Expo Go. You must use the prebuild workflow to generate native projects.
Installation
Install the package
npx expo install whisper.rn
Prebuild your project
Generate the native iOS and Android projects:This creates ios/ and android/ directories with the native code. Run on a device or simulator
# iOS
npx expo run:ios
# Android
npx expo run:android
Configuration
App Config (app.json)
Add necessary permissions to your app.json or app.config.js:
{
"expo": {
"name": "Your App",
"slug": "your-app",
"ios": {
"bundleIdentifier": "com.yourcompany.yourapp",
"infoPlist": {
"NSMicrophoneUsageDescription": "This app requires microphone access to transcribe speech"
}
},
"android": {
"package": "com.yourcompany.yourapp",
"permissions": [
"android.permission.RECORD_AUDIO"
]
},
"plugins": [
// Add any other plugins you need
]
}
}
Using app.config.js for Dynamic Configuration
For more control, use app.config.js:
export default {
expo: {
name: 'Your App',
slug: 'your-app',
ios: {
bundleIdentifier: 'com.yourcompany.yourapp',
infoPlist: {
NSMicrophoneUsageDescription: 'This app requires microphone access to transcribe speech',
},
// For medium/large models
entitlements: {
'com.apple.developer.kernel.extended-virtual-addressing': true,
},
},
android: {
package: 'com.yourcompany.yourapp',
permissions: ['android.permission.RECORD_AUDIO'],
},
},
}
iOS Configuration
After prebuild, you may need to install CocoaPods dependencies:
For custom build configurations (optional):
- Open the generated Xcode workspace:
ios/YourApp.xcworkspace
- Follow the iOS Setup guide for:
- Extended Virtual Addressing (for large models)
- Core ML configuration
- Custom build flags
Android Configuration
ProGuard Rules
If you’re building release APKs with minification enabled, add ProGuard rules.
Create or edit android/app/proguard-rules.pro:
# whisper.rn
-keep class com.rnwhisper.** { *; }
Then ensure it’s referenced in android/app/build.gradle:
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
}
}
}
NDK Version
For Apple Silicon Macs, set the NDK version in android/build.gradle:
buildscript {
ext {
ndkVersion = "24.0.8215888"
}
}
Metro Configuration
If you want to bundle models or audio files as assets, configure Metro bundler.
Create or edit metro.config.js in your project root:
const { getDefaultConfig } = require('expo/metro-config')
const config = getDefaultConfig(__dirname)
// Add asset extensions for whisper models
config.resolver.assetExts.push(
'bin', // GGML model files
'mil' // Core ML model files (iOS)
)
module.exports = config
Then you can use require() to bundle assets:
import { initWhisper } from 'whisper.rn'
const whisperContext = await initWhisper({
filePath: require('../assets/ggml-tiny.en.bin'),
})
Bundling large models significantly increases your app size. The React Native packager has a 2GB file limit, so you cannot bundle the original f16 large model (2.9GB).
Development Builds
Create a Development Build
For Expo projects, you’ll need a development build instead of Expo Go:
# Install expo-dev-client
npx expo install expo-dev-client
# Run prebuild
npx expo prebuild
# Build and run
npx expo run:ios
# or
npx expo run:android
EAS Build
For building with EAS:
Build for development
eas build --profile development --platform ios
# or
eas build --profile development --platform android
Example eas.json:
{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"ios": {
"resourceClass": "m-medium"
},
"android": {
"buildType": "apk"
}
},
"preview": {
"distribution": "internal"
},
"production": {
"ios": {
"resourceClass": "m-medium"
}
}
}
}
Requesting Permissions
Use expo-permissions or React Native’s built-in APIs:
Using React Native APIs
import { PermissionsAndroid, Platform } from 'react-native'
import { request, PERMISSIONS, RESULTS } from 'react-native-permissions'
const requestMicrophonePermission = async () => {
if (Platform.OS === 'android') {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO
)
return granted === PermissionsAndroid.RESULTS.GRANTED
}
if (Platform.OS === 'ios') {
const result = await request(PERMISSIONS.IOS.MICROPHONE)
return result === RESULTS.GRANTED
}
return false
}
// Use before starting realtime transcription
const hasPermission = await requestMicrophonePermission()
if (!hasPermission) {
console.log('Microphone permission denied')
}
Workflow Comparison
Managed Workflow ❌
Expo Go → whisper.rn (Native modules) → NOT COMPATIBLE
Prebuild Workflow ✅
npx expo prebuild → Native projects generated → whisper.rn works
Bare Workflow ✅
React Native CLI project → Add Expo → whisper.rn works
Common Issues
”Module not found” in Expo Go
Error: Cannot use whisper.rn in Expo Go
Solution: Use prebuild and create a development build:
npx expo prebuild
npx expo run:ios # or run:android
Prebuild Fails
Error: Prebuild command fails
Solution: Ensure you have the required tools:
- iOS: Xcode and CocoaPods installed
- Android: Android Studio and Android SDK installed
# Install CocoaPods (iOS)
sudo gem install cocoapods
# Verify Android SDK
adb --version
Permission Denied at Runtime
Error: Microphone permission not granted
Solution: Verify permissions are in app.json and request at runtime before using:
// Request before using realtime features
const hasPermission = await requestMicrophonePermission()
Build Fails with Large Models
Error: Bundle size exceeds limit
Solution: Download models at runtime instead of bundling:
import RNFS from 'react-native-fs'
// Download model at runtime
const modelPath = `${RNFS.DocumentDirectoryPath}/ggml-tiny.en.bin`
await RNFS.downloadFile({
fromUrl: 'https://your-cdn.com/ggml-tiny.en.bin',
toFile: modelPath,
}).promise
const whisperContext = await initWhisper({
filePath: modelPath,
})
Testing
Development Build
Test in development mode:
npx expo run:ios
# or
npx expo run:android
Release Build
Test performance with optimized release build:
# iOS
npx expo run:ios --configuration Release
# Android
npx expo run:android --variant release
Always test performance with release builds. Development builds can be significantly slower.
EAS Update
After creating a development build, you can use EAS Update for OTA updates of your JavaScript code (but not native changes):
eas update --branch production
If you modify native code or update whisper.rn, you need to create a new build. OTA updates only work for JavaScript changes.
Example Project Structure
my-expo-app/
├── app.json (or app.config.js)
├── metro.config.js
├── package.json
├── assets/
│ └── ggml-tiny.en.bin (optional, if bundling)
├── ios/ (generated by prebuild)
│ └── Podfile
├── android/ (generated by prebuild)
│ └── app/
│ ├── build.gradle
│ └── proguard-rules.pro
└── src/
└── App.tsx
Next Steps