Skip to content

Medium Mobile App Development Interview Questions

103 medium questions with answers. Applied questions that check whether you can use the concepts on real work.

Topics in the medium set

React Native Navigation, State and Native Modules: 16 Mobile Development Fundamentals: 15 Flutter State Management and Architecture: 15 React Native Core: 12 Testing, Performance and CI/CD: 12 App Store and Play Store Publishing: 12 Dart and Flutter Basics: 11 Mobile Backend, APIs and Firebase: 10
Solved — mediumStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

How does Flutter render UI differently from React Native?

Save to ▾
Show answer
Flutter draws every pixel itself using its own rendering engine, Impeller, onto a canvas, so widgets look identical across platforms and do not depend on native UI components. React Native maps components like View and Text to real native views, so the UI uses platform controls. Flutter gives pixel consistency and predictable performance; React Native gives native look and easier reuse of native view libraries, plus web developer familiarity with JavaScript.
02

Explain the mobile app lifecycle states on Android and iOS.

Save to ▾
Show answer
Both platforms move apps between foreground active, inactive, background and terminated states. On iOS, an app goes inactive during interruptions like calls, then background, where it gets limited time before suspension. On Android, activities move through resumed, paused and stopped, and the process can be killed in background. Cross-platform apps observe these through AppLifecycleListener in Flutter or AppState in React Native to pause work and save data.
03

What are the main differences between Android and iOS that a cross-platform developer must know?

Save to ▾
Show answer
Navigation patterns differ: Android has a system back gesture while iOS relies on swipe-back and navigation bars. Permissions, notification setup, background execution limits, file systems and store review rules differ. iOS builds require a Mac and Xcode, with signing through certificates and provisioning profiles. Design guidelines differ between Material Design and Human Interface Guidelines, so good cross-platform apps adapt some UI per platform.
04

What are runtime permissions and how do they differ between platforms?

Save to ▾
Show answer
Both platforms require runtime approval for sensitive features like camera, location, contacts and notifications. Android requires declarations in AndroidManifest.xml and runtime requests for dangerous permissions; iOS requires usage description strings in Info.plist, and the app crashes if a description is missing when requesting. iOS allows asking only once; later the user must change settings. Plugins like permission_handler or react-native-permissions unify the API.
05

What is responsive design in mobile apps and how do you handle different screen sizes?

Save to ▾
Show answer
Responsive design means layouts adapt to screen width, orientation, foldables and tablets instead of using fixed sizes. Use flexible layouts, percentages or flex, and breakpoints for compact, medium and expanded widths. In Flutter use LayoutBuilder and MediaQuery.sizeOf; in React Native use flexbox and useWindowDimensions. Respect safe areas for notches and system bars, support text scaling for accessibility, and test on small budget phones.
06

How do deep links and universal links work?

Save to ▾
Show answer
Deep links open a specific screen in your app from a URL. Custom schemes like myapp://order/42 work but are not verified. Verified HTTPS links are App Links on Android, using assetlinks.json, and Universal Links on iOS, using an apple-app-site-association file on your domain. When verified, the link opens your app directly instead of the browser. The routing library, like go_router or React Navigation linking, maps URLs to screens.
07

How do you design a mobile app for users on low-end devices and poor networks?

Save to ▾
Show answer
Keep the app size small, avoid heavy animations on low-end phones, and load images at the right resolution with caching. Use pagination and compressed API responses, cache data locally so screens open offline, and show skeleton loaders and clear retry options. Defer non-critical SDK initialisation to speed up startup. Test on budget devices with 2 or 3 GB RAM and throttled networks, since many users in India use them.
08

What is accessibility in mobile apps and how do you implement it?

Save to ▾
Show answer
Accessibility makes apps usable by people with disabilities. Provide labels for icons and images so screen readers like TalkBack and VoiceOver can announce them, keep touch targets at least 44 to 48 points, support dynamic text sizes, ensure colour contrast, and avoid conveying information only by colour. Flutter uses Semantics widgets, and React Native uses accessibilityLabel and accessibilityRole. Test with screen readers enabled.
09

A startup asks you to choose between Flutter, React Native and native for their new delivery app. How do you decide?

Save to ▾
Show answer
I would ask about team skills, timeline, budget, required features and long-term plans. If the team knows JavaScript and has a web app, React Native allows code and skill sharing. If they want a consistent custom UI and fast development from scratch, Flutter is strong. Heavy background location and maps work well in both with plugins, but if the app depends deeply on platform features, native may be safer. I would prototype one key screen first.
10

The client wants the app to look exactly like iOS on iPhones and like Material on Android. How do you approach this in a cross-platform app?

Save to ▾
Show answer
Identify which elements truly need platform-specific behaviour: navigation transitions, back gestures, date pickers, switches and dialogs. In Flutter, use adaptive constructors like Switch.adaptive or Cupertino widgets based on Theme.of(context).platform. In React Native, many components are native already, and Platform.select handles differences. Keep shared business logic and most layout common, and limit platform branches to a component library so they stay manageable.
11

How would you structure the folder layout of a medium-sized cross-platform app?

Save to ▾
Show answer
Organise by feature rather than by type: features/auth, features/cart, features/profile, each containing UI, state logic and data code. Keep shared pieces in core folders such as core/network, core/storage, core/theme and core/widgets or components. Put configuration for environments separately. This keeps related code together, makes ownership clear and lets features be moved into packages later. Enforce the structure with lint rules and code review.
12

How do you set up multiple environments such as dev, staging and production in a mobile app?

Save to ▾
Show answer
Create build flavours on Android and schemes or configurations on iOS, each with its own app ID suffix, app name, icon and API base URL, so all can be installed side by side. In Flutter, use --flavor with --dart-define-from-file for config values; in React Native, use react-native-config or Expo app config with environment variables. Keep secrets out of the repo and set them in CI.
13

What questions would you ask before estimating a new mobile app project?

Save to ▾
Show answer
I would ask about target platforms and minimum OS versions, user types and key flows, design readiness, backend availability and API documentation, offline needs, payments, notifications, analytics, third-party SDKs, security or compliance requirements, languages to support, and release expectations including store accounts. I would also ask who maintains the app afterward. Then I break features into tasks, estimate with a buffer for store review and testing.
14

Tell me about a time you had to learn a new framework under a deadline.

Save to ▾
Show answer
Situation: my team decided to build a client app in Flutter, and I had only React Native experience. Task: deliver the login and dashboard screens in three weeks. Action: I completed the official codelabs in the first week, mapped concepts I knew like components and hooks to widgets and state, and asked for early code reviews. Result: the screens shipped on time, and I later wrote a short guide for other React Native developers moving to Flutter.
15

How do you balance speed and quality when a client wants features fast?

Save to ▾
Show answer
I agree on what quality means for this release, such as no crashes in key flows, working offline basics and tests for payment logic. I deliver the smallest useful version first, behind feature flags if needed, and avoid shortcuts in areas that are expensive to fix later, like data models and security. I make technical debt visible in the backlog with an estimate so it is planned rather than forgotten.
16

What is BuildContext?

Save to ▾
Show answer
BuildContext is a handle to a widget's location in the element tree. It is used to look up inherited data like Theme.of(context), MediaQuery and Navigator, and providers. Each widget's build method gets its own context. Common mistakes are using a context from above a widget that provides data, or using a context after an async gap when the widget may be unmounted; check context.mounted before using it after await.
17

Explain the StatefulWidget lifecycle methods.

Save to ▾
Show answer
createState creates the State. initState runs once for setup like controllers and subscriptions; do not use inherited widgets there. didChangeDependencies runs after initState and when inherited data changes. build runs on every rebuild. didUpdateWidget runs when the parent rebuilds with new configuration. dispose runs when removed permanently, where you cancel streams, dispose controllers and timers to avoid memory leaks.
18

What are keys in Flutter and when do you need them?

Save to ▾
Show answer
Keys help Flutter match widgets to existing elements and state when the widget list changes. Without keys, Flutter matches by type and position, so reordering or removing items in a list of stateful widgets can attach state to the wrong item. Use ValueKey with a unique ID for list items, UniqueKey to force recreation, and GlobalKey rarely, for accessing state across the tree such as a Form.
19

What is a Stream in Dart and how is it used in Flutter?

Save to ▾
Show answer
A Stream delivers a sequence of asynchronous events, such as real-time database updates, location changes or WebSocket messages. You listen with listen() or await for, and transform with map, where and debounce from packages. Single-subscription streams allow one listener; broadcast streams allow many. In Flutter, StreamBuilder rebuilds UI on each event. Always cancel subscriptions in dispose to prevent leaks.
20

What are isolates and when should you use them?

Save to ▾
Show answer
Isolates are Dart's units of concurrency, each with its own memory and event loop, communicating by messages. Heavy CPU work like parsing a large JSON file, image processing or encryption on the main isolate causes jank. Use Isolate.run or compute to run such work in a separate isolate and return the result. For network or file I/O, async-await is enough because that work is not CPU-bound.
21

Write a Dart sealed class for API results and handle it with an exhaustive switch.

Save to ▾
Show answer
sealed class Result<T> {} class Success<T> extends Result<T> { Success(this.data); final T data; } class Failure<T> extends Result<T> { Failure(this.message); final String message; } Widget view(Result<List<String>> r) => switch (r) { Success(:final data) => ListView(children: [for (final s in data) Text(s)]), Failure(:final message) => Center(child: Text(message)), };
22

Write a Flutter screen that fetches a list from an API using FutureBuilder.

Save to ▾
Show answer
class UsersPage extends StatefulWidget { const UsersPage({super.key}); @override State<UsersPage> createState() => _UsersPageState(); } class _UsersPageState extends State<UsersPage> { late final Future<List<User>> _future = api.fetchUsers(); @override Widget build(BuildContext context) => FutureBuilder<List<User>>( future: _future, builder: (context, snap) { if (snap.connectionState != ConnectionState.done) { return const Center(child: CircularProgressIndicator()); } if (snap.hasError) return const Center(child: Text('Something went wrong')); final users = snap.data!; return ListView.builder( itemCount: users.length, itemBuilder: (_, i) => ListTile(title: Text(users[i].name)), ); }, ); }
23

After an API call finishes, the app throws an error about using BuildContext across async gaps or setState after dispose. How do you fix it?

Save to ▾
Show answer
The user left the screen before the Future completed, so the widget was unmounted. Before using context or calling setState after await, check if (!context.mounted) return; or if (!mounted) return; in State. Better still, move async logic out of widgets into a state management layer that the UI listens to, and cancel subscriptions or timers in dispose so no callbacks run on a dead widget.
24

Parsing a 10 MB JSON file freezes the Flutter UI for two seconds. How do you fix it?

Save to ▾
Show answer
JSON decoding is CPU-bound and runs on the main isolate, blocking frames. Move it to a background isolate with Isolate.run(() => parseProducts(jsonString)) or compute. Also consider whether the API can paginate or return less data, and parse lazily. Test in profile mode with DevTools performance view to confirm the frame time improvement, since debug mode exaggerates slowness.
25

How do you create reusable custom widgets in Flutter?

Save to ▾
Show answer
Extract repeated UI into a StatelessWidget class with clear constructor parameters, rather than helper methods that return widgets, because classes get their own element, can be const and rebuild independently. Accept callbacks for events, use the theme for colours and text styles, and provide sensible defaults. Group them into a shared widgets folder or design system package and document them with widget previews or a showcase screen.
26

How do you implement a form with validation in Flutter?

Save to ▾
Show answer
Wrap fields in a Form with a GlobalKey<FormState>, use TextFormField with a validator function that returns an error string or null, and call formKey.currentState!.validate() on submit. Use TextEditingController for values and dispose it, set keyboardType and textInputAction for each field, and autovalidateMode onUserInteraction to show errors as the user types. Keep validation rules in testable functions outside widgets.
27

What is InheritedWidget and how does Provider build on it?

Save to ▾
Show answer
InheritedWidget lets descendants read data efficiently via context and rebuild when it changes, which is how Theme and MediaQuery work. Writing it by hand is verbose. Provider wraps InheritedWidget with a simpler API: ChangeNotifierProvider exposes a ChangeNotifier, and widgets use context.watch to rebuild or context.read to call methods without rebuilding. It is simple and suitable for small to medium apps.
28

Compare Provider, Riverpod and Bloc.

Save to ▾
Show answer
Provider is simple and built on InheritedWidget but depends on BuildContext and can throw provider-not-found errors at runtime. Riverpod, from the same author, is compile-safe, independent of the widget tree, supports async providers and easy overrides for testing. Bloc uses events and states with streams, enforcing strict separation and traceability, popular in large teams and enterprises. Choose based on team familiarity and app complexity.
29

Explain the Bloc pattern and Cubit.

Save to ▾
Show answer
In Bloc, the UI adds events, the Bloc handles them with on<Event> handlers and emits new immutable states, and widgets rebuild with BlocBuilder or react with BlocListener. A Cubit is a simpler version where the UI calls methods directly and the Cubit emits states, without event classes. Use Cubit for straightforward logic and full Bloc when you need event transformations like debounce or detailed traceability.
30

Write a Cubit that loads products and emits loading, success and error states.

Save to ▾
Show answer
sealed class ProductState {} class ProductLoading extends ProductState {} class ProductLoaded extends ProductState { ProductLoaded(this.items); final List<Product> items; } class ProductError extends ProductState { ProductError(this.message); final String message; } class ProductCubit extends Cubit<ProductState> { ProductCubit(this._repo) : super(ProductLoading()); final ProductRepository _repo; Future<void> load() async { emit(ProductLoading()); try { emit(ProductLoaded(await _repo.fetchProducts())); } catch (_) { emit(ProductError('Could not load products')); } } }
31

Write a Riverpod provider that fetches data asynchronously and display it in a widget.

Save to ▾
Show answer
final productsProvider = FutureProvider.autoDispose<List<Product>>((ref) { final repo = ref.watch(productRepositoryProvider); return repo.fetchProducts(); }); class ProductsView extends ConsumerWidget { const ProductsView({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final products = ref.watch(productsProvider); return products.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => const Center(child: Text('Failed to load')), data: (items) => ListView(children: [for (final p in items) ListTile(title: Text(p.name))]), ); } }
32

What is clean architecture in a Flutter app?

Save to ▾
Show answer
Clean architecture separates code into presentation (widgets and state notifiers or blocs), domain (entities, use cases and repository interfaces) and data (repository implementations, API clients, local storage and DTOs). Dependencies point inward, so the domain knows nothing about Flutter or HTTP. It improves testability and lets you swap data sources. For small apps it may be heavy, so many teams keep presentation and data layers and add domain only when logic grows.
33

Write a go_router configuration with an auth redirect.

Save to ▾
Show answer
final router = GoRouter( initialLocation: '/', refreshListenable: authNotifier, redirect: (context, state) { final loggedIn = authNotifier.isLoggedIn; final goingToLogin = state.matchedLocation == '/login'; if (!loggedIn && !goingToLogin) return '/login'; if (loggedIn && goingToLogin) return '/'; return null; }, routes: [ GoRoute(path: '/', builder: (_, __) => const HomePage()), GoRoute(path: '/login', builder: (_, __) => const LoginPage()), GoRoute( path: '/product/:id', builder: (_, state) => ProductPage(id: state.pathParameters['id']!), ), ], );
34

What is dependency injection in Flutter and how is it done?

Save to ▾
Show answer
Dependency injection supplies objects like API clients and repositories from outside instead of creating them inside widgets or blocs. In Flutter it is commonly done with Riverpod providers, Provider or RepositoryProvider in Bloc, or a service locator like get_it, sometimes with injectable for code generation. It makes code testable because tests can override dependencies with fakes, and it centralises object lifetimes.
35

What is the freezed package used for?

Save to ▾
Show answer
freezed generates immutable data classes with copyWith, equality, toString and union types or sealed classes, and integrates with json_serializable for fromJson and toJson. It removes boilerplate when modelling state such as loading, data and error variants. You annotate a class, run build_runner, and get generated code in a part file. With Dart 3 sealed classes and records, some teams need it less, but it is still widely used.
36

How would you test a Bloc or Riverpod notifier?

Save to ▾
Show answer
Test business logic without widgets. For Bloc, the bloc_test package's blocTest builds the bloc with a fake repository, acts by adding events, and expects a list of emitted states. For Riverpod, create a ProviderContainer with overrides for repository providers, read the notifier, call methods and assert the state. Use mocktail for mocks and keep tests fast, deterministic and independent of the network.
37

The cart total shows stale values on the checkout screen after items are removed on the cart screen. How do you fix it?

Save to ▾
Show answer
Each screen probably holds its own copy of cart data. Move cart state into a single shared state object, such as a Riverpod notifier or a Cubit provided above both screens, and have both screens watch it. All mutations go through that object, which emits a new immutable state. Derived values like total should be computed from the state, not stored separately, so they can never become inconsistent.
38

Your Flutter codebase mixes setState, Provider and get_it randomly across screens. How would you clean it up?

Save to ▾
Show answer
Agree on one approach with the team, for example Riverpod for app state and setState only for local widget state, and document examples. Migrate gradually, starting with the most buggy or most changed features, and write tests before moving logic. Add lint rules and pull request checklists so new code follows the standard. Avoid a big-bang rewrite that blocks feature work for weeks.
39

How do you manage form state and validation across multiple steps in a Flutter onboarding flow?

Save to ▾
Show answer
Keep the onboarding data in one state object owned by a notifier or cubit scoped to the flow, with each step updating its part. Validate per step before moving forward and again on final submit. Save progress locally so users can resume if they leave. Keep validation rules in pure functions that are unit tested. Dispose the state when the flow completes so data does not leak into later sessions.
40

What is the difference between ref.watch, ref.read and ref.listen in Riverpod?

Save to ▾
Show answer
ref.watch subscribes to a provider and rebuilds the widget or recomputes the provider when it changes; use it in build methods. ref.read gets the current value once without subscribing; use it in callbacks like onPressed to call notifier methods. ref.listen runs a callback when a provider changes without rebuilding, useful for side effects like showing a snackbar or navigating after a state change.
41

Tell me about a technical decision you made that you later regretted, and what you learned.

Save to ▾
Show answer
Situation: on an earlier project I chose a lesser-known state management package because it looked simpler. Task: support the app as it grew. Action: when the package stopped being maintained, I led a migration to Riverpod feature by feature with tests. Result: the migration took three sprints. I learned to evaluate packages by maintenance activity, community size and testing support, not just initial simplicity, and to document decisions.
42

What is Hermes and why is it the default engine?

Save to ▾
Show answer
Hermes is a JavaScript engine optimised for React Native. It compiles JavaScript to bytecode at build time, so the app does not parse and compile JavaScript on startup, which reduces time to interactive, memory use and app size. It is the default engine on Android and iOS. It supports debugging with Chrome DevTools-based tools and sampling profiling to find slow JavaScript.
43

What are useMemo, useCallback and React.memo used for?

Save to ▾
Show answer
React.memo skips re-rendering a component when its props are shallowly equal. useCallback keeps the same function reference between renders, and useMemo caches a computed value, both only changing when dependencies change. They help when passing callbacks to memoised list items or computing expensive values. Overusing them adds complexity with little gain; the React Compiler can now apply such memoisation automatically in supported projects.
44

Write a FlatList that shows products with pull-to-refresh and infinite scroll.

Save to ▾
Show answer
function ProductList({ items, loading, onRefresh, onEndReached }) { const renderItem = useCallback(({ item }) => <ProductRow product={item} />, []); return ( <FlatList data={items} keyExtractor={(item) => item.id} renderItem={renderItem} refreshing={loading} onRefresh={onRefresh} onEndReached={onEndReached} onEndReachedThreshold={0.5} ListEmptyComponent={!loading ? <Text>No products</Text> : null} /> ); }
45

Write a custom hook that fetches data with loading and error states.

Save to ▾
Show answer
function useFetch(url) { const [state, setState] = useState({ data: null, loading: true, error: null }); useEffect(() => { const controller = new AbortController(); fetch(url, { signal: controller.signal }) .then((r) => { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); }) .then((data) => setState({ data, loading: false, error: null })) .catch((e) => { if (e.name !== 'AbortError') setState({ data: null, loading: false, error: e.message }); }); return () => controller.abort(); }, [url]); return state; }
46

What is Metro?

Save to ▾
Show answer
Metro is the JavaScript bundler for React Native. It resolves modules, transforms code with Babel, and serves the bundle to the app during development with Fast Refresh. For release builds, it produces a minified bundle that is compiled to Hermes bytecode. It supports platform-specific extensions, asset handling and configuration in metro.config.js for things like SVG transformers or monorepo setups with watch folders.
47

How does the keyboard affect layouts in React Native and how do you handle it?

Save to ▾
Show answer
When the keyboard opens it can cover inputs, especially at the bottom of the screen. Use KeyboardAvoidingView with behavior padding on iOS, and rely on Android's adjustResize window setting, or use react-native-keyboard-controller for consistent behaviour on both. Wrap forms in a ScrollView with keyboardShouldPersistTaps set to handled so buttons work while the keyboard is open, and dismiss the keyboard on submit.
48

A React Native list of 2000 items scrolls slowly and shows blank areas. How do you fix it?

Save to ▾
Show answer
Use FlatList or FlashList rather than ScrollView with map. Provide a stable keyExtractor, memoise row components with React.memo, avoid inline functions and heavy computation in renderItem, and use getItemLayout or fixed item sizes where possible. Tune windowSize and maxToRenderPerBatch, compress and cache images with a library like expo-image, and test a release build, since dev mode is much slower.
49

A screen re-renders every time the user types in a search box, making it laggy. How do you fix it?

Save to ▾
Show answer
Keep the search text state local to the search input component so only it re-renders, debounce the query before updating the list or calling the API, and memoise the list and row components. Avoid storing frequently changing values in a global store that many components subscribe to. Use the React DevTools profiler to confirm which components render, and useDeferredValue to keep typing responsive.
50

Your web team wants to reuse React code in the mobile app. How much can realistically be shared?

Save to ▾
Show answer
Business logic, API clients, validation, state management, types and utility hooks can be shared through a monorepo package. UI components usually cannot be shared directly because web uses DOM elements and mobile uses native components, unless you adopt React Native for Web or a universal design system. Navigation and storage differ too. Plan a shared core package and platform-specific UI to avoid forcing awkward compromises.
51

How do you debug a React Native app?

Save to ▾
Show answer
Use React Native DevTools, the default debugger since 0.76, for console logs, breakpoints, React component inspection and profiling. Inspect network requests with the network panel or a proxy. For native crashes, check Logcat in Android Studio and the Xcode console. Use the performance monitor overlay for frame rates, and add a crash reporting tool like Sentry or Crashlytics for production errors with source maps uploaded.
52

Describe a time you had to deliver a feature with incomplete requirements.

Save to ▾
Show answer
Situation: product asked for a referral feature with only a one-line description. Task: deliver in a sprint. Action: I listed open questions, met the product manager for 20 minutes to agree on core rules, built the agreed version with configurable reward values from the backend, and documented assumptions in the ticket. Result: we shipped on time, and later changes needed only config updates instead of a new release.
53

Write a React Native component that requests location permission and shows the coordinates using Expo.

Save to ▾
Show answer
import * as Location from 'expo-location'; export function MyLocation() { const [coords, setCoords] = useState(null); const [error, setError] = useState(null); useEffect(() => { (async () => { const { status } = await Location.requestForegroundPermissionsAsync(); if (status !== 'granted') { setError('Location permission denied'); return; } const pos = await Location.getCurrentPositionAsync({}); setCoords(pos.coords); })(); }, []); if (error) return <Text>{error}</Text>; if (!coords) return <ActivityIndicator />; return <Text>{coords.latitude}, {coords.longitude}</Text>; }
54
Save to ▾
Show answer
Expo Router is a file-based router built on React Navigation. Files in the app directory become routes, so app/product/[id].tsx maps to /product/42. Layout files define stacks and tabs, and every screen is deep-linkable automatically on mobile and web. It supports typed routes, protected routes for auth, and API routes. It reduces navigation boilerplate and makes URL-based linking consistent across platforms.
55

Write a React Navigation setup with a stack containing a tab navigator and a details screen.

Save to ▾
Show answer
const Tab = createBottomTabNavigator(); const Stack = createNativeStackNavigator(); function HomeTabs() { return ( <Tab.Navigator> <Tab.Screen name="Feed" component={FeedScreen} /> <Tab.Screen name="Profile" component={ProfileScreen} /> </Tab.Navigator> ); } export default function App() { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Home" component={HomeTabs} options={{ headerShown: false }} /> <Stack.Screen name="Details" component={DetailsScreen} /> </Stack.Navigator> </NavigationContainer> ); }
56

Compare Redux Toolkit, Zustand and React Context for state in React Native.

Save to ▾
Show answer
Context is built in and fine for rarely changing values like theme or auth, but every consumer re-renders on change. Redux Toolkit gives a predictable global store with slices, middleware and excellent DevTools, suited to large teams, and RTK Query handles API caching. Zustand is small and simple, with selector-based subscriptions that limit re-renders. Server data is often better handled by TanStack Query than by any global store.
57

Why use TanStack Query for server state in mobile apps?

Save to ▾
Show answer
Server state, such as data fetched from APIs, has caching, refetching, staleness and retry concerns that client state libraries do not handle well. TanStack Query caches responses by query keys, deduplicates requests, refetches on focus or reconnect, supports pagination and infinite queries, optimistic updates and offline persistence. It removes large amounts of useEffect and loading-state code and keeps screens consistent.
58

Write a Redux Toolkit slice for a cart.

Save to ▾
Show answer
const cartSlice = createSlice({ name: 'cart', initialState: { items: [] }, reducers: { addItem(state, action) { const existing = state.items.find((i) => i.id === action.payload.id); if (existing) existing.qty += 1; else state.items.push({ ...action.payload, qty: 1 }); }, removeItem(state, action) { state.items = state.items.filter((i) => i.id !== action.payload); }, }, }); export const { addItem, removeItem } = cartSlice.actions; export const selectTotal = (s) => s.cart.items.reduce((t, i) => t + i.price * i.qty, 0);
59

How do you implement authentication flow screens in React Navigation?

Save to ▾
Show answer
Conditionally render screen groups based on auth state: if the user is signed out, the navigator shows login and signup; when signed in, it shows the app screens. Changing state automatically switches stacks and prevents going back to login with the back button. Restore tokens from secure storage on startup while showing a splash screen. Expo Router offers protected routes for the same pattern.
60

What are optimistic updates and how do you implement them?

Save to ▾
Show answer
An optimistic update changes the UI immediately as if the server request succeeded, such as liking a post, then rolls back if the request fails. It makes apps feel fast on slow networks. With TanStack Query, use onMutate to update the cache and save the previous value, onError to restore it, and onSettled to refetch. Use it for low-risk actions, not payments.
61

A global Redux store causes the whole app to re-render on every small change. How do you fix it?

Save to ▾
Show answer
Components are probably selecting large parts of state or creating new objects in selectors. Select only the fields each component needs with useSelector, memoise derived data with createSelector, and keep state normalised. Move server data to RTK Query or TanStack Query and local UI state back into components. Verify improvements with the React profiler, checking which components render after each action.
62

Deep links open the app but land on the home screen instead of the product page. How do you debug it?

Save to ▾
Show answer
Check that the link configuration maps the URL path to the right screen name, including nested navigators, and that path parameters match. Verify verified link setup on both platforms: assetlinks.json for Android and the associated domains entitlement plus the site association file for iOS. Test with adb shell am start and xcrun simctl openurl. Also handle links when the app is cold started versus already running.
63

The product team wants the same app on mobile and web from one codebase. What would you propose?

Save to ▾
Show answer
With React Native, Expo with Expo Router and React Native Web lets one codebase target Android, iOS and web, with file-based routes working as URLs. With Flutter, the web target exists but suits app-like experiences more than SEO-heavy pages. I would share business logic and most screens, keep SEO landing pages on a web framework, and plan for platform-specific tweaks like hover states and keyboard navigation.
64

How do you handle gestures such as swipe to delete in React Native?

Save to ▾
Show answer
Use react-native-gesture-handler, which processes gestures on the native side, often with Reanimated for smooth animations. For swipe to delete, the Swipeable or ReanimatedSwipeable component renders action buttons behind a row. Define gestures with the Gesture API, such as Gesture.Pan, and compose them when needed. Wrap the app root in GestureHandlerRootView. Provide an accessible alternative like a long-press menu for screen reader users.
65

How do you persist state in React Native between app launches?

Save to ▾
Show answer
For small key-value data use AsyncStorage or MMKV, which is much faster and synchronous. Persist Redux with redux-persist or Zustand with its persist middleware, choosing only the slices that need it. Store tokens in secure storage like expo-secure-store or Keychain and Keystore wrappers, never in plain storage. For larger structured data use SQLite through expo-sqlite or an ORM like WatermelonDB.
66

How do you handle error boundaries in a React Native app?

Save to ▾
Show answer
An error boundary is a class component, or a library like react-error-boundary, that catches rendering errors in its child tree and shows a fallback UI instead of crashing the whole app. Place one at the app root and around risky screens. They do not catch errors in event handlers or async code, so use try-catch there. Report caught errors to a crash reporting tool with context for debugging.
67

How would you migrate a large React Native app from JavaScript to TypeScript?

Save to ▾
Show answer
Enable TypeScript with allowJs so both coexist, start with a relaxed tsconfig, and convert shared code first: API types, models, utilities and navigation param lists. Then convert screens feature by feature, tightening strict options gradually. Add type checks to CI so new files must be TypeScript. Avoid using any to silence errors; use unknown and narrow. Track progress and celebrate milestones to keep momentum.
68

Tell me about a time you improved app performance in a cross-platform app.

Save to ▾
Show answer
Situation: our React Native order history screen took three seconds to render and scrolled poorly. Task: make it smooth. Action: I profiled with React Native DevTools, replaced ScrollView with FlashList, memoised rows, moved date formatting into the API layer and switched images to a caching library. Result: render time dropped below 600 milliseconds, and frame drops nearly disappeared on budget phones.
69

What would you do if you joined a project and found the codebase poorly structured?

Save to ▾
Show answer
I would first understand why it is that way, since deadlines and changing requirements often explain it. I would document the main pain points with examples, such as frequent bugs in a module, and propose small improvements tied to upcoming features rather than a rewrite. I would add tests around risky areas first. Showing measurable wins, like fewer bugs, builds trust for larger refactors later.
70

How do you secure Cloud Firestore data accessed directly from a mobile app?

Save to ▾
Show answer
Because the app talks to the database directly, security rules are the backend. Write rules that check request.auth for authentication and that users can read or write only their own documents, for example allow read, write: if request.auth.uid == userId. Validate fields and types in rules, never leave test mode rules open, and move sensitive operations like payments or role changes to Cloud Functions. Test rules with the emulator suite.
71

How does token-based authentication work in mobile apps?

Save to ▾
Show answer
The user signs in and the server returns a short-lived access token, often a JWT, and a longer-lived refresh token. The app stores them securely in Keychain or Keystore-backed storage and sends the access token in the Authorization header. When it expires, the app uses the refresh token to get a new one, retrying the failed request. On logout, tokens are deleted and ideally revoked on the server.
72

Write a Dart HTTP client using dio with an interceptor that adds an auth token.

Save to ▾
Show answer
final dio = Dio(BaseOptions( baseUrl: 'https://api.example.com', connectTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 15), )); dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) async { final token = await secureStorage.read(key: 'access_token'); if (token != null) options.headers['Authorization'] = 'Bearer $token'; handler.next(options); }, onError: (e, handler) { if (e.response?.statusCode == 401) authNotifier.logout(); handler.next(e); }, ));
73

How do push notifications work end to end?

Save to ▾
Show answer
The app registers with the platform push service, FCM on Android and APNs on iOS, often both through FCM, and receives a device token. The app sends this token to your backend, linked to the user. When an event happens, the backend sends a message to FCM or APNs with the token, which delivers it to the device. The app requests notification permission, handles taps to open the right screen, and refreshes tokens when they change.
74

What is the difference between REST and GraphQL for mobile clients?

Save to ▾
Show answer
REST exposes resources at fixed endpoints, which can lead to over-fetching or many round trips for one screen. GraphQL exposes one endpoint where the client asks exactly for the fields it needs, reducing payload size and requests, which helps on slow mobile networks. GraphQL adds complexity in caching, error handling and server performance. Clients like Apollo or graphql_flutter provide normalised caching and code generation.
75

How do you implement OTP login with a phone number?

Save to ▾
Show answer
The user enters a phone number, the backend or an auth service sends an OTP via SMS and returns a verification ID. The user enters the code, which is verified to issue session tokens. On Android, use the SMS Retriever or User Consent API to auto-read the code without SMS permissions; on iOS, set the text content type to one-time code for autofill. Rate-limit requests, expire codes quickly and protect against abuse.
76

Push notifications arrive on Android but not on iOS. How do you debug it?

Save to ▾
Show answer
Check that the push notifications capability and background modes are enabled in Xcode, that an APNs authentication key is uploaded to the push provider, and that notification permission was granted. Verify the app gets an APNs token and the provider token, and that the right environment, development or production, is used. Test on a real device, since simulators have limited push support, and check payload format.
77

The API responses are slow on mobile networks. What can the mobile team ask the backend team to change?

Save to ▾
Show answer
Ask for pagination with sensible page sizes, gzip or brotli compression, removing unused fields or providing screen-specific endpoints, and aggregated endpoints to avoid multiple sequential calls. Request proper cache headers and ETags so the client can reuse responses. Ask for resized images through a CDN and HTTP/2 or HTTP/3 support. Share measured timings from real devices to justify the requests.
78

How do you handle pressure when a production issue affects many users?

Save to ▾
Show answer
I stay calm and focus on reducing impact first: confirm the issue, communicate status to the team, and look for the fastest safe mitigation such as a remote config switch, server-side fix or pausing a rollout. Then I find the root cause, ship a proper fix and write a short postmortem. Clear, regular updates to stakeholders reduce panic and let others plan around the issue.
79

What is Supabase and how does it compare to Firebase?

Save to ▾
Show answer
Supabase is an open-source backend platform built on PostgreSQL, offering authentication, a relational database with auto-generated APIs, row level security, storage, edge functions and real-time subscriptions. Firebase uses NoSQL databases like Firestore. Supabase suits apps with relational data and SQL needs, and can be self-hosted, while Firebase has a richer mobile ecosystem including Crashlytics, Remote Config and FCM. Many apps combine them.
80

What is Maestro and why do mobile teams use it?

Save to ▾
Show answer
Maestro is an open-source mobile UI testing framework where flows are written in simple YAML, such as launchApp, tapOn "Login" and assertVisible "Welcome". It works with native, Flutter and React Native apps on Android and iOS, handles waiting automatically, and reduces flakiness compared to many older tools. Teams use it for smoke tests of critical journeys in CI because tests are quick to write and readable by QA.
81

How do you measure performance in a Flutter app?

Save to ▾
Show answer
Run the app in profile mode on a real device, not debug or emulator. Use Flutter DevTools: the performance view shows frame build and raster times, the CPU profiler finds expensive functions, and the memory view tracks allocations and leaks. Target under about 16 milliseconds per frame for 60 fps. The performance overlay shows UI and raster thread graphs, and rebuild tracking highlights widgets rebuilding too often.
82

How do you reduce app size for Flutter and React Native apps?

Save to ▾
Show answer
Publish Android App Bundles so users download only their architecture and density resources. In Flutter, use --split-debug-info and --obfuscate, remove unused packages and fonts, compress images and use tree-shaken icons. In React Native, enable Hermes, R8 minification and resource shrinking, and remove heavy libraries. For both, analyse size with tools like flutter build --analyze-size or APK Analyzer and lazy-load large assets.
83

How do you detect and fix memory leaks in cross-platform apps?

Save to ▾
Show answer
Leaks usually come from subscriptions, timers, controllers and listeners that are never disposed, or global caches that grow without limits. In Flutter, dispose controllers and cancel stream subscriptions in dispose, and check the DevTools memory view for growing instances. In React Native, return cleanup functions from useEffect and remove event listeners. Repeatedly open and close a screen while profiling to confirm memory returns to baseline.
84

How do you set up CI/CD for a cross-platform mobile app?

Save to ▾
Show answer
On every pull request, run lint, formatting checks, unit and widget or component tests. On merge, build signed Android and iOS release artifacts using CI services such as GitHub Actions, Codemagic, Bitrise or EAS Build, with signing keys stored as secrets. Use fastlane or EAS Submit to upload to internal testing tracks and TestFlight. Automate version numbers, generate release notes and run smoke tests with Maestro.
85

Write a GitHub Actions workflow that runs Flutter tests on every pull request.

Save to ▾
Show answer
name: flutter-ci on: pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2 with: channel: stable cache: true - run: flutter pub get - run: dart format --set-exit-if-changed . - run: flutter analyze - run: flutter test --coverage
86

What security practices should every mobile app follow?

Save to ▾
Show answer
Use HTTPS everywhere and consider certificate pinning for high-risk apps. Store tokens only in secure storage, never log sensitive data, and keep secrets on the server. Obfuscate release builds, validate all input on the server, and protect sensitive screens from screenshots where needed. Check device integrity with platform attestation APIs for high-risk actions, and follow the OWASP Mobile Application Security Verification Standard as a checklist.
87

Integration tests pass locally but fail randomly in CI. How do you make them reliable?

Save to ▾
Show answer
Flaky tests usually come from timing assumptions, shared state, network dependence or slow emulators. Replace fixed delays with waiting for specific conditions, mock or stub network calls with predictable responses, reset app data between tests, and use stable selectors like keys or test IDs instead of text that changes. Give CI emulators enough resources, retry only as a temporary measure, and track flaky tests separately to fix them.
88

After a release, crash reports show a spike only on one Android OS version. What steps do you take?

Save to ▾
Show answer
Pause the staged rollout to limit impact. Filter crash reports by OS version and device to find the top stack trace, and check behaviour changes for that version, such as permission, background or edge-to-edge rules. Reproduce on an emulator of that version, fix it, add a regression test and resume rollout with a hotfix. Add that OS version to the regular test device matrix.
89

Your team has no automated tests and frequent regressions. How would you introduce testing?

Save to ▾
Show answer
Start where bugs hurt most: write unit tests for business logic like pricing, validation and state transitions, and a few end-to-end smoke tests for login, checkout and payment flows with Maestro or integration tests. Run them in CI on every pull request so failures block merges. Require tests for bug fixes going forward. Show reduced regressions after a few sprints to build team support.
90

A security audit finds that the app stores the access token in plain shared preferences. How do you fix it?

Save to ▾
Show answer
Move tokens to secure storage backed by Keychain on iOS and Keystore on Android, such as flutter_secure_storage or expo-secure-store. Migrate existing users by reading the old value once, writing it securely and deleting the plain copy. Shorten access token lifetime, use refresh tokens, exclude sensitive files from backups, and clear tokens on logout. Retest with the audit team to confirm the issue is closed.
91

How do you decide which devices to test on for an Indian user base?

Save to ▾
Show answer
Use analytics from the existing app or market data to identify the most common manufacturers, OS versions, screen sizes and RAM levels among your users. Cover a budget device with 3 to 4 GB RAM, a mid-range phone, a recent flagship, an older OS version you still support, and at least one iPhone and tablet. Use cloud device farms for wider coverage and add devices that generate many crashes.
92

What is app signing and why must you protect the keys?

Save to ▾
Show answer
Signing proves the app comes from you and that updates are from the same developer. On Android, you sign uploads with an upload key and Play App Signing re-signs with the app signing key held by the store; a lost upload key can be reset, but losing a self-managed app key meant you could never update the app. On iOS, signing uses certificates and provisioning profiles. Store keys in a secure vault and CI secrets, never in the repository.
93

What are over-the-air updates and what are their limits?

Save to ▾
Show answer
Over-the-air updates push new JavaScript bundles and assets to React Native apps without a store release, using services like EAS Update. They fix bugs quickly but can only change JavaScript and assets, not native code, permissions or SDK versions, which need a new build. Store policies allow them only if the app's core purpose does not change. Use runtime versions to ensure updates match compatible native builds, and roll out gradually.
94

What are privacy declarations required by the app stores?

Save to ▾
Show answer
The Play Store requires a data safety form describing what data is collected, shared, encrypted and deletable, plus a privacy policy link and account deletion option for apps with accounts. The iOS App Store requires privacy nutrition labels, a privacy manifest file for the app and listed third-party SDKs describing data use and required reason APIs, and App Tracking Transparency permission before tracking users across apps.
95

How do you build a release version of a Flutter app for both stores?

Save to ▾
Show answer
flutter build appbundle --release --obfuscate --split-debug-info=build/symbols # Output: build/app/outputs/bundle/release/app-release.aab flutter build ipa --release --obfuscate --split-debug-info=build/symbols # Output: build/ios/ipa/*.ipa, upload with Transporter or xcrun altool # Version comes from pubspec.yaml, for example: # version: 2.3.1+45 (name 2.3.1, build number 45)
96

Write an EAS configuration for development, preview and production builds.

Save to ▾
Show answer
{ "cli": { "version": ">= 12.0.0" }, "build": { "development": { "developmentClient": true, "distribution": "internal" }, "preview": { "distribution": "internal", "channel": "preview" }, "production": { "autoIncrement": true, "channel": "production" } }, "submit": { "production": {} } }
97

What is App Store Optimisation and what can a developer influence?

Save to ▾
Show answer
App Store Optimisation improves an app's visibility and conversion in store search. Key factors are the app title, subtitle or short description, keywords, long description, screenshots, preview videos, ratings and reviews. Developers influence it by keeping app size small, crash rates low and performance high, since store algorithms consider quality signals, by adding in-app review prompts at good moments, and by supporting localisation for regional languages.
98

How do you force users to update when an old version has a critical bug?

Save to ▾
Show answer
Keep a minimum supported version in remote config or an API endpoint, check it at startup and show a blocking update screen linking to the store. On Android, use the Play In-App Updates API with the immediate flow for critical updates and flexible flow for normal ones. Keep the backend compatible with older versions for a defined period, and use forced updates sparingly because they frustrate users.
99

Your iOS app was rejected for guideline 5.1.1 about data collection. What do you do?

Save to ▾
Show answer
Read the reviewer's message in App Store Connect carefully. Guideline 5.1.1 issues often involve requesting permissions without clear purpose strings, requiring sign-up for features that do not need an account, or missing account deletion. Fix the specific problem, for example improving usage description text or adding in-app account deletion, and reply in Resolution Center explaining the changes. Ask for clarification if the rejection is unclear.
100

Store review is delaying your launch date. How do you plan releases to avoid this?

Save to ▾
Show answer
Submit builds early, a few days before the planned date, and use manual release so you can publish the approved build at launch time. Ship the code behind a remote feature flag so the feature can be enabled on launch day without a new review. Keep a pre-approved build ready, follow store guidelines closely and include clear review notes and demo login details for reviewers.
101

A user reports that they cannot find your app in the store on their old phone. Why could this happen?

Save to ▾
Show answer
The app may not be available for their device because the minimum OS version is higher than theirs, the device lacks a required hardware feature declared in the manifest, the app is not released in their country, or the device architecture is excluded. Check the device catalogue in Play Console and the deployment target on iOS. Decide whether supporting that segment is worth lowering requirements.
102

How do you communicate a delayed release to stakeholders?

Save to ▾
Show answer
I inform them as soon as I know, not on the release day. I explain the reason briefly, such as a store rejection or critical bug, the impact, the new estimated date, and what we are doing to avoid repeating it. I offer options, like releasing other features first. Regular short updates until release keep trust, and I note learnings in the release retrospective.
103

How do you handle account deletion requirements in mobile apps?

Save to ▾
Show answer
Both major stores require apps that let users create accounts to also let them delete their account from within the app, and the Play Store also requires a web link for deletion requests. Implement a clear settings option, confirm the action, call a backend endpoint that deletes or anonymises user data according to retention rules, revoke tokens, clear local data and sign the user out. Document what is retained for legal reasons.

Frequently asked questions

Who should practise medium Mobile App Development questions?

Anyone with some hands-on practice: most real interview time is spent on medium questions like these.

How should I practise these?

Answer each question aloud before opening the answer, mark it as solved only when your answer matches the key idea, and save misses to Last-Minute Revision.

Other difficulty levels