// @flow import { AsyncStorage, NativeModules, PermissionsAndroid } from "react-native"; type Status = "authorized" | "denied" | "restricted" | "undetermined"; type Rationale = { title: string, message: string }; type CheckOptions = string | { type: string }; type RequestOptions = string | { type: string, rationale?: Rationale }; const permissionTypes = { location: PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, camera: PermissionsAndroid.PERMISSIONS.CAMERA, microphone: PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, contacts: PermissionsAndroid.PERMISSIONS.READ_CONTACTS, event: PermissionsAndroid.PERMISSIONS.READ_CALENDAR, storage: PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, photo: PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, callPhone: PermissionsAndroid.PERMISSIONS.CALL_PHONE, readSms: PermissionsAndroid.PERMISSIONS.READ_SMS, receiveSms: PermissionsAndroid.PERMISSIONS.RECEIVE_SMS, }; const RESULTS = { [PermissionsAndroid.RESULTS.GRANTED]: "authorized", [PermissionsAndroid.RESULTS.DENIED]: "denied", [PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN]: "restricted", }; const STORAGE_KEY = "@RNPermissions:didAskPermission:"; const setDidAskOnce = (permission: string) => AsyncStorage.setItem(STORAGE_KEY + permission, "true"); const getDidAskOnce = (permission: string) => AsyncStorage.getItem(STORAGE_KEY + permission).then(item => !!item); class ReactNativePermissions { canOpenSettings: () => Promise = () => Promise.resolve(false); openSettings: () => Promise<*> = () => Promise.reject(new Error("'openSettings' is deprecated on android")); getTypes: () => Array = () => Object.keys(permissionTypes); check = (permission: string, options?: CheckOptions): Promise => { if (!permissionTypes[permission]) { const error = new Error( `ReactNativePermissions: ${permission} is not a valid permission type on Android`, ); return Promise.reject(error); } return PermissionsAndroid.check(permissionTypes[permission]).then( isAuthorized => { if (isAuthorized) { return "authorized"; } return getDidAskOnce(permission).then(didAsk => { if (didAsk) { return NativeModules.PermissionsAndroid.shouldShowRequestPermissionRationale( permissionTypes[permission], ).then(shouldShow => (shouldShow ? "denied" : "restricted")); } return "undetermined"; }); }, ); }; request = (permission: string, options?: RequestOptions): Promise => { if (!permissionTypes[permission]) { const error = new Error( `ReactNativePermissions: ${permission} is not a valid permission type on Android`, ); return Promise.reject(error); } let rationale; if (options && options.rationale) { rationale = options.rationale; } return PermissionsAndroid.request( permissionTypes[permission], rationale, ).then(result => { // PermissionsAndroid.request() to native module resolves to boolean // rather than string if running on OS version prior to Android M if (typeof result === "boolean") { return result ? "authorized" : "denied"; } return setDidAskOnce(permission).then(() => RESULTS[result]); }); }; checkMultiple = (permissions: Array): Promise<{ [string]: string }> => Promise.all(permissions.map(permission => this.check(permission))).then( result => result.reduce((acc, value, index) => { const name = permissions[index]; acc[name] = value; return acc; }, {}), ); } export default new ReactNativePermissions();