Using Key-Value Stores for Secure Data Storage
Key-value stores use AES-256 encryption and are stored on the device file system, each in its own directory. For each store, you provide a name that becomes the file name prefix. Store names can contain only letters, digits, and underscores, and can’t exceed 96 characters. An app can create as many stores as the device’s free space allows. Like SmartStore instances, key-value stores can be either user-based or global, depending on your use case.
Key-value stores are data-type agnostic and can contain different shapes and formats. For example, one value can be a JavaScript file, while the next is HTML, and the next a PNG image. A store doesn’t recognize or require relationships between its values.
To store binary data securely, the key-value store API provides special methods. Use these methods instead of legacy techniques such as creating a JSON envelope in SmartStore, or creating a file using the Mobile SDK file encryption APIs.
For larger data sets on Android, you can buffer data and stream the values into the key-value store. For example, you can build a REST response cache and then import it by passing restResponse.asInputStream() to the saveStream() method. The key-value store reads buffers in a loop from the data source and writes them to the store file. Similar streaming isn’t supported on Mobile SDK for iOS.
Key-Value Store or SmartStore?
- A simple look-up by key serves your data set well.
- Your values aren’t stored as JSON or otherwise structured for atomic access.
- You're storing a large data set.
- You're storing binary data.
- You're developing a native app. In Mobile SDK 8.2, this feature isn’t available for hybrid or React Native apps.
SmartStore remains a better choice if:
- Your app demands more complex querying power—for example, query predicates that filter on multiple fields, or relational queries such as joins.
- Your app must be able to retrieve parts of the data. You can’t extract smaller parts of a value as you can with a SmartStore query such as select {soup:some_indexfield} from {soup}.
- Values are at least semi-structured. For example, your data set is JSON, but the shapes of individual values vary.
- You're developing a hybrid or React Native app.
Key-Value Store Versions
Mobile SDK 8.2, 8.3, and 9.0 use version 1 of the key-value store. Mobile SDK 9.1 introduces version 2. These versions implement the same basic functionality, but version 2 adds a public accessor that returns a list of all keys in a given store. Invoking this accessor on version 1 stores returns nil on iOS and throws an exception on Android.
- Create a store in Mobile SDK 9.1.
- Use an iterative process to recreate your key-value pairs in the new store.
Key-Value Store Classes
- Android only: import com.salesforce.androidsdk.smartstore.app.SmartStoreSDKManager
- iOS (Swift): KeyValueEncryptedFileStore.swift (included in SalesforceSDKCore)
- Android: KeyValueEncryptedFileStore.java (com.salesforce.androidsdk.smartstore.store package)
Set Up a Key-Value Store
- Construct an instance of KeyValueEncryptedFileStore.
- iOS
- This constructor creates a store for the current
user.
1let kv = KeyValueEncryptedFileStore.shared(withName: "<some name>") - Android
-
1KeyValueEncryptedFileStore kv = SmartStoreSDKManager.getKeyValueStore("<some name>")
- Add static key-value pairs.
- iOS (Swift)
-
1kv.saveValue(value, forKey: key) - Android (Java)
-
1kv.saveValue(key, value)
- iOS (Swift)
- Not supported
- Android (Java)
-
1kv.saveStream(key, stream)
Store and Retrieve Binary Data (Key-Value Store Version 2 or Later)
For managing binary data in a key-value store, Mobile SDK 10.0 introduces new iOS methods and reuses existing Android methods. Use these methods instead of the Mobile SDK file encryption APIs or a JSON envelope in SmartStore.
- iOS (Swift)
-
1/// Saving binary data to a key value store 2/// Updates the data stored for the given key or adds a new entry 3/// if the key does not exist. 4/// - Parameters: 5/// - data: Data to add to the store. 6/// - key: Key associated with the data. 7/// - Returns: True on success, false on failure. 8@objc @discardableResult 9public func saveData(_ data: Data, forKey key: String) → Bool 10 11/// Accesses the data associated with the given key. 12@objc public func readData(key: String) → Data?- Example
-
1// Saving binary data to key value store 2let sampleData = ... 3store.saveData(sampleData, forKey:"key") 4 5// Retrieving binary data back from key value store 6let savedData = store.readData(key: "key")
- Android (Java)
-
1/** 2 * Save value given as an input stream for the given key. 3 * Note: This method does not close the provided input stream 4 * 5 * @param key Unique identifier. 6 * @param stream Stream to be persisted. 7 * @return True - if successful, False - otherwise. 8 */ 9public boolean saveStream(String key, InputStream stream) throws IOException; 10 11* Retrieving binary data from a key value store. 12 13/** 14 * Returns stream for value of given key. 15 * 16 * @param key Unique identifier. 17 * @return stream to value for given key or null if key not found. 18 */ 19public InputStream getStream(String key);- Example
-
1// Saving binary data to key value store 2// 3 4byte[] arrayToWrite = ...; 5 6// In real life, you probably would start from a stream 7// (e.g. from a network call's response) 8InputStream streamToWrite = 9 new ByteArrayInputStream(arrayToWrite); 10keyValueStore.saveStream("key", streamToWrite); 11 12// 13// Retrieving binary data back from key value store 14// 15 16InputStream streamToRead = keyValueStore.getStream("key"); 17byte[] arrayRead = Encryptor. 18 getByteArrayStreamFromStream(streamToRead).toByteArray();
Get All Keys in a Store (Key-Value Store Version 2 or Later)
These methods return all keys in the given store.
- iOS (Swift)
-
1/// All keys in the store 2/// - Returns: all keys of stored values in a v2 store, nil if it's a v1 store 3@objc public func allKeys() -> [String]? - Android (Java)
-
1/** 2 * Get all keys. 3 * NB: will throw UnsupportedOperationException for a v1 store 4 */ 5public Set<String> keySet()
Get the Key-Value Store Version
These APIs let you determine a store’s version at runtime.
- iOS (Swift)
-
1@objc public private(set) var storeVersion: Int - Android (Java)
-
1public int getStoreVersion()
Inspect a Key-Value Store
To view a list of keys and values, select Inspect Key-Value Store in the Dev Support menu. This tool lets you search a store for all or part of a key name, returning all matching values.


Example
1...
2writeToKv(value: "Joe", key: "Trader")
3...
4
5func writeToKv(value: String, key: String) {
6 if let kv = KeyValueEncryptedFileStore.shared(
7 withName: "testShared") {
8 if kv.saveValue(value, forKey: key) {
9 let numEntries = kv.count()
10 SalesforceLogger.d(RootViewController.self,
11 message:"\nValue added: \(value), " +
12 "Number of entries: \(numEntries)")
13 }
14 }
15}