Files
english/.opencode/skills/mobile-development/references/mobile-best-practices.md
2026-04-12 01:06:31 +07:00

546 lines
12 KiB
Markdown

# Mobile Development Best Practices
Cross-platform best practices for modern mobile development (2024-2025).
## Mobile-First Design Principles
### Core Principles
1. **Content First**: Remove chrome, focus on content
2. **Progressive Disclosure**: Hide complexity behind layers
3. **Thumb-Friendly**: Primary actions within reach
4. **Performance Budget**: <2s launch, <1s screen load
5. **Offline-First**: Design for unreliable networks
### Touch Targets
- **iOS**: 44x44px minimum (HIG guideline)
- **Android**: 48x48px minimum (Material Design)
- **Optimal**: 44-57px for important actions
- **Spacing**: 8px minimum between targets
### Typography
- **iOS**: San Francisco (system font)
- **Android**: Roboto (Material)
- **Minimum**: 16px body text (accessibility)
- **Line height**: 1.5x for readability
## Performance Optimization
### Launch Time Optimization
**Targets:**
- Cold start: <2s
- Warm start: <1s
- Hot start: <0.5s
**Techniques:**
- Defer non-critical initialization
- Lazy load dependencies
- Preload critical data only
- Show UI before data ready
### Memory Management
**Targets:**
- Typical screen: <100MB
- Peak usage: <200MB
**Techniques:**
- Image pagination/virtualization
- Release resources in background
- Profile with Instruments/Profiler
- Avoid retain cycles/memory leaks
**React Native Example:**
```javascript
// Use FlatList instead of ScrollView for long lists
<FlatList
data={items}
renderItem={({ item }) => <ItemCard item={item} />}
keyExtractor={(item) => item.id}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
/>
```
### Network Optimization
**Techniques:**
- Batch API requests
- Cache aggressively
- Compress images (WebP, AVIF)
- Use CDN for static assets
- Implement request deduplication
**Example Strategy:**
```
User opens screen
├─ Show cached data immediately (stale-while-revalidate)
├─ Fetch fresh data in background
└─ Update UI when fresh data arrives
```
### Battery Optimization
**Techniques:**
- Batch network requests
- Reduce GPS accuracy when possible
- Use push instead of polling
- Respect Doze Mode (Android)
- Background App Refresh (iOS)
**Targets:**
- Active use: <5% per hour
- Background: <1% per hour
## Offline-First Architecture
### Local Storage Options
**React Native:**
- AsyncStorage (small data, <6MB)
- Realm (complex objects, relationships)
- SQLite (relational data)
- MMKV (fastest key-value)
**Flutter:**
- SharedPreferences (small data)
- Hive (NoSQL, fast)
- Drift (SQLite wrapper)
- ObjectBox (object database)
**iOS:**
- UserDefaults (small data)
- Core Data (complex objects)
- SwiftData (modern replacement)
- Realm
**Android:**
- SharedPreferences (small data)
- Room (SQLite ORM)
- Realm
- DataStore (Preferences + Proto)
### Data Synchronization Strategies
**1. Write-Through Cache**
```
User makes change
├─ Update local database immediately
├─ Update UI optimistically
├─ Queue sync operation
└─ Sync to server in background
```
**2. Hybrid Sync (Push + Pull)**
```
Push Sync (Real-time)
├─ WebSocket connection for critical updates
└─ Immediate notification of changes
Pull Sync (Periodic)
├─ Periodic polling for non-critical data
├─ Pull on app foreground
└─ Incremental sync (only changes since last sync)
```
**3. Conflict Resolution**
- **Last-write-wins**: Use timestamps
- **Operational transformation**: Merge changes
- **CRDT**: Conflict-free replicated data
- **Manual resolution**: User chooses
### Example: Offline-First Comments
```typescript
// React Native + TypeScript
class CommentService {
async postComment(text: string, postId: string) {
const tempId = generateTempId();
const comment = {
id: tempId,
text,
postId,
synced: false,
timestamp: Date.now()
};
// 1. Save locally immediately
await db.comments.insert(comment);
// 2. Update UI (optimistic)
eventBus.emit('comment:added', comment);
// 3. Sync to server in background
try {
const serverComment = await api.postComment(text, postId);
// Replace temp ID with server ID
await db.comments.update(tempId, {
id: serverComment.id,
synced: true
});
} catch (error) {
// Mark as pending sync, retry later
await db.comments.update(tempId, {
syncError: error.message
});
syncQueue.add({ type: 'comment', id: tempId });
}
}
}
```
## Mobile Analytics & Monitoring
### Analytics Platforms (2024-2025)
**Firebase Analytics (Recommended)**
- Free tier generous
- Mobile-specific events
- Integrated with Crashlytics
- AI-powered insights
- Supports all platforms
**Sentry**
- Error tracking + performance
- Cross-platform support
- Source map upload
- Release tracking
- Custom breadcrumbs
**Amplitude**
- Product analytics
- User behavior tracking
- Cohort analysis
- A/B testing integration
### Essential Events to Track
**User Journey:**
- App opened
- Screen viewed
- Feature used
- Conversion events
- User retention
**Performance:**
- App launch time
- Screen load time
- API latency
- Crash-free rate
- ANR rate (Android)
**Business:**
- Purchases
- Subscriptions
- Ad impressions
- Feature adoption
- Referrals
### Crashlytics Integration
**React Native:**
```javascript
import crashlytics from '@react-native-firebase/crashlytics';
// Log events
crashlytics().log('User tapped purchase button');
// Set user attributes
crashlytics().setUserId(user.id);
// Log non-fatal errors
try {
await riskyOperation();
} catch (error) {
crashlytics().recordError(error);
}
```
**Flutter:**
```dart
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
// Log events
FirebaseCrashlytics.instance.log('User tapped purchase');
// Set user ID
FirebaseCrashlytics.instance.setUserIdentifier(userId);
// Record errors
await FirebaseCrashlytics.instance.recordError(
error,
stackTrace,
reason: 'API call failed',
);
```
## Push Notifications Best Practices
### Platforms
- **iOS**: APNs (Apple Push Notification service)
- **Android**: FCM (Firebase Cloud Messaging)
- **Cross-platform**: OneSignal, Firebase, AWS SNS
### Best Practices
**1. Permission Request Strategy**
```
❌ Bad: Request permission on app launch
✅ Good: Request after user sees value
Flow:
1. User interacts with feature
2. Show custom modal explaining benefits
3. Request system permission
4. Handle denial gracefully
```
**2. Personalization**
- Segment users by behavior
- Send at optimal times (time zones)
- Personalize content
- A/B test messaging
**3. Frequency**
- Avoid notification spam
- Respect user preferences
- Implement quiet hours
- Group related notifications
**4. Deep Linking**
```javascript
// React Native
import messaging from '@react-native-firebase/messaging';
messaging().onNotificationOpenedApp(remoteMessage => {
const { screen, params } = remoteMessage.data;
navigation.navigate(screen, params);
});
```
**Impact:**
- 25% revenue increase with proper personalization
- 88% opt-in rate with pre-permission modal (vs 40% without)
## Authentication & Authorization
### Modern Auth Stack (2024-2025)
**Standard Pattern:**
```
OAuth 2.0 (Authorization)
├─ JWT (Stateless auth tokens)
├─ Refresh tokens (Long-term access)
└─ Biometric (Convenient re-auth)
```
### Implementation
**Biometric Authentication (iOS)**
```swift
import LocalAuthentication
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,
localizedReason: "Unlock your account") { success, error in
if success {
// Authenticated
}
}
}
```
**Biometric Authentication (Android)**
```kotlin
import androidx.biometric.BiometricPrompt
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric login")
.setSubtitle("Log in using your biometric credential")
.setNegativeButtonText("Use account password")
.build()
val biometricPrompt = BiometricPrompt(this, executor,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
// Authenticated
}
})
biometricPrompt.authenticate(promptInfo)
```
### Secure Token Storage
**iOS: Keychain**
```swift
import Security
func saveToken(_ token: String, for key: String) {
let data = token.data(using: .utf8)!
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecValueData as String: data,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
SecItemAdd(query as CFDictionary, nil)
}
```
**Android: EncryptedSharedPreferences**
```kotlin
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val sharedPreferences = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
sharedPreferences.edit().putString("auth_token", token).apply()
```
**React Native: react-native-keychain**
```javascript
import * as Keychain from 'react-native-keychain';
// Save credentials
await Keychain.setGenericPassword('username', token, {
accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET,
accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
});
// Retrieve credentials
const credentials = await Keychain.getGenericPassword();
const token = credentials.password;
```
## App Store Deployment
### App Store (iOS)
**Requirements (2024-2025):**
- Xcode 15+ with iOS 17 SDK (minimum)
- Xcode 16+ with iOS 18 SDK (recommended for 2025)
- Privacy manifest required
- Account deletion in-app mandatory
**Release Process:**
1. Archive in Xcode
2. Upload to App Store Connect
3. Submit for review
4. Phased release (7-day rollout)
**Review Time:**
- Average: 1-2 days
- Expedited: 1-2 hours (emergencies only)
**Rejection Reasons:**
- Crashes (50%)
- Privacy violations (25%)
- Incomplete information (15%)
- Guideline violations (10%)
### Google Play (Android)
**Requirements (2024-2025):**
- Target Android 14 (API 34) now
- Target Android 15 (API 35) by Aug 31, 2025
- Privacy policy required
- Data safety form required
**Release Process:**
1. Build signed AAB (Android App Bundle)
2. Upload to Play Console
3. Submit to production track
4. Staged rollout (10% 50% 100%)
**Review Time:**
- Average: 1-3 days
- Updates: 1-2 days
### Staged Rollout Strategy
**Week 1:**
- 10% of users
- Monitor crash-free rate
- Watch for critical bugs
**Week 2:**
- 50% of users
- Validate performance metrics
- Check user feedback
**Week 3:**
- 100% of users
- Full release if metrics healthy
**Rollback Triggers:**
- Crash-free rate drops >5%
- Critical bug discovered
- Major user complaints
## Cross-Platform Comparison
### Flutter vs React Native (2024-2025)
| Metric | React Native | Flutter |
|--------|--------------|---------|
| **Adoption** | 35% | 46% |
| **Performance** | 80-90% | 85-95% |
| **App Size** | 40-50MB | 15-20MB |
| **Dev Speed** | Fast | Very Fast |
| **Commercial** | 12.57% | 5.24% |
| **Developers** | 20:1 ratio | 1 ratio |
| **Best For** | JS teams | Performance |
### Architecture Comparison
**MVVM (Small Apps):**
```
View
ViewModel (business logic)
Model (data)
```
**Clean Architecture (Large Apps):**
```
Presentation (UI)
Domain (business logic, use cases)
Data (repositories, APIs, DB)
```
## Resources
**Performance:**
- iOS: https://developer.apple.com/documentation/xcode/improving-your-app-s-performance
- Android: https://developer.android.com/topic/performance
- React Native: https://reactnative.dev/docs/performance
**Analytics:**
- Firebase: https://firebase.google.com/docs/analytics
- Sentry: https://docs.sentry.io/platforms/react-native/
- Amplitude: https://amplitude.com/docs
**Security:**
- OWASP Mobile: https://owasp.org/www-project-mobile-top-10/
- iOS Security: https://support.apple.com/guide/security/
- Android Security: https://source.android.com/docs/security
**Testing:**
- Detox: https://wix.github.io/Detox/
- Appium: https://appium.io/docs/en/latest/
- XCTest: https://developer.apple.com/documentation/xctest
- Espresso: https://developer.android.com/training/testing/espresso