1. Courses
  2. Engineering Roles
  3. Mobile Apps with React Native
  4. Stop 4

35 minIntermediate

Device features

A phone's camera, its location and its notifications are what make a mobile app worth installing, and each one sits behind a permission the user can refuse. This lesson shows you how the Mangrove Rider app asks at the right moment, keeps working when the answer is no, captures a small proof photo and a drop location, and sends a "new job" push that riders want to receive.

By the end you can

  • Design a permission flow as a small state machine: explain, ask, use, or send the rider to Settings, always with a fallback
  • Take a proof-of-delivery photo with expo-camera and shrink it to a size that uploads on patchy mobile data
  • Record a drop location in the foreground with the right accuracy, and judge when background location is really needed
  • Explain how a push travels from your server through Expo, FCM and APNs to the phone, and register and refresh push tokens
  • Set up Android notification channels, ask for notification permission on Android 13+ and iOS, and open the right job when a rider taps

The everyday picture

Think of a rider arriving at a tall apartment building with a guard at the gate. A good rider does not shout "let me in" from the street before he even has a parcel. He walks up when he has a delivery, shows the order on his phone and says which flat it is for. The guard has a reason, so he usually says yes.

Sometimes the guard still says no. A good rider does not argue every day. He calls the customer, who comes down to the gate and reads out a code, and the delivery still happens. And if the building office has put the rider on a "do not admit" list, asking the guard again is pointless: only the office can change it.

Phone permissions work the same way. Ask when the feature is needed, with a reason the person can see. Have a way to finish the job without it. And when the operating system has stopped asking, the only door left is the phone's Settings app, which the user opens and changes themselves.

Permissions are a small state machine

Camera, location and notifications are . The app cannot draw the system dialog itself or change its wording, and it gets very few chances to show it. In Expo every permission call returns the same shape, a PermissionResponse with three fields that matter:

  • status: 'undetermined' (never asked), 'granted' or 'denied'.
  • canAskAgain: false when the operating system will no longer show its dialog. From then on, only the Settings app can change the answer.
  • granted: a shortcut for status === 'granted'.

The two platforms spend your chances differently. On iOS the system dialog appears once: a single "Don't Allow" sets canAskAgain to false. On Android, the Android docs say that if the user taps Deny more than once for the same permission, the system treats it as "don't ask again" and stops showing the dialog. Since Android 11, camera and location dialogs also offer Only this time, so a permission can be gone the next time the rider opens the app. That is why you check the status every time the feature starts, never once at launch.

Because the system dialog is precious, show your own explanation screen first. It costs nothing: it is a normal screen with a short reason and two buttons, Continue and Not now. Only Continue calls the system request. If the rider taps Not now, you have spent nothing and can ask next time. The flow becomes four outcomes:

  • use: permission granted, open the camera.
  • explain: not granted yet and the rider has not seen the reason in this flow, so show the explanation screen.
  • ask: the rider tapped Continue, so call the system request.
  • settings: canAskAgain is false, so show a button that opens the app's page in Settings with Linking.openSettings() from React Native.

Every branch except use also offers the . For proof of delivery that is the one-time code the customer reads out from the Mangrove app. Both stores ask for this: Apple's review guidelines tell apps to offer alternatives where possible when people refuse access, and Android's docs say to degrade gracefully so the user can carry on.

Quick check

The Rider app asks for camera permission on its very first screen, before the rider has seen a job. An iPhone rider taps "Don't Allow". What happens next week, when she taps "Take photo" at a door?

Not asked yet undetermined taps Take photo Explain first your own screen Continue System prompt OS dialog Allow Deny last deny Granted use camera Denied explain again Blocked OS won't ask for now Code fallback customer's OTP Settings link + fallback Not now
The respectful permission flow. Your own explanation screen comes before the one system dialog you get. Not now and Deny both lead to the code fallback, so the delivery still finishes, and the reason is shown again next time. Blocked means the operating system will not ask again (after one refusal on iOS, usually two on Android), so the app offers a Settings link and the same fallback.

Loading the rest of the lesson…