Data Storage
Data storage is an essential part of mobile application development. uni-app provides multiple storage solutions to meet different data storage needs, including local storage, database storage, and cloud storage.
Local Storage
Local storage is the most commonly used data storage method, suitable for storing user preferences, application configuration, temporary data, etc.
uni.setStorage()
Store data to local storage asynchronously.
// Store string data
uni.setStorage({
key: 'username',
data: 'john_doe',
success: function() {
console.log('Storage successful');
},
fail: function(err) {
console.error('Storage failed:', err);
}
});
// Store object data
uni.setStorage({
key: 'userInfo',
data: {
id: 123,
name: 'John Doe',
email: 'john@example.com',
preferences: {
theme: 'dark',
language: 'en'
}
},
success: function() {
console.log('User info stored successfully');
}
});
// Store array data
uni.setStorage({
key: 'favoriteList',
data: [
{ id: 1, title: 'Item 1' },
{ id: 2, title: 'Item 2' },
{ id: 3, title: 'Item 3' }
]
});
uni.setStorageSync()
Store data to local storage synchronously.
try {
// Synchronous storage
uni.setStorageSync('token', 'abc123xyz');
uni.setStorageSync('settings', {
notifications: true,
autoSync: false
});
console.log('Data stored successfully');
} catch (e) {
console.error('Storage failed:', e);
}
uni.getStorage()
Retrieve data from local storage asynchronously.
// Get string data
uni.getStorage({
key: 'username',
success: function(res) {
console.log('Username:', res.data);
},
fail: function(err) {
console.log('Data not found or error:', err);
}
});
// Get object data
uni.getStorage({
key: 'userInfo',
success: function(res) {
const userInfo = res.data;
console.log('User ID:', userInfo.id);
console.log('User Name:', userInfo.name);
console.log('Theme:', userInfo.preferences.theme);
}
});
uni.getStorageSync()
Retrieve data from local storage synchronously.
try {
const token = uni.getStorageSync('token');
const settings = uni.getStorageSync('settings');
if (token) {
console.log('Token:', token);
}
if (settings) {
console.log('Notifications enabled:', settings.notifications);
}
} catch (e) {
console.error('Failed to get data:', e);
}
uni.removeStorage()
Remove data from local storage asynchronously.
uni.removeStorage({
key: 'tempData',
success: function() {
console.log('Data removed successfully');
},
fail: function(err) {
console.error('Failed to remove data:', err);
}
});
uni.removeStorageSync()
Remove data from local storage synchronously.
try {
uni.removeStorageSync('tempData');
console.log('Data removed successfully');
} catch (e) {
console.error('Failed to remove data:', e);
}
uni.clearStorage()
Clear all local storage data asynchronously.
uni.clearStorage({
success: function() {
console.log('All data cleared successfully');
},
fail: function(err) {
console.error('Failed to clear data:', err);
}
});
uni.clearStorageSync()
Clear all local storage data synchronously.
try {
uni.clearStorageSync();
console.log('All data cleared successfully');
} catch (e) {
console.error('Failed to clear data:', e);
}
uni.getStorageInfo()
Get local storage information asynchronously.
uni.getStorageInfo({
success: function(res) {
console.log('Storage keys:', res.keys);
console.log('Current size:', res.currentSize);
console.log('Limit size:', res.limitSize);
}
});
uni.getStorageInfoSync()
Get local storage information synchronously.
try {
const info = uni.getStorageInfoSync();
console.log('Storage keys:', info.keys);
console.log('Current size:', info.currentSize + 'KB');
console.log('Limit size:', info.limitSize + 'KB');
} catch (e) {
console.error('Failed to get storage info:', e);
}
Storage Best Practices
1. Data Validation and Error Handling
// Storage utility class
class StorageUtil {
// Store data with validation
static setItem(key, value) {
if (!key || typeof key !== 'string') {
throw new Error('Invalid key');
}
try {
const data = typeof value === 'object' ? JSON.stringify(value) : value;
uni.setStorageSync(key, data);
return true;
} catch (error) {
console.error('Storage error:', error);
return false;
}
}
// Get data with default value
static getItem(key, defaultValue = null) {
if (!key || typeof key !== 'string') {
return defaultValue;
}
try {
const data = uni.getStorageSync(key);
if (data === '') {
return defaultValue;
}
// Try to parse JSON
try {
return JSON.parse(data);
} catch {
return data;
}
} catch (error) {
console.error('Get storage error:', error);
return defaultValue;
}
}
// Remove data
static removeItem(key) {
if (!key || typeof key !== 'string') {
return false;
}
try {
uni.removeStorageSync(key);
return true;
} catch (error) {
console.error('Remove storage error:', error);
return false;
}
}
// Check if key exists
static hasItem(key) {
try {
const data = uni.getStorageSync(key);
return data !== '';
} catch {
return false;
}
}
// Get all keys
static getAllKeys() {
try {
const info = uni.getStorageInfoSync();
return info.keys || [];
} catch {
return [];
}
}
// Clear all data
static clear() {
try {
uni.clearStorageSync();
return true;
} catch (error) {
console.error('Clear storage error:', error);
return false;
}
}
}
// Usage examples
StorageUtil.setItem('user', { id: 1, name: 'John' });
const user = StorageUtil.getItem('user', {});
const hasUser = StorageUtil.hasItem('user');
2. Data Encryption
For sensitive data, consider encryption before storage:
// Simple encryption utility (for demonstration only, use proper encryption in production)
class EncryptedStorage {
static encrypt(text) {
// Simple Base64 encoding (use proper encryption in production)
return btoa(unescape(encodeURIComponent(text)));
}
static decrypt(encodedText) {
try {
return decodeURIComponent(escape(atob(encodedText)));
} catch {
return null;
}
}
static setSecureItem(key, value) {
try {
const encrypted = this.encrypt(JSON.stringify(value));
uni.setStorageSync(key, encrypted);
return true;
} catch (error) {
console.error('Secure storage error:', error);
return false;
}
}
static getSecureItem(key, defaultValue = null) {
try {
const encrypted = uni.getStorageSync(key);
if (!encrypted) return defaultValue;
const decrypted = this.decrypt(encrypted);
return decrypted ? JSON.parse(decrypted) : defaultValue;
} catch (error) {
console.error('Secure get error:', error);
return defaultValue;
}
}
}
// Usage
EncryptedStorage.setSecureItem('sensitiveData', {
token: 'abc123',
password: 'secret'
});
const sensitiveData = EncryptedStorage.getSecureItem('sensitiveData');
3. Storage Quota Management
class StorageManager {
static checkStorageQuota() {
try {
const info = uni.getStorageInfoSync();
const usagePercent = (info.currentSize / info.limitSize) * 100;
console.log(`Storage usage: ${usagePercent.toFixed(2)}%`);
if (usagePercent > 80) {
console.warn('Storage usage is high, consider cleaning up');
return false;
}
return true;
} catch (error) {
console.error('Failed to check storage quota:', error);
return false;
}
}
static cleanupOldData(maxAge = 7 * 24 * 60 * 60 * 1000) { // 7 days
try {
const info = uni.getStorageInfoSync();
const now = Date.now();
info.keys.forEach(key => {
if (key.startsWith('temp_') || key.startsWith('cache_')) {
try {
const data = uni.getStorageSync(key);
const parsed = JSON.parse(data);
if (parsed.timestamp && (now - parsed.timestamp) > maxAge) {
uni.removeStorageSync(key);
console.log(`Cleaned up old data: ${key}`);
}
} catch {
// If parsing fails, remove the key
uni.removeStorageSync(key);
}
}
});
} catch (error) {
console.error('Cleanup failed:', error);
}
}
static storeWithTimestamp(key, data) {
const timestampedData = {
data: data,
timestamp: Date.now()
};
return StorageUtil.setItem(key, timestampedData);
}
static getWithTimestamp(key, maxAge = null) {
const stored = StorageUtil.getItem(key);
if (!stored || !stored.timestamp) {
return null;
}
if (maxAge && (Date.now() - stored.timestamp) > maxAge) {
StorageUtil.removeItem(key);
return null;
}
return stored.data;
}
}
// Usage
StorageManager.checkStorageQuota();
StorageManager.cleanupOldData();
StorageManager.storeWithTimestamp('cache_data', { items: [] });
Platform Differences
Storage Limits
Different platforms have different storage limits:
- WeChat Mini Program: 10MB per domain
- Alipay Mini Program: 10MB per app
- H5: Depends on browser, typically 5-10MB
- App: Limited by device storage
Storage Location
- Mini Programs: Platform-specific storage
- H5: Browser localStorage/sessionStorage
- App: Device file system
Data Persistence
// Check platform and adjust storage strategy
class PlatformStorage {
static getStorageStrategy() {
// #ifdef MP-WEIXIN
return {
limit: 10 * 1024 * 1024, // 10MB
persistent: true,
encrypted: false
};
// #endif
// #ifdef H5
return {
limit: 5 * 1024 * 1024, // 5MB
persistent: false, // May be cleared by browser
encrypted: false
};
// #endif
// #ifdef APP-PLUS
return {
limit: 1024 * 1024 * 1024, // 1GB
persistent: true,
encrypted: true // Can use device encryption
};
// #endif
return {
limit: 1024 * 1024, // 1MB default
persistent: false,
encrypted: false
};
}
static checkStorageSupport() {
const strategy = this.getStorageStrategy();
try {
const info = uni.getStorageInfoSync();
const available = strategy.limit - (info.currentSize * 1024);
return {
supported: true,
available: available,
persistent: strategy.persistent,
encrypted: strategy.encrypted
};
} catch (error) {
return {
supported: false,
available: 0,
persistent: false,
encrypted: false
};
}
}
}
// Usage
const storageInfo = PlatformStorage.checkStorageSupport();
console.log('Storage info:', storageInfo);
Common Issues and Solutions
1. Storage Quota Exceeded
function handleStorageQuotaExceeded() {
try {
const info = uni.getStorageInfoSync();
if (info.currentSize >= info.limitSize * 0.9) {
// Clean up old cache data
const keys = info.keys.filter(key =>
key.startsWith('cache_') || key.startsWith('temp_')
);
keys.forEach(key => {
try {
uni.removeStorageSync(key);
} catch (e) {
console.error('Failed to remove key:', key, e);
}
});
console.log(`Cleaned up ${keys.length} cache items`);
}
} catch (error) {
console.error('Storage cleanup failed:', error);
}
}
2. Data Corruption
function validateStoredData(key, validator) {
try {
const data = uni.getStorageSync(key);
if (!data) {
return null;
}
// Validate data structure
if (typeof validator === 'function' && !validator(data)) {
console.warn(`Invalid data for key: ${key}`);
uni.removeStorageSync(key);
return null;
}
return data;
} catch (error) {
console.error('Data validation failed:', error);
// Remove corrupted data
try {
uni.removeStorageSync(key);
} catch (e) {
console.error('Failed to remove corrupted data:', e);
}
return null;
}
}
// Usage
const userInfo = validateStoredData('userInfo', (data) => {
return data && typeof data === 'object' && data.id && data.name;
});
3. Cross-Platform Compatibility
class CrossPlatformStorage {
static setItem(key, value) {
try {
// Handle different data types across platforms
let processedValue = value;
// #ifdef MP-WEIXIN
// WeChat Mini Program has specific handling for certain data types
if (value instanceof Date) {
processedValue = value.toISOString();
}
// #endif
// #ifdef H5
// H5 localStorage only supports strings
if (typeof value !== 'string') {
processedValue = JSON.stringify(value);
}
// #endif
uni.setStorageSync(key, processedValue);
return true;
} catch (error) {
console.error('Cross-platform storage failed:', error);
return false;
}
}
static getItem(key, defaultValue = null) {
try {
const value = uni.getStorageSync(key);
if (value === '' || value === null || value === undefined) {
return defaultValue;
}
// #ifdef H5
// Try to parse JSON in H5
if (typeof value === 'string') {
try {
return JSON.parse(value);
} catch {
return value;
}
}
// #endif
return value;
} catch (error) {
console.error('Cross-platform get failed:', error);
return defaultValue;
}
}
}
Best Practices Summary
1. Performance Optimization
- Use batch operations to reduce I/O overhead
- Implement lazy loading for large datasets
- Use memory caching for frequently accessed data
- Compress large data before storage
2. Security Considerations
- Encrypt sensitive data before storage
- Validate data integrity when reading
- Implement proper error handling
- Regular cleanup of expired data
3. Storage Strategy
- Choose appropriate storage method based on data characteristics
- Set reasonable expiration times for different data types
- Implement data synchronization for critical information
- Provide backup and restore functionality
4. Error Handling
- Always wrap storage operations in try-catch blocks
- Provide fallback values for missing data
- Log errors for debugging purposes
- Gracefully handle storage quota exceeded scenarios
5. Testing
- Test storage functionality across all target platforms
- Verify data persistence after app restart
- Test storage limits and cleanup mechanisms
- Validate data integrity after storage operations
Conclusion
Effective data storage is crucial for creating robust uni-app applications. By understanding the various storage options available, implementing proper error handling, and following best practices, you can ensure your application provides a reliable and performant user experience across all platforms.
Key takeaways:
- Choose the right storage method for your data type and usage pattern
- Implement proper error handling and data validation
- Consider platform differences when designing storage strategies
- Optimize performance through caching and batch operations
- Secure sensitive data with encryption and proper access controls
- Plan for data migration and backup scenarios
- Test thoroughly across all target platforms
Remember to regularly review and optimize your storage implementation as your application grows and evolves.