Mobile Development

Creating applications for smartphones and tablets.

1. React Native โ€” Basic App with Navigation

1. React Native โ€” Basic App with Navigation is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

2. Flutter โ€” Stateful Widget with API Call

2. Flutter โ€” Stateful Widget with API Call is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Syntax and semantics, best practices, debugging techniques, and project-based application.

3. Kotlin โ€” Android Activity with RecyclerView

3. Kotlin โ€” Android Activity with RecyclerView is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

4. Swift โ€” SwiftUI List with Data Persistence

4. Swift โ€” SwiftUI List with Data Persistence is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

5. React Native โ€” Offline Storage with AsyncStorage

5. React Native โ€” Offline Storage with AsyncStorage is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

6. Firebase โ€” Authentication & Firestore

6. Firebase โ€” Authentication & Firestore is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

7. Flutter โ€” BLoC Pattern for State Management

7. Flutter โ€” BLoC Pattern for State Management is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

8. React Native โ€” Push Notifications

8. React Native โ€” Push Notifications is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

9. Kotlin โ€” Coroutines & Flow for Network Calls

9. Kotlin โ€” Coroutines & Flow for Network Calls is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

10. React Native โ€” Animations with Reanimated

10. React Native โ€” Animations with Reanimated is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Native vs. Hybrid vs. Cross-Platform

Native vs. Hybrid vs. Cross-Platform is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Mobile App Architecture Patterns

Mobile App Architecture Patterns is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Mobile UI/UX Principles

Mobile UI/UX Principles is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

State Management

State Management is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Mobile Networking

Mobile Networking is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Mobile App Performance

Mobile App Performance is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

App Store Deployment

App Store Deployment is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Push Notifications

Push Notifications is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Key Code Examples

1. React Native โ€” Basic App with Navigation

import React, { useState } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, FlatList } from 'react-native'; import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; const Stack = createNativeStackNavigator(); // Home Screen Component function HomeScreen({ navigation }) { const [tasks, setTasks] = useState([ { id: '1', title: 'Buy groceries', completed: false }, { id: '2', title: 'Walk the dog', completed: true }, { id: '3', title: 'Read a book', completed: false }, ]); const toggleTask = (id) => { setTasks(prev => prev.map(task => task.id === id ? { ...task, completed: !task.completed } : task )); }; return ( My Tasks item.id} renderItem={({ item }) => ( toggleTask(item.id)} > {item.title} {item.completed ? 'โœ“' : 'โ—‹'} )} /> navigation.navigate('AddTask')} > + Add Task ); } const styles = StyleSheet.create({ container: { flex: 1, padding: 20, backgroundColor: '#f5f5f5' }, title: { fontSize: 28, fontWeight: 'bold', marginBottom: 20 }, taskItem: { flexDirection: 'row', justifyContent: 'space-between', padding: 15, backgroundColor: 'white', borderRadius: 8, marginBottom: 10, elevation: 2, }, completed: { opacity: 0.6 }, taskText: { fontSize: 16 }, button: { backgroundColor: '#007AFF', padding: 15, borderRadius: 8, alignItems: 'center', }, buttonText: { color: 'white', fontSize: 18, fontWeight: '600' }, }); export default function App() { return ( ); }

2. Flutter โ€” Stateful Widget with API Call

import 'package:flutter/material.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Weather App', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true, ), home: const WeatherScreen(), ); } } class WeatherScreen extends StatefulWidget { const WeatherScreen({super.key}); @override State createState() => _WeatherScreenState(); } class _WeatherScreenState extends State { String _temperature = '--'; String _condition = 'Loading...'; String _city = 'London'; bool _isLoading = false; Future _fetchWeather() async { setState(() => _isLoading = true); try { final response = await http.get( Uri.parse('https://api.openweathermap.org/data/2.5/' 'weather?q=$_city&appid=YOUR_API_KEY&units=metric'), ); if (response.statusCode == 200) { final data = json.decode(response.body); setState(() { _temperature = '${data['main']['temp'].round()}ยฐC'; _condition = data['weather'][0]['description']; }); } } catch (e) { setState(() => _condition = 'Error: $e'); } setState(() => _isLoading = false); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Weather in $_city')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(_getIcon(_condition), size: 80, color: Colors.orange), const SizedBox(height: 20), Text(_temperature, style: const TextStyle(fontSize: 48)), Text(_condition, style: const TextStyle(fontSize: 24)), const SizedBox(height: 20), ElevatedButton( onPressed: _isLoading ? null : _fetchWeather, child: _isLoading ? const CircularProgressIndicator() : const Text('Refresh'), ), ], ), ), ); } IconData _getIcon(String condition) { if (condition.contains('cloud')) return Icons.cloud; if (condition.contains('rain')) return Icons.water_drop; return Icons.wb_sunny; } }

3. Kotlin โ€” Android Activity with RecyclerView

class MainActivity : AppCompatActivity() { private lateinit var recyclerView: RecyclerView private lateinit var adapter: ProductAdapter private val products = mutableListOf() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setupRecyclerView() loadProducts() setupSwipeRefresh() } private fun setupRecyclerView() { recyclerView = findViewById(R.id.recyclerView) adapter = ProductAdapter(products) { product -> onProductClicked(product) } recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.adapter = adapter // Add dividers recyclerView.addItemDecoration( DividerItemDecoration(this, DividerItemDecoration.VERTICAL) ) } private fun loadProducts() { lifecycleScope.launch { try { val response = RetrofitClient.apiService.getProducts() products.clear() products.addAll(response) adapter.notifyDataSetChanged() } catch (e: Exception) { Toast.makeText(this@MainActivity, "Error: ${e.message}", Toast.LENGTH_SHORT).show() } } } private fun setupSwipeRefresh() { val swipeRefresh: SwipeRefreshLayout = findViewById(R.id.swipeRefresh) swipeRefresh.setOnRefreshListener { loadProducts() } } private fun onProductClicked(product: Product) { val intent = Intent(this, ProductDetailActivity::class.java).apply { putExtra("product_id", product.id) } startActivity(intent) } } // RecyclerView Adapter class ProductAdapter( private val items: List, private val onClick: (Product) -> Unit ) : RecyclerView.Adapter() { class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { val nameText: TextView = view.findViewById(R.id.productName) val priceText: TextView = view.findViewById(R.id.productPrice) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_product, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = items[position] holder.nameText.text = item.name holder.priceText.text = "$${item.price}" holder.itemView.setOnClickListener { onClick(item) } } override fun getItemCount() = items.size }

4. Swift โ€” SwiftUI List with Data Persistence

import SwiftUI struct Todo: Identifiable, Codable { let id: UUID var title: String var isCompleted: Bool var createdAt: Date init(title: String) { self.id = UUID() self.title = title self.isCompleted = false self.createdAt = Date() } } class TodoStore: ObservableObject { @Published var todos: [Todo] = [] { didSet { save() } } private let key = "SavedTodos" init() { load() } func add(title: String) { todos.append(Todo(title: title)) } func toggle(_ todo: Todo) { if let index = todos.firstIndex(where: { $0.id == todo.id }) { todos[index].isCompleted.toggle() } } func delete(at offsets: IndexSet) { todos.remove(atOffsets: offsets) } private func save() { if let data = try? JSONEncoder().encode(todos) { UserDefaults.standard.set(data, forKey: key) } } private func load() { if let data = UserDefaults.standard.data(forKey: key), let decoded = try? JSONDecoder().decode([Todo].self, from: data) { todos = decoded } } } struct ContentView: View { @StateObject private var store = TodoStore() @State private var newTodoTitle = "" var body: some View { NavigationView { List { ForEach(store.todos) { todo in HStack { Image(systemName: todo.isCompleted ? "checkmark.circle.fill" : "circle") .foregroundColor(todo.isCompleted ? .green : .gray) .onTapGesture { store.toggle(todo) } Text(todo.title) .strikethrough(todo.isCompleted) Spacer() } } .onDelete(perform: store.delete) } .navigationTitle("Todos") .toolbar { HStack { TextField("New todo", text: $newTodoTitle) Button("Add") { if !newTodoTitle.isEmpty { store.add(title: newTodoTitle) newTodoTitle = "" } } } } } } }

5. React Native โ€” Offline Storage with AsyncStorage

import React, { useState, useEffect } from 'react'; import { View, Text, TextInput, Button, FlatList, StyleSheet } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; const STORAGE_KEY = '@notes_app'; function NotesApp() { const [notes, setNotes] = useState([]); const [title, setTitle] = useState(''); const [body, setBody] = useState(''); const [isLoading, setIsLoading] = useState(true); // Load notes on app start useEffect(() => { loadNotes(); }, []); const loadNotes = async () => { try { const stored = await AsyncStorage.getItem(STORAGE_KEY); if (stored) { setNotes(JSON.parse(stored)); } } catch (error) { console.error('Failed to load notes:', error); } setIsLoading(false); }; const saveNotes = async (updatedNotes) => { try { await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(updatedNotes)); } catch (error) { console.error('Failed to save notes:', error); } }; const addNote = () => { if (!title.trim()) return; const newNote = { id: Date.now().toString(), title: title.trim(), body: body.trim(), createdAt: new Date().toISOString(), }; const updated = [newNote, ...notes]; setNotes(updated); saveNotes(updated); setTitle(''); setBody(''); }; const deleteNote = (id) => { const updated = notes.filter(n => n.id !== id); setNotes(updated); saveNotes(updated); }; if (isLoading) return Loading...; return ( Offline Notes

6. Firebase โ€” Authentication & Firestore

// Firebase config (firebase.js) import { initializeApp } from 'firebase/app'; import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut } from 'firebase/auth'; import { getFirestore, collection, addDoc, getDocs, query, where, orderBy, serverTimestamp } from 'firebase/firestore'; const firebaseConfig = { apiKey: "YOUR_API_KEY", authDomain: "your-app.firebaseapp.com", projectId: "your-app", appId: "YOUR_APP_ID" }; const app = initializeApp(firebaseConfig); export const auth = getAuth(app); export const db = getFirestore(app); // Auth Service export async function registerUser(email, password, displayName) { const cred = await createUserWithEmailAndPassword(auth, email, password); await addDoc(collection(db, 'users'), { uid: cred.user.uid, email, displayName, createdAt: serverTimestamp(), }); return cred.user; } export async function loginUser(email, password) { const cred = await signInWithEmailAndPassword(auth, email, password); return cred.user; } // Firestore Service export async function getUserTasks(userId) { const q = query( collection(db, 'tasks'), where('userId', '==', userId), orderBy('createdAt', 'desc') ); const snapshot = await getDocs(q); return snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); } export async function addTask(userId, title, description) { return await addDoc(collection(db, 'tasks'), { userId, title, description, completed: false, createdAt: serverTimestamp(), }); } // Auth Hook (React) import { useState, useEffect } from 'react'; import { onAuthStateChanged } from 'firebase/auth'; export function useAuth() { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const unsubscribe = onAuthStateChanged(auth, (user) => { setUser(user); setLoading(false); }); return unsubscribe; }, []); return { user, loading }; }

7. Flutter โ€” BLoC Pattern for State Management

import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:equatable/equatable.dart'; // ===== Events ===== abstract class CounterEvent extends Equatable { @override List get props => []; } class CounterIncrement extends CounterEvent {} class CounterDecrement extends CounterEvent {} class CounterReset extends CounterEvent {} // ===== State ===== class CounterState extends Equatable { final int value; const CounterState({this.value = 0}); @override List get props => [value]; } // ===== BLoC ===== class CounterBloc extends Bloc { CounterBloc() : super(const CounterState()) { on((event, emit) { emit(CounterState(value: state.value + 1)); }); on((event, emit) { emit(CounterState(value: state.value - 1)); }); on((event, emit) { emit(const CounterState(value: 0)); }); } } // ===== UI ===== class CounterPage extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( create: (_) => CounterBloc(), child: Scaffold( appBar: AppBar(title: const Text('BLoC Counter')), body: BlocBuilder( builder: (context, state) { return Center( child: Text( '${state.value}', style: const TextStyle(fontSize: 72), ), ); }, ), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ FloatingActionButton( onPressed: () => context.read().add(CounterIncrement()), child: const Icon(Icons.add), ), const SizedBox(height: 8), FloatingActionButton( onPressed: () => context.read().add(CounterDecrement()), child: const Icon(Icons.remove), ), const SizedBox(height: 8), FloatingActionButton( onPressed: () => context.read().add(CounterReset()), child: const Icon(Icons.refresh), ), ], ), ), ); } }

8. React Native โ€” Push Notifications

import React, { useEffect, useState } from 'react'; import { View, Text, Platform, Alert } from 'react-native'; import messaging from '@react-native-firebase/messaging'; import notifee, { AndroidImportance } from '@notifee/react-native'; // Request notification permission (iOS) async function requestPermission() { const authStatus = await messaging().requestPermission(); const enabled = authStatus === messaging.AuthorizationStatus.AUTHORIZED || authStatus === messaging.AuthorizationStatus.PROVISIONAL; if (enabled) { console.log('Notification permission granted'); const token = await messaging().getToken(); console.log('FCM Token:', token); // Send token to your server } } // Create notification channel (Android) async function createChannel() { await notifee.createChannel({ id: 'default', name: 'Default Channel', importance: AndroidImportance.HIGH, }); } // Foreground message handler function setupMessageHandler() { messaging().onMessage(async remoteMessage => { console.log('Foreground message:', remoteMessage); // Display local notification await notifee.displayNotification({ title: remoteMessage.notification?.title, body: remoteMessage.notification?.body, android: { channelId: 'default', importance: AndroidImportance.HIGH, pressAction: { id: 'default' }, }, }); }); // Background/quit state handler messaging().setBackgroundMessageHandler(async remoteMessage => { console.log('Background message:', remoteMessage); }); // Notification opened app messaging().onNotificationOpenedApp(remoteMessage => { console.log('Notification opened app:', remoteMessage.notification); }); } function App() { useEffect(() => { requestPermission(); createChannel(); setupMessageHandler(); }, []); return ( Push Notification Demo ); } export default App;

9. Kotlin โ€” Coroutines & Flow for Network Calls

// Repository pattern with Coroutines and Flow class WeatherRepository(private val api: WeatherApi) { fun getWeatherStream(city: String): Flow> = flow { emit(Result.Loading) try { val response = api.getWeather(city) emit(Result.Success(response)) } catch (e: Exception) { emit(Result.Error(e.message ?: "Unknown error")) } }.flowOn(Dispatchers.IO) // Run on IO thread .catch { e -> emit(Result.Error(e.message ?: "Network error")) } } // ViewModel class WeatherViewModel( private val repository: WeatherRepository ) : ViewModel() { private val _weather = MutableStateFlow?>(null) val weather: StateFlow?> = _weather.asStateFlow() fun loadWeather(city: String) { viewModelScope.launch { repository.getWeatherStream(city).collect { result -> _weather.value = result } } } } // UI (Jetpack Compose) @Composable fun WeatherScreen(viewModel: WeatherViewModel) { val weatherState by viewModel.weather.collectAsState() Column(modifier = Modifier.fillMaxSize().padding(16)) { when (val state = weatherState) { is Result.Loading -> CircularProgressIndicator() is Result.Success -> { Text("Temp: ${state.data.temp}ยฐC", style = MaterialTheme.typography.headlineMedium) Text("Condition: ${state.data.condition}") } is Result.Error -> Text("Error: ${state.message}", color = Color.Red) null -> Text("Enter a city to get weather") } } } // Retrofit API Interface interface WeatherApi { @GET("weather") suspend fun getWeather( @Query("q") city: String, @Query("appid") apiKey: String, @Query("units") units: String = "metric" ): Weather }

10. React Native โ€” Animations with Reanimated

import React, { useState } from 'react'; import { View, StyleSheet, Button } from 'react-native'; import Animated, { useSharedValue, useAnimatedStyle, withSpring, withTiming, withRepeat, withSequence, Easing, } from 'react-native-reanimated'; function AnimatedCard() { const [expanded, setExpanded] = useState(false); const scale = useSharedValue(1); const rotation = useSharedValue(0); const opacity = useSharedValue(1); const offsetX = useSharedValue(0); const animatedStyle = useAnimatedStyle(() => ({ transform: [ { scale: scale.value }, { translateX: offsetX.value }, { rotate: `${rotation.value}deg` }, ], opacity: opacity.value, })); const handleTap = () => { scale.value = withSpring(scale.value === 1 ? 1.2 : 1); rotation.value = withSequence( withTiming(10, { duration: 100 }), withTiming(-10, { duration: 100 }), withTiming(0, { duration: 100 }) ); }; const handleShake = () => { offsetX.value = withRepeat( withSequence( withTiming(10, { duration: 50 }), withTiming(-10, { duration: 50 }) ), 3, true ); }; const handlePulse = () => { opacity.value = withRepeat( withSequence( withTiming(0.3, { duration: 500 }), withTiming(1, { duration: 500 }) ), -1, true // Infinite ); }; return (

Core Concepts

Native vs. Hybrid vs. Cross-Platform

Native: Built specifically for one platform (iOS Swift/Obj-C, Android Kotlin/Java). Best performance and UI consistency.

Hybrid: Web app wrapped in native container (Cordova, Ionic). Single codebase, WebView-based.

Cross-Platform: Single codebase compiles to native (React Native, Flutter). Near-native performance.

ApproachPerformanceDev SpeedUI Quality
Nativeโ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…
Cross-Platformโ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…
Hybridโ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…

Mobile App Architecture Patterns

  • MVC (Model-View-Controller): Traditional pattern; Controller mediates between Model and View. Common in iOS (UIKit).
  • MVVM (Model-View-ViewModel): ViewModel exposes data streams to View; binding connects them. Popular in Android and SwiftUI.
  • BLoC (Business Logic Component): Events in โ†’ BLoC โ†’ States out. Flutter's recommended pattern.
  • Redux: Single state tree, reducers handle actions. Popular in React Native.

Mobile UI/UX Principles

  • Touch Targets: Minimum 44ร—44pt (iOS) / 48ร—48dp (Android) for tappable elements
  • Thumb Zone: Place primary actions within easy thumb reach
  • Responsive Layouts: Use constraints, not fixed positions
  • Platform Guidelines: Follow Material Design (Android) and Human Interface Guidelines (iOS)
  • Navigation: Tab bars, stack navigation, drawer menus
  • Accessibility: VoiceOver/TalkBack support, dynamic text sizing

State Management

Definition: Managing the data (state) that drives the UI of an application.

  • Local State: useState (React), State (Flutter) โ€” component-level
  • App State: Redux, MobX, Riverpod, BLoC โ€” global/shared state
  • Server State: React Query, SWR โ€” cached server data with sync
  • Persistence: SharedPreferences, UserDefaults, AsyncStorage โ€” local storage

Mobile Networking

  • REST APIs: HTTP/JSON communication with backend services
  • GraphQL: Query language for APIs โ€” fetch exactly what you need
  • WebSockets: Persistent two-way connection for real-time data
  • Offline-First: Local database (SQLite, Realm, Hive) with sync when online
  • Security: Certificate pinning, OAuth 2.0, token refresh, encryption at rest

Mobile App Performance

  • Startup Time: Cold start < 2s, warm start < 1s
  • Frame Rate: Maintain 60fps (16ms per frame) for smooth scrolling
  • Memory: Avoid leaks; use profiling tools (Instruments, Android Profiler)
  • Battery: Minimize network calls, use batch processing, reduce wake locks
  • App Size: Use ProGuard/R8 (Android), App Thinning (iOS), code splitting
  • Lists: Use virtualization (FlatList, RecyclerView) for large datasets

App Store Deployment

iOS (App Store):

  • Apple Developer account ($99/year)
  • Archive build in Xcode โ†’ Upload to App Store Connect
  • App review process (24-48 hours)
  • TestFlight for beta testing

Android (Google Play):

  • Google Play Developer account ($25 one-time)
  • Generate signed AAB (Android App Bundle)
  • Upload to Google Play Console
  • Automated review (hours to days)

Push Notifications

Definition: Messages sent from a server to a user's device even when the app is not active.

  • FCM (Firebase Cloud Messaging): Cross-platform (Android + iOS), free
  • APNs (Apple Push Notification service): Apple-only, requires certificate
  • Local Notifications: Scheduled by the app, no server needed
  • Deep Linking: Notification opens specific app screen
  • Best Practices: Personalize, allow opt-out, respect quiet hours

Worked Examples

Example 1: Build a Complete React Native Screen

Problem: Create a profile screen with avatar, name, bio, and edit button.

function ProfileScreen({ navigation }) { const [profile, setProfile] = useState({ name: 'Jane Doe', email: 'jane@example.com', bio: 'Mobile developer & coffee lover', }); return ( {profile.name} {profile.email} About {profile.bio} navigation.navigate('EditProfile', { profile, onSave: (updated) => setProfile(updated), })} > Edit Profile ); }

Example 2: Flutter Form Validation

Problem: Create a login form with email and password validation.

class LoginForm extends StatefulWidget { @override _LoginFormState createState() => _LoginFormState(); } class _LoginFormState extends State { final _formKey = GlobalKey(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); bool _isLoading = false; String? validateEmail(String? value) { if (value == null || value.isEmpty) return 'Email is required'; if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) { return 'Enter a valid email'; } return null; } String? validatePassword(String? value) { if (value == null || value.isEmpty) return 'Password is required'; if (value.length < 8) return 'Password must be 8+ characters'; return null; } Future _submit() async { if (!_formKey.currentState!.validate()) return; setState(() => _isLoading = true); await Future.delayed(Duration(seconds: 2)); // API call setState(() => _isLoading = false); Navigator.pushReplacementNamed(context, '/home'); } @override Widget build(BuildContext context) { return Form( key: _formKey, child: Column(children: [ TextFormField( controller: _emailController, keyboardType: TextInputType.emailAddress, decoration: InputDecoration(labelText: 'Email'), validator: validateEmail, ), TextFormField( controller: _passwordController, obscureText: true, decoration: InputDecoration(labelText: 'Password'), validator: validatePassword, ), ElevatedButton( onPressed: _isLoading ? null : _submit, child: _isLoading ? CircularProgressIndicator() : Text('Login'), ), ]), ); } }

Example 3: Implement Offline-First Sync

Problem: Build a notes app that works offline and syncs when online.

// Sync manager using React Native + NetInfo import NetInfo from '@react-native-community/netinfo'; import AsyncStorage from '@react-native-async-storage/async-storage'; class SyncManager { private pendingChanges = []; private isOnline = true; constructor() { NetInfo.addEventListener(state => { this.isOnline = state.isConnected; if (this.isOnline) this.flushChanges(); }); } async saveNote(note) { // Always save locally first await this.saveLocally(note); if (this.isOnline) { try { await api.post('/notes', note); await this.markAsSynced(note.id); } catch (e) { this.pendingChanges.push({ type: 'create', note }); } } else { this.pendingChanges.push({ type: 'create', note }); await this.savePendingChanges(); } } async flushChanges() { const pending = await this.getPendingChanges(); for (const change of pending) { try { await api[change.type](change.note); await this.removePending(change.id); } catch (e) { console.error('Sync failed:', e); break; } } } private async saveLocally(note) { const notes = await this.getLocalNotes(); notes.unshift(note); await AsyncStorage.setItem('notes', JSON.stringify(notes)); } }

Example 4: Kotlin โ€” Custom View with Canvas

Problem: Create a custom circular progress indicator in Android.

class CircularProgressView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { private var progress = 0f private val paint = Paint(Paint.ANTI_ALIAS_FLAG) private val rect = RectF() init { paint.style = Paint.Style.STROKE paint.strokeWidth = 20f paint.strokeCap = Paint.Cap.ROUND } fun setProgress(value: Float) { progress = value.coerceIn(0f, 100f) invalidate() // Trigger redraw } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) val padding = 20f rect.set(padding, padding, width - padding, height - padding) // Background circle paint.color = Color.LTGRAY canvas.drawArc(rect, 0f, 360f, false, paint) // Progress arc paint.color = Color.parseColor("#4CAF50") val sweepAngle = (progress / 100f) * 360f canvas.drawArc(rect, -90f, sweepAngle, false, paint) // Center text paint.style = Paint.Style.FILL paint.textSize = 48f paint.textAlign = Paint.Align.CENTER paint.color = Color.BLACK val text = "${progress.toInt()}%" val y = height / 2f - (paint.descent() + paint.ascent()) / 2f canvas.drawText(text, width / 2f, y, paint) } }

Example 5: App Deep Linking Configuration

Problem: Configure deep links so myapp://product/123 opens the product detail screen.

<!-- Android Manifest --> <activity android:name=".ProductDetailActivity"> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="myapp" android:host="product" /> </intent-filter> </activity>
// Handle deep link in Activity override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val data: Uri? = intent?.data if (data != null && data.scheme == "myapp") { val segments = data.pathSegments if (segments[0] == "product") { val productId = segments[1] loadProduct(productId) } } }

Practice Problems

Problem 1: Implement Infinite Scroll

Create a React Native FlatList that loads more items when reaching the end.

function InfiniteScrollList() { const [data, setData] = useState([]); const [page, setPage] = useState(1); const [loading, setLoading] = useState(false); const [hasMore, setHasMore] = useState(true); const loadData = async (pageNum) => { if (loading || !hasMore) return; setLoading(true); const response = await fetch(`/api/items?page=${pageNum}&limit=20`); const newData = await response.json(); setData(prev => [...prev, ...newData.items]); setHasMore(newData.hasMore); setLoading(false); }; return ( } keyExtractor={item => item.id} onEndReached={() => { const nextPage = page + 1; setPage(nextPage); loadData(nextPage); }} onEndReachedThreshold={0.5} ListFooterComponent={ loading ? : null } /> ); }

Problem 2: Flutter Responsive Layout

Create a layout that adapts to different screen sizes (phone vs tablet).

class ResponsiveLayout extends StatelessWidget { @override Widget build(BuildContext context) { final screenWidth = MediaQuery.of(context).size.width; final isTablet = screenWidth > 600; return Scaffold( body: isTablet ? Row( children: [ Expanded(flex: 2, child: Sidebar()), Expanded(flex: 3, child: MainContent()), ], ) : Column( children: [ Expanded(child: MainContent()), BottomNavBar(), ], ), ); } }

Problem 3: Implement Pull-to-Refresh

Add pull-to-refresh functionality to a React Native list.

function RefreshableList() { const [refreshing, setRefreshing] = useState(false); const [data, setData] = useState([]); const onRefresh = async () => { setRefreshing(true); try { const response = await fetch('/api/data'); const newData = await response.json(); setData(newData); } finally { setRefreshing(false); } }; return ( } keyExtractor={item => item.id} refreshControl={ } /> ); }

Problem 4: Kotlin โ€” ViewBinding Migration

Convert findViewById usage to ViewBinding in an Android Activity.

// Before (findViewById) class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val textView = findViewById(R.id.textView) val button = findViewById

Problem 5: Implement Biometric Authentication

Add fingerprint/face ID authentication to a React Native app.

import ReactNativeBiometrics from 'react-native-biometrics'; async function authenticateWithBiometrics() { try { const { available, biometryType } = await ReactNativeBiometrics.isSensorAvailable(); if (!available) { Alert.alert('Biometrics not available'); return; } const { success } = await ReactNativeBiometrics.simplePrompt({ promptMessage: 'Authenticate to continue', }); if (success) { console.log('Authentication successful'); // Proceed with app } } catch (error) { console.error('Biometric error:', error); } }

Problem 6: Custom Transition Animation

Create a shared element transition between two screens in React Native.

import { createSharedElementStackNavigator } from 'react-navigation-shared-element'; const Stack = createSharedElementStackNavigator(); function App() { return ( { const { item } = route.params; return [`item.${item.id}.image`]; }} options={{ transitionSpec: { open: { animation: 'timing', duration: 300 }, close: { animation: 'timing', duration: 300 }, }, }} /> ); } // In both screens: // // //

Problem 7: Implement Dark Mode

Add dark mode support to a React Native app with system preference detection.

import { useColorScheme } from 'react-native'; import { ThemeProvider } from './ThemeContext'; const lightTheme = { background: '#FFFFFF', text: '#1a1a1a', card: '#F5F5F5', primary: '#007AFF', }; const darkTheme = { background: '#1a1a1a', text: '#FFFFFF', card: '#2a2a2a', primary: '#0A84FF', }; function ThemeProvider({ children }) { const systemScheme = useColorScheme(); const [isDark, setIsDark] = useState(systemScheme === 'dark'); const theme = isDark ? darkTheme : lightTheme; const toggleTheme = () => setIsDark(prev => !prev); return ( {children} ); } // Usage function MyComponent() { const { theme } = useContext(ThemeContext); return ( Hello ); }

Problem 8: Unit Test a React Native Component

Write tests for a simple component using Jest and React Testing Library.

import { render, fireEvent, screen } from '@testing-library/react-native'; import Counter from '../Counter'; describe('Counter Component', () => { it('renders with initial count of 0', () => { render(); expect(screen.getByText('Count: 0')).toBeTruthy(); }); it('increments count when button pressed', () => { render(); fireEvent.press(screen.getByText('+')); expect(screen.getByText('Count: 1')).toBeTruthy(); }); it('decrements count when minus pressed', () => { render(); fireEvent.press(screen.getByText('-')); expect(screen.getByText('Count: -1')).toBeTruthy(); }); });

Problem 9: Flutter โ€” Pagination with Infinite Scroll

Implement an infinite scrolling list in Flutter with loading indicator.

class InfiniteScrollView extends StatefulWidget { @override _InfiniteScrollViewState createState() => _InfiniteScrollViewState(); } class _InfiniteScrollViewState extends State { final ScrollController _scrollController = ScrollController(); final List _items = []; int _page = 1; bool _isLoading = false; bool _hasMore = true; @override void initState() { super.initState(); _loadMore(); _scrollController.addListener(() { if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 200) { _loadMore(); } }); } Future _loadMore() async { if (_isLoading || !_hasMore) return; setState(() => _isLoading = true); final newItems = await api.getItems(page: _page); setState(() { _items.addAll(newItems); _page++; _hasMore = newItems.length == 20; _isLoading = false; }); } @override Widget build(BuildContext context) { return ListView.builder( controller: _scrollController, itemCount: _items.length + (_isLoading ? 1 : 0), itemBuilder: (context, index) { if (index == _items.length) { return Center(child: CircularProgressIndicator()); } return ListTile(title: Text(_items[index].title)); }, ); } }

Problem 10: Implement App Analytics

Set up Firebase Analytics to track screen views and custom events.

// Analytics service import analytics from '@react-native-firebase/analytics'; class AnalyticsService { static async trackScreen(screenName) { await analytics().logScreenView({ screen_name: screenName, screen_class: screenName, }); } static async trackEvent(eventName, params = {}) { await analytics().logEvent(eventName, params); } static async trackPurchase(amount, currency, itemId) { await analytics().logPurchase({ value: amount, currency: currency, items: [{ item_id: itemId }], }); } static async trackSearch(searchTerm) { await analytics().logSearch({ search_term: searchTerm }); } } // Usage in navigation navigation.addListener('state', () => { const currentRoute = navigation.getCurrentRoute(); AnalyticsService.trackScreen(currentRoute.name); });

๐Ÿ“š Related Subjects

๐Ÿ“š Related Subjects