;
16 | checkMultiple(
17 | permissions: P,
18 | ): Promise>;
19 | checkNotifications(): Promise;
20 | openPhotoPicker(): Promise;
21 | openSettings(type?: 'application' | 'alarms' | 'fullscreen' | 'notifications'): Promise;
22 | request(permission: Permission, rationale?: Rationale): Promise;
23 | requestLocationAccuracy(options: LocationAccuracyOptions): Promise;
24 | requestMultiple(
25 | permissions: P,
26 | ): Promise>;
27 | requestNotifications(
28 | options?: NotificationOption[],
29 | rationale?: Rationale,
30 | ): Promise;
31 | };
32 |
--------------------------------------------------------------------------------
/src/expo.ts:
--------------------------------------------------------------------------------
1 | import {type ConfigPlugin, createRunOncePlugin, withDangerousMod} from '@expo/config-plugins';
2 | import {mergeContents} from '@expo/config-plugins/build/utils/generateCode';
3 | import * as fs from 'fs/promises';
4 | import * as path from 'path';
5 |
6 | type Props = {
7 | iosPermissions?: (
8 | | 'AppTrackingTransparency'
9 | | 'Bluetooth'
10 | | 'Calendars'
11 | | 'CalendarsWriteOnly'
12 | | 'Camera'
13 | | 'Contacts'
14 | | 'FaceID'
15 | | 'LocationAccuracy'
16 | | 'LocationAlways'
17 | | 'LocationWhenInUse'
18 | | 'MediaLibrary'
19 | | 'Microphone'
20 | | 'Motion'
21 | | 'Notifications'
22 | | 'PhotoLibrary'
23 | | 'PhotoLibraryAddOnly'
24 | | 'Reminders'
25 | | 'Siri'
26 | | 'SpeechRecognition'
27 | | 'StoreKit'
28 | )[];
29 | };
30 |
31 | const withPermissions: ConfigPlugin = (config, {iosPermissions = []}) =>
32 | withDangerousMod(config, [
33 | 'ios',
34 | async (config) => {
35 | const file = path.join(config.modRequest.platformProjectRoot, 'Podfile');
36 | const contents = await fs.readFile(file, 'utf8');
37 |
38 | if (iosPermissions.length === 0) {
39 | return config;
40 | }
41 |
42 | const withRequire = mergeContents({
43 | tag: 'require',
44 | src: contents,
45 | anchor:
46 | /^require File\.join\(File\.dirname\(`node --print "require\.resolve\('react-native\/package\.json'\)"`\), "scripts\/react_native_pods"\)$/m,
47 | newSrc: `require File.join(File.dirname(\`node --print "require.resolve('react-native-permissions/package.json')"\`), "scripts/setup")`,
48 | offset: 1,
49 | comment: '#',
50 | });
51 |
52 | const withSetup = mergeContents({
53 | tag: 'setup',
54 | src: withRequire.contents,
55 | anchor: /^prepare_react_native_project!$/m,
56 | newSrc: `setup_permissions([
57 | ${iosPermissions.map((permission) => ` '${permission}',`).join('\n')}
58 | ])`,
59 | offset: 1,
60 | comment: '#',
61 | });
62 |
63 | await fs.writeFile(file, withSetup.contents, 'utf-8');
64 | return config;
65 | },
66 | ]);
67 |
68 | export default createRunOncePlugin(withPermissions, 'react-native-permissions');
69 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import {methods} from './methods';
2 | import {PERMISSIONS} from './permissions';
3 | import {RESULTS} from './results';
4 |
5 | export {PERMISSIONS} from './permissions';
6 | export {RESULTS} from './results';
7 |
8 | export * from './types';
9 |
10 | export const canScheduleExactAlarms = methods.canScheduleExactAlarms;
11 | export const canUseFullScreenIntent = methods.canUseFullScreenIntent;
12 | export const check = methods.check;
13 | export const checkLocationAccuracy = methods.checkLocationAccuracy;
14 | export const checkMultiple = methods.checkMultiple;
15 | export const checkNotifications = methods.checkNotifications;
16 | export const openPhotoPicker = methods.openPhotoPicker;
17 | export const openSettings = methods.openSettings;
18 | export const request = methods.request;
19 | export const requestLocationAccuracy = methods.requestLocationAccuracy;
20 | export const requestMultiple = methods.requestMultiple;
21 | export const requestNotifications = methods.requestNotifications;
22 |
23 | export default {
24 | PERMISSIONS,
25 | RESULTS,
26 |
27 | canScheduleExactAlarms,
28 | canUseFullScreenIntent,
29 | check,
30 | checkLocationAccuracy,
31 | checkMultiple,
32 | checkNotifications,
33 | openPhotoPicker,
34 | openSettings,
35 | request,
36 | requestLocationAccuracy,
37 | requestMultiple,
38 | requestNotifications,
39 | };
40 |
--------------------------------------------------------------------------------
/src/methods.android.ts:
--------------------------------------------------------------------------------
1 | import {Alert, Platform} from 'react-native';
2 | import NativeModule from './NativeRNPermissions';
3 | import type {Contract} from './contract';
4 | import type {NotificationsResponse, Permission, PermissionStatus, Rationale} from './types';
5 | import {
6 | checkLocationAccuracy,
7 | openPhotoPicker,
8 | requestLocationAccuracy,
9 | } from './unsupportedMethods';
10 | import {uniq} from './utils';
11 |
12 | const POST_NOTIFICATIONS = 'android.permission.POST_NOTIFICATIONS' as Permission;
13 | const USES_LEGACY_NOTIFICATIONS = (Platform.OS === 'android' ? Platform.Version : 0) < 33;
14 |
15 | const shouldRequestPermission = async (
16 | permission: Permission,
17 | rationale: Rationale | undefined,
18 | ): Promise => {
19 | if (rationale == null || !(await NativeModule.shouldShowRequestRationale(permission))) {
20 | return true;
21 | }
22 |
23 | if (typeof rationale === 'function') {
24 | return rationale();
25 | }
26 |
27 | return new Promise((resolve) => {
28 | const {buttonNegative} = rationale;
29 |
30 | Alert.alert(
31 | rationale.title,
32 | rationale.message,
33 | [
34 | ...(buttonNegative ? [{text: buttonNegative, onPress: () => resolve(false)}] : []),
35 | {text: rationale.buttonPositive, onPress: () => resolve(true)},
36 | ],
37 | {cancelable: false},
38 | );
39 | });
40 | };
41 |
42 | const openSettings: Contract['openSettings'] = async (type = 'application') => {
43 | await NativeModule.openSettings(type);
44 | };
45 |
46 | const canScheduleExactAlarms: Contract['canScheduleExactAlarms'] = () =>
47 | NativeModule.canScheduleExactAlarms();
48 |
49 | const canUseFullScreenIntent: Contract['canUseFullScreenIntent'] = () =>
50 | NativeModule.canUseFullScreenIntent();
51 |
52 | const check: Contract['check'] = async (permission) => {
53 | const status = (await NativeModule.check(permission)) as PermissionStatus;
54 | return status;
55 | };
56 |
57 | const request: Contract['request'] = async (permission, rationale) => {
58 | const fn = (await shouldRequestPermission(permission, rationale))
59 | ? NativeModule.request
60 | : NativeModule.check;
61 |
62 | const status = (await fn(permission)) as PermissionStatus;
63 | return status;
64 | };
65 |
66 | const checkNotifications: Contract['checkNotifications'] = async () => {
67 | if (USES_LEGACY_NOTIFICATIONS) {
68 | const response = (await NativeModule.checkNotifications()) as NotificationsResponse;
69 | return response;
70 | } else {
71 | const status = await check(POST_NOTIFICATIONS);
72 | return {status, settings: {}};
73 | }
74 | };
75 |
76 | const requestNotifications: Contract['requestNotifications'] = async (options = [], rationale) => {
77 | if (USES_LEGACY_NOTIFICATIONS) {
78 | const response = (await NativeModule.requestNotifications(options)) as NotificationsResponse;
79 | return response;
80 | } else {
81 | const status = await request(POST_NOTIFICATIONS, rationale);
82 | return {status, settings: {}};
83 | }
84 | };
85 |
86 | const checkMultiple: Contract['checkMultiple'] = (permissions) => {
87 | return NativeModule.checkMultiple(uniq(permissions)) as ReturnType;
88 | };
89 |
90 | const requestMultiple: Contract['requestMultiple'] = (permissions) => {
91 | return NativeModule.requestMultiple(uniq(permissions)) as ReturnType;
92 | };
93 |
94 | export const methods: Contract = {
95 | canScheduleExactAlarms,
96 | canUseFullScreenIntent,
97 | check,
98 | checkLocationAccuracy,
99 | checkMultiple,
100 | checkNotifications,
101 | openPhotoPicker,
102 | openSettings,
103 | request,
104 | requestLocationAccuracy,
105 | requestMultiple,
106 | requestNotifications,
107 | };
108 |
--------------------------------------------------------------------------------
/src/methods.ios.ts:
--------------------------------------------------------------------------------
1 | import type {Contract} from './contract';
2 | import NativeModule from './NativeRNPermissions';
3 | import type {LocationAccuracy, NotificationsResponse, PermissionStatus} from './types';
4 | import {canScheduleExactAlarms, canUseFullScreenIntent} from './unsupportedMethods';
5 | import {uniq} from './utils';
6 |
7 | const openPhotoPicker: Contract['openPhotoPicker'] = async () => {
8 | await NativeModule.openPhotoPicker();
9 | };
10 |
11 | const openSettings: Contract['openSettings'] = async (type = 'application') => {
12 | await NativeModule.openSettings(type);
13 | };
14 |
15 | const check: Contract['check'] = async (permission) => {
16 | const status = (await NativeModule.check(permission)) as PermissionStatus;
17 | return status;
18 | };
19 |
20 | const request: Contract['request'] = async (permission) => {
21 | const status = (await NativeModule.request(permission)) as PermissionStatus;
22 | return status;
23 | };
24 |
25 | const checkLocationAccuracy: Contract['checkLocationAccuracy'] = async () => {
26 | const accuracy = (await NativeModule.checkLocationAccuracy()) as LocationAccuracy;
27 | return accuracy;
28 | };
29 |
30 | const requestLocationAccuracy: Contract['requestLocationAccuracy'] = async ({purposeKey}) => {
31 | const accuracy = (await NativeModule.requestLocationAccuracy(purposeKey)) as LocationAccuracy;
32 | return accuracy;
33 | };
34 |
35 | const checkNotifications: Contract['checkNotifications'] = async () => {
36 | const response = (await NativeModule.checkNotifications()) as NotificationsResponse;
37 | return response;
38 | };
39 |
40 | const requestNotifications: Contract['requestNotifications'] = async (
41 | options = ['alert', 'badge', 'sound'],
42 | ) => {
43 | const response = (await NativeModule.requestNotifications(options)) as NotificationsResponse;
44 | return response;
45 | };
46 |
47 | const checkMultiple: Contract['checkMultiple'] = async (permissions) => {
48 | const output: Record = {};
49 |
50 | for (const permission of uniq(permissions)) {
51 | output[permission] = await check(permission);
52 | }
53 |
54 | return output as Awaited>;
55 | };
56 |
57 | const requestMultiple: Contract['requestMultiple'] = async (permissions) => {
58 | const output: Record = {};
59 |
60 | for (const permission of uniq(permissions)) {
61 | output[permission] = await request(permission);
62 | }
63 |
64 | return output as Awaited>;
65 | };
66 |
67 | export const methods: Contract = {
68 | canScheduleExactAlarms,
69 | canUseFullScreenIntent,
70 | check,
71 | checkLocationAccuracy,
72 | checkMultiple,
73 | checkNotifications,
74 | openPhotoPicker,
75 | openSettings,
76 | request,
77 | requestLocationAccuracy,
78 | requestMultiple,
79 | requestNotifications,
80 | };
81 |
--------------------------------------------------------------------------------
/src/methods.ts:
--------------------------------------------------------------------------------
1 | import type {Contract} from './contract';
2 | import {RESULTS} from './results';
3 | import type {PermissionStatus} from './types';
4 | import {
5 | checkLocationAccuracy,
6 | openPhotoPicker,
7 | requestLocationAccuracy,
8 | } from './unsupportedMethods';
9 |
10 | const check: Contract['check'] = async () => {
11 | return RESULTS.UNAVAILABLE;
12 | };
13 |
14 | const checkNotifications: Contract['checkNotifications'] = async () => {
15 | return {status: RESULTS.UNAVAILABLE, settings: {}};
16 | };
17 |
18 | const checkMultiple: Contract['checkMultiple'] = async (permissions) => {
19 | const output: Record = {};
20 |
21 | for (const permission of permissions) {
22 | output[permission] = RESULTS.UNAVAILABLE;
23 | }
24 |
25 | return output as Awaited>;
26 | };
27 |
28 | export const methods: Contract = {
29 | canScheduleExactAlarms: Promise.reject,
30 | canUseFullScreenIntent: Promise.reject,
31 | check,
32 | checkLocationAccuracy,
33 | checkMultiple,
34 | checkNotifications,
35 | openPhotoPicker,
36 | openSettings: Promise.reject,
37 | request: check,
38 | requestLocationAccuracy,
39 | requestMultiple: checkMultiple,
40 | requestNotifications: checkNotifications,
41 | };
42 |
--------------------------------------------------------------------------------
/src/methods.windows.ts:
--------------------------------------------------------------------------------
1 | import NativeModule from './NativeRNPermissions';
2 | import type {Contract} from './contract';
3 | import type {NotificationsResponse, PermissionStatus} from './types';
4 | import {
5 | canScheduleExactAlarms,
6 | canUseFullScreenIntent,
7 | checkLocationAccuracy,
8 | openPhotoPicker,
9 | requestLocationAccuracy,
10 | } from './unsupportedMethods';
11 | import {uniq} from './utils';
12 |
13 | const openSettings: Contract['openSettings'] = async () => {
14 | await NativeModule.openSettings('N/A');
15 | };
16 |
17 | const check: Contract['check'] = async (permission) => {
18 | const response = (await NativeModule.check(permission)) as PermissionStatus;
19 | return response;
20 | };
21 |
22 | const request: Contract['request'] = async (permission) => {
23 | const response = (await NativeModule.request(permission)) as PermissionStatus;
24 | return response;
25 | };
26 |
27 | const checkNotifications: Contract['checkNotifications'] = async () => {
28 | const response = (await NativeModule.checkNotifications()) as NotificationsResponse;
29 | return response;
30 | };
31 |
32 | const checkMultiple: Contract['checkMultiple'] = async (permissions) => {
33 | const output: Record = {};
34 |
35 | for (const permission of uniq(permissions)) {
36 | output[permission] = await check(permission);
37 | }
38 |
39 | return output as Awaited>;
40 | };
41 |
42 | const requestMultiple: Contract['requestMultiple'] = async (permissions) => {
43 | const output: Record = {};
44 |
45 | for (const permission of uniq(permissions)) {
46 | output[permission] = await request(permission);
47 | }
48 |
49 | return output as Awaited>;
50 | };
51 |
52 | export const methods: Contract = {
53 | canScheduleExactAlarms,
54 | canUseFullScreenIntent,
55 | check,
56 | checkLocationAccuracy,
57 | checkMultiple,
58 | checkNotifications,
59 | openPhotoPicker,
60 | openSettings,
61 | request,
62 | requestLocationAccuracy,
63 | requestMultiple,
64 | requestNotifications: checkNotifications,
65 | };
66 |
--------------------------------------------------------------------------------
/src/permissions.android.ts:
--------------------------------------------------------------------------------
1 | import type {IOSPermissionMap} from './permissions.ios';
2 | import type {WindowsPermissionMap} from './permissions.windows';
3 | import {proxifyPermissions} from './utils';
4 |
5 | const ANDROID = Object.freeze({
6 | ACCEPT_HANDOVER: 'android.permission.ACCEPT_HANDOVER',
7 | ACCESS_BACKGROUND_LOCATION: 'android.permission.ACCESS_BACKGROUND_LOCATION',
8 | ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION',
9 | ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION',
10 | ACCESS_MEDIA_LOCATION: 'android.permission.ACCESS_MEDIA_LOCATION',
11 | ACTIVITY_RECOGNITION: 'android.permission.ACTIVITY_RECOGNITION',
12 | ADD_VOICEMAIL: 'com.android.voicemail.permission.ADD_VOICEMAIL',
13 | ANSWER_PHONE_CALLS: 'android.permission.ANSWER_PHONE_CALLS',
14 | BLUETOOTH_ADVERTISE: 'android.permission.BLUETOOTH_ADVERTISE',
15 | BLUETOOTH_CONNECT: 'android.permission.BLUETOOTH_CONNECT',
16 | BLUETOOTH_SCAN: 'android.permission.BLUETOOTH_SCAN',
17 | BODY_SENSORS: 'android.permission.BODY_SENSORS',
18 | BODY_SENSORS_BACKGROUND: 'android.permission.BODY_SENSORS_BACKGROUND',
19 | CALL_PHONE: 'android.permission.CALL_PHONE',
20 | CAMERA: 'android.permission.CAMERA',
21 | GET_ACCOUNTS: 'android.permission.GET_ACCOUNTS',
22 | NEARBY_WIFI_DEVICES: 'android.permission.NEARBY_WIFI_DEVICES',
23 | PROCESS_OUTGOING_CALLS: 'android.permission.PROCESS_OUTGOING_CALLS',
24 | READ_CALENDAR: 'android.permission.READ_CALENDAR',
25 | READ_CALL_LOG: 'android.permission.READ_CALL_LOG',
26 | READ_CONTACTS: 'android.permission.READ_CONTACTS',
27 | READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE',
28 | READ_MEDIA_AUDIO: 'android.permission.READ_MEDIA_AUDIO',
29 | READ_MEDIA_IMAGES: 'android.permission.READ_MEDIA_IMAGES',
30 | READ_MEDIA_VIDEO: 'android.permission.READ_MEDIA_VIDEO',
31 | READ_MEDIA_VISUAL_USER_SELECTED: 'android.permission.READ_MEDIA_VISUAL_USER_SELECTED',
32 | READ_PHONE_NUMBERS: 'android.permission.READ_PHONE_NUMBERS',
33 | READ_PHONE_STATE: 'android.permission.READ_PHONE_STATE',
34 | READ_SMS: 'android.permission.READ_SMS',
35 | RECEIVE_MMS: 'android.permission.RECEIVE_MMS',
36 | RECEIVE_SMS: 'android.permission.RECEIVE_SMS',
37 | RECEIVE_WAP_PUSH: 'android.permission.RECEIVE_WAP_PUSH',
38 | RECORD_AUDIO: 'android.permission.RECORD_AUDIO',
39 | SEND_SMS: 'android.permission.SEND_SMS',
40 | USE_SIP: 'android.permission.USE_SIP',
41 | UWB_RANGING: 'android.permission.UWB_RANGING',
42 | WRITE_CALENDAR: 'android.permission.WRITE_CALENDAR',
43 | WRITE_CALL_LOG: 'android.permission.WRITE_CALL_LOG',
44 | WRITE_CONTACTS: 'android.permission.WRITE_CONTACTS',
45 | WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE',
46 | } as const);
47 |
48 | export type AndroidPermissionMap = typeof ANDROID;
49 |
50 | export const PERMISSIONS = Object.freeze({
51 | ANDROID,
52 | IOS: proxifyPermissions('ios'),
53 | WINDOWS: proxifyPermissions('windows'),
54 | } as const);
55 |
--------------------------------------------------------------------------------
/src/permissions.ios.ts:
--------------------------------------------------------------------------------
1 | import type {AndroidPermissionMap} from './permissions.android';
2 | import type {WindowsPermissionMap} from './permissions.windows';
3 | import {proxifyPermissions} from './utils';
4 |
5 | const IOS = Object.freeze({
6 | APP_TRACKING_TRANSPARENCY: 'ios.permission.APP_TRACKING_TRANSPARENCY',
7 | BLUETOOTH: 'ios.permission.BLUETOOTH',
8 | CALENDARS: 'ios.permission.CALENDARS',
9 | CALENDARS_WRITE_ONLY: 'ios.permission.CALENDARS_WRITE_ONLY',
10 | CAMERA: 'ios.permission.CAMERA',
11 | CONTACTS: 'ios.permission.CONTACTS',
12 | FACE_ID: 'ios.permission.FACE_ID',
13 | LOCATION_ALWAYS: 'ios.permission.LOCATION_ALWAYS',
14 | LOCATION_WHEN_IN_USE: 'ios.permission.LOCATION_WHEN_IN_USE',
15 | MEDIA_LIBRARY: 'ios.permission.MEDIA_LIBRARY',
16 | MICROPHONE: 'ios.permission.MICROPHONE',
17 | MOTION: 'ios.permission.MOTION',
18 | PHOTO_LIBRARY: 'ios.permission.PHOTO_LIBRARY',
19 | PHOTO_LIBRARY_ADD_ONLY: 'ios.permission.PHOTO_LIBRARY_ADD_ONLY',
20 | REMINDERS: 'ios.permission.REMINDERS',
21 | SIRI: 'ios.permission.SIRI',
22 | SPEECH_RECOGNITION: 'ios.permission.SPEECH_RECOGNITION',
23 | STOREKIT: 'ios.permission.STOREKIT',
24 | } as const);
25 |
26 | export type IOSPermissionMap = typeof IOS;
27 |
28 | export const PERMISSIONS = Object.freeze({
29 | ANDROID: proxifyPermissions('android'),
30 | IOS,
31 | WINDOWS: proxifyPermissions('windows'),
32 | } as const);
33 |
--------------------------------------------------------------------------------
/src/permissions.ts:
--------------------------------------------------------------------------------
1 | import type {AndroidPermissionMap} from './permissions.android';
2 | import type {IOSPermissionMap} from './permissions.ios';
3 | import type {WindowsPermissionMap} from './permissions.windows';
4 | import {proxifyPermissions} from './utils';
5 |
6 | export const PERMISSIONS = Object.freeze({
7 | ANDROID: proxifyPermissions('android'),
8 | IOS: proxifyPermissions('ios'),
9 | WINDOWS: proxifyPermissions('windows'),
10 | } as const);
11 |
--------------------------------------------------------------------------------
/src/results.ts:
--------------------------------------------------------------------------------
1 | export const RESULTS = Object.freeze({
2 | UNAVAILABLE: 'unavailable',
3 | BLOCKED: 'blocked',
4 | DENIED: 'denied',
5 | GRANTED: 'granted',
6 | LIMITED: 'limited',
7 | } as const);
8 |
9 | export type ResultMap = typeof RESULTS;
10 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | import type {AndroidPermissionMap} from './permissions.android';
2 | import type {IOSPermissionMap} from './permissions.ios';
3 | import type {WindowsPermissionMap} from './permissions.windows';
4 | import type {ResultMap} from './results';
5 |
6 | type ValueOf = T[keyof T];
7 |
8 | export type AndroidPermission = ValueOf;
9 | export type IOSPermission = ValueOf;
10 | export type WindowsPermission = ValueOf;
11 | export type Permission = AndroidPermission | IOSPermission | WindowsPermission;
12 | export type PermissionStatus = ValueOf;
13 |
14 | export type RationaleObject = {
15 | title: string;
16 | message: string;
17 | buttonPositive: string;
18 | buttonNegative?: string;
19 | };
20 |
21 | export type Rationale = RationaleObject | (() => Promise);
22 |
23 | export type LocationAccuracy = 'full' | 'reduced';
24 | export type LocationAccuracyOptions = {purposeKey: string};
25 |
26 | export type NotificationOption =
27 | | 'alert'
28 | | 'badge'
29 | | 'sound'
30 | | 'carPlay'
31 | | 'criticalAlert'
32 | | 'provisional'
33 | | 'providesAppSettings';
34 |
35 | export type NotificationSettings = {
36 | alert?: boolean;
37 | badge?: boolean;
38 | sound?: boolean;
39 | carPlay?: boolean;
40 | criticalAlert?: boolean;
41 | provisional?: boolean;
42 | providesAppSettings?: boolean;
43 | lockScreen?: boolean;
44 | notificationCenter?: boolean;
45 | };
46 |
47 | export type NotificationsResponse = {
48 | status: PermissionStatus;
49 | settings: NotificationSettings;
50 | };
51 |
--------------------------------------------------------------------------------
/src/unsupportedMethods.ts:
--------------------------------------------------------------------------------
1 | import type {Contract} from './contract';
2 |
3 | const getUnsupportedError = (os: 'iOS' | 'Android', version: number) =>
4 | new Error(`Only supported by ${os} ${version} and above`);
5 |
6 | export const canScheduleExactAlarms: Contract['canScheduleExactAlarms'] = async () => {
7 | throw getUnsupportedError('Android', 12);
8 | };
9 |
10 | export const canUseFullScreenIntent: Contract['canUseFullScreenIntent'] = async () => {
11 | throw getUnsupportedError('Android', 14);
12 | };
13 |
14 | export const openPhotoPicker: Contract['openPhotoPicker'] = async () => {
15 | throw getUnsupportedError('iOS', 14);
16 | };
17 |
18 | export const requestLocationAccuracy: Contract['requestLocationAccuracy'] = async () => {
19 | throw getUnsupportedError('iOS', 14);
20 | };
21 |
22 | export const checkLocationAccuracy: Contract['checkLocationAccuracy'] = async () => {
23 | throw getUnsupportedError('iOS', 14);
24 | };
25 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | export const proxifyPermissions = >(
2 | platform: 'android' | 'ios' | 'windows',
3 | ) =>
4 | new Proxy({} as T, {
5 | get: (_, prop) => (typeof prop === 'string' ? `${platform}.permission.${prop}` : prop),
6 | });
7 |
8 | export const uniq = (array: T[]): T[] => {
9 | return array.filter((item, index) => item != null && array.indexOf(item) === index);
10 | };
11 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "ESNext",
4 | "lib": ["ES2017"],
5 | "jsx": "react-native",
6 | "moduleResolution": "Node",
7 |
8 | "allowJs": false,
9 | "strict": true,
10 | "declaration": true,
11 | "sourceMap": true,
12 | "stripInternal": true,
13 | "skipLibCheck": true,
14 | "verbatimModuleSyntax": true,
15 |
16 | "allowUnreachableCode": false,
17 | "allowUnusedLabels": false,
18 | "noFallthroughCasesInSwitch": true,
19 | "noImplicitOverride": true,
20 | "noImplicitReturns": false,
21 | "noUncheckedIndexedAccess": true,
22 | "noUnusedLocals": true,
23 | "noUnusedParameters": true
24 | },
25 | "include": ["src"],
26 | "exclude": ["example", "node_modules"]
27 | }
28 |
--------------------------------------------------------------------------------
/windows/.gitignore:
--------------------------------------------------------------------------------
1 | *AppPackages*
2 | *BundleArtifacts*
3 |
4 | #OS junk files
5 | [Tt]humbs.db
6 | *.DS_Store
7 |
8 | #Visual Studio files
9 | *.[Oo]bj
10 | *.user
11 | *.aps
12 | *.pch
13 | *.vspscc
14 | *.vssscc
15 | *_i.c
16 | *_p.c
17 | *.ncb
18 | *.suo
19 | *.tlb
20 | *.tlh
21 | *.bak
22 | *.[Cc]ache
23 | *.ilk
24 | *.log
25 | *.lib
26 | *.sbr
27 | *.sdf
28 | *.opensdf
29 | *.opendb
30 | *.unsuccessfulbuild
31 | ipch/
32 | [Oo]bj/
33 | [Bb]in
34 | [Dd]ebug*/
35 | [Rr]elease*/
36 | Ankh.NoLoad
37 | .vs/
38 | # Visual C++ cache files
39 |
40 | #Files generated by the VS build
41 | **/Generated Files/**
42 |
--------------------------------------------------------------------------------
/windows/ExperimentalFeatures.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 | true
16 |
17 |
28 | true
29 |
30 | true
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/windows/RNPermissions.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32929.385
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RNPermissions", "RNPermissions\RNPermissions.vcxproj", "{99677B9D-A27B-4239-930E-C36C8D339C54}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Debug|ARM64 = Debug|ARM64
13 | Release|x64 = Release|x64
14 | Release|x86 = Release|x86
15 | Release|ARM64 = Release|ARM64
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x64.ActiveCfg = Debug|x64
19 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x64.Build.0 = Debug|x64
20 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x64.Deploy.0 = Debug|x64
21 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x86.ActiveCfg = Debug|Win32
22 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x86.Build.0 = Debug|Win32
23 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x86.Deploy.0 = Debug|Win32
24 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|ARM64.ActiveCfg = Debug|ARM64
25 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|ARM64.Build.0 = Debug|ARM64
26 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|ARM64.Deploy.0 = Debug|ARM64
27 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x64.ActiveCfg = Release|x64
28 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x64.Build.0 = Release|x64
29 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x64.Deploy.0 = Release|x64
30 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x86.ActiveCfg = Release|Win32
31 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x86.Build.0 = Release|Win32
32 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x86.Deploy.0 = Release|Win32
33 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|ARM64.ActiveCfg = Release|ARM64
34 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|ARM64.Build.0 = Release|ARM64
35 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|ARM64.Deploy.0 = Release|ARM64
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/windows/RNPermissions/PropertySheet.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/windows/RNPermissions/RNPermissions.def:
--------------------------------------------------------------------------------
1 | EXPORTS
2 | DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
3 | DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
4 |
--------------------------------------------------------------------------------
/windows/RNPermissions/RNPermissions.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 | #include "resource.h"
5 |
6 | #include
7 |
8 | #include "codegen/NativeRnPermissionsDataTypes.g.h"
9 | #include "codegen/NativeRnPermissionsSpec.g.h"
10 |
11 | using namespace RNPermissionsCodegen;
12 | namespace winrt::RNPermissions
13 | {
14 |
15 | REACT_MODULE(RNPermissions)
16 | struct RNPermissions
17 | {
18 | using ModuleSpec = RNPermissionsCodegen::RNPermissionsSpec;
19 |
20 | REACT_INIT(Initialize);
21 | void Initialize(React::ReactContext const& reactContext) noexcept;
22 |
23 | REACT_METHOD(OpenSettings, L"openSettings");
24 | void OpenSettings(std::wstring type, React::ReactPromise&& promise) noexcept;
25 |
26 | REACT_METHOD(OpenPhotoPicker, L"openPhotoPicker");
27 | void OpenPhotoPicker(React::ReactPromise&& promise) noexcept;
28 |
29 | REACT_METHOD(CanScheduleExactAlarms, L"canScheduleExactAlarms");
30 | void CanScheduleExactAlarms(React::ReactPromise&& promise) noexcept;
31 |
32 | REACT_METHOD(CanUseFullScreenIntent, L"canUseFullScreenIntent");
33 | void CanUseFullScreenIntent(React::ReactPromise&& promise) noexcept;
34 |
35 | REACT_METHOD(CheckLocationAccuracy, L"checkLocationAccuracy");
36 | void CheckLocationAccuracy(React::ReactPromise&& promise) noexcept;
37 |
38 | REACT_METHOD(CheckNotifications, L"checkNotifications");
39 | void CheckNotifications(React::ReactPromise&& promise) noexcept;
40 |
41 | REACT_METHOD(Check, L"check");
42 | void Check(std::wstring permission, React::ReactPromise&& promise) noexcept;
43 |
44 | REACT_METHOD(CheckMultiple, L"checkMultiple");
45 | void CheckMultiple(std::vector permissions, React::ReactPromise<::React::JSValue>&& promise) noexcept;
46 |
47 | REACT_METHOD(Request, L"request");
48 | void Request(std::wstring permission, React::ReactPromise&& promise) noexcept;
49 |
50 | REACT_METHOD(RequestMultiple, L"requestMultiple");
51 | void RequestMultiple(std::vector permissions, React::ReactPromise<::React::JSValue>&& promise) noexcept;
52 |
53 | REACT_METHOD(RequestNotifications, L"requestNotifications");
54 | void RequestNotifications(std::vector options, React::ReactPromise&& promise) noexcept;
55 |
56 | REACT_METHOD(RequestLocationAccuracy, L"requestLocationAccuracy");
57 | void RequestLocationAccuracy(std::wstring purposeKey, React::ReactPromise&& promise) noexcept;
58 |
59 | REACT_METHOD(ShouldShowRequestRationale, L"shouldShowRequestRationale");
60 | void ShouldShowRequestRationale(std::wstring permission, React::ReactPromise&& promise) noexcept;
61 |
62 | private:
63 | React::ReactContext m_context;
64 | };
65 |
66 | } // namespace winrt::RNPermissions
67 |
--------------------------------------------------------------------------------
/windows/RNPermissions/RNPermissions.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/windows/RNPermissions/RNPermissions.rc
--------------------------------------------------------------------------------
/windows/RNPermissions/RNPermissions.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 |
32 |
33 | Source Files
34 |
35 |
36 | Source Files
37 |
38 |
39 |
40 |
41 | Resource Files
42 |
43 |
44 |
--------------------------------------------------------------------------------
/windows/RNPermissions/ReactPackageProvider.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 |
3 | #include "ReactPackageProvider.h"
4 | #if __has_include("ReactPackageProvider.g.cpp")
5 | #include "ReactPackageProvider.g.cpp"
6 | #endif
7 |
8 | #include "RNPermissions.h"
9 |
10 | using namespace winrt::Microsoft::ReactNative;
11 |
12 | namespace winrt::RNPermissions::implementation
13 | {
14 |
15 | void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept
16 | {
17 | #ifdef RnwNewArch
18 | AddAttributedModules(packageBuilder, true);
19 | #else
20 | AddAttributedModules(packageBuilder);
21 | #endif
22 | }
23 |
24 | } // namespace winrt::RNPermissions::implementation
25 |
--------------------------------------------------------------------------------
/windows/RNPermissions/ReactPackageProvider.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "ReactPackageProvider.g.h"
4 |
5 | using namespace winrt::Microsoft::ReactNative;
6 |
7 | namespace winrt::RNPermissions::implementation
8 | {
9 |
10 | struct ReactPackageProvider : ReactPackageProviderT
11 | {
12 | ReactPackageProvider() = default;
13 |
14 | void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept;
15 | };
16 |
17 | } // namespace winrt::RNPermissions::implementation
18 |
19 | namespace winrt::RNPermissions::factory_implementation
20 | {
21 |
22 | struct ReactPackageProvider : ReactPackageProviderT {};
23 |
24 | } // namespace winrt::RNPermissions::factory_implementation
25 |
--------------------------------------------------------------------------------
/windows/RNPermissions/ReactPackageProvider.idl:
--------------------------------------------------------------------------------
1 | namespace RNPermissions
2 | {
3 | [webhosthidden]
4 | [default_interface]
5 | runtimeclass ReactPackageProvider : Microsoft.ReactNative.IReactPackageProvider
6 | {
7 | ReactPackageProvider();
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/windows/RNPermissions/codegen/.clang-format:
--------------------------------------------------------------------------------
1 | DisableFormat: true
2 | SortIncludes: false
3 |
--------------------------------------------------------------------------------
/windows/RNPermissions/codegen/NativeRNPermissionsDataTypes.g.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * This file is auto-generated from a NativeModule spec file in js.
4 | *
5 | * This is a C++ Spec class that should be used with MakeTurboModuleProvider to register native modules
6 | * in a way that also verifies at compile time that the native module matches the interface required
7 | * by the TurboModule JS spec.
8 | */
9 | #pragma once
10 | // clang-format off
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | namespace RNPermissionsCodegen {
18 |
19 | struct RNPermissionsSpec_NotificationsResponse {
20 | ::React::JSValue status;
21 | ::React::JSValue settings;
22 | };
23 |
24 | } // namespace RNPermissionsCodegen
25 |
--------------------------------------------------------------------------------
/windows/RNPermissions/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/windows/RNPermissions/packages.lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "dependencies": {
4 | "native,Version=v0.0": {
5 | "boost": {
6 | "type": "Direct",
7 | "requested": "[1.83.0, )",
8 | "resolved": "1.83.0",
9 | "contentHash": "cy53VNMzysEMvhBixDe8ujPk67Fcj3v6FPHQnH91NYJNLHpc6jxa2xq9ruCaaJjE4M3YrGSHDi4uUSTGBWw6EQ=="
10 | },
11 | "Microsoft.ReactNative": {
12 | "type": "Direct",
13 | "requested": "[0.77.2-Fabric, )",
14 | "resolved": "0.77.2-Fabric",
15 | "contentHash": "tE/bhrg3qoxQoJofScQWP8fx/xnbdmo0DuLAjNkSv3gy9RNpEQdMAzlUHo5+3lJcPGJ4wAzlue2Nsdb0YJQ2Lw=="
16 | },
17 | "Microsoft.ReactNative.Cxx": {
18 | "type": "Direct",
19 | "requested": "[0.77.2-Fabric, )",
20 | "resolved": "0.77.2-Fabric",
21 | "contentHash": "Xc20uZX79+pK7uiqlrd9jVMTqMkC5KgWTLs9poZa9Q+xKbObmIVD17kLFZ2hwvWgVwhVhI+jVRXAAoyNNJBw+Q==",
22 | "dependencies": {
23 | "Microsoft.ReactNative": "0.77.2-Fabric"
24 | }
25 | },
26 | "Microsoft.VCRTForwarders.140": {
27 | "type": "Direct",
28 | "requested": "[1.0.2-rc, )",
29 | "resolved": "1.0.2-rc",
30 | "contentHash": "/r+sjtEeCIGyDhobIZ5hSmYhC/dSyGZxf1SxYJpElUhB0LMCktOMFs9gXrauXypIFECpVynNyVjAmJt6hjJ5oQ=="
31 | },
32 | "Microsoft.Windows.CppWinRT": {
33 | "type": "Direct",
34 | "requested": "[2.0.230706.1, )",
35 | "resolved": "2.0.230706.1",
36 | "contentHash": "l0D7oCw/5X+xIKHqZTi62TtV+1qeSz7KVluNFdrJ9hXsst4ghvqQ/Yhura7JqRdZWBXAuDS0G0KwALptdoxweQ=="
37 | },
38 | "Microsoft.WindowsAppSDK": {
39 | "type": "Direct",
40 | "requested": "[1.6.240923002, )",
41 | "resolved": "1.6.240923002",
42 | "contentHash": "7PfOz2scXU+AAM/GYge+f6s7k3DVI+R1P8MNPZQr56GOPCGw+csvcg3S5KZg47z/o04kNvWH3GKtWT1ML9tpZw==",
43 | "dependencies": {
44 | "Microsoft.Web.WebView2": "1.0.2651.64",
45 | "Microsoft.Windows.SDK.BuildTools": "10.0.22621.756"
46 | }
47 | },
48 | "Microsoft.Web.WebView2": {
49 | "type": "Transitive",
50 | "resolved": "1.0.2651.64",
51 | "contentHash": "f5sc/vcAoTCTEW7Nqzp4galAuTRguZViw8ksn+Nx2uskEBPm0/ubzy6gVjvXS/P96jLS89C8T9I0hPc417xpNg=="
52 | },
53 | "Microsoft.Windows.SDK.BuildTools": {
54 | "type": "Transitive",
55 | "resolved": "10.0.22621.756",
56 | "contentHash": "7ZL2sFSioYm1Ry067Kw1hg0SCcW5kuVezC2SwjGbcPE61Nn+gTbH86T73G3LcEOVj0S3IZzNuE/29gZvOLS7VA=="
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/windows/RNPermissions/pch.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 |
--------------------------------------------------------------------------------
/windows/RNPermissions/pch.h:
--------------------------------------------------------------------------------
1 | // pch.h : include file for standard system include files,
2 | // or project specific include files that are used frequently, but
3 | // are changed infrequently
4 | //
5 |
6 | #pragma once
7 |
8 | #include "targetver.h"
9 |
10 | #define NOMINMAX 1
11 | #define WIN32_LEAN_AND_MEAN 1
12 | #define WINRT_LEAN_AND_MEAN 1
13 |
14 | // Windows Header Files
15 | #include
16 | #undef GetCurrentTime
17 | #include
18 |
19 | // WinRT Header Files
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 |
33 | // C RunTime Header Files
34 | #include
35 | #include
36 | #include
37 | #include
38 |
39 | // Reference additional headers your project requires here
40 |
--------------------------------------------------------------------------------
/windows/RNPermissions/resource.h:
--------------------------------------------------------------------------------
1 | //
2 | // Microsoft Visual C++ generated include file.
3 | // Used by RNPermissions.rc
4 |
5 | #pragma once
6 |
--------------------------------------------------------------------------------
/windows/RNPermissions/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------