permissions.android.js 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // @flow
  2. import { AsyncStorage, NativeModules, PermissionsAndroid } from 'react-native'
  3. type Status = 'authorized' | 'denied' | 'restricted' | 'undetermined'
  4. type Rationale = { title: string, message: string }
  5. type Options = string | { type: string, rationale?: Rationale }
  6. const permissionTypes = {
  7. location: PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
  8. camera: PermissionsAndroid.PERMISSIONS.CAMERA,
  9. microphone: PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
  10. contacts: PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
  11. event: PermissionsAndroid.PERMISSIONS.READ_CALENDAR,
  12. storage: PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
  13. photo: PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
  14. callPhone: PermissionsAndroid.PERMISSIONS.CALL_PHONE,
  15. readSms: PermissionsAndroid.PERMISSIONS.READ_SMS,
  16. receiveSms: PermissionsAndroid.PERMISSIONS.RECEIVE_SMS,
  17. }
  18. const RESULTS = {
  19. [PermissionsAndroid.RESULTS.GRANTED]: 'authorized',
  20. [PermissionsAndroid.RESULTS.DENIED]: 'denied',
  21. [PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN]: 'restricted',
  22. }
  23. const STORAGE_KEY = '@RNPermissions:didAskPermission:'
  24. const setDidAskOnce = (permission: string) =>
  25. AsyncStorage.setItem(STORAGE_KEY + permission, 'true')
  26. const getDidAskOnce = (permission: string) =>
  27. AsyncStorage.getItem(STORAGE_KEY + permission).then(item => !!item)
  28. class ReactNativePermissions {
  29. canOpenSettings: () => Promise<boolean> = () => Promise.resolve(false)
  30. openSettings: () => Promise<*> = () =>
  31. Promise.reject(new Error("'openSettings' is deprecated on android"))
  32. getTypes: () => Array<string> = () => Object.keys(permissionTypes)
  33. check = (permission: string, type?: string): Promise<Status> => {
  34. if (!permissionTypes[permission]) {
  35. const error = new Error(
  36. `ReactNativePermissions: ${
  37. permission
  38. } is not a valid permission type on Android`,
  39. )
  40. return Promise.reject(error)
  41. }
  42. return PermissionsAndroid.check(permissionTypes[permission]).then(
  43. isAuthorized => {
  44. if (isAuthorized) {
  45. return 'authorized'
  46. }
  47. return getDidAskOnce(permission).then(didAsk => {
  48. if (didAsk) {
  49. return NativeModules.PermissionsAndroid.shouldShowRequestPermissionRationale(
  50. permissionTypes[permission],
  51. ).then(shouldShow => (shouldShow ? 'denied' : 'restricted'))
  52. }
  53. return 'undetermined'
  54. })
  55. },
  56. )
  57. }
  58. request = (permission: string, options?: Options): Promise<Status> => {
  59. if (!permissionTypes[permission]) {
  60. const error = new Error(
  61. `ReactNativePermissions: ${
  62. permission
  63. } is not a valid permission type on Android`,
  64. )
  65. return Promise.reject(error)
  66. }
  67. let rationale
  68. if (options && options.rationale) {
  69. rationale = options.rationale
  70. }
  71. return PermissionsAndroid.request(
  72. permissionTypes[permission],
  73. rationale,
  74. ).then(result => {
  75. // PermissionsAndroid.request() to native module resolves to boolean
  76. // rather than string if running on OS version prior to Android M
  77. if (typeof result === 'boolean') {
  78. return result ? 'authorized' : 'denied'
  79. }
  80. return setDidAskOnce(permission).then(() => RESULTS[result])
  81. })
  82. }
  83. checkMultiple = (permissions: Array<string>): Promise<{ [string]: string }> =>
  84. Promise.all(permissions.map(permission => this.check(permission))).then(
  85. result =>
  86. result.reduce((acc, value, index) => {
  87. const name = permissions[index]
  88. acc[name] = value
  89. return acc
  90. }, {}),
  91. )
  92. }
  93. module.exports = new ReactNativePermissions()