Expo SecureStore iconExpo SecureStore

一个库,提供一种在设备本地加密和安全存储键值对的方法。

Android
iOS
tvOS
Included in Expo Go
Bundled version:
~15.0.8

expo-secure-store 提供了一种方法,可以在设备上本地加密并安全存储键值对。每个 Expo 项目都有独立的存储系统,无法访问其他 Expo 项目的存储。

底层平台可能会拒绝大型负载。历史上,一些 iOS 版本拒绝大约 2048 字节以上的值。Expo 不强制限制,因此如果你计划存储非常大的字符串,请确保处理原生错误。

当生物识别身份验证可用时,由于缺少 NSFaceIDUsageDescription 密钥,Expo Go 不支持 requireAuthentication 选项。

安装

🌐 Installation

Terminal
npx expo install expo-secure-store

If you are installing this in an existing React Native app, make sure to install expo in your project.

应用配置中的配置

🌐 Configuration in app config

如果你在项目中使用配置插件(连续原生生成 (CNG)),可以使用其内置的 配置插件 来配置 expo-secure-store。该插件允许你配置无法在运行时设置并且需要构建新的应用二进制文件才能生效的各种属性。如果你的应用使用 CNG,那么你需要手动配置该库。

🌐 You can configure expo-secure-store using its built-in config plugin if you use config plugins in your project (Continuous Native Generation (CNG)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does not use CNG, then you'll need to manually configure the library.

Example app.json with config plugin

app.json
{ "expo": { "plugins": [ [ "expo-secure-store", { "configureAndroidBackup": true, "faceIDPermission": "Allow $(PRODUCT_NAME) to access your Face ID biometric data." } ] ] } }

Configurable properties

NameDefaultDescription
configureAndroidBackuptrue
Only for:
Android

一个布尔值,指示是否配置自动 Android 备份以正确使用 expo-secure-store了解更多

faceIDPermission"允许 $(PRODUCT_NAME) 访问你的 Face ID 生物识别数据。"
Only for:
iOS

一个字符串,用于设置 NSFaceIDUsageDescription 权限提示信息。

Are you using this library in an existing React Native app?

NSFaceIDUsageDescription 键添加到 Info.plist

🌐 Add NSFaceIDUsageDescription key to Info.plist:

Info.plist
<key>NSFaceIDUsageDescription</key> <string>Allow $(PRODUCT_NAME) to access your Face ID biometric data.</string>

平台值存储

🌐 Platform value storage

安卓

🌐 Android

在 Android 上,值存储在 SharedPreferences 中,并使用 Android 的密钥库系统 加密。

🌐 On Android, values are stored in SharedPreferences, encrypted with Android's Keystore system.

iOS

在 iOS 上,数值使用 密钥串服务kSecClassGenericPassword 的形式存储。由于 iOS 密钥串的底层特性,使用 expo-secure-store 存储的数据在应用卸载后重新使用相同的 bundle ID 安装时仍会保留。 这是 iOS 密钥串系统的预期行为,在设计应用的数据处理时应加以考虑。iOS 还提供了设置数值 kSecAttrAccessible 属性的额外选项,该属性控制数值何时可被获取。

🌐 On iOS, values are stored using the keychain services as kSecClassGenericPassword. Due to the underlying nature of iOS Keychain, data stored with expo-secure-store will persist across app uninstallations when the app is reinstalled with the same bundle ID. This is an expected behavior of the iOS Keychain system and should be considered when designing your app's data handling. iOS has the additional option of being able to set the value's kSecAttrAccessible attribute, which controls when the value is available to be fetched.

数据持久性

🌐 Data persistence

expo-secure-store 旨在提供一种在应用重启和更新过程中保持持久数据存储的解决方案。然而,重要的是不要将其作为不可替代的关键数据的唯一可信来源。

  • 在 Android 上: 使用 expo-secure-store 保存的数据 在卸载应用时不会被保留
  • 在 iOS 上: 使用 expo-secure-store 保存的数据 在应用卸载后重新安装同一 bundle ID 的应用时仍会保留。这是由于 iOS 密钥串管理存储凭证的方式所致。请记住,这并非保证行为,你不应依赖这一实现细节。

此外,任何使用 requireAuthentication 选项设置为 true 保护的数据,如果用户的生物识别设置发生更改(例如添加新的指纹),将变得无法访问。

🌐 Additionally, any data protected with the requireAuthentication option set to true will become inaccessible if there are changes to the user's biometric settings, such as adding a new fingerprint.

免除加密提示

🌐 Exempting encryption prompt

苹果 App Store Connect 会提示你选择应用使用的加密算法类型。这被称为出口合规信息。在发布应用或提交 TestFlight 时会要求填写此信息。

🌐 Apple App Store Connect prompts you to select the type of encryption algorithm your app implements. This is known as Export Compliance Information. It is asked when publishing the app or submitting for TestFlight.

使用 expo-secure-store 时,你可以在应用配置中将 ios.config.usesNonExemptEncryption 属性设置为 false

🌐 When using expo-secure-store, you can set the ios.config.usesNonExemptEncryption property to false in the app config:

app.json
{ "expo": { "ios": { "config": { "usesNonExemptEncryption": false } %%placeholder-start%%... %%placeholder-end%% } } }

设置此属性会自动处理合规性信息提示。

🌐 Setting this property automatically handles the compliance information prompt.

Android 自动备份

🌐 Android Auto Backup

Android 自动备份应用 会自动备份用户在针对 Android 6.0(API 级别 23)或更高版本运行的应用中的数据。

必须配置自动备份系统以排除 expo-secure-store 共享偏好条目,因为在恢复备份后无法解密它们——当应用被卸载时,应用的条目会从 Android 密钥存储中删除。

🌐 The Auto Backup system has to be configured to exclude expo-secure-store shared preferences entries, as it's impossible to decrypt them after restoring the backup — app's entries are deleted from the Android Key Store when the app is uninstalled.

如果你的应用没有任何自定义备份配置,expo-secure-store 将自动配置自动备份系统以忽略 expo-secure-store 数据。

🌐 If your app doesn't have any custom backup configuration, expo-secure-store will automatically configure the Auto Backup system to ignore the expo-secure-store data.

如果你使用自己的自动备份配置,你应该在 sharedpref 域下排除 SecureStore,并在 配置插件配置 中将 configureAndroidBackup 设置为 false

🌐 If you are using your own Auto Backup configuration, you should exclude the SecureStore under the sharedpref domain and set the configureAndroidBackup to false in the config plugin configuration.

<!-- Auto Backup configuration for Android 12 and higher --> <data-extraction-rules> <cloud-backup> <include domain="sharedpref" path="."/> <exclude domain="sharedpref" path="SecureStore"/> </cloud-backup> <device-transfer> <include domain="sharedpref" path="."/> <exclude domain="sharedpref" path="SecureStore"/> </device-transfer> </data-extraction-rules>
<!-- Auto Backup configuration for Android 11 and lower --> <full-backup-content> <include domain="sharedpref" path="."/> <exclude domain="sharedpref" path="SecureStore"/> </full-backup-content>

用法

🌐 Usage

SecureStore
import { useState } from 'react'; import { Text, View, StyleSheet, TextInput, Button } from 'react-native'; import * as SecureStore from 'expo-secure-store'; async function save(key, value) { await SecureStore.setItemAsync(key, value); } async function getValueFor(key) { let result = await SecureStore.getItemAsync(key); if (result) { alert("🔐 Here's your value 🔐 \n" + result); } else { alert('No values stored under that key.'); } } export default function App() { const [key, onChangeKey] = useState('Your key here'); const [value, onChangeValue] = useState('Your value here'); return ( <View style={styles.container}> <Text style={styles.paragraph}>Save an item, and grab it later!</Text> {%%placeholder-start%%Add some TextInput components... %%placeholder-end%%} <TextInput style={styles.textInput} clearTextOnFocus onChangeText={text => onChangeKey(text)} value={key} /> <TextInput style={styles.textInput} clearTextOnFocus onChangeText={text => onChangeValue(text)} value={value} /> {} <Button title="保存此键/值对" onPress={() => { save(key, value); onChangeKey('Your key here'); onChangeValue('Your value here'); }} /> <Text style={styles.paragraph}>🔐 Enter your key 🔐</Text> <TextInput style={styles.textInput} onSubmitEditing={event => { getValueFor(event.nativeEvent.text); }} placeholder="Enter the key for the value you want to get" /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', paddingTop: 10, backgroundColor: '#ecf0f1', padding: 8, }, paragraph: { marginTop: 34, margin: 24, fontSize: 18, fontWeight: 'bold', textAlign: 'center', }, textInput: { height: 35, borderColor: 'gray', borderWidth: 0.5, padding: 4, }, });

应用接口

🌐 API

import * as SecureStore from 'expo-secure-store';

Constants

SecureStore.AFTER_FIRST_UNLOCK

Android
iOS
tvOS

Type: KeychainAccessibilityConstant

The data in the keychain item cannot be accessed after a restart until the device has been unlocked once by the user. This may be useful if you need to access the item when the phone is locked.

SecureStore.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY

Android
iOS
tvOS

Type: KeychainAccessibilityConstant

Similar to AFTER_FIRST_UNLOCK, except the entry is not migrated to a new device when restoring from a backup.

Deprecated: Use an accessibility level that provides some user protection, such as AFTER_FIRST_UNLOCK.

SecureStore.ALWAYS

Android
iOS
tvOS

Type: KeychainAccessibilityConstant

The data in the keychain item can always be accessed regardless of whether the device is locked. This is the least secure option.

Deprecated: Use an accessibility level that provides some user protection, such as AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY.

SecureStore.ALWAYS_THIS_DEVICE_ONLY

Android
iOS
tvOS

Type: KeychainAccessibilityConstant

Similar to ALWAYS, except the entry is not migrated to a new device when restoring from a backup.

SecureStore.WHEN_PASSCODE_SET_THIS_DEVICE_ONLY

Android
iOS
tvOS

Type: KeychainAccessibilityConstant

Similar to WHEN_UNLOCKED_THIS_DEVICE_ONLY, except the user must have set a passcode in order to store an entry. If the user removes their passcode, the entry will be deleted.

SecureStore.WHEN_UNLOCKED

Android
iOS
tvOS

Type: KeychainAccessibilityConstant

The data in the keychain item can be accessed only while the device is unlocked by the user.

SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY

Android
iOS
tvOS

Type: KeychainAccessibilityConstant

Similar to WHEN_UNLOCKED, except the entry is not migrated to a new device when restoring from a backup.

Methods

SecureStore.canUseBiometricAuthentication()

Android
iOS

Checks if the value can be saved with requireAuthentication option enabled.

Returns:
boolean

true if the device supports biometric authentication and the enrolled method is sufficiently secure. Otherwise, returns false. Always returns false on tvOS.

SecureStore.deleteItemAsync(key, options)

Android
iOS
tvOS
ParameterTypeDescription
keystring

The key that was used to store the associated value.

options(optional)SecureStoreOptions

An SecureStoreOptions object.

Default:{}

Delete the value associated with the provided key.

Returns:
Promise<void>

A promise that rejects if the value can't be deleted.

SecureStore.getItem(key, options)

Android
iOS
tvOS
ParameterTypeDescription
keystring

The key that was used to store the associated value.

options(optional)SecureStoreOptions

An SecureStoreOptions object.

Default:{}

Synchronously reads the stored value associated with the provided key.

Note: This function blocks the JavaScript thread, so the application may not be interactive when reading a value with requireAuthentication option set to true until the user authenticates.

Returns:
string | null

Previously stored value. It resolves with null if there is no entry for the given key or if the key has been invalidated.

SecureStore.getItemAsync(key, options)

Android
iOS
tvOS
ParameterTypeDescription
keystring

The key that was used to store the associated value.

options(optional)SecureStoreOptions

An SecureStoreOptions object.

Default:{}

Reads the stored value associated with the provided key.

Returns:
Promise<string | null>

A promise that resolves to the previously stored value. It resolves with null if there is no entry for the given key or if the key has been invalidated. It rejects if an error occurs while retrieving the value.

Keys are invalidated by the system when biometrics change, such as adding a new fingerprint or changing the face profile used for face recognition. After a key has been invalidated, it becomes impossible to read its value. This only applies to values stored with requireAuthentication set to true.

SecureStore.isAvailableAsync()

Android
iOS
tvOS

Returns whether the SecureStore API is enabled on the current device. This does not check the app permissions.

Returns:
Promise<boolean>

Promise which fulfils with a boolean, indicating whether the SecureStore API is available on the current device. Currently, this resolves true on Android and iOS only.

SecureStore.setItem(key, value, options)

Android
iOS
tvOS
ParameterTypeDescription
keystring

The key to associate with the stored value. Keys may contain alphanumeric characters, ., -, and _.

valuestring

The value to store.

options(optional)SecureStoreOptions

An SecureStoreOptions object.

Default:{}

Stores a key–value pair synchronously.

Note: This function blocks the JavaScript thread, so the application may not be interactive when the requireAuthentication option is set to true until the user authenticates.

Returns:
void

SecureStore.setItemAsync(key, value, options)

Android
iOS
tvOS
ParameterTypeDescription
keystring

The key to associate with the stored value. Keys may contain alphanumeric characters, ., -, and _.

valuestring

The value to store.

options(optional)SecureStoreOptions

An SecureStoreOptions object.

Default:{}

Stores a key–value pair.

Returns:
Promise<void>

A promise that rejects if value cannot be stored on the device.

Types

KeychainAccessibilityConstant

Android
iOS
tvOS

Type: number

SecureStoreOptions

Android
iOS
tvOS
PropertyTypeDescription
accessGroup(optional)string
Only for:
iOS

Specifies the access group the stored entry belongs to.

authenticationPrompt(optional)string

Custom message displayed to the user while requireAuthentication option is turned on.

keychainAccessible(optional)KeychainAccessibilityConstant
Only for:
iOS

Specifies when the stored entry is accessible, using iOS's kSecAttrAccessible property.

Default:SecureStore.WHEN_UNLOCKED

See: Apple's documentation on keychain item accessibility.

keychainService(optional)string
  • Android: Equivalent of the public/private key pair Alias.
  • iOS: The item's service, equivalent to kSecAttrService.

If the item is set with the keychainService option, it will be required to later fetch the value.

requireAuthentication(optional)boolean

Option responsible for enabling the usage of the user authentication methods available on the device while accessing data stored in SecureStore.

  • Android: Equivalent to setUserAuthenticationRequired(true) (requires API 23).
  • iOS: Equivalent to biometryCurrentSet. Complete functionality is unlocked only with a freshly generated key - this would not work in tandem with the keychainService value used for the others non-authenticated operations.

This option works slightly differently across platforms: On Android, user authentication is required for all operations. On iOS, the user is prompted to authenticate only when reading or updating an existing value (not when creating a new one).

Warning: This option is not supported in Expo Go when biometric authentication is available due to a missing NSFaceIDUsageDescription. In release builds or when using continuous native generation, make sure to use the expo-secure-store config plugin.