├── .gitignore ├── src ├── ReactNativeUserDefaults.ts ├── index.ts └── ReactNativeUserDefaults.ios.ts ├── .DS_Store ├── expo-module.config.json ├── .eslintrc.js ├── babel.config.js ├── tsconfig.json ├── ios ├── ReactNativeUserDefaults.podspec └── ReactNativeUserDefaultsModule.swift ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /src/ReactNativeUserDefaults.ts: -------------------------------------------------------------------------------- 1 | export default class UserDefaults {} 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrew-levy/react-native-userdefaults/HEAD/.DS_Store -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import UserDefaults from "./ReactNativeUserDefaults"; 2 | export default UserDefaults; 3 | -------------------------------------------------------------------------------- /expo-module.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "platforms": ["ios"], 3 | "ios": { 4 | "modules": ["ReactNativeUserDefaultsModule"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['universe/native', 'universe/web'], 4 | ignorePatterns: ['build'], 5 | }; 6 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | // @generated by expo-module-scripts 2 | { 3 | "extends": "expo-module-scripts/tsconfig.base", 4 | "compilerOptions": { 5 | "outDir": "./build" 6 | }, 7 | "include": ["./src"], 8 | "exclude": ["**/__mocks__/*", "**/__tests__/*"] 9 | } 10 | -------------------------------------------------------------------------------- /ios/ReactNativeUserDefaults.podspec: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json'))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'ReactNativeUserDefaults' 7 | s.version = package['version'] 8 | s.summary = package['description'] 9 | s.description = package['description'] 10 | s.license = package['license'] 11 | s.author = package['author'] 12 | s.homepage = package['homepage'] 13 | s.platform = :ios, '13.0' 14 | s.swift_version = '5.4' 15 | s.source = { git: 'https://github.com/andrew-levy/react-native-userdefaults' } 16 | s.static_framework = true 17 | 18 | s.dependency 'ExpoModulesCore' 19 | 20 | # Swift/Objective-C compatibility 21 | s.pod_target_xcconfig = { 22 | 'DEFINES_MODULE' => 'YES', 23 | 'SWIFT_COMPILATION_MODE' => 'wholemodule' 24 | } 25 | 26 | s.source_files = "**/*.{h,m,swift}" 27 | end 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@alevy97/react-native-userdefaults", 3 | "version": "0.2.2", 4 | "description": "UserDefaults in React Native", 5 | "main": "build/index.js", 6 | "types": "build/index.d.ts", 7 | "scripts": { 8 | "build": "expo-module build", 9 | "lint": "expo-module lint" 10 | }, 11 | "keywords": [ 12 | "react-native", 13 | "expo", 14 | "react-native-userdefaults", 15 | "ReactNativeUserDefaults" 16 | ], 17 | "repository": "https://github.com/andrew-levy/react-native-userdefaults", 18 | "author": "Andrew Levy", 19 | "license": "MIT", 20 | "homepage": "https://github.com/andrew-levy/react-native-userdefaults", 21 | "devDependencies": { 22 | "@types/react": "^18.0.25", 23 | "@types/react-native": "^0.70.6", 24 | "expo-module-scripts": "^3.0.3", 25 | "expo-modules-core": "^1.0.3" 26 | }, 27 | "peerDependencies": { 28 | "expo": "*", 29 | "react": "*", 30 | "react-native": "*" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ReactNativeUserDefaults.ios.ts: -------------------------------------------------------------------------------- 1 | import { requireNativeModule } from "expo-modules-core"; 2 | 3 | const ReactNativeUserDefaults = requireNativeModule("ReactNativeUserDefaults"); 4 | 5 | export default class UserDefaults { 6 | private suiteName: string; 7 | private isStandard: boolean; 8 | 9 | static standard = new UserDefaults(); 10 | 11 | constructor(suiteName?: string) { 12 | this.isStandard = suiteName === undefined; 13 | this.suiteName = suiteName || ""; 14 | } 15 | 16 | async get(forKey: string) { 17 | const result = await ReactNativeUserDefaults.get( 18 | forKey, 19 | this.suiteName, 20 | this.isStandard 21 | ); 22 | return result === null ? undefined : result; 23 | } 24 | async set(forKey: string, value: any) { 25 | if (value === undefined || value === null) { 26 | return await this.remove(forKey); 27 | } 28 | switch (typeof value) { 29 | case "string": 30 | return await ReactNativeUserDefaults.setString( 31 | forKey, 32 | value, 33 | this.suiteName, 34 | this.isStandard 35 | ); 36 | case "number": 37 | return await ReactNativeUserDefaults.setNumber( 38 | forKey, 39 | value, 40 | this.suiteName, 41 | this.isStandard 42 | ); 43 | case "boolean": 44 | return await ReactNativeUserDefaults.setBool( 45 | forKey, 46 | value, 47 | this.suiteName, 48 | this.isStandard 49 | ); 50 | case "object": 51 | if (Array.isArray(value)) { 52 | return await ReactNativeUserDefaults.setArray( 53 | forKey, 54 | value, 55 | this.suiteName, 56 | this.isStandard 57 | ); 58 | } 59 | return await ReactNativeUserDefaults.setObject( 60 | forKey, 61 | value, 62 | this.suiteName, 63 | this.isStandard 64 | ); 65 | } 66 | } 67 | 68 | async remove(forKey: string) { 69 | return await ReactNativeUserDefaults.remove( 70 | forKey, 71 | this.suiteName, 72 | this.isStandard 73 | ); 74 | } 75 | async getAll() { 76 | return await ReactNativeUserDefaults.getAll( 77 | this.suiteName, 78 | this.isStandard 79 | ); 80 | } 81 | async removeAll() { 82 | return await ReactNativeUserDefaults.removeAll( 83 | this.suiteName, 84 | this.isStandard 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /ios/ReactNativeUserDefaultsModule.swift: -------------------------------------------------------------------------------- 1 | import ExpoModulesCore 2 | 3 | public class ReactNativeUserDefaultsModule: Module { 4 | 5 | public func definition() -> ModuleDefinition { 6 | Name("ReactNativeUserDefaults") 7 | 8 | AsyncFunction("setString") { (forKey: String, value: String, suiteName: String, isStandard: Bool) in 9 | let userDefaults = isStandard ? UserDefaults.standard : UserDefaults(suiteName: suiteName) 10 | userDefaults?.set(value, forKey: forKey) 11 | } 12 | 13 | AsyncFunction("setBool") { (forKey: String, value: Bool, suiteName: String, isStandard: Bool) in 14 | let userDefaults = isStandard ? UserDefaults.standard : UserDefaults(suiteName: suiteName) 15 | userDefaults?.set(value, forKey: forKey) 16 | } 17 | 18 | AsyncFunction("setArray") { (forKey: String, value: [Any], suiteName: String, isStandard: Bool) in 19 | let userDefaults = isStandard ? UserDefaults.standard : UserDefaults(suiteName: suiteName) 20 | userDefaults?.set(value, forKey: forKey) 21 | } 22 | 23 | AsyncFunction("setObject") { (forKey: String, value: [String: Any], suiteName: String, isStandard: Bool) in 24 | let userDefaults = isStandard ? UserDefaults.standard : UserDefaults(suiteName: suiteName) 25 | userDefaults?.set(value, forKey: forKey) 26 | } 27 | 28 | AsyncFunction("setNumber") { (forKey: String, value: Double, suiteName: String, isStandard: Bool) in 29 | let userDefaults = isStandard ? UserDefaults.standard : UserDefaults(suiteName: suiteName) 30 | userDefaults?.set(value, forKey: forKey) 31 | } 32 | 33 | AsyncFunction("get") { (forKey: String, suiteName: String, isStandard: Bool) -> Any? in 34 | let userDefaults = isStandard ? UserDefaults.standard : UserDefaults(suiteName: suiteName) 35 | return userDefaults?.object(forKey: forKey) 36 | } 37 | 38 | AsyncFunction("getAll") { (suiteName: String, isStandard: Bool) -> [String : Any] in 39 | let userDefaults = isStandard ? UserDefaults.standard : UserDefaults(suiteName: suiteName) 40 | return userDefaults?.dictionaryRepresentation() ?? [:] 41 | } 42 | 43 | AsyncFunction("remove") { (forKey: String, suiteName: String, isStandard: Bool) in 44 | let userDefaults = isStandard ? UserDefaults.standard : UserDefaults(suiteName: suiteName) 45 | userDefaults?.removeObject(forKey: forKey) 46 | } 47 | 48 | AsyncFunction("removeAll") { (suiteName: String, isStandard: Bool) in 49 | let userDefaults = isStandard ? UserDefaults.standard : UserDefaults(suiteName: suiteName) 50 | userDefaults?.dictionaryRepresentation().forEach { (key: String, value: Any) in 51 | userDefaults?.removeObject(forKey: key) 52 | } 53 | } 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UserDefaults 2 | 3 | An interface to the user’s defaults database, where you store key-value pairs persistently across launches of your app. Inspired by [UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults). 4 | 5 | - :white_check_mark: Built with [Expo's Module API](https://docs.expo.dev/modules/module-api/) 6 | - :white_check_mark: Written in TypeScript and Swift 7 | - :apple: Currently iOS only 8 | 9 | ## Installation 10 | 11 | 1. Install the package 12 | 13 | ```console 14 | yarn add @alevy97/react-native-userdefaults 15 | ``` 16 | 17 | 2. Install pods 18 | 19 | ```console 20 | npx pod-install 21 | ``` 22 | 23 | ## Usage 24 | 25 | ### Standard Defaults 26 | 27 | The most common use case for using `UserDefaults` is to store small chunks of data to the standard defaults system. You can access the standard defaults system using the static property `UserDefaults.standard` or by creating a new `UserDefaults` instance. 28 | 29 | ```tsx 30 | UserDefaults.standard; 31 | ``` 32 | 33 | or equivalently 34 | 35 | ```tsx 36 | new UserDefaults(); 37 | ``` 38 | 39 | ### Defaults with Suite Name 40 | 41 | UserDefaults can also be used to store data that can be shared across multiple apps belonging to the same [App Group](https://developer.apple.com/documentation/xcode/configuring-app-groups?changes=_3), also known as a suite. To achieve this, provide a suite name (app group identifier) when creating a `UserDefaults` instance. 42 | 43 | ```tsx 44 | new UserDefaults("group.com.example.app"); 45 | ``` 46 | 47 | ### Example 48 | 49 | ```tsx 50 | import { Button, View } from "react-native"; 51 | import UserDefaults from "@alevy97/react-native-userdefaults"; 52 | 53 | const standardDefaults = UserDefaults.standard; // or new UserDefaults() 54 | const groupDefaults = new UserDefaults("group.com.example.app"); 55 | 56 | function App() { 57 | return ( 58 | 59 |