Ionic 2: Camera permissions example for iOS and Android

Turns out permissions on iOS are a pile of balls and they don't act in a sensible way. If you've previously denied access to a permission, requesting it again literally does nothing. So you have to tell the user to manually go and change it. LAME.

The Problem:

One of my apps needs to get permission to use the camera. On Android this is easy, just check the status and if not requested or denied, simply ask for it again. Turns out, that doesn't work with iOS. Asking for permission if it's already been denied for some inexplicable reason does fuck all. Thanks Apple.

The Fix:

Here's the code I use that seems to work for permissions. Might be a better way to do it, but this works, so whatever:

Here's my example PermissionsService.ts class:

import { Injectable } from '@angular/core';
import { Platform } from 'ionic-angular';
import { Diagnostic } from '@ionic-native/diagnostic';


@Injectable()
export class PermissionsService {

    constructor(
        public _platform: Platform,
        public _Diagnostic: Diagnostic
    ) {
    }

    isAndroid() {
        return this._platform.is('android')
    }

    isiOS() {
        return this._platform.is('ios');
    }

    isUndefined(type) {
        return typeof type === "undefined";
    }

    pluginsAreAvailable() {
        return !this.isUndefined(window.plugins);
    }


    checkCameraPermissions(): Promise<boolean> {
        return new Promise(resolve => {
            if (!this.pluginsAreAvailable()) {
                alert('Dev: Camera plugin unavailable.');
                resolve(false);
            }
            else if (this.isiOS()) {
                this._Diagnostic.getCameraAuthorizationStatus().then(status => {
                    if (status == this._Diagnostic.permissionStatus.GRANTED) {
                        resolve(true);
                    }
                    else if (status == this._Diagnostic.permissionStatus.DENIED) {
                        resolve(false);
                    }
                    else if (status == this._Diagnostic.permissionStatus.NOT_REQUESTED || status.toLowerCase() == 'not_determined') {
                        this._Diagnostic.requestCameraAuthorization().then(authorisation => {
                            resolve(authorisation == this._Diagnostic.permissionStatus.GRANTED);
                        });
                    }                    
                });
            }
            else if (this.isAndroid()) {
                this._Diagnostic.isCameraAuthorized().then(authorised => {
                    if (authorised) {
                        resolve(true);
                    }
                    else {
                        this._Diagnostic.requestCameraAuthorization().then(authorisation => {
                            resolve(authorisation == this._Diagnostic.permissionStatus.GRANTED);
                        });
                    }
                });
            }
        });
    }
    
}

Then, in some page, import the class and just call the method:

PermissionsClass.checkCameraPermissions().then(permissionOk => {
  if (permissionOk) {
    alert('awesome!');
  }
  else {
    alert('balls.');
  }
})

Testing:

Turns out iOS stores permissions for 24 hours even you delete an app and reinstall. So you have to reset your permissions to test the code properly. Stupid. To test this and how it handles its different states on iOS, you can reset permissions by going to:

Settings -> General -> Reset -> Reset Location & Privacy

Note: This will reset ALL permission settings for all apps. Don't run this on your personal device or you will be pissed off.

Conclusion:

iOS permissions are balls.

Cheers.

Comments: