0
# Platform-Specific Features
1
2
iOS location accuracy control, Android alarm permissions, and other platform-specific functionality that extends beyond basic permission checking and requesting.
3
4
## Capabilities
5
6
### iOS Location Accuracy Control
7
8
iOS 14+ provides users with the option to grant apps reduced location accuracy. These methods help manage location accuracy permissions.
9
10
```typescript { .api }
11
/**
12
* Check the current location accuracy authorization level (iOS only)
13
* @returns Promise resolving to current location accuracy level
14
*/
15
function checkLocationAccuracy(): Promise<LocationAccuracy>;
16
17
/**
18
* Request location accuracy upgrade from reduced to full (iOS only)
19
* @param options - Configuration with purpose key from Info.plist
20
* @returns Promise resolving to the granted accuracy level
21
*/
22
function requestLocationAccuracy(options: LocationAccuracyOptions): Promise<LocationAccuracy>;
23
24
type LocationAccuracy = 'full' | 'reduced';
25
26
interface LocationAccuracyOptions {
27
purposeKey: string; // Must match a key in Info.plist NSLocationTemporaryUsageDescriptionDictionary
28
}
29
```
30
31
**Usage Examples:**
32
33
```typescript
34
import {
35
checkLocationAccuracy,
36
requestLocationAccuracy,
37
check,
38
request,
39
PERMISSIONS,
40
RESULTS
41
} from "react-native-permissions";
42
43
async function handleLocationAccuracy() {
44
// First ensure location permission is granted
45
let locationStatus = await check(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
46
47
if (locationStatus !== RESULTS.GRANTED) {
48
locationStatus = await request(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
49
}
50
51
if (locationStatus === RESULTS.GRANTED) {
52
// Check current accuracy level
53
const accuracy = await checkLocationAccuracy();
54
console.log("Current location accuracy:", accuracy);
55
56
if (accuracy === 'reduced') {
57
console.log("Location accuracy is reduced. Requesting full accuracy...");
58
59
// Request full accuracy using Info.plist purpose key
60
const newAccuracy = await requestLocationAccuracy({
61
purposeKey: 'FindNearbyRestaurants' // Must be defined in Info.plist
62
});
63
64
if (newAccuracy === 'full') {
65
console.log("Full location accuracy granted");
66
// Now can access precise location
67
} else {
68
console.log("User chose to keep reduced accuracy");
69
// Continue with approximate location
70
}
71
} else {
72
console.log("Already have full location accuracy");
73
}
74
}
75
}
76
77
// Example usage in a restaurant finder app
78
async function findNearbyRestaurants() {
79
const accuracy = await checkLocationAccuracy();
80
81
if (accuracy === 'reduced') {
82
// Explain why full accuracy is needed
83
const upgraded = await requestLocationAccuracy({
84
purposeKey: 'FindNearbyRestaurants'
85
});
86
87
if (upgraded === 'full') {
88
// Use precise location for accurate results
89
return searchRestaurantsWithPreciseLocation();
90
} else {
91
// Fall back to approximate location search
92
return searchRestaurantsWithApproximateLocation();
93
}
94
} else {
95
return searchRestaurantsWithPreciseLocation();
96
}
97
}
98
```
99
100
**Info.plist Configuration:**
101
102
For `requestLocationAccuracy` to work, you must define purpose keys in your iOS app's Info.plist:
103
104
```xml
105
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
106
<dict>
107
<key>FindNearbyRestaurants</key>
108
<string>Find the most relevant restaurants and delivery options near your exact location</string>
109
<key>NavigationAccuracy</key>
110
<string>Provide turn-by-turn navigation with precise location tracking</string>
111
</dict>
112
```
113
114
### iOS Photo Picker Access
115
116
Provides access to the iOS photo picker without requiring full photo library permission.
117
118
```typescript { .api }
119
/**
120
* Open the iOS photo picker without requiring photo library permission
121
* @returns Promise that resolves when picker is dismissed
122
*/
123
function openPhotoPicker(): Promise<void>;
124
```
125
126
**Usage Examples:**
127
128
```typescript
129
import { openPhotoPicker, check, PERMISSIONS, RESULTS } from "react-native-permissions";
130
131
async function selectPhotos() {
132
// iOS 14+ allows photo picker access without photo library permission
133
try {
134
await openPhotoPicker();
135
console.log("Photo picker was opened successfully");
136
// User can select photos through the picker
137
// Selected photos are available to your app without library permission
138
} catch (error) {
139
console.error("Failed to open photo picker:", error);
140
141
// Fallback: request full photo library permission
142
const photoLibraryStatus = await check(PERMISSIONS.IOS.PHOTO_LIBRARY);
143
if (photoLibraryStatus !== RESULTS.GRANTED) {
144
console.log("Photo picker failed, requesting photo library permission...");
145
// Handle full permission request
146
}
147
}
148
}
149
150
// Example in an image sharing app
151
async function addPhotosToPost() {
152
if (Platform.OS === 'ios') {
153
// Try photo picker first (no permission required)
154
try {
155
await openPhotoPicker();
156
return; // Success - user can select photos
157
} catch (error) {
158
console.log("Photo picker not available, requesting full library access");
159
}
160
}
161
162
// Android or iOS fallback - request full photo library permission
163
const status = await request(PERMISSIONS.IOS.PHOTO_LIBRARY);
164
if (status === RESULTS.GRANTED) {
165
// Access full photo library
166
openFullPhotoLibrary();
167
}
168
}
169
```
170
171
### Android Alarm Permissions
172
173
Android 12+ introduces restrictions on exact alarm scheduling. These methods help check alarm capabilities.
174
175
```typescript { .api }
176
/**
177
* Check if the app can schedule exact alarms (Android 12+)
178
* @returns Promise resolving to boolean indicating exact alarm capability
179
*/
180
function canScheduleExactAlarms(): Promise<boolean>;
181
182
/**
183
* Check if the app can use full screen intents (Android)
184
* @returns Promise resolving to boolean indicating full screen intent capability
185
*/
186
function canUseFullScreenIntent(): Promise<boolean>;
187
```
188
189
**Usage Examples:**
190
191
```typescript
192
import { canScheduleExactAlarms, canUseFullScreenIntent, openSettings } from "react-native-permissions";
193
194
async function setupAlarmFeatures() {
195
if (Platform.OS === 'android') {
196
// Check exact alarm capability
197
const canScheduleExact = await canScheduleExactAlarms();
198
console.log("Can schedule exact alarms:", canScheduleExact);
199
200
if (!canScheduleExact) {
201
console.log("Exact alarms not available - directing user to settings");
202
// Direct user to alarm settings
203
await openSettings('alarms');
204
}
205
206
// Check full screen intent capability
207
const canUseFullScreen = await canUseFullScreenIntent();
208
console.log("Can use full screen intents:", canUseFullScreen);
209
210
if (!canUseFullScreen) {
211
console.log("Full screen intents not available");
212
await openSettings('fullscreen');
213
}
214
}
215
}
216
217
// Example in an alarm clock app
218
async function scheduleAlarm(time: Date) {
219
if (Platform.OS === 'android') {
220
const canScheduleExact = await canScheduleExactAlarms();
221
222
if (canScheduleExact) {
223
// Schedule exact alarm
224
await scheduleExactAlarm(time);
225
console.log("Exact alarm scheduled");
226
} else {
227
// Show rationale and direct to settings
228
Alert.alert(
229
"Exact Alarms Required",
230
"To ensure your alarms ring on time, please enable 'Alarms & reminders' in settings.",
231
[
232
{ text: "Open Settings", onPress: () => openSettings('alarms') },
233
{ text: "Cancel", style: "cancel" }
234
]
235
);
236
}
237
}
238
}
239
240
// Example for urgent notifications
241
async function sendUrgentNotification() {
242
if (Platform.OS === 'android') {
243
const canUseFullScreen = await canUseFullScreenIntent();
244
245
if (canUseFullScreen) {
246
// Show full screen notification for urgent alerts
247
await showFullScreenNotification();
248
} else {
249
// Fall back to regular notification
250
await showRegularNotification();
251
}
252
}
253
}
254
```
255
256
### Settings Access
257
258
Direct users to specific system settings for permission management.
259
260
```typescript { .api }
261
/**
262
* Open device settings for permission management
263
* @param type - Specific settings type to open (optional)
264
* @returns Promise that resolves when settings are opened
265
*/
266
function openSettings(type?: 'application' | 'alarms' | 'fullscreen' | 'notifications'): Promise<void>;
267
```
268
269
**Usage Examples:**
270
271
```typescript
272
import { openSettings, check, PERMISSIONS, RESULTS } from "react-native-permissions";
273
274
// Open general app settings
275
async function openAppSettings() {
276
await openSettings('application');
277
console.log("Opened app settings");
278
}
279
280
// Open specific settings based on permission state
281
async function handleBlockedPermission(permission: Permission) {
282
const status = await check(permission);
283
284
if (status === RESULTS.BLOCKED) {
285
if (permission === PERMISSIONS.ANDROID.POST_NOTIFICATIONS) {
286
await openSettings('notifications');
287
} else {
288
await openSettings('application');
289
}
290
}
291
}
292
293
// Handle blocked notification permissions (iOS uses checkNotifications/requestNotifications)
294
async function handleBlockedNotifications() {
295
const notificationResult = await checkNotifications();
296
297
if (notificationResult.status === RESULTS.BLOCKED) {
298
await openSettings('notifications');
299
}
300
}
301
302
// Platform-specific settings access
303
async function openPlatformSpecificSettings() {
304
if (Platform.OS === 'android') {
305
// Android-specific settings
306
await openSettings('alarms'); // Alarm & reminders settings
307
await openSettings('fullscreen'); // Full screen intent settings
308
}
309
310
// Common settings
311
await openSettings('notifications'); // Notification settings
312
await openSettings('application'); // General app settings
313
}
314
315
// Example usage in permission flow
316
async function requestPermissionWithFallback(permission: Permission) {
317
let status = await check(permission);
318
319
if (status === RESULTS.DENIED) {
320
status = await request(permission);
321
}
322
323
if (status === RESULTS.BLOCKED) {
324
Alert.alert(
325
"Permission Required",
326
"This permission has been blocked. Please enable it in Settings to continue.",
327
[
328
{
329
text: "Open Settings",
330
onPress: async () => {
331
if (permission.includes('NOTIFICATION')) {
332
await openSettings('notifications');
333
} else {
334
await openSettings('application');
335
}
336
}
337
},
338
{ text: "Cancel", style: "cancel" }
339
]
340
);
341
}
342
343
return status === RESULTS.GRANTED;
344
}
345
```
346
347
## Platform-Specific Implementation Details
348
349
### iOS Implementation Notes
350
351
```typescript
352
// iOS-specific features are only available on iOS
353
import { Platform } from 'react-native';
354
355
if (Platform.OS === 'ios') {
356
// Safe to use iOS-specific methods
357
const accuracy = await checkLocationAccuracy();
358
await openPhotoPicker();
359
await requestLocationAccuracy({ purposeKey: 'MyPurpose' });
360
}
361
362
// iOS location accuracy requires iOS 14+
363
if (Platform.OS === 'ios' && parseInt(Platform.Version, 10) >= 14) {
364
const accuracy = await checkLocationAccuracy();
365
}
366
```
367
368
### Android Implementation Notes
369
370
```typescript
371
// Android-specific features require specific Android versions
372
import { Platform } from 'react-native';
373
374
if (Platform.OS === 'android') {
375
// Exact alarms introduced in Android 12 (API level 31)
376
if (Platform.Version >= 31) {
377
const canSchedule = await canScheduleExactAlarms();
378
}
379
380
// Full screen intents
381
const canUseFullScreen = await canUseFullScreenIntent();
382
}
383
```
384
385
## Error Handling for Platform-Specific Features
386
387
```typescript
388
import { Platform } from 'react-native';
389
390
async function safePlatformSpecificCall<T>(
391
androidFn?: () => Promise<T>,
392
iosFn?: () => Promise<T>
393
): Promise<T | null> {
394
try {
395
if (Platform.OS === 'android' && androidFn) {
396
return await androidFn();
397
} else if (Platform.OS === 'ios' && iosFn) {
398
return await iosFn();
399
}
400
return null;
401
} catch (error) {
402
console.error("Platform-specific method failed:", error);
403
return null;
404
}
405
}
406
407
// Usage
408
const accuracy = await safePlatformSpecificCall(
409
undefined, // No Android equivalent
410
() => checkLocationAccuracy()
411
);
412
413
const canSchedule = await safePlatformSpecificCall(
414
() => canScheduleExactAlarms(),
415
undefined // No iOS equivalent
416
);
417
```
418
419
## Common Integration Patterns
420
421
### Feature Detection Pattern
422
423
```typescript
424
import { Platform } from 'react-native';
425
426
interface PlatformCapabilities {
427
hasLocationAccuracy: boolean;
428
hasPhotoPicker: boolean;
429
hasExactAlarms: boolean;
430
hasFullScreenIntents: boolean;
431
}
432
433
function detectPlatformCapabilities(): PlatformCapabilities {
434
return {
435
hasLocationAccuracy: Platform.OS === 'ios' && parseInt(Platform.Version, 10) >= 14,
436
hasPhotoPicker: Platform.OS === 'ios' && parseInt(Platform.Version, 10) >= 14,
437
hasExactAlarms: Platform.OS === 'android' && Platform.Version >= 31,
438
hasFullScreenIntents: Platform.OS === 'android'
439
};
440
}
441
442
// Adapt UI based on capabilities
443
const capabilities = detectPlatformCapabilities();
444
if (capabilities.hasLocationAccuracy) {
445
// Show location accuracy toggle in settings
446
}
447
```
448
449
### Progressive Enhancement Pattern
450
451
```typescript
452
async function enhancedLocationRequest() {
453
// Basic location permission
454
const locationStatus = await request(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
455
456
if (locationStatus === RESULTS.GRANTED && Platform.OS === 'ios') {
457
// Enhanced: Request full accuracy if available
458
try {
459
const accuracy = await checkLocationAccuracy();
460
if (accuracy === 'reduced') {
461
await requestLocationAccuracy({ purposeKey: 'PreciseLocation' });
462
}
463
} catch (error) {
464
console.log("Location accuracy enhancement not available");
465
}
466
}
467
468
return locationStatus;
469
}
470
```