or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdnotification-permissions.mdpermission-checking.mdpermission-constants.mdpermission-requesting.mdplatform-specific-features.md

platform-specific-features.mddocs/

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

```