A React Native mobile application demonstrating the Unforgettable SDK for secure key recovery across iOS and Android.
- Mode Selection: Create new recovery or restore existing keys
- Recovery Factors: Select from multiple recovery factors (Face, Image, Password)
- Group Support: Optional group identifier for multi-user scenarios
- WebView Integration: In-app browser for recovery process with camera permissions
- Automatic Polling: Continuously checks for recovery completion (2-second intervals)
- Key Display: Shows recovered private key and derived Ethereum address
- Copy to Clipboard: Easy copying of keys and addresses
- Node.js >= 18
- React Native development environment set up
- For iOS: Xcode and CocoaPods
- For Android: Android Studio and JDK
Note: This example is a standalone project (not part of the Yarn workspace) to avoid React Native build issues.
# Navigate to the example
cd examples/react-native
# Install dependencies
yarn install
# or
npm install
# iOS only - install pods
cd ios && pod install && cd ..# Run on iOS
yarn ios
# or
npm run ios
# Run on Android
yarn android
# or
npm run android
# Start Metro bundler separately (optional)
yarn start
# or
npm start- Select Create mode
- Choose recovery factors (e.g., Face + Password)
- Optionally enter a group
- Tap Generate Recovery URL
- Tap Open in WebView to complete the recovery setup
- The URL will open in an embedded browser
- Follow the on-screen instructions to set up recovery
- The app will automatically poll for the recovery data
- Select Restore mode
- Choose the same recovery factors used during creation
- Optionally enter the wallet address or group
- Tap Generate Recovery URL
- Tap Open in WebView
- Complete the recovery challenges in the browser
- The app will automatically poll for the recovery data
- Once complete, the decrypted private key will be displayed
- Tap Copy Key to copy it to clipboard
- Uses
@rarimo/unforgettable-sdkTypeScript SDK (via local file reference) - React Native WebView for in-app recovery UI with camera permissions
- Polling mechanism for recovery status (404 error handling)
- Polyfills for crypto and URL APIs
- Cross-platform (iOS & Android)
react: 18.2.0react-native: 0.73.2@rarimo/unforgettable-sdk: file:../../packages/core (local package)viem: ^2.40.2 (Ethereum utilities)
react-native-webview: ^13.6.4 (WebView component)react-native-get-random-values: 1.11.0 (crypto.getRandomValues polyfill)react-native-url-polyfill: ^3.0.0 (URLSearchParams polyfill)buffer: ^6.0.3 (Buffer polyfill for Node.js APIs)fastestsmallesttextencoderdecoder: ^1.0.22 (TextEncoder/Decoder polyfill)
react-native/
├── App.tsx # Main application component with UI and logic
├── index.js # Entry point (registers app component)
├── package.json # Dependencies (standalone, uses file: for SDK)
├── tsconfig.json # TypeScript configuration
├── babel.config.js # Babel configuration
├── metro.config.js # Metro bundler configuration
├── jest.config.js # Jest testing configuration
├── ios/ # iOS native code and Xcode project
│ ├── Podfile # CocoaPods dependencies
│ └── ...
└── android/ # Android native code and Gradle project
├── build.gradle # Android build configuration
└── ...
The app requires several polyfills for Web APIs not available in React Native:
import 'react-native-get-random-values' // crypto.getRandomValues()
import 'react-native-url-polyfill/auto' // URLSearchParams
import 'fastestsmallesttextencoderdecoder' // TextEncoder/TextDecoder
import { Buffer } from 'buffer'
global.Buffer = Buffer // Node.js Buffer APIimport { UnforgettableSdk, RecoveryFactor } from '@rarimo/unforgettable-sdk'
const sdk = new UnforgettableSdk({
mode: 'restore',
factors: [RecoveryFactor.Face, RecoveryFactor.Image, RecoveryFactor.Password, RecoveryFactor.Geolocation],
walletAddress: '0x123...',
group: 'my-group'
})
const recoveryUrl = await sdk.getRecoveryUrl()import { NotFoundError } from '@rarimo/unforgettable-sdk'
const pollingInterval = setInterval(async () => {
try {
const data = await sdk.getRecoveredData()
setRecoveredKey(data.recoveryKey)
clearInterval(pollingInterval)
} catch (error) {
// Continue polling on 404 (data not ready yet)
if (error instanceof NotFoundError) {
return
}
// Stop on other errors
console.error(error)
clearInterval(pollingInterval)
}
}, 2000)<WebView
source={{ uri: recoveryUrl }}
javaScriptEnabled={true}
domStorageEnabled={true}
mediaPlaybackRequiresUserAction={false}
allowsInlineMediaPlayback={true}
mediaCapturePermissionGrantType='grant' // Auto-grant camera
allowsProtectedMedia={true}
/>If you see errors about missing modules:
# Clear Metro cache
yarn start --reset-cache# Clean and reinstall pods
cd ios
rm -rf Pods Podfile.lock
pod install
cd ..# Clean Gradle cache
cd android
./gradlew clean
cd ..Make sure the Buffer polyfill is imported at the top of App.tsx:
import { Buffer } from 'buffer'
global.Buffer = BufferIn production:
- Never log or display private keys in plaintext
- Use React Native Keychain or Secure Storage for sensitive data
- Implement proper error handling
- Add authentication before displaying keys
- Consider using biometric authentication
- Standalone project (not in Yarn workspace) due to React Native Xcode integration
- Uses file: protocol for SDK dependency (relative path)
- Requires manual rebuild if SDK packages change
- WebView doesn't support all desktop browser features
MIT License - see LICENSE file for details
For issues or questions:
- SDK Documentation: See main README
- GitHub Issues: https://github.com/rarimo/unforgettable-sdk/issues
- Website: https://unforgettable.app