Home
Softono
z

zoontek

Professional software vendor delivering innovative solutions on the Softono platform. Specialized in both open-source and proprietary software development.

Total Products
4

Software by zoontek

react-native-permissions
Open Source

react-native-permissions

# ☝🏼 react-native-permissions An unified permissions API for React Native on iOS, Android and Windows.<br> (For Windows only builds 18362 and later are supported) [![mit licence](https://img.shields.io/dub/l/vibe-d.svg?style=for-the-badge)](https://github.com/zoontek/react-native-permissions/blob/master/LICENSE) [![npm version](https://img.shields.io/npm/v/react-native-permissions?style=for-the-badge)](https://www.npmjs.org/package/react-native-permissions) [![npm downloads](https://img.shields.io/npm/dt/react-native-permissions.svg?label=downloads&style=for-the-badge)](https://www.npmjs.org/package/react-native-permissions) <br /> [![platform - android](https://img.shields.io/badge/platform-Android-3ddc84.svg?logo=android&style=for-the-badge)](https://www.android.com) [![platform - ios](https://img.shields.io/badge/platform-iOS-000.svg?logo=apple&style=for-the-badge)](https://developer.apple.com/ios) [![platform - windows](https://img.shields.io/badge/platform-Windows-0067b8.svg?logo=windows&style=for-the-badge)](https://www.microsoft.com/en-us/windows) ## Support This library follows the React Native [releases support policy](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).<br> It is supporting the **latest version**, and the **two previous minor series**. ## Setup ```bash $ npm i -S react-native-permissions # --- or --- $ yarn add react-native-permissions ``` ### iOS 1. By default, no permissions are available. First, require the `setup` script in your `Podfile`: ```diff # Transform this into a `node_require` generic function: - # Resolve react_native_pods.rb with node to allow for hoisting - require Pod::Executable.execute_command('node', ['-p', - 'require.resolve( - "react-native/scripts/react_native_pods.rb", - {paths: [process.argv[1]]}, - )', __dir__]).strip + def node_require(script) + # Resolve script with node to allow for hoisting + require Pod::Executable.execute_command('node', ['-p', + "require.resolve( + '#{script}', + {paths: [process.argv[1]]}, + )", __dir__]).strip + end # Use it to require both react-native's and this package's scripts: + node_require('react-native/scripts/react_native_pods.rb') + node_require('react-native-permissions/scripts/setup.rb') ``` 2. In the same `Podfile`, call `setup_permissions` with the permissions you need. Only the permissions specified here will be added: ```ruby # … platform :ios, min_ios_version_supported prepare_react_native_project! # ⬇️ uncomment the permissions you need setup_permissions([ # 'AppTrackingTransparency', # 'Bluetooth', # 'Calendars', # 'CalendarsWriteOnly', # 'Camera', # 'Contacts', # 'FaceID', # 'LocationAccuracy', # 'LocationAlways', # 'LocationWhenInUse', # 'MediaLibrary', # 'Microphone', # 'Motion', # 'Notifications', # 'PhotoLibrary', # 'PhotoLibraryAddOnly', # 'Reminders', # 'Siri', # 'SpeechRecognition', # 'StoreKit', ]) # … ``` 3. Then execute `pod install` in your `ios` directory _(📌  Note that it must be re-executed each time you update this config)_. 4. Finally, add the corresponding permissions usage descriptions to your `Info.plist`. For example: ```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <!-- 🚨 Keep only the permissions specified in `setup_permissions` 🚨 --> <key>NSAppleMusicUsageDescription</key> <string>[REASON]</string> <key>NSBluetoothAlwaysUsageDescription</key> <string>[REASON]</string> <key>NSBluetoothPeripheralUsageDescription</key> <string>[REASON]</string> <key>NSCalendarsFullAccessUsageDescription</key> <string>[REASON]</string> <key>NSCalendarsWriteOnlyAccessUsageDescription</key> <string>[REASON]</string> <key>NSCameraUsageDescription</key> <string>[REASON]</string> <key>NSContactsUsageDescription</key> <string>[REASON]</string> <key>NSFaceIDUsageDescription</key> <string>[REASON]</string> <key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <string>[REASON]</string> <key>NSLocationTemporaryUsageDescriptionDictionary</key> <dict> <key>YOUR-PURPOSE-KEY</key> <string>[REASON]</string> </dict> <key>NSLocationWhenInUseUsageDescription</key> <string>[REASON]</string> <key>NSMicrophoneUsageDescription</key> <string>[REASON]</string> <key>NSMotionUsageDescription</key> <string>[REASON]</string> <key>NSPhotoLibraryUsageDescription</key> <string>[REASON]</string> <key>NSPhotoLibraryAddUsageDescription</key> <string>[REASON]</string> <key>NSRemindersFullAccessUsageDescription</key> <string>[REASON]</string> <key>NSSpeechRecognitionUsageDescription</key> <string>[REASON]</string> <key>NSSiriUsageDescription</key> <string>[REASON]</string> <key>NSUserTrackingUsageDescription</key> <string>[REASON]</string> <!-- … --> </dict> </plist> ``` ### Android Add all wanted permissions to your app `android/app/src/main/AndroidManifest.xml` file: ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 🚨 Keep only the permissions used in your app 🚨 --> <uses-permission android:name="android.permission.ACCEPT_HANDOVER" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" /> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" /> <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" /> <uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" /> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BODY_SENSORS" /> <uses-permission android:name="android.permission.BODY_SENSORS_BACKGROUND" /> <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> <uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.READ_CALL_LOG" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" /> <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_SMS" /> <uses-permission android:name="android.permission.RECEIVE_MMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" /> <uses-permission android:name="android.permission.USE_SIP" /> <uses-permission android:name="android.permission.UWB_RANGING" /> <uses-permission android:name="android.permission.WRITE_CALENDAR" /> <uses-permission android:name="android.permission.WRITE_CALL_LOG" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- … --> </manifest> ``` ### Expo If you use Expo, the previous sections don't apply. Instead just update your app config file with the corresponding values, using one of the syntaxes exemplified below: <details open> <summary><strong>Dynamic configuration (app.config.js, app.config.ts)</strong></summary> ```ts import type {ConfigContext, ExpoConfig} from 'expo/config'; import permissions from 'react-native-permissions/expo'; // use `require` in app.config.js export default ({config}: ConfigContext): ExpoConfig => ({ // … plugins: [ permissions({ // Add setup_permissions to your Podfile (see iOS setup - steps 1, 2 and 3) iosPermissions: ['Camera', 'Microphone'], }), ], ios: { // Add descriptions to your Info.plist (see iOS setup - step 4) infoPlist: { NSCameraUsageDescription: '[REASON]', NSMicrophoneUsageDescription: '[REASON]', }, }, android: { // Add permissions to your AndroidManifest.xml (see Android setup) permissions: ['android.permission.CAMERA', 'android.permission.RECORD_AUDIO'], }, }); ``` </details> <details> <summary><strong>Static configuration (app.json)</strong></summary> ```jsonc { "expo": { // … "plugins": [ [ "react-native-permissions", { // Add setup_permissions to your Podfile (see iOS setup - steps 1, 2 and 3) "iosPermissions": ["Camera", "Microphone"], }, ], ], "ios": { // Add descriptions to your Info.plist (see iOS setup - step 4) "infoPlist": { "NSCameraUsageDescription": "[REASON]", "NSMicrophoneUsageDescription": "[REASON]", }, }, "android": { // Add permissions to your AndroidManifest.xml (see Android setup) "permissions": ["android.permission.CAMERA", "android.permission.RECORD_AUDIO"], }, }, } ``` </details> ### Windows Open the project solution file from the `windows` folder. In the app project open `Package.appxmanifest` file. From there you can select which capabilites you want your app to support. ## 🆘 Manual linking Because this package targets recent React Native versions, you probably don't need to link it manually. But if you have a special case, follow these additional instructions: <details> <summary><b>👀 See manual linking instructions</b></summary> ### iOS Add this line to your `ios/Podfile` file, then run `pod install`. ```bash target 'YourAwesomeProject' do # … pod 'RNPermissions', :path => '../node_modules/react-native-permissions' end ``` ### Android 1. Add the following lines to `android/settings.gradle`: ```gradle include ':react-native-permissions' project(':react-native-permissions').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-permissions/android') ``` 2. Add the implementation line to the dependencies in `android/app/build.gradle`: ```gradle dependencies { // ... implementation project(':react-native-permissions') } ``` 3. Add the import and link the package in `MainApplication.java`: ```java import com.zoontek.rnpermissions.RNPermissionsPackage; // <- add the RNPermissionsPackage import public class MainApplication extends Application implements ReactApplication { // … @Override protected List<ReactPackage> getPackages() { @SuppressWarnings("UnnecessaryLocalVariable") List<ReactPackage> packages = new PackageList(this).getPackages(); // … packages.add(new RNPermissionsPackage()); return packages; } // … } ``` ### Windows 1. In `windows/myapp.sln` add the `RNCConfig` project to your solution: - Open the solution in Visual Studio 2019 - Right-click Solution icon in Solution Explorer > Add > Existing Project - Select `node_modules\react-native-permissions\windows\RNPermissions\RNPermissions.vcxproj` 2. In `windows/myapp/myapp.vcxproj` ad a reference to `RNPermissions` to your main application project. From Visual Studio 2019: - Right-click main application project > Add > Reference... - Check `RNPermissions` from Solution Projects. 3. In `pch.h` add `#include "winrt/RNPermissions.h"`. 4. In `app.cpp` add `PackageProviders().Append(winrt::RNPermissions::ReactPackageProvider());` before `InitializeComponent();`. </details> ## Understanding permission flow As permissions are not handled in the same way on iOS, Android and Windows, this library provides an abstraction over the three platforms behaviors. To understand it a little better, take a look to this flowchart: ``` ┏━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ check(PERMISSIONS.X.Y) ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┌─────────────────────┐ Is the feature available ───────── NO ─────▶ │ RESULTS.UNAVAILABLE │ on this device ? └─────────────────────┘ │ YES │ ┌───────────────────────────┐ Is the permission ─────────── YES ─────▶ │ RESULTS.GRANTED / LIMITED │ already granted ? └───────────────────────────┘ │ NO │ ┌─────────────────┐ Is the permission requestable, ───── NO ─────▶ │ RESULTS.BLOCKED │ or is the platform Android ? └─────────────────┘ │ YES │ ▼ ┌────────────────┐ │ RESULTS.DENIED │ └────────────────┘ │ ▼ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ request(PERMISSIONS.X.Y) ┃◀─────────────────────────┐ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ │ YES │ │ Did the user see and ──────── NO ──────── Is the permission accept the request ? still requestable ? │ │ YES NO │ │ ▼ ▼ ┌───────────────────────────┐ ┌─────────────────┐ │ RESULTS.GRANTED / LIMITED │ │ RESULTS.BLOCKED │ └───────────────────────────┘ └─────────────────┘ ``` This can be implemented as follows: - `check` the permission status - If `granted`, use the feature - If `blocked`, display a screen prompting the user to go to settings (using `openSettings`) _(This will not be shown on Android)_ - If `denied`, display a button to `request` permission: - If `granted`, use the feature - If `blocked`, display an alert prompting the user to go to settings (using `openSettings`) The user experience (UX) is excellent on iOS and acceptable on Android, considering the platform's limitations. > [!IMPORTANT] > _One-time permissions on Android 11+_ > > When a user grants a one-time permission (such as for location, camera, or microphone), Android treats the session as active while the app is in use — even if it's backgrounded or reopened shortly after being closed. > > The system will revoke the permission automatically within **30 to 60 seconds** if: > > - The app is terminated (e.g. swiped away or force-closed). > - The app is backgrounded and unused. > > The exact timing may vary depending on the Android version and device. For more informations, see the official [Android 11 permissions documentation](https://developer.android.com/about/versions/11/privacy/permissions#one-time-permission). ## API ### Supported permissions <details> <summary><b>Android permissions</b></summary> ```js import {PERMISSIONS} from 'react-native-permissions'; PERMISSIONS.ANDROID.ACCEPT_HANDOVER; PERMISSIONS.ANDROID.ACCESS_BACKGROUND_LOCATION; PERMISSIONS.ANDROID.ACCESS_COARSE_LOCATION; PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION; PERMISSIONS.ANDROID.ACCESS_MEDIA_LOCATION; PERMISSIONS.ANDROID.ACTIVITY_RECOGNITION; PERMISSIONS.ANDROID.ADD_VOICEMAIL; PERMISSIONS.ANDROID.ANSWER_PHONE_CALLS; PERMISSIONS.ANDROID.BLUETOOTH_ADVERTISE; PERMISSIONS.ANDROID.BLUETOOTH_CONNECT; PERMISSIONS.ANDROID.BLUETOOTH_SCAN; PERMISSIONS.ANDROID.BODY_SENSORS; PERMISSIONS.ANDROID.BODY_SENSORS_BACKGROUND; PERMISSIONS.ANDROID.CALL_PHONE; PERMISSIONS.ANDROID.CAMERA; PERMISSIONS.ANDROID.GET_ACCOUNTS; PERMISSIONS.ANDROID.NEARBY_WIFI_DEVICES; PERMISSIONS.ANDROID.POST_NOTIFICATIONS; PERMISSIONS.ANDROID.PROCESS_OUTGOING_CALLS; PERMISSIONS.ANDROID.READ_CALENDAR; PERMISSIONS.ANDROID.READ_CALL_LOG; PERMISSIONS.ANDROID.READ_CONTACTS; PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE; PERMISSIONS.ANDROID.READ_MEDIA_AUDIO; PERMISSIONS.ANDROID.READ_MEDIA_IMAGES; PERMISSIONS.ANDROID.READ_MEDIA_VIDEO; PERMISSIONS.ANDROID.READ_MEDIA_VISUAL_USER_SELECTED; PERMISSIONS.ANDROID.READ_PHONE_NUMBERS; PERMISSIONS.ANDROID.READ_PHONE_STATE; PERMISSIONS.ANDROID.READ_SMS; PERMISSIONS.ANDROID.RECEIVE_MMS; PERMISSIONS.ANDROID.RECEIVE_SMS; PERMISSIONS.ANDROID.RECEIVE_WAP_PUSH; PERMISSIONS.ANDROID.RECORD_AUDIO; PERMISSIONS.ANDROID.SEND_SMS; PERMISSIONS.ANDROID.USE_SIP; PERMISSIONS.ANDROID.UWB_RANGING; PERMISSIONS.ANDROID.WRITE_CALENDAR; PERMISSIONS.ANDROID.WRITE_CALL_LOG; PERMISSIONS.ANDROID.WRITE_CONTACTS; PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE; ``` </details> <details> <summary><b>iOS permissions</b></summary> ```js import {PERMISSIONS} from 'react-native-permissions'; PERMISSIONS.IOS.APP_TRACKING_TRANSPARENCY; PERMISSIONS.IOS.BLUETOOTH; PERMISSIONS.IOS.CALENDARS; PERMISSIONS.IOS.CALENDARS_WRITE_ONLY; PERMISSIONS.IOS.CAMERA; PERMISSIONS.IOS.CONTACTS; PERMISSIONS.IOS.FACE_ID; PERMISSIONS.IOS.LOCATION_ALWAYS; PERMISSIONS.IOS.LOCATION_WHEN_IN_USE; PERMISSIONS.IOS.MEDIA_LIBRARY; PERMISSIONS.IOS.MICROPHONE; PERMISSIONS.IOS.MOTION; PERMISSIONS.IOS.PHOTO_LIBRARY; PERMISSIONS.IOS.PHOTO_LIBRARY_ADD_ONLY; PERMISSIONS.IOS.REMINDERS; PERMISSIONS.IOS.SIRI; PERMISSIONS.IOS.SPEECH_RECOGNITION; PERMISSIONS.IOS.STOREKIT; ``` </details> <details> <summary><b>Windows permissions</b></summary> ```js import {PERMISSIONS} from 'react-native-permissions'; PERMISSIONS.WINDOWS.ACCESSORY_MANAGER; PERMISSIONS.WINDOWS.ACTIVITY; PERMISSIONS.WINDOWS.ALLOW_ELEVATION; PERMISSIONS.WINDOWS.ALL_APP_MODS; PERMISSIONS.WINDOWS.ALL_JOYN; PERMISSIONS.WINDOWS.APPOINTMENTS; PERMISSIONS.WINDOWS.APPOINTMENTS_SYSTEM; PERMISSIONS.WINDOWS.APP_BROADCAST_SERVICES; PERMISSIONS.WINDOWS.APP_CAPTURE_SERVICES; PERMISSIONS.WINDOWS.APP_CAPTURE_SETTINGS; PERMISSIONS.WINDOWS.APP_DIAGNOSTICS; PERMISSIONS.WINDOWS.APP_LICENSING; PERMISSIONS.WINDOWS.AUDIO_DEVICE_CONFIGURATION; PERMISSIONS.WINDOWS.BACKGROUND_MEDIA_PLAYBACK; PERMISSIONS.WINDOWS.BACKGROUND_MEDIA_RECORDING; PERMISSIONS.WINDOWS.BACKGROUND_SPATIAL_PERCEPTION; PERMISSIONS.WINDOWS.BACKGROUND_VOIP; PERMISSIONS.WINDOWS.BLOCKED_CHAT_MESSAGES; PERMISSIONS.WINDOWS.BLUETOOTH; PERMISSIONS.WINDOWS.BROAD_FILE_SYSTEM_ACCESS; PERMISSIONS.WINDOWS.CAMERA_PROCESSING_EXTENSION; PERMISSIONS.WINDOWS.CELLULAR_DEVICE_CONTROL; PERMISSIONS.WINDOWS.CELLULAR_DEVICE_IDENTITY; PERMISSIONS.WINDOWS.CELLULAR_MESSAGING; PERMISSIONS.WINDOWS.CHAT_SYSTEM; PERMISSIONS.WINDOWS.CODE_GENERATION; PERMISSIONS.WINDOWS.CONFIRM_APP_CLOSE; PERMISSIONS.WINDOWS.CONTACTS; PERMISSIONS.WINDOWS.CONTACTS_SYSTEM; PERMISSIONS.WINDOWS.CORTANA_PERMISSIONS; PERMISSIONS.WINDOWS.CORTANA_SPEECH_ACCESSORY; PERMISSIONS.WINDOWS.CUSTOM_INSTALL_ACTIONS; PERMISSIONS.WINDOWS.DEVELOPMENT_MODE_NETWORK; PERMISSIONS.WINDOWS.DEVICE_MANAGEMENT_DM_ACCOUNT; PERMISSIONS.WINDOWS.DEVICE_MANAGEMENT_EMAIL_ACCOUNT; PERMISSIONS.WINDOWS.DEVICE_MANAGEMENT_FOUNDATION; PERMISSIONS.WINDOWS.DEVICE_MANAGEMENT_WAP_SECURITY_POLICIES; PERMISSIONS.WINDOWS.DEVICE_PORTAL_PROVIDER; PERMISSIONS.WINDOWS.DEVICE_UNLOCK; PERMISSIONS.WINDOWS.DOCUMENTS_LIBRARY; PERMISSIONS.WINDOWS.DUAL_SIM_TILES; PERMISSIONS.WINDOWS.EMAIL; PERMISSIONS.WINDOWS.EMAIL_SYSTEM; PERMISSIONS.WINDOWS.ENTERPRISE_AUTHENTICATION; PERMISSIONS.WINDOWS.ENTERPRISE_CLOUD_S_S_O; PERMISSIONS.WINDOWS.ENTERPRISE_DATA_POLICY; PERMISSIONS.WINDOWS.ENTERPRISE_DEVICE_LOCKDOWN; PERMISSIONS.WINDOWS.EXPANDED_RESOURCES; PERMISSIONS.WINDOWS.EXTENDED_BACKGROUND_TASK_TIME; PERMISSIONS.WINDOWS.EXTENDED_EXECUTION_BACKGROUND_AUDIO; PERMISSIONS.WINDOWS.EXTENDED_EXECUTION_CRITICAL; PERMISSIONS.WINDOWS.EXTENDED_EXECUTION_UNCONSTRAINED; PERMISSIONS.WINDOWS.FIRST_SIGN_IN_SETTINGS; PERMISSIONS.WINDOWS.GAME_BAR_SERVICES; PERMISSIONS.WINDOWS.GAME_LIST; PERMISSIONS.WINDOWS.GAME_MONITOR; PERMISSIONS.WINDOWS.GAZE_INPUT; PERMISSIONS.WINDOWS.GLOBAL_MEDIA_CONTROL; PERMISSIONS.WINDOWS.HUMANINTERFACEDEVICE; PERMISSIONS.WINDOWS.INPUT_FOREGROUND_OBSERVATION; PERMISSIONS.WINDOWS.INPUT_INJECTION_BROKERED; PERMISSIONS.WINDOWS.INPUT_OBSERVATION; PERMISSIONS.WINDOWS.INPUT_SUPPRESSION; PERMISSIONS.WINDOWS.INTERNET_CLIENT; PERMISSIONS.WINDOWS.INTERNET_CLIENT_SERVER; PERMISSIONS.WINDOWS.INTEROP_SERVICES; PERMISSIONS.WINDOWS.IOT; PERMISSIONS.WINDOWS.LOCAL_SYSTEM_SERVICES; PERMISSIONS.WINDOWS.LOCATION; PERMISSIONS.WINDOWS.LOCATION_HISTORY; PERMISSIONS.WINDOWS.LOCATION_SYSTEM; PERMISSIONS.WINDOWS.LOW_LEVEL; PERMISSIONS.WINDOWS.LOW_LEVEL_DEVICES; PERMISSIONS.WINDOWS.MICROPHONE; PERMISSIONS.WINDOWS.MOBILE; PERMISSIONS.WINDOWS.MODIFIABLE_APP; PERMISSIONS.WINDOWS.MUSIC_LIBRARY; PERMISSIONS.WINDOWS.NETWORKING_VPN_PROVIDER; PERMISSIONS.WINDOWS.NETWORK_CONNECTION_MANAGER_PROVISIONING; PERMISSIONS.WINDOWS.NETWORK_DATA_PLAN_PROVISIONING; PERMISSIONS.WINDOWS.NETWORK_DATA_USAGE_MANAGEMENT; PERMISSIONS.WINDOWS.OEM_DEPLOYMENT; PERMISSIONS.WINDOWS.OEM_PUBLIC_DIRECTORY; PERMISSIONS.WINDOWS.ONE_PROCESS_VOIP; PERMISSIONS.WINDOWS.OPTICAL; PERMISSIONS.WINDOWS.PACKAGED_SERVICES; PERMISSIONS.WINDOWS.PACKAGES_SERVICES; PERMISSIONS.WINDOWS.PACKAGE_MANAGEMENT; PERMISSIONS.WINDOWS.PACKAGE_POLICY_SYSTEM; PERMISSIONS.WINDOWS.PACKAGE_QUERY; PERMISSIONS.WINDOWS.PACKAGE_WRITE_REDIRECTION_COMPATIBILITY_SHIM; PERMISSIONS.WINDOWS.PHONE_CALL; PERMISSIONS.WINDOWS.PHONE_CALL_HISTORY; PERMISSIONS.WINDOWS.PHONE_CALL_HISTORY_SYSTEM; PERMISSIONS.WINDOWS.PHONE_LINE_TRANSPORT_MANAGEMENT; PERMISSIONS.WINDOWS.PICTURES_LIBRARY; PERMISSIONS.WINDOWS.POINT_OF_SERVICE; PERMISSIONS.WINDOWS.PREVIEW_INK_WORKSPACE; PERMISSIONS.WINDOWS.PREVIEW_PEN_WORKSPACE; PERMISSIONS.WINDOWS.PREVIEW_STORE; PERMISSIONS.WINDOWS.PREVIEW_UI_COMPOSITION; PERMISSIONS.WINDOWS.PRIVATE_NETWORK_CLIENT_SERVER; PERMISSIONS.WINDOWS.PROTECTED_APP; PERMISSIONS.WINDOWS.PROXIMITY; PERMISSIONS.WINDOWS.RADIOS; PERMISSIONS.WINDOWS.RECORDED_CALLS_FOLDER; PERMISSIONS.WINDOWS.REMOTE_PASSPORT_AUTHENTICATION; PERMISSIONS.WINDOWS.REMOTE_SYSTEM; PERMISSIONS.WINDOWS.REMOVABLE_STORAGE; PERMISSIONS.WINDOWS.RESCAP; PERMISSIONS.WINDOWS.RUN_FULL_TRUST; PERMISSIONS.WINDOWS.SCREEN_DUPLICATION; PERMISSIONS.WINDOWS.SECONDARY_AUTHENTICATION_FACTOR; PERMISSIONS.WINDOWS.SECURE_ASSESSMENT; PERMISSIONS.WINDOWS.SERIALCOMMUNICATION; PERMISSIONS.WINDOWS.SHARED_USER_CERTIFICATES; PERMISSIONS.WINDOWS.SLAPI_QUERY_LICENSE_VALUE; PERMISSIONS.WINDOWS.SMBIOS; PERMISSIONS.WINDOWS.SMS_SEND; PERMISSIONS.WINDOWS.SPATIAL_PERCEPTION; PERMISSIONS.WINDOWS.START_SCREEN_MANAGEMENT; PERMISSIONS.WINDOWS.STORE_LICENSE_MANAGEMENT; PERMISSIONS.WINDOWS.SYSTEM_MANAGEMENT; PERMISSIONS.WINDOWS.TARGETED_CONTENT; PERMISSIONS.WINDOWS.TEAM_EDITION_DEVICE_CREDENTIAL; PERMISSIONS.WINDOWS.TEAM_EDITION_EXPERIENCE; PERMISSIONS.WINDOWS.TEAM_EDITION_VIEW; PERMISSIONS.WINDOWS.UAP; PERMISSIONS.WINDOWS.UI_AUTOMATION; PERMISSIONS.WINDOWS.UNVIRTUALIZED_RESOURCES; PERMISSIONS.WINDOWS.USB; PERMISSIONS.WINDOWS.USER_ACCOUNT_INFORMATION; PERMISSIONS.WINDOWS.USER_DATA_ACCOUNTS_PROVIDER; PERMISSIONS.WINDOWS.USER_DATA_SYSTEM; PERMISSIONS.WINDOWS.USER_PRINCIPAL_NAME; PERMISSIONS.WINDOWS.USER_SYSTEM_ID; PERMISSIONS.WINDOWS.VIDEOS_LIBRARY; PERMISSIONS.WINDOWS.VOIP_CALL; PERMISSIONS.WINDOWS.WALLET_SYSTEM; PERMISSIONS.WINDOWS.WEBCAM; PERMISSIONS.WINDOWS.WIFI_CONTROL; PERMISSIONS.WINDOWS.XBOX_ACCESSORY_MANAGEMENT; ``` </details> ### Permissions statuses Permission checks and requests resolve into one of these statuses: | Return value | Notes | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `RESULTS.UNAVAILABLE` | This feature is not available (on this device / in this context) | | `RESULTS.DENIED` | The permission has not been requested / is denied but requestable | | `RESULTS.BLOCKED` | The permission is denied and not requestable | | `RESULTS.GRANTED` | The permission is granted | | `RESULTS.LIMITED` | The permission is granted but with limitations<br>_Only for iOS `Contacts`, `PhotoLibrary`, `PhotoLibraryAddOnly` and `Notifications`_ | ### Types ```ts type ValueOf<T> = T[keyof T]; type Permission = | ValueOf<typeof PERMISSIONS.ANDROID> | ValueOf<typeof PERMISSIONS.IOS> | ValueOf<typeof PERMISSIONS.WINDOWS>; type PermissionStatus = ValueOf<typeof RESULTS>; type RationaleObject = { title: string; message: string; buttonPositive: string; buttonNegative?: string; }; type Rationale = RationaleObject | (() => Promise<boolean>); type NotificationOption = | 'alert' | 'badge' | 'sound' | 'carPlay' | 'criticalAlert' | 'provisional' | 'providesAppSettings'; type NotificationSettings = { // unavailable settings will not be included in the response object alert?: boolean; badge?: boolean; sound?: boolean; carPlay?: boolean; criticalAlert?: boolean; provisional?: boolean; providesAppSettings?: boolean; lockScreen?: boolean; notificationCenter?: boolean; }; type NotificationsResponse = { status: PermissionStatus; settings: NotificationSettings; }; type LocationAccuracy = 'full' | 'reduced'; type LocationAccuracyOptions = {purposeKey: string}; ``` ### Methods #### check Check one permission status. > [!IMPORTANT] > On Android, the `check` function will never return a `blocked` status. You need to call `request` to obtain that information. ```ts function check(permission: Permission): Promise<PermissionStatus>; ``` ```ts check(PERMISSIONS.IOS.CAMERA).then((status) => { switch (status) { case RESULTS.UNAVAILABLE: return console.log('This feature is not available (on this device / in this context)'); case RESULTS.DENIED: return console.log('The permission has not been requested / is denied but requestable'); case RESULTS.BLOCKED: return console.log('The permission is denied and not requestable'); case RESULTS.GRANTED: return console.log('The permission is granted'); case RESULTS.LIMITED: return console.log('The permission is granted but with limitations'); } }); ``` #### request Request one permission. The `rationale` is only available and used on Android. It can be a native alert (a `RationaleObject`) or a custom implementation (that resolves with a `boolean`). ```ts function request(permission: Permission, rationale?: Rationale): Promise<PermissionStatus>; ``` ```ts import {request, PERMISSIONS} from 'react-native-permissions'; request(PERMISSIONS.IOS.CAMERA).then((status) => { // … }); ``` #### checkNotifications Check notifications permission status and get notifications settings values. > [!IMPORTANT] > On Android 13+, the `checkNotifications` function will never return a `blocked` status. You need to call `requestNotifications` to obtain that information. ```ts function checkNotifications(): Promise<NotificationsResponse>; ``` ```ts import {checkNotifications} from 'react-native-permissions'; checkNotifications().then(({status, settings}) => { // … }); ``` #### requestNotifications Request notifications permission status and get notifications settings values. - You have to [target at least SDK 33](https://github.com/zoontek/react-native-permissions/releases/tag/3.5.0) to perform a runtime request on Android 13+. - You cannot request notifications permissions on Windows. Disabling / enabling them can only be done through the app settings. The `rationale` is only available and used on Android. It can be a native alert (a `RationaleObject`) or a custom implementation (that resolves with a `boolean`). ```ts function requestNotifications( options?: NotificationOption[], // only used by iOS rationale?: Rationale, ): Promise<NotificationsResponse>; ``` ```ts import {requestNotifications} from 'react-native-permissions'; requestNotifications(['alert', 'sound']).then(({status, settings}) => { // … }); ``` #### checkMultiple Check multiples permissions in parallel. > [!IMPORTANT] > On Android, the `checkMultiple` function will never return a `blocked` status. You need to call `requestMultiple` to obtain that information. ```ts function checkMultiple<P extends Permission[]>( permissions: P, ): Promise<Record<P[number], PermissionStatus>>; ``` ```ts import {checkMultiple, PERMISSIONS} from 'react-native-permissions'; checkMultiple([PERMISSIONS.IOS.CAMERA, PERMISSIONS.IOS.FACE_ID]).then((statuses) => { console.log('Camera', statuses[PERMISSIONS.IOS.CAMERA]); console.log('FaceID', statuses[PERMISSIONS.IOS.FACE_ID]); }); ``` #### requestMultiple Request multiple permissions in sequence. ```ts function requestMultiple<P extends Permission[]>( permissions: P, ): Promise<Record<P[number], PermissionStatus>>; ``` ```ts import {requestMultiple, PERMISSIONS} from 'react-native-permissions'; requestMultiple([PERMISSIONS.IOS.CAMERA, PERMISSIONS.IOS.FACE_ID]).then((statuses) => { console.log('Camera', statuses[PERMISSIONS.IOS.CAMERA]); console.log('FaceID', statuses[PERMISSIONS.IOS.FACE_ID]); }); ``` #### openSettings Open application / alarms / notifications / fullscreen settings (default to `application`). > [!NOTE] > > - `notifications` settings are only available on Android 8+ and iOS 15.4+ > - `alarms` settings are only available on Android 12+ > - `fullscreen` settings are only available on Android 14+ > - If a choice is not available, it fallbacks to `application` settings ```ts function openSettings( type?: 'application' | 'alarms' | 'fullscreen' | 'notifications', ): Promise<void>; ``` ```ts import {openSettings} from 'react-native-permissions'; openSettings('application').catch(() => console.warn('Cannot open app settings')); ``` #### canScheduleExactAlarms (Android) Check if your app can schedule exact alarms. ```ts function canScheduleExactAlarms(): Promise<boolean>; ``` ```ts import {canScheduleExactAlarms} from 'react-native-permissions'; canScheduleExactAlarms() .then((value) => console.log(`Can schedule exact alarms: ${value}`)) .catch(() => console.warn('Cannot check exact alarms scheduling setting')); ``` #### canUseFullScreenIntent (Android) Check if your app can use full screen intent. ```ts function canUseFullScreenIntent(): Promise<boolean>; ``` ```ts import {canUseFullScreenIntent} from 'react-native-permissions'; canUseFullScreenIntent() .then((value) => console.log(`Can use full screen intent: ${value}`)) .catch(() => console.warn('Cannot check full screen intent using setting')); ``` #### openPhotoPicker (iOS 14+) Open a picker to update the photo selection when `PhotoLibrary` permission is `limited`. This will reject if unsupported or if full permission is already `granted`. ```ts function openPhotoPicker(): Promise<void>; ``` ```ts import {openPhotoPicker} from 'react-native-permissions'; openPhotoPicker().catch(() => console.warn('Cannot open photo library picker')); ``` #### checkLocationAccuracy (iOS 14+) When `LocationAlways` or `LocationWhenInUse` is `granted`, allow checking if the user share his precise location. ```ts function checkLocationAccuracy(): Promise<LocationAccuracy>; ``` ```ts import {checkLocationAccuracy} from 'react-native-permissions'; checkLocationAccuracy() .then((accuracy) => console.log(`Location accuracy is: ${accuracy}`)) .catch(() => console.warn('Cannot check location accuracy')); ``` #### requestLocationAccuracy (iOS 14+) When `LocationAlways` or `LocationWhenInUse` is `granted`, allow requesting the user for his precise location. Will resolve immediately if `full` accuracy is already authorized. ```ts function requestLocationAccuracy(options: LocationAccuracyOptions): Promise<LocationAccuracy>; ``` ```js import {requestLocationAccuracy} from 'react-native-permissions'; requestLocationAccuracy({purposeKey: 'YOUR-PURPOSE-KEY'}) .then((accuracy) => console.log(`Location accuracy is: ${accuracy}`)) .catch(() => console.warn('Cannot request location accuracy')); ``` ### About iOS `LOCATION_ALWAYS` permission On iOS, background location permission can be requested in two different ways ([Apple Developer Docs 📘](https://developer.apple.com/documentation/corelocation/cllocationmanager/1620551-requestalwaysauthorization#3578736)). #### Request `LOCATION_ALWAYS` after `LOCATION_WHEN_IN_USE` If the user chooses _Allow While Using App_ when calling `request(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE)`, then calling `request(PERMISSIONS.IOS.LOCATION_ALWAYS)` afterward will immediately prompt the user: <img width="250" src="./docs/location_always_upgrade.png" alt="Location upgrade"> | Option | `LOCATION_ALWAYS` status | `LOCATION_WHEN_IN_USE` status | | ---------------------- | ------------------------ | ----------------------------- | | Keep Only While Using | `RESULTS.BLOCKED` | `RESULTS.GRANTED` | | Change to Always Allow | `RESULTS.GRANTED` | `RESULTS.GRANTED` | --- #### Request `LOCATION_ALWAYS` directly The user is immediately prompted: <img width="250" src="./docs/location_always_first_prompt.png" alt="Location first prompt"> | Option | `LOCATION_ALWAYS` status | `LOCATION_WHEN_IN_USE` status | | --------------------- | ------------------------ | ----------------------------- | | Allow Once | `RESULTS.BLOCKED` | `RESULTS.GRANTED` | | Allow While Using App | `RESULTS.GRANTED` | `RESULTS.GRANTED` | | Don’t Allow | `RESULTS.BLOCKED` | `RESULTS.BLOCKED` | In this scenario, if the user chooses `Allow While Using App`, they will see `While Using` in the app settings and will later be informed that your app is using their location in background with the option to confirm / change it: <img width="250" src="./docs/location_always_second_prompt.png" alt="Location second prompt"> ### Testing with Jest If you don't already have a Jest setup file configured, please add the following to your Jest configuration file and create the new `jest.setup.js` file in project root: ```js setupFiles: ['<rootDir>/jest.setup.js']; ``` You can then add the following line to that setup file to mock the `NativeModule.RNPermissions`: ```js jest.mock('react-native-permissions', () => require('react-native-permissions/mock')); ``` ## Sponsors This module is provided **as is**, I work on it in my free time. If you or your company uses it in a production app, consider sponsoring this project 💰. You also can contact me for **premium** enterprise support: help with issues, prioritize bugfixes, feature requests, etc. <a href="https://github.com/sponsors/zoontek"><img align="center" alt="Sponsors list" src="https://raw.githubusercontent.com/zoontek/sponsors/main/sponsorkit/sponsors.svg"></a>

Developer Tools Mobile Development
4.4K Github Stars
react-native-bootsplash
Open Source

react-native-bootsplash

# 🚀 react-native-bootsplash Show a splash screen during app startup. Hide it when you are ready.<br> **For migration from the v6, check the [`MIGRATION.md` guide](./MIGRATION.md).** [![mit licence](https://img.shields.io/dub/l/vibe-d.svg?style=for-the-badge)](https://github.com/zoontek/react-native-bootsplash/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/react-native-bootsplash?style=for-the-badge)](https://www.npmjs.org/package/react-native-bootsplash) [![npm downloads](https://img.shields.io/npm/dt/react-native-bootsplash.svg?label=downloads&style=for-the-badge)](https://www.npmjs.org/package/react-native-bootsplash) <br /> [![platform - android](https://img.shields.io/badge/platform-Android-3ddc84.svg?logo=android&style=for-the-badge)](https://www.android.com) [![platform - ios](https://img.shields.io/badge/platform-iOS-000.svg?logo=apple&style=for-the-badge)](https://developer.apple.com/ios) <p> <img width="393" src="./docs/demo_static.png" alt="Demo"> <img width="255" src="./docs/demo.gif" alt="Demo"> </p> ## Support This library follows the React Native [releases support policy](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).<br> It is supporting the **latest version**, and the **two previous minor series**. ## Installation ```bash $ npm install --save react-native-bootsplash # --- or --- $ yarn add react-native-bootsplash ``` _⚠️  Don't forget going into the `ios` directory to execute a `pod install`._ ## Setup ### Assets generation In order to speed up the setup, we provide a **CLI** to generate assets, update config files, create the Android Drawable XML file and the iOS Storyboard file automatically ✨. ```bash $ npx react-native-bootsplash generate --help # --- or --- $ yarn react-native-bootsplash generate --help ``` The command can take multiple arguments: ```bash Usage: react-native-bootsplash generate [options] <logo> Generate a launch screen using a logo file path (PNG or SVG) Arguments: logo Logo file path (PNG or SVG) Options: --platforms <list> Platforms to generate for, separated by a comma (default: "android,ios,web") --background <string> Background color (in hexadecimal format) (default: "#fff") --logo-width <number> Logo width at @1x (in dp - we recommend approximately ~100) (default: 100) --assets-output <string> Assets output directory path (default: "assets/bootsplash") --flavor <string> Android flavor build variant (where your resource directory is) (default: "main") --html <string> HTML template file path (your web app entry point) (default: "public/index.html") --plist <string> Custom Info.plist file path --license-key <string> License key to enable brand and dark mode assets generation --brand <string> Brand file path (PNG or SVG) --brand-width <number> Brand width at @1x (in dp - we recommend approximately ~80) (default: 80) --dark-background <string> [dark mode] Background color (in hexadecimal format) --dark-logo <string> [dark mode] Logo file path (PNG or SVG) --dark-brand <string> [dark mode] Brand file path (PNG or SVG) -h, --help display help for command ``` #### 💪 Unlock the CLI full potential In order to use the `--brand`, `--brand-width` and `--dark-*` options, you must specify a `--license-key`. With it, the generator is able to output over **50 files** (logo and brand images generated in all pixel densities, dark mode versions, etc.), saving you (and your company!) a massive amount of time not only at creation, but also at each adjustment ⏱️ _📍 This license key grants unlimited and unrestricted usage of the generator for the buyer's purposes (meaning you can execute the assets generation as much as you want)._ <a href="https://zoontek.gumroad.com/l/bootsplash-generator"> <img width="280" src="./docs/gumroad_button.png" alt="Gumroad button"> </a> #### Full command usage example ```bash # Without license key yarn react-native-bootsplash generate svgs/light-logo.svg \ --platforms=android,ios,web \ --background=F5FCFF \ --logo-width=100 \ --assets-output=assets/bootsplash \ --flavor=main \ --html=public/index.html # With license key 🔑 yarn react-native-bootsplash generate svgs/light-logo.svg \ --platforms=android,ios,web \ --background=F5FCFF \ --logo-width=100 \ --assets-output=assets/bootsplash \ --flavor=main \ --html=public/index.html \ --license-key=xxxxx \ --brand=svgs/light-brand.svg \ --brand-width=80 \ --dark-background=00090A \ --dark-logo=svgs/dark-logo.svg \ --dark-brand=svgs/dark-brand.svg ``` ![](./docs/cli_generator.png) ### With Expo 1. First, uninstall `expo-splash-screen`: ```bash $ npm uninstall expo-splash-screen # --- or --- $ yarn remove expo-splash-screen ``` ```diff { "expo": { "plugins": [ - [ - "expo-splash-screen", - { - "image": "./assets/images/splash-icon.png", - "imageWidth": 200, - "resizeMode": "contain", - "backgroundColor": "#ffffff" - } - ], ] } } ``` 2. Add the plugin in your app config (_if you have a license key, pass it via the `BOOTSPLASH_LICENSE_KEY` environment variable_): <details open> <summary><strong>Dynamic configuration (app.config.js, app.config.ts)</strong></summary> ```ts import type { ConfigContext, ExpoConfig } from "expo/config"; import bootsplash from "react-native-bootsplash/expo"; // use `require` in app.config.js export default ({ config }: ConfigContext): ExpoConfig => ({ // … platforms: ["android", "ios", "web"], // must be explicit plugins: [ bootsplash({ logo: "./assets/logo.png", logoWidth: 100, background: "#f5fcff", // … }), ], }); ``` </details> <details> <summary><strong>Static configuration (app.json)</strong></summary> ```jsonc { "expo": { // … "platforms": ["android", "ios", "web"], // must be explicit "plugins": [ [ "react-native-bootsplash", { "logo": "./assets/logo.png", "logoWidth": 100, "background": "#f5fcff", // … }, ], ], }, } ``` </details> _📌 The available plugins options are:_ ```ts type PluginOptions = { android?: { darkContentBarsStyle?: boolean; // Enforce system bars style (default: undefined) }; logo: string; // Logo file path (PNG or SVG) - required background?: string; // Background color (in hexadecimal format) (default: "#fff") logoWidth?: number; // Logo width at @1x (in dp - we recommend approximately ~100) (default: 100) assetsOutput?: string; // Assets output directory path (default: "assets/bootsplash") // Addon options brand?: string; // Brand file path (PNG or SVG) brandWidth?: number; // Brand width at @1x (in dp - we recommend approximately ~80) (default: 80) darkBackground?: string; // [dark mode] Background color (in hexadecimal format) darkLogo?: string; // [dark mode] Logo file path (PNG or SVG) darkBrand?: string; // [dark mode] Brand file path (PNG or SVG) }; ``` ### With bare React Native #### iOS Edit your `ios/YourApp/AppDelegate.swift` file: ```swift import ReactAppDependencyProvider import RNBootSplash // ⬅️ add this import // … class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { // … // ⬇️ override this method override func customize(_ rootView: RCTRootView) { super.customize(rootView) RNBootSplash.initWithStoryboard("BootSplash", rootView: rootView) // ⬅️ initialize the splash screen } } ``` #### Android Edit your `android/app/src/main/java/com/yourapp/MainActivity.kt` file: <details open> <summary><strong>Without react-native-screens</strong></summary> ```kotlin // ⬇️ add these required imports import android.os.Bundle import com.zoontek.rnbootsplash.RNBootSplash // … class MainActivity : ReactActivity() { // … override fun onCreate(savedInstanceState: Bundle?) { RNBootSplash.init(this, R.style.BootTheme) // ⬅️ initialize the splash screen super.onCreate(savedInstanceState) } } ``` </details> <details> <summary><strong>With react-native-screens >= v4.16.0</strong></summary> ```kotlin // ⬇️ add these required imports import android.os.Bundle import com.swmansion.rnscreens.fragment.restoration.RNScreensFragmentFactory import com.zoontek.rnbootsplash.RNBootSplash // … class MainActivity : ReactActivity() { // … override fun onCreate(savedInstanceState: Bundle?) { supportFragmentManager.fragmentFactory = RNScreensFragmentFactory() RNBootSplash.init(this, R.style.BootTheme) // ⬅️ initialize the splash screen super.onCreate(savedInstanceState) } } ``` </details> <details> <summary><strong>With react-native-screens < v4.16.0</strong></summary> ```kotlin // ⬇️ add these required imports import android.os.Bundle import com.zoontek.rnbootsplash.RNBootSplash // … class MainActivity : ReactActivity() { // … override fun onCreate(savedInstanceState: Bundle?) { RNBootSplash.init(this, R.style.BootTheme) // ⬅️ initialize the splash screen super.onCreate(null) } } ``` </details> _ℹ️ Refer to [previous package documentation](https://github.com/zoontek/react-native-bootsplash/tree/6.3.12?tab=readme-ov-file#with-bare-react-native) for setup steps with React Native < 0.80._ ## API ### hide() Hide the splash screen (immediately, or with a fade out). #### Method type ```ts type hide = (config?: { fade?: boolean }) => Promise<void>; ``` #### Usage ```tsx import { useEffect } from "react"; import { Text } from "react-native"; import BootSplash from "react-native-bootsplash"; const App = () => { useEffect(() => { const init = async () => { // …do multiple sync or async tasks }; init().finally(async () => { await BootSplash.hide({ fade: true }); console.log("BootSplash has been hidden successfully"); }); }, []); return <Text>My awesome app</Text>; }; ``` ### isVisible() Return the current visibility status of the native splash screen. #### Method type ```ts type isVisible = () => boolean; ``` #### Usage ```ts import BootSplash from "react-native-bootsplash"; if (BootSplash.isVisible()) { // Do something } ``` ### useHideAnimation() A hook to easily create a custom hide animation by animating all splash screen elements using `Animated`, `react-native-reanimated` or else (similar as the video on top of this documentation). #### Method type ```ts type useHideAnimation = (config: { ready?: boolean; // a boolean flag to delay the animate execution (default: true) // the required generated assets manifest: Manifest; // the manifest file is generated in your assets directory logo?: ImageRequireSource; darkLogo?: ImageRequireSource; brand?: ImageRequireSource; darkBrand?: ImageRequireSource; // specify if you are using translucent status / navigation bars // in order to avoid a shift between the native and JS splash screen statusBarTranslucent?: boolean; navigationBarTranslucent?: boolean; animate: () => void; }) => { container: ContainerProps; logo: LogoProps; brand: BrandProps; }; ``` #### Usage ```tsx import { useState } from "react"; import { Animated, Image } from "react-native"; import BootSplash from "react-native-bootsplash"; type Props = { onAnimationEnd: () => void; }; const AnimatedBootSplash = ({ onAnimationEnd }: Props) => { const [opacity] = useState(() => new Animated.Value(1)); const { container, logo /*, brand */ } = BootSplash.useHideAnimation({ manifest: require("../assets/bootsplash/manifest.json"), logo: require("../assets/bootsplash/logo.png"), // darkLogo: require("../assets/bootsplash/dark-logo.png"), // brand: require("../assets/bootsplash/brand.png"), // darkBrand: require("../assets/bootsplash/dark-brand.png"), animate: () => { // Perform animations and call onAnimationEnd Animated.timing(opacity, { useNativeDriver: true, toValue: 0, duration: 500, }).start(() => { onAnimationEnd(); }); }, }); return ( <Animated.View {...container} style={[container.style, { opacity }]}> <Image {...logo} /> {/* <Image {...brand} /> */} </Animated.View> ); }; const App = () => { const [visible, setVisible] = useState(true); return ( <View style={{ flex: 1 }}> {/* content */} {visible && ( <AnimatedBootSplash onAnimationEnd={() => { setVisible(false); }} /> )} </View> ); }; ``` **This example is simple for documentation purpose (we only animate the container).**<br> **🤙 A more complex example is available in the [`/example` folder](./example/src/AnimatedBootSplash.tsx).** ## FAQ ### How can I enforce the splash screen system bar colors? By default, the system bars uses `dark-content` in light mode and `light-content` in dark mode. To enforce a specific value, edit your `values/styles.xml` file: ```xml <resources> <!-- … --> <style name="BootTheme" parent="Theme.BootSplash"> <item name="darkContentBarsStyle">true</item> <!-- … --> </style> </resources> ``` ### Why are both light and dark assets inlined in my index.html? For the sake of simplicity. Since the light and dark versions of your assets are likely identical (except for the colors), if your `index.html` file is compressed with **gzip**, the size difference will be negligible. ### How should I use it with React Navigation? If you are using React Navigation, you can hide the splash screen once the navigation container and all children have finished mounting by using the `onReady` function. ```tsx import { NavigationContainer } from "@react-navigation/native"; import BootSplash from "react-native-bootsplash"; const App = () => ( <NavigationContainer onReady={() => { BootSplash.hide(); }} > {/* content */} </NavigationContainer> ); ``` ### How can I mock the module in my tests? Testing code which uses this library requires some setup since we need to mock the native methods. To add the mocks, create a file `jest/setup.js` (or any other file name) containing the following code: ```ts jest.mock("react-native-bootsplash", () => { return { hide: jest.fn().mockResolvedValue(), isVisible: jest.fn(), useHideAnimation: jest.fn().mockReturnValue({ container: {}, logo: { source: 0 }, brand: { source: 0 }, }), }; }); ``` After that, we need to add the setup file in the jest config. You can add it under [setupFiles](https://jestjs.io/docs/en/configuration.html#setupfiles-array) option in your jest config file: ```json { "setupFiles": ["<rootDir>/jest/setup.js"] } ``` ## Sponsors This module is provided **as is**, I work on it in my free time. If you or your company uses it in a production app, consider sponsoring this project 💰. You also can contact me for **premium** enterprise support: help with issues, prioritize bugfixes, feature requests, etc. <a href="https://github.com/sponsors/zoontek"><img align="center" alt="Sponsors list" src="https://raw.githubusercontent.com/zoontek/sponsors/main/sponsorkit/sponsors.svg"></a>

Developer Tools Mobile Development
4.3K Github Stars
react-native-localize
Open Source

react-native-localize

# 🌍  react-native-localize A toolbox for your React Native app localization. [![mit licence](https://img.shields.io/dub/l/vibe-d.svg?style=for-the-badge)](https://github.com/zoontek/react-native-localize/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/react-native-localize?style=for-the-badge)](https://www.npmjs.org/package/react-native-localize) [![npm downloads](https://img.shields.io/npm/dt/react-native-localize.svg?label=downloads&style=for-the-badge)](https://www.npmjs.org/package/react-native-localize) <br /> [![platform - android](https://img.shields.io/badge/platform-Android-3ddc84.svg?logo=android&style=for-the-badge)](https://www.android.com) [![platform - ios](https://img.shields.io/badge/platform-iOS-000.svg?logo=apple&style=for-the-badge)](https://developer.apple.com/ios) [![platform - macos](https://img.shields.io/badge/platform-macOS-000.svg?logo=apple&style=for-the-badge)](https://developer.apple.com/macos) [![platform - web](https://img.shields.io/badge/platform-Web-1977f2.svg?logo=html5&logoColor=fff&style=for-the-badge)](https://developer.mozilla.org) <img width="350" src="./docs/screenshot.png" /> ## Support This library follows the React Native [releases support policy](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).<br> It is supporting the **latest version**, and the **two previous minor series**. ## Setup ```bash $ npm install --save react-native-localize # --- or --- $ yarn add react-native-localize ``` _Don't forget to run `pod install` after that !_ ### Expo plugin If you're using Expo, you can specify the supported locales in your `app.json` or `app.config.js` using the config plugin. This enables Android 13+ and iOS to display the available locales in the system settings, allowing users to select their preferred language for your app. <details open> <summary><strong>Dynamic configuration (app.config.js, app.config.ts)</strong></summary> ```ts import type { ConfigContext, ExpoConfig } from "expo/config"; import localize from "react-native-localize/expo"; // use `require` in app.config.js export default ({ config }: ConfigContext): ExpoConfig => ({ plugins: [ localize({ locales: ["en", "fr"], // or { android: ["en"], ios: ["en", "fr"] } }), ], }); ``` </details> <details> <summary><strong>Static configuration (app.json)</strong></summary> ```jsonc { "expo": { "plugins": [ [ "react-native-localize", { "locales": ["en", "fr"], // or { android: ["en"], ios: ["en", "fr"] } }, ], ], }, } ``` </details> ### Web support This package supports `react-native-web`. Follow their [official guide](https://necolas.github.io/react-native-web/docs/multi-platform/#compiling-and-bundling) to configure `webpack`. ## Basic usage example ```ts import { getCurrencies, getLocales } from "react-native-localize"; console.log(getLocales()); console.log(getCurrencies()); ``` ## API ### getCalendar() Returns the user preferred calendar format. #### Method type ```ts type getCalendar = () => | "gregorian" | "buddhist" | "coptic" | "ethiopic" | "ethiopic-amete-alem" | "hebrew" | "indian" | "islamic" | "islamic-umm-al-qura" | "islamic-civil" | "islamic-tabular" | "iso8601" | "japanese" | "persian"; ``` #### Usage example ```ts import { getCalendar } from "react-native-localize"; console.log(getCalendar()); // -> "gregorian" ``` --- ### getCountry() Returns the user current country code (based on its device locale, **not** on its position). #### Method type ```ts type getCountry = () => string; ``` #### Usage example ```ts import { getCountry } from "react-native-localize"; console.log(getCountry()); // -> "FR" ``` #### Note Devices using Latin American regional settings will return "UN" instead of "419", as the latter is not a standard country code. --- ### getCurrencies() Returns the user preferred currency codes, in order. #### Method type ```ts type getCurrencies = () => string[]; ``` #### Usage example ```ts import { getCurrencies } from "react-native-localize"; console.log(getCurrencies()); // -> ["EUR", "GBP", "USD"] ``` --- ### getLocales() Returns the user preferred locales, in order. #### Method type ```ts type getLocales = () => Array<{ languageCode: string; scriptCode?: string; countryCode: string; languageTag: string; isRTL: boolean; }>; ``` #### Usage example ```ts import { getLocales } from "react-native-localize"; console.log(getLocales()); /* -> [ { countryCode: "GB", languageTag: "en-GB", languageCode: "en", isRTL: false }, { countryCode: "US", languageTag: "en-US", languageCode: "en", isRTL: false }, { countryCode: "FR", languageTag: "fr-FR", languageCode: "fr", isRTL: false }, ] */ ``` --- ### getNumberFormatSettings() Returns number formatting settings. #### Method type ```ts type getNumberFormatSettings = () => { decimalSeparator: string; groupingSeparator: string; }; ``` #### Usage example ```ts import { getNumberFormatSettings } from "react-native-localize"; console.log(getNumberFormatSettings()); /* -> { decimalSeparator: ".", groupingSeparator: ",", } */ ``` --- ### getTemperatureUnit() Returns the user preferred temperature unit. #### Method type ```ts type getTemperatureUnit = () => "celsius" | "fahrenheit"; ``` #### Usage example ```ts import { getTemperatureUnit } from "react-native-localize"; console.log(getTemperatureUnit()); // -> "celsius" ``` --- ### getTimeZone() Returns the user preferred timezone (based on its device settings, **not** on its position). #### Method type ```ts type getTimeZone = () => string; ``` #### Usage example ```ts import { getTimeZone } from "react-native-localize"; console.log(getTimeZone()); // -> "Europe/Paris" ``` --- ### uses24HourClock() Returns `true` if the user prefers 24h clock format, `false` if they prefer 12h clock format. #### Method type ```ts type uses24HourClock = () => boolean; ``` #### Usage example ```ts import { uses24HourClock } from "react-native-localize"; console.log(uses24HourClock()); // -> true ``` --- ### usesMetricSystem() Returns `true` if the user prefers metric measure system, `false` if they prefer imperial. #### Method type ```ts type usesMetricSystem = () => boolean; ``` #### Usage example ```ts import { usesMetricSystem } from "react-native-localize"; console.log(usesMetricSystem()); // -> true ``` --- ### usesAutoDateAndTime() Tells if the automatic date & time setting is enabled on the phone. **Android only** #### Method type ```ts type usesAutoDateAndTime = () => boolean | undefined; ``` #### Usage example ```ts import { usesAutoDateAndTime } from "react-native-localize"; console.log(usesAutoDateAndTime()); // true or false ``` --- ### usesAutoTimeZone() Tells if the automatic time zone setting is enabled on the phone. **Android only** #### Method type ```ts type usesAutoTimeZone = () => boolean | undefined; ``` #### Usage example ```ts import { usesAutoTimeZone } from "react-native-localize"; console.log(usesAutoTimeZone()); ``` --- ### findBestLanguageTag() Returns the best language tag possible and its reading direction. Useful to pick the best translation available. > [!NOTE] > > It respects the user preferred languages list order (see [explanations](https://github.com/zoontek/react-native-localize/issues/57#issuecomment-508456427)). #### Method type ```ts type findBestLanguageTag = ( languageTags: string[], ) => { languageTag: string; isRTL: boolean } | undefined; ``` #### Usage example ```ts import { findBestLanguageTag } from "react-native-localize"; console.log(findBestLanguageTag(["en-US", "en", "fr"])); // -> { languageTag: "en-US", isRTL: false } ``` --- ### openAppLanguageSettings() Opens the app language settings. > [!WARNING] > > This feature is available only on Android 13+ and require [configuring your app's supported locales](https://developer.android.com/guide/topics/resources/app-languages#use-localeconfig). #### Method type ```ts type openAppLanguageSettings = () => Promise<void>; ``` #### Usage example ```ts import { openAppLanguageSettings } from "react-native-localize"; openAppLanguageSettings("application").catch((error) => { console.warn("Cannot open app language settings", error); }); ``` ## Server-side rendering On the client, `react-native-localize` uses `navigator.languages`. During SSR, it gets language preferences from the server via the parsed `Accept-Language` header. #### 1. Wrap your app with `ServerLanguagesProvider` On the server, wrap your app with `ServerLanguagesProvider` and pass the user's languages: ```tsx import accepts from "accepts"; import { ServerLanguagesProvider } from "react-native-localize"; // parse the Accept-Language header; any approach returning string[] is fine const languages = accepts(request).languages(); const html = renderToString( <ServerLanguagesProvider value={languages}> <App /> </ServerLanguagesProvider>, ); ``` #### 2. Use the `useLocalize` hook in your components In your components, use the `useLocalize` hook instead of calling the API methods directly: ```tsx import { useLocalize } from "react-native-localize"; const App = () => { const { getCountry } = useLocalize(); return <Text>Country: {getCountry()}</Text>; }; ``` ## Examples with [@formatjs/intl](https://formatjs.io/docs/intl) Browse the files in the [/example](https://github.com/zoontek/react-native-localize/tree/master/example) directory. ## How to update supported localizations (iOS) You can add / remove supported localizations in your Xcode project infos: ![](./docs/xcode-adding-locales.png) ## How to test your code Because it's a native module, you need to mock this package.<br /> The package provides a default mock you may import in your `__mocks__` directory: ```ts // __mocks__/react-native-localize.ts export * from "react-native-localize/mock"; // or "react-native-localize/mock/jest" ``` ## Sponsors This module is provided **as is**, I work on it in my free time. If you or your company uses it in a production app, consider sponsoring this project 💰. You also can contact me for **premium** enterprise support: help with issues, prioritize bugfixes, feature requests, etc. <a href="https://github.com/sponsors/zoontek"><img align="center" alt="Sponsors list" src="https://raw.githubusercontent.com/zoontek/sponsors/main/sponsorkit/sponsors.svg"></a>

JavaScript Libraries & Components i18n & Localisation
2.4K Github Stars
react-native-edge-to-edge
Open Source

react-native-edge-to-edge

# react-native-edge-to-edge Effortlessly enable [edge-to-edge](https://developer.android.com/develop/ui/views/layout/edge-to-edge) display in React Native, allowing your Android (v6 and above) app content to flow seamlessly beneath the system bars. > [!TIP] > If you're running React Native 0.81 or later, consider using the built-in `edgeToEdgeEnabled=true` Gradle property along with [`@zoontek/react-native-navigation-bar`](https://github.com/zoontek/react-native-navigation-bar) instead. [![mit licence](https://img.shields.io/dub/l/vibe-d.svg?style=for-the-badge)](https://github.com/zoontek/react-native-edge-to-edge/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/react-native-edge-to-edge?style=for-the-badge)](https://www.npmjs.org/package/react-native-edge-to-edge) [![npm downloads](https://img.shields.io/npm/dt/react-native-edge-to-edge.svg?label=downloads&style=for-the-badge)](https://www.npmjs.org/package/react-native-edge-to-edge) <img width="210" src="./docs/logo.svg" alt="Logo"> ## Credits This project has been built and is maintained thanks to the support from [Expo](https://expo.dev). <a href="https://expo.io"> <img width="180" src="./docs/expo.svg" alt="Expo"> </a> ## Support This library follows the React Native [releases support policy](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).<br> It is supporting the **latest version**, and the **two previous minor series**. ## Motivations ### Android 15 Recently, Google introduced a significant change: apps targeting SDK 35 will have edge-to-edge display [enforced by default](https://developer.android.com/about/versions/15/behavior-changes-15#edge-to-edge) on Android 15+. Google is _likely_ to mandate that app updates on the Play Store target SDK 35 starting on August 31, 2025. This assumption is based on the [previous years' requirements following a similar timeline](https://support.google.com/googleplay/android-developer/answer/11926878?sjid=11853000253346477363-EU#zippy=%2Care-there-any-exceptions-for-existing-apps-targeting-api-or-below:~:text=App%20update%20requirements). ### Consistency iOS has long used edge-to-edge displays, so adopting this design across all platforms ensures a consistent user experience. It also simplifies managing safe areas, eliminating the need for special cases specific to Android. ### Immersive mode [Immersive mode](https://developer.android.com/develop/ui/views/layout/immersive) allows you to hide the status and navigation bars, making it ideal for full-screen experiences. Currently, the built-in [`StatusBar`](https://reactnative.dev/docs/statusbar) component uses [`FLAG_FULLSCREEN`](https://developer.android.com/reference/android/view/WindowManager.LayoutParams#FLAG_FULLSCREEN), a flag that has been deprecated since Android 11. ## Installation ```bash $ npm i -S react-native-edge-to-edge # --- or --- $ yarn add react-native-edge-to-edge ``` ### Pick a parent theme This library requires you to update the parent of your Android `AppTheme` to an edge-to-edge version. Don't worry, it's very easy to understand! You just need to choose a theme based on the current value: | If you currently have… | …you should use | | :------------------------------------------------------------- | :--------------------------------------------------- | | `Theme.AppCompat.DayNight.NoActionBar` | `Theme.EdgeToEdge` | | `Theme.MaterialComponents.DayNight.NoActionBar` | `Theme.EdgeToEdge.Material2` | | `Theme.Material3.DayNight.NoActionBar` | `Theme.EdgeToEdge.Material3` | | `Theme.Material3.DynamicColors.DayNight.NoActionBar` | `Theme.EdgeToEdge.Material3.Dynamic` | | `Theme.Material3Expressive.DayNight.NoActionBar` | `Theme.EdgeToEdge.Material3Expressive` | | `Theme.Material3Expressive.DynamicColors.DayNight.NoActionBar` | `Theme.EdgeToEdge.Material3Expressive.Dynamic` | | `Theme.AppCompat.Light.NoActionBar` | `Theme.EdgeToEdge.Light` | | `Theme.MaterialComponents.Light.NoActionBar` | `Theme.EdgeToEdge.Material2.Light` | | `Theme.Material3.Light.NoActionBar` | `Theme.EdgeToEdge.Material3.Light` | | `Theme.Material3.DynamicColors.Light.NoActionBar` | `Theme.EdgeToEdge.Material3.Dynamic.Light` | | `Theme.Material3Expressive.Light.NoActionBar` | `Theme.EdgeToEdge.Material3Expressive.Light` | | `Theme.Material3Expressive.DynamicColors.Light.NoActionBar` | `Theme.EdgeToEdge.Material3Expressive.Dynamic.Light` | ### Expo Add the library plugin in your app config file and [create a new build](https://docs.expo.dev/develop/development-builds/create-a-build) 👷: <details open> <summary><strong>Dynamic configuration (app.config.js, app.config.ts)</strong></summary> ```ts import type { ConfigContext, ExpoConfig } from "expo/config"; import edgeToEdge from "react-native-edge-to-edge/expo"; // use `require` in app.config.js export default ({ config }: ConfigContext): ExpoConfig => ({ // … plugins: [ edgeToEdge({ android: { parentTheme: "Default", enforceNavigationBarContrast: false, }, }), ], }); ``` </details> <details> <summary><strong>Static configuration (app.json)</strong></summary> ```jsonc { "expo": { // … "plugins": [ [ "react-native-edge-to-edge", { "android": { "parentTheme": "Default", "enforceNavigationBarContrast": false, }, }, ], ], }, } ``` </details> _📌 The available plugins options are:_ ```ts type ParentTheme = | "Default" // uses `Theme.EdgeToEdge` | "Material2" // uses `Theme.EdgeToEdge.Material2` | "Material3" // uses `Theme.EdgeToEdge.Material3` | "Material3.Dynamic" // uses `Theme.EdgeToEdge.Material3.Dynamic` | "Material3Expressive" // uses `Theme.EdgeToEdge.Material3Expressive` | "Material3Expressive.Dynamic" // uses `Theme.EdgeToEdge.Material3Expressive.Dynamic` | "Light" // uses `Theme.EdgeToEdge.Light` | "Material2.Light" // uses `Theme.EdgeToEdge.Material2.Light` | "Material3.Light" // uses `Theme.EdgeToEdge.Material3.Light` | "Material3.Dynamic.Light" // uses `Theme.EdgeToEdge.Material3.Dynamic.Light` | "Material3Expressive.Light" // uses `Theme.EdgeToEdge.Material3Expressive.Light` | "Material3Expressive.Dynamic.Light"; // uses `Theme.EdgeToEdge.Material3Expressive.Dynamic.Light` type Options = { android?: { // see the "Pick a parent theme" section parentTheme?: ParentTheme; // optional (default: `Default`) // see the "Transparent navigation bar" section enforceNavigationBarContrast?: boolean; // optional (default: `true`) }; }; ``` > [!NOTE] > These configuration properties are not supported in the [Expo Go](https://expo.dev/go) sandbox app, use a [development build](https://docs.expo.dev/develop/development-builds/create-a-build/). ### Bare React Native Edit your `android/app/src/main/res/values/styles.xml` file to inherit from one of the provided themes: ```xml <resources> <!-- update your AppTheme parent (see the "Pick a parent theme" section) --> <style name="AppTheme" parent="Theme.EdgeToEdge"> <!-- … --> <!-- disable the contrasting background of the navigation bar (optional) --> <item name="enforceNavigationBarContrast">false</item> </style> </resources> ``` ## Considerations ### Transparent navigation bar By default, this library adopts [Android 15 defaults](https://developer.android.com/about/versions/15/behavior-changes-15#ux): a fully transparent status bar, a fully transparent gesture navigation bar, and a semi-opaque button navigation bar. To enforce full transparency in all cases, set the `enforceNavigationBarContrast` option to `false`.<br/> Note that by doing so, you will need to manage the navigation bar style (using `SystemBars`) in the same way you handle the status bar. ### Keyboard management Enabling edge-to-edge display disrupts Android keyboard management (`android:windowSoftInputMode="adjustResize"`), requiring an alternative solution. While [`KeyboardAvoidingView`](https://reactnative.dev/docs/keyboardavoidingview) is a viable option, we recommend using [react-native-keyboard-controller](https://github.com/kirillzyusko/react-native-keyboard-controller) for its enhanced capabilities. ### Safe area management Effective safe area management is essential to prevent content from being displayed behind transparent system bars. To achieve this, we highly recommend using [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context), a well-known and trusted library. ### Modal component quirks React native built-in [`Modal`](https://reactnative.dev/docs/modal) component runs in its own native context, so be sure to set both the `statusBarTranslucent` and `navigationBarTranslucent` props to `true`. However, we recommend using the [react-navigation modals](https://reactnavigation.org/docs/modal) or the [`expo-router` modal screens](https://docs.expo.dev/router/advanced/modals/#modal-screen-using-expo-router) instead. ## API ### SystemBars Using [`StatusBar`](https://reactnative.dev/docs/statusbar), [`expo-status-bar`](https://docs.expo.dev/versions/latest/sdk/status-bar), or [`expo-navigation-bar`](https://docs.expo.dev/versions/latest/sdk/navigation-bar/) in apps with edge-to-edge layout enabled may cause unexpected behavior, as they currently use [deprecated APIs](https://developer.android.com/about/versions/15/behavior-changes-15#deprecated-apis).<br/> To address this, we provide a component to replace them and manage your app's system bars: `<SystemBars />`. ```tsx import { SystemBars } from "react-native-edge-to-edge"; // "auto" is based on current color scheme (light -> dark content, dark -> light content) type Style = "auto" | "inverted" | "light" | "dark"; type SystemBarsProps = { // set the color of the system bar content (as no effect on semi-opaque navigation bar) style?: Style | { statusBar?: Style; navigationBar?: Style }; // hide system bars (the navigation bar cannot be hidden on iOS) hidden?: boolean | { statusBar?: boolean; navigationBar?: boolean }; }; const App = () => ( <> <SystemBars style="light" /> {/* … */} </> ); ``` #### SystemBars.pushStackEntry Push a `SystemBars` entry onto the stack. The return value should be passed to `popStackEntry` when complete. ```ts const entry: SystemBarsEntry = SystemBars.pushStackEntry( props /*: SystemBarsProps */, ); ``` #### SystemBars.popStackEntry Remove an existing `SystemBars` stack entry from the stack. ```ts SystemBars.popStackEntry(entry /*: SystemBarsEntry */); ``` #### SystemBars.replaceStackEntry Replace an existing `SystemBars` stack entry with new props. ```ts const entry: SystemBarsEntry = SystemBars.replaceStackEntry( entry /*: SystemBarsEntry */, props /*: SystemBarsProps */, ); ``` #### SystemBars.setStyle Set the system bars style. ```ts SystemBars.setStyle(style /*: SystemBarsProps["style"] */); ``` #### SystemBars.setHidden Show or hide the system bars. ```ts SystemBars.setHidden(style /*: SystemBarsProps["hidden"] */); ``` ## Third-party libraries 🧩 If you're an author and your package interferes with edge-to-edge, refer to the [`react-native-is-edge-to-edge` `README.md`](./react-native-is-edge-to-edge) for compatibility instructions. ## Troubleshooting 🤔 #### The navigation bar style is erratic There's currently [an open issue](https://issuetracker.google.com/issues/346386744) with the Android 15 emulator image regarding the navigation bar style when it is is fully transparent. This issue does not occur on physical devices. #### The system bars stays opaque In recent months, support has been added across the React Native ecosystem. If you use any of the following libraries, make sure you're on the latest version: - `expo-router` - `galeria` - `react-native-avoid-softinput` - `react-native-bootsplash` - `react-native-bottom-tabs` - `react-native-keyboard-controller` - `react-native-reanimated` - `react-native-screens` - `react-native-true-sheet` - `react-native-unistyles (v3)` Make also sure to replace all occurrences of the built-in `StatusBar`, [`expo-status-bar`](https://docs.expo.dev/versions/latest/sdk/status-bar) and [`expo-navigation-bar`](https://docs.expo.dev/versions/latest/sdk/navigation-bar/) with `SystemBars`.

JavaScript Libraries & Components Mobile Development
1K Github Stars