Last active
November 13, 2019 21:25
-
-
Save walidvb/741186db857592706c93d82ea7a9616f to your computer and use it in GitHub Desktop.
This allows displaying a dialog to the user before actually requesting permissions from the OS. Ultimately, it allows to request that permission multiple times, which iOS prevents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requestPermissions from './requestPermissions' | |
requestPermission(pickFromCamera, { | |
permissionNames: ['CAMERA', 'CAMERA_ROLL'], | |
alertTitle: '📷Camera📸', | |
alertBody: 'Use your camera now.', | |
}) | |
// Only request every n times this is run | |
// useful to ask for notification permission | |
// every now and then 👍🏻 | |
requestPermission(onGranted, { | |
permissionNames: ['NOTIFICATIONS'] , | |
alertTitle: '🎶Notifications🎶', | |
alertBody: 'Get notified when your session has closed and never miss an opportunity to enter your contributions.', | |
askEvery: [0, 1, 5, 10, 20, 30, 50], | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as Permissions from 'expo-permissions'; | |
import { AsyncStorage, Platform, Alert } from 'react-native'; | |
const key = (name) => `@YOUR-APP:${name}-request-status` | |
const countKey = (name) => `@YOUR-APP:${name}-request-count` | |
async function requestPermission(callback, { | |
permissionNames, | |
alertBody, | |
alertTitle, | |
askEvery | |
}) { | |
const statii = await Promise.all(permissionNames.map(async name => await Permissions.getAsync(Permissions[name]))) | |
// only ask if permissions have not already been determined, because | |
// iOS won't necessarily prompt the user a second time. | |
if (statii.find(s => s !== 'granted')) { | |
return Platform.OS === 'ios' ? askLocal() : askForReal() | |
} | |
callback() | |
async function askSinglePermission(permissionName) { | |
const { status } = await Permissions.askAsync(Permissions[permissionName]); | |
return status | |
} | |
async function askForReal() { | |
const statii = await Promise.all(permissionNames.map(async name => await askSinglePermission(name))) | |
if (statii.find(s => s !== 'granted')) { | |
return; | |
} | |
return callback() | |
} | |
async function askLocal() { | |
if (await hasAcceptedLocal()) { | |
return askForReal() | |
} | |
// this only considers the first permission request count | |
// as i only know of one case where both would be needed. | |
const visitsCountKey = countKey(permissionNames[0]) | |
const oldCountKey = await AsyncStorage.getItem(visitsCountKey) | |
const visitsCount = parseInt(oldCountKey || 0) | |
AsyncStorage.setItem(visitsCountKey, `${visitsCount + 1}`) | |
if (!askEvery || askEvery.includes(visitsCount)) { | |
Alert.alert( | |
alertTitle, alertBody, | |
[ | |
{ | |
text: 'Maybe later', | |
onPress: cancel, | |
style: 'cancel', | |
}, | |
{ | |
text: 'Allow', | |
onPress: acceptLocal | |
}, | |
]) | |
function cancel() { | |
} | |
} | |
} | |
// as iOS returns 'undetermined' for denied permissions, | |
// we have no way to know whether it was denied or not. | |
// therefore, we assume that if Local was granted | |
// native also was | |
async function hasAcceptedLocal() { | |
const all = await Promise.all(permissionNames.map(async (name) => (await AsyncStorage.getItem(key(name))) === '1')) | |
return !all.includes(false) | |
} | |
async function acceptLocal() { | |
permissionNames.map(async name => AsyncStorage.setItem(key(name), '1')) | |
askForReal() | |
} | |
} | |
export default requestPermission |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment