or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

error-handling.mdevent-management.mdindex.mdnative-modules.mdnative-views.mdpermissions.mdplatform-utilities.mdutilities.md

permissions.mddocs/

0

# Permission Management

1

2

Complete permission system with React hooks for managing app permissions, providing standardized interfaces for requesting and checking permission status across platforms.

3

4

## Capabilities

5

6

### PermissionStatus Enum

7

8

Standard permission status values used across all permission types.

9

10

```typescript { .api }

11

/**

12

* Standard permission status values

13

*/

14

enum PermissionStatus {

15

GRANTED = 'granted',

16

UNDETERMINED = 'undetermined',

17

DENIED = 'denied'

18

}

19

```

20

21

### PermissionResponse Interface

22

23

Standard response format for all permission operations.

24

25

```typescript { .api }

26

/**

27

* Standard permission response interface

28

*/

29

interface PermissionResponse {

30

/**

31

* Current permission status

32

*/

33

status: PermissionStatus;

34

35

/**

36

* When the permission expires ('never' for permanent permissions)

37

*/

38

expires: PermissionExpiration;

39

40

/**

41

* Whether permission is currently granted (convenience property)

42

*/

43

granted: boolean;

44

45

/**

46

* Whether the system will show permission dialog if requested

47

*/

48

canAskAgain: boolean;

49

}

50

51

type PermissionExpiration = 'never' | number;

52

```

53

54

**Usage Examples:**

55

56

```typescript

57

import { PermissionResponse, PermissionStatus } from "@unimodules/core";

58

59

// Check permission response

60

function handlePermissionResponse(response: PermissionResponse) {

61

console.log('Status:', response.status);

62

console.log('Granted:', response.granted);

63

console.log('Can ask again:', response.canAskAgain);

64

65

switch (response.status) {

66

case PermissionStatus.GRANTED:

67

console.log('Permission granted');

68

break;

69

case PermissionStatus.DENIED:

70

if (response.canAskAgain) {

71

console.log('Permission denied, but can ask again');

72

} else {

73

console.log('Permission permanently denied');

74

}

75

break;

76

case PermissionStatus.UNDETERMINED:

77

console.log('Permission not yet requested');

78

break;

79

}

80

}

81

```

82

83

### createPermissionHook Function

84

85

Factory function for creating permission-specific React hooks with built-in state management.

86

87

```typescript { .api }

88

/**

89

* Create a permission hook with built-in methods

90

*/

91

function createPermissionHook<Permission extends PermissionResponse, Options extends object>(

92

methods: PermissionHookMethods<Permission, Options>

93

): (options?: PermissionHookOptions<Options>) => [

94

Permission | null, // Current permission status

95

() => Promise<Permission>, // Request permission function

96

() => Promise<Permission> // Get permission function

97

];

98

99

/**

100

* Methods required for permission hook

101

*/

102

interface PermissionHookMethods<Permission extends PermissionResponse, Options = never> {

103

/**

104

* Request permission from user

105

*/

106

requestMethod: (options?: Options) => Promise<Permission>;

107

108

/**

109

* Get current permission status without requesting

110

*/

111

getMethod: (options?: Options) => Promise<Permission>;

112

}

113

114

/**

115

* Options for permission hook behavior

116

*/

117

interface PermissionHookBehavior {

118

/**

119

* Automatically fetch permission status on mount

120

*/

121

get?: boolean;

122

123

/**

124

* Automatically request permission on mount

125

*/

126

request?: boolean;

127

}

128

129

type PermissionHookOptions<Options extends object> = PermissionHookBehavior & Options;

130

```

131

132

**Usage Examples:**

133

134

```typescript

135

import { createPermissionHook, PermissionResponse } from "@unimodules/core";

136

137

// Define custom permission interface

138

interface CameraPermission extends PermissionResponse {

139

accessPrivileges?: 'full' | 'limited';

140

}

141

142

// Create camera permission hook

143

const useCameraPermission = createPermissionHook<CameraPermission, {}>({

144

requestMethod: async () => {

145

const result = await NativeModulesProxy.Camera.requestPermissionsAsync();

146

return result;

147

},

148

getMethod: async () => {

149

const result = await NativeModulesProxy.Camera.getPermissionsAsync();

150

return result;

151

}

152

});

153

154

// Use in React component

155

function CameraComponent() {

156

// Hook returns [status, requestFn, getFn]

157

const [cameraPermission, requestCameraPermission, getCameraPermission] = useCameraPermission({

158

get: true, // Automatically get status on mount

159

request: false // Don't auto-request

160

});

161

162

const handleRequestPermission = async () => {

163

try {

164

const result = await requestCameraPermission();

165

if (result.granted) {

166

console.log('Camera permission granted');

167

} else {

168

console.log('Camera permission denied');

169

}

170

} catch (error) {

171

console.error('Failed to request permission:', error);

172

}

173

};

174

175

if (!cameraPermission) {

176

return <Text>Loading permission status...</Text>;

177

}

178

179

if (!cameraPermission.granted) {

180

return (

181

<View>

182

<Text>Camera permission required</Text>

183

<Button title="Grant Permission" onPress={handleRequestPermission} />

184

</View>

185

);

186

}

187

188

return <CameraView />;

189

}

190

```

191

192

### Advanced Permission Hooks

193

194

Create permission hooks with options and complex behaviors.

195

196

**Usage Examples:**

197

198

```typescript

199

import { createPermissionHook, PermissionResponse } from "@unimodules/core";

200

201

// Location permission with options

202

interface LocationPermission extends PermissionResponse {

203

accuracy?: 'fine' | 'coarse';

204

}

205

206

interface LocationOptions {

207

accuracy?: 'fine' | 'coarse';

208

background?: boolean;

209

}

210

211

const useLocationPermission = createPermissionHook<LocationPermission, LocationOptions>({

212

requestMethod: async (options) => {

213

return await NativeModulesProxy.Location.requestPermissionsAsync(options);

214

},

215

getMethod: async (options) => {

216

return await NativeModulesProxy.Location.getPermissionsAsync(options);

217

}

218

});

219

220

// Usage with options

221

function LocationComponent() {

222

const [locationPermission, requestLocation] = useLocationPermission({

223

get: true,

224

accuracy: 'fine',

225

background: false

226

});

227

228

const requestBackgroundLocation = async () => {

229

await requestLocation({ accuracy: 'fine', background: true });

230

};

231

232

return (

233

<View>

234

<Text>Location: {locationPermission?.status}</Text>

235

<Button title="Request Background" onPress={requestBackgroundLocation} />

236

</View>

237

);

238

}

239

```

240

241

### Multiple Permission Management

242

243

Handle multiple permissions in a single component.

244

245

**Usage Examples:**

246

247

```typescript

248

import { createPermissionHook } from "@unimodules/core";

249

250

// Create multiple permission hooks

251

const useCameraPermission = createPermissionHook(/* camera methods */);

252

const useMicrophonePermission = createPermissionHook(/* microphone methods */);

253

const useLocationPermission = createPermissionHook(/* location methods */);

254

255

function MultiPermissionComponent() {

256

const [cameraPermission, requestCamera] = useCameraPermission({ get: true });

257

const [micPermission, requestMic] = useMicrophonePermission({ get: true });

258

const [locationPermission, requestLocation] = useLocationPermission({ get: true });

259

260

const requestAllPermissions = async () => {

261

const results = await Promise.allSettled([

262

requestCamera(),

263

requestMic(),

264

requestLocation()

265

]);

266

267

results.forEach((result, index) => {

268

const permissionName = ['Camera', 'Microphone', 'Location'][index];

269

if (result.status === 'fulfilled' && result.value.granted) {

270

console.log(`${permissionName} permission granted`);

271

} else {

272

console.log(`${permissionName} permission failed`);

273

}

274

});

275

};

276

277

const allPermissionsGranted =

278

cameraPermission?.granted &&

279

micPermission?.granted &&

280

locationPermission?.granted;

281

282

return (

283

<View>

284

<Text>Camera: {cameraPermission?.status}</Text>

285

<Text>Microphone: {micPermission?.status}</Text>

286

<Text>Location: {locationPermission?.status}</Text>

287

288

{!allPermissionsGranted && (

289

<Button title="Request All Permissions" onPress={requestAllPermissions} />

290

)}

291

</View>

292

);

293

}

294

```

295

296

## Advanced Usage

297

298

### Permission State Management

299

300

```typescript

301

import { createPermissionHook, PermissionResponse, PermissionStatus } from "@unimodules/core";

302

303

class PermissionManager {

304

private static permissionCache = new Map<string, PermissionResponse>();

305

306

static async checkPermission(key: string, getMethod: () => Promise<PermissionResponse>) {

307

const cached = this.permissionCache.get(key);

308

if (cached && Date.now() - cached.expires < 5 * 60 * 1000) { // 5 minute cache

309

return cached;

310

}

311

312

const permission = await getMethod();

313

this.permissionCache.set(key, permission);

314

return permission;

315

}

316

317

static async requestWithRationale(

318

requestMethod: () => Promise<PermissionResponse>,

319

rationale: string

320

): Promise<PermissionResponse> {

321

// Show rationale before requesting

322

const shouldRequest = await showPermissionRationale(rationale);

323

if (!shouldRequest) {

324

return {

325

status: PermissionStatus.DENIED,

326

expires: 'never',

327

granted: false,

328

canAskAgain: true

329

};

330

}

331

332

return await requestMethod();

333

}

334

}

335

336

// Declare this function elsewhere

337

declare function showPermissionRationale(message: string): Promise<boolean>;

338

```

339

340

### Custom Permission Types

341

342

```typescript

343

import { PermissionResponse, PermissionStatus, createPermissionHook } from "@unimodules/core";

344

345

// Custom permission for app-specific features

346

interface NotificationPermission extends PermissionResponse {

347

allowsAlert?: boolean;

348

allowsBadge?: boolean;

349

allowsSound?: boolean;

350

allowsCriticalAlerts?: boolean;

351

}

352

353

interface MediaLibraryPermission extends PermissionResponse {

354

accessPrivileges?: 'all' | 'limited' | 'none';

355

selectedAssets?: string[];

356

}

357

358

// Create hooks for custom permissions

359

const useNotificationPermission = createPermissionHook<NotificationPermission, {}>({

360

requestMethod: async () => {

361

const result = await NativeModulesProxy.Notifications.requestPermissionsAsync();

362

return result;

363

},

364

getMethod: async () => {

365

return await NativeModulesProxy.Notifications.getPermissionsAsync();

366

}

367

});

368

369

const useMediaLibraryPermission = createPermissionHook<MediaLibraryPermission, {}>({

370

requestMethod: async () => {

371

return await NativeModulesProxy.MediaLibrary.requestPermissionsAsync();

372

},

373

getMethod: async () => {

374

return await NativeModulesProxy.MediaLibrary.getPermissionsAsync();

375

}

376

});

377

```

378

379

### Permission Flow Patterns

380

381

```typescript

382

import { PermissionStatus } from "@unimodules/core";

383

384

class PermissionFlow {

385

static async requestWithFallback<T extends PermissionResponse>(

386

requestMethod: () => Promise<T>,

387

fallbackAction: () => void

388

): Promise<T | null> {

389

const result = await requestMethod();

390

391

if (result.status === PermissionStatus.DENIED && !result.canAskAgain) {

392

// Permission permanently denied, show settings prompt

393

const shouldOpenSettings = await showSettingsPrompt();

394

if (shouldOpenSettings) {

395

await openAppSettings();

396

} else {

397

fallbackAction();

398

}

399

return null;

400

}

401

402

return result;

403

}

404

405

static async ensurePermission<T extends PermissionResponse>(

406

getMethod: () => Promise<T>,

407

requestMethod: () => Promise<T>

408

): Promise<T> {

409

let permission = await getMethod();

410

411

if (permission.status === PermissionStatus.UNDETERMINED) {

412

permission = await requestMethod();

413

}

414

415

return permission;

416

}

417

}

418

419

// Declare these functions elsewhere

420

declare function showSettingsPrompt(): Promise<boolean>;

421

declare function openAppSettings(): Promise<void>;

422

```

423

424

## Types

425

426

```typescript { .api }

427

type RequestPermissionMethod<Permission extends PermissionResponse> = () => Promise<Permission>;

428

type GetPermissionMethod<Permission extends PermissionResponse> = () => Promise<Permission>;

429

430

interface PermissionHook<Permission extends PermissionResponse> {

431

(options?: PermissionHookOptions<any>): [

432

Permission | null,

433

RequestPermissionMethod<Permission>,

434

GetPermissionMethod<Permission>

435

];

436

}

437

438

type PermissionHookReturnType<Permission extends PermissionResponse> = [

439

Permission | null,

440

RequestPermissionMethod<Permission>,

441

GetPermissionMethod<Permission>

442

];

443

```