@ibrahim-rahhal/expo-exit-app
v1.0.0
Published
A React Native package for gracefully exiting Expo applications
Maintainers
Readme
@ibrahim-rahhal/expo-exit-app
A React Native package for gracefully exiting Expo applications with multiple fallback strategies.
🚀 Features
- Multiple Exit Strategies: BackHandler, Updates reload, and force crash
- Graceful Fallbacks: Automatically tries multiple methods
- TypeScript Support: Fully typed for better development experience
- React Hooks: Easy integration with React components
- Platform Detection: Automatically detects available exit methods
- Customizable: Configure error messages, delays, and strategies
📦 Installation
npm install @ibrahim-rahhal/expo-exit-appor
yarn add @ibrahim-rahhal/expo-exit-app🔧 Basic Usage
Using the Hook (Recommended)
import React from 'react';
import { View, Button, Alert } from 'react-native';
import { useExitApp } from '@ibrahim-rahhal/expo-exit-app';
export default function App() {
const { exit } = useExitApp();
const handleExit = () => {
Alert.alert(
'Exit App',
'Are you sure you want to exit?',
[
{ text: 'Cancel', style: 'cancel' },
{
text: 'Exit',
onPress: async () => {
const result = await exit({
errorMessage: 'User requested app exit',
});
console.log('Exit result:', result);
},
},
]
);
};
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Button title="Exit App" onPress={handleExit} />
</View>
);
}Using the Class Directly
import { ExitApp, ExitStrategy } from '@ibrahim-rahhal/expo-exit-app';
// Simple exit with default options
await ExitApp.exit();
// Exit with custom options
await ExitApp.exit({
errorMessage: 'Custom exit message',
useReload: true,
forceDelay: 200,
});
// Exit with specific strategy
await ExitApp.exitWithStrategy(ExitStrategy.BACK_HANDLER);📚 API Reference
useExitApp() Hook
Returns an object with the following methods:
const {
exit,
exitWithStrategy,
isBackHandlerSupported,
isReloadSupported,
getSupportedStrategies,
} = useExitApp();Methods
exit(options?): Exit using graceful strategy with fallbacksexitWithStrategy(strategy, options?): Exit using a specific strategyisBackHandlerSupported(): Check if BackHandler.exitApp() is availableisReloadSupported(): Check if Updates.reloadAsync() is availablegetSupportedStrategies(): Get array of supported exit strategies
ExitApp Class
Static methods for app termination:
ExitApp.exit(options?): Promise<ExitResult>
Gracefully exit the app using multiple fallback strategies.
ExitApp.exitWithStrategy(strategy, options?): Promise<ExitResult>
Exit using a specific strategy.
Platform Detection Methods
ExitApp.isBackHandlerSupported(): booleanExitApp.isReloadSupported(): booleanExitApp.getSupportedStrategies(): ExitStrategy[]
Types
ExitOptions
interface ExitOptions {
/** Custom error message to use when forcing app termination */
errorMessage?: string;
/** Whether to try Updates.reloadAsync() first (default: true) */
useReload?: boolean;
/** Delay in milliseconds before attempting force termination (default: 100) */
forceDelay?: number;
}ExitStrategy
enum ExitStrategy {
BACK_HANDLER = 'backHandler', // Use BackHandler.exitApp()
RELOAD = 'reload', // Use Updates.reloadAsync()
FORCE_CRASH = 'forceCrash', // Force crash with unhandled error
GRACEFUL = 'graceful', // Try all strategies with fallbacks
}ExitResult
interface ExitResult {
/** Whether the exit attempt was successful */
success: boolean;
/** The strategy that was used */
strategy: ExitStrategy;
/** Error message if the exit failed */
error?: string;
}🎯 Exit Strategies
1. Graceful (Default)
Tries multiple strategies in order:
Updates.reloadAsync()(if enabled anduseReload: true)BackHandler.exitApp()(if available)- Force crash with unhandled error
2. BackHandler
Uses BackHandler.exitApp() - works primarily on Android.
3. Reload
Uses Updates.reloadAsync() to reload the app, effectively restarting it.
4. Force Crash
Forces an unhandled error to crash the app. Uses ErrorUtils.reportFatalError() if available, otherwise throws an error.
🔍 Advanced Examples
Custom Exit Flow
import { useExitApp, ExitStrategy } from '@ibrahim-rahhal/expo-exit-app';
export function useCustomExit() {
const { exitWithStrategy, getSupportedStrategies } = useExitApp();
const customExit = async () => {
const strategies = getSupportedStrategies();
// Try BackHandler first if available
if (strategies.includes(ExitStrategy.BACK_HANDLER)) {
const result = await exitWithStrategy(ExitStrategy.BACK_HANDLER);
if (result.success) return result;
}
// Fallback to force crash
return exitWithStrategy(ExitStrategy.FORCE_CRASH, {
errorMessage: 'Custom exit flow terminated app',
forceDelay: 500,
});
};
return { customExit };
}Region Check Example (Based on Your Code)
import React, { useEffect } from 'react';
import { Alert } from 'react-native';
import { useExitApp } from '@ibrahim-rahhal/expo-exit-app';
export function RegionCheck() {
const { exit } = useExitApp();
useEffect(() => {
const timer = setTimeout(() => {
Alert.alert(
'Region Not Supported',
"Your region isn't supported",
[
{
text: 'OK',
onPress: async () => {
await exit({
errorMessage: 'App terminated due to unsupported region',
useReload: true,
forceDelay: 100,
});
},
},
],
{ cancelable: false }
);
}, 3000);
return () => clearTimeout(timer);
}, [exit]);
return null; // This is just a utility component
}🛠️ Platform Support
| Platform | BackHandler | Updates Reload | Force Crash | |----------|-------------|----------------|-------------| | Android | ✅ | ✅ | ✅ | | iOS | ❌ | ✅ | ✅ | | Web | ❌ | ✅ | ✅ |
Note: iOS doesn't allow apps to programmatically exit, but force crash will work for development/testing.
⚠️ Important Notes
iOS Behavior: Apple doesn't allow apps to programmatically exit on iOS. The force crash method is mainly for development/testing purposes.
Production Use: Be careful when using force crash in production apps, as it may affect crash reporting and user experience.
Updates.reloadAsync(): Only works when Expo Updates is enabled and configured.
Testing: Test thoroughly on your target platforms, as behavior may vary.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
👨💻 Author
Ibrahim Rahhal - @Ibrahimrahhal
- Email: [email protected]
- Website: rahhalesta.com
- Twitter: @IbrahimRahhal18
🙏 Acknowledgments
- Inspired by react-native-exit-app
- Built for the Expo ecosystem
- Thanks to the React Native and Expo communities
