Supporting Android permissions in React Native

Alex Sullivan

Google recently updated the Play Store to only accept new applications that are targeting API 26 or above, and starting November 1st the play store will only accept updates that are targeting API 26 or above. That means many React Native applications, which targeted API 23 by default before v0.57, will need to be updated.

The most obvious update will be that apps will now have to support the modern Android permission model. That means that instead of having all permissions automatically granted at runtime, the app will have to specifically ask for the permissions it needs before the user can use whatever feature makes use of those permissions.

We can walk through a quick example to make things more clear.

export default class ContactsDisplay extends Component {
    render() {
        return (
            <View>
                <Button title="Press me for contacts!" onPress={this.getContacts} />
            </View>
        )
    }

    getContacts = () => {
        Contacts.getAll((err, contacts) => {
            if (err) throw err;
            alert("We got some contacts!")
        })
    }
}

Here’s an example of an application that accesses a user’s contacts. It uses the react-native-contacts library. Accessing a users contact’s requires the READ_CONTACTS permission. Before targeting API 26, this component would run A-OK. However, if you update the app to target API 26 or above, the above code will crash with a SecurityException. Instead, we have to specifically request the correct permission:

export default class ContactsDisplay extends Component {
    render() {
        return (
            <View>
                <Button title="Press me for contacts!" onPress={this.getContacts} />
            </View>
        )
    }

    async requestContactsPermission() {
        const granted = await PermissionsAndroid.request(
            PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
            {
                title: 'Hey you need to give us contacts permissions!',
                message: 'We need to read your contacts so we can sell them to advertisers.'
            }
        )
        return granted === PermissionsAndroid.RESULTS.GRANTED
    }

    getContacts = () => {
        this.requestContactsPermission()
            .then(function (didGetPermission: boolean) {
                if (didGetPermission) {
                    Contacts.getAll((err, contacts) => {
                        if (err) throw err;
                        alert("We got some contacts!")
                    })
                } else {
                    alert("Oh no no permissions!")
                }
            })
    }
}

You can use the PermissionsAndroid.request() method to request the relevant permission. The supplied object will show a dialog to your user explaining why you need the permission before the system actually asks for the permission.

To check if your app is already targeting an sdk ≥ 26, you can open the build.gradle file and check the value of the targetSdkVersion field. Note that a compileSdkVersion value ≥ 26 is not what you’re looking for - it’s specifically the targetSdkVersion.

The move to runtime permissions was a huge win for Android users, but it does require a bit more thought from the developers standpoint. That being said, making the switch shouldn’t be too hard, so don’t be intimidated!