or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

configuration.mdindex.mdmedia-selection.mdpermissions.md
tile.json

permissions.mddocs/

Permission Management

Functions and React hooks for managing camera and media library permissions across platforms.

Capabilities

Camera Permissions

Functions and hooks for managing camera access permissions.

/**
 * Checks user's permissions for accessing camera.
 * @returns Promise resolving to current camera permission status
 */
function getCameraPermissionsAsync(): Promise<CameraPermissionResponse>;

/**
 * Asks the user to grant permissions for accessing camera.
 * This does nothing on web because the browser camera is not used.
 * @returns Promise resolving to camera permission response after request
 */
function requestCameraPermissionsAsync(): Promise<CameraPermissionResponse>;

/**
 * React hook for camera permissions management.
 * Combines both checking and requesting permissions.
 * @param options Optional configuration for the permission hook
 * @returns Tuple of [status, requestPermission, getPermission]
 */
const useCameraPermissions: (
  options?: PermissionHookOptions
) => [
  PermissionResponse | null,
  () => Promise<PermissionResponse>,
  () => Promise<PermissionResponse>
];

Usage Examples:

import * as ImagePicker from 'expo-image-picker';

// Check camera permissions
const checkCameraPermissions = async () => {
  const { status, canAskAgain } = await ImagePicker.getCameraPermissionsAsync();
  console.log('Camera permission status:', status);
  
  if (status === 'denied' && !canAskAgain) {
    // User permanently denied, direct to settings
    alert('Camera access permanently denied. Please enable in settings.');
  }
};

// Request camera permissions
const requestCameraAccess = async () => {
  const { status } = await ImagePicker.requestCameraPermissionsAsync();
  
  if (status === 'granted') {
    console.log('Camera access granted');
    // Proceed with camera functionality
  } else {
    console.log('Camera access denied');
  }
};

// Using camera permissions hook
import { useCameraPermissions } from 'expo-image-picker';

function CameraComponent() {
  const [status, requestPermission] = useCameraPermissions();

  const handleCameraPress = async () => {
    if (status?.granted) {
      // Permission already granted
      launchCamera();
    } else {
      // Request permission
      const newStatus = await requestPermission();
      if (newStatus.granted) {
        launchCamera();
      }
    }
  };

  const launchCamera = async () => {
    const result = await ImagePicker.launchCameraAsync({
      mediaTypes: 'images',
      quality: 0.8,
    });
  };

  return (
    <button onClick={handleCameraPress}>
      {status?.granted ? 'Take Photo' : 'Grant Camera Permission'}
    </button>
  );
}

Media Library Permissions

Functions and hooks for managing photo library access permissions.

/**
 * Checks user's permissions for accessing photos.
 * @param writeOnly Whether to check write-only or read-write permissions (default: false)
 * @returns Promise resolving to current media library permission status
 */
function getMediaLibraryPermissionsAsync(
  writeOnly?: boolean
): Promise<MediaLibraryPermissionResponse>;

/**
 * Asks the user to grant permissions for accessing user's photos.
 * This method does nothing on web.
 * @param writeOnly Whether to request write-only or read-write permissions (default: false)
 * @returns Promise resolving to media library permission response after request
 */
function requestMediaLibraryPermissionsAsync(
  writeOnly?: boolean
): Promise<MediaLibraryPermissionResponse>;

/**
 * React hook for media library permissions management.
 * Combines both checking and requesting permissions.
 * @param options Optional configuration including writeOnly setting
 * @returns Tuple of [status, requestPermission, getPermission]
 */
const useMediaLibraryPermissions: (
  options?: PermissionHookOptions<{ writeOnly?: boolean }>
) => [
  MediaLibraryPermissionResponse | null,
  () => Promise<MediaLibraryPermissionResponse>,
  () => Promise<MediaLibraryPermissionResponse>
];

Usage Examples:

import * as ImagePicker from 'expo-image-picker';

// Check media library permissions
const checkLibraryPermissions = async () => {
  const { status, accessPrivileges } = await ImagePicker.getMediaLibraryPermissionsAsync();
  console.log('Library permission status:', status);
  console.log('Access privileges:', accessPrivileges);
  
  if (accessPrivileges === 'limited') {
    console.log('User granted limited photo access');
  }
};

// Request full media library access
const requestLibraryAccess = async () => {
  const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(false);
  
  if (status === 'granted') {
    console.log('Full media library access granted');
  } else {
    console.log('Media library access denied');
  }
};

// Request write-only permissions (for saving photos)
const requestWriteAccess = async () => {
  const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(true);
  
  if (status === 'granted') {
    console.log('Write access granted');
  }
};

// Using media library permissions hook
import { useMediaLibraryPermissions } from 'expo-image-picker';

function PhotoLibraryComponent() {
  const [status, requestPermission] = useMediaLibraryPermissions();

  const handleLibraryPress = async () => {
    if (status?.granted) {
      // Permission already granted
      openLibrary();
    } else {
      // Request permission
      const newStatus = await requestPermission();
      if (newStatus.granted) {
        openLibrary();
      }
    }
  };

  const openLibrary = async () => {
    const result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: 'images',
      allowsMultipleSelection: true,
      quality: 0.8,
    });
  };

  const getStatusMessage = () => {
    if (!status) return 'Checking permissions...';
    if (status.granted) {
      if (status.accessPrivileges === 'limited') {
        return 'Limited photo access granted';
      }
      return 'Full photo access granted';
    }
    return 'Photo access required';
  };

  return (
    <div>
      <p>{getStatusMessage()}</p>
      <button onClick={handleLibraryPress}>
        {status?.granted ? 'Open Photo Library' : 'Grant Library Permission'}
      </button>
    </div>
  );
}

Permission Types

// Camera permission type (alias of PermissionResponse)
type CameraPermissionResponse = PermissionResponse;

// Media library permission type (extends PermissionResponse)
interface MediaLibraryPermissionResponse extends PermissionResponse {
  /**
   * iOS/Android 34+ specific field indicating level of photo access:
   * - 'all': Full photo library access
   * - 'limited': Access to selected photos only
   * - 'none': No access granted
   */
  accessPrivileges?: 'all' | 'limited' | 'none';
}

// Base permission response (from expo-modules-core)
interface PermissionResponse {
  status: PermissionStatus;
  expires: PermissionExpiration;
  granted: boolean;
  canAskAgain: boolean;
}

enum PermissionStatus {
  DENIED = 'denied',
  GRANTED = 'granted',
  UNDETERMINED = 'undetermined'
}

type PermissionExpiration = 'never' | number;

// Hook options
interface PermissionHookOptions<T = object> {
  get?: boolean;
  request?: boolean;
} & T;

Best Practices

Permission Flow

import * as ImagePicker from 'expo-image-picker';

const handleImageSelection = async () => {
  // 1. Check current permission status
  const { status, canAskAgain } = await ImagePicker.getMediaLibraryPermissionsAsync();
  
  if (status === 'granted') {
    // Permission already granted - proceed
    launchLibrary();
  } else if (status === 'denied') {
    if (canAskAgain) {
      // Can ask again - request permission
      const result = await ImagePicker.requestMediaLibraryPermissionsAsync();
      if (result.status === 'granted') {
        launchLibrary();
      } else {
        showPermissionDeniedMessage();
      }
    } else {
      // Permission permanently denied - direct to settings
      showSettingsAlert();
    }
  } else {
    // Status is 'undetermined' - request permission
    const result = await ImagePicker.requestMediaLibraryPermissionsAsync();
    if (result.status === 'granted') {
      launchLibrary();
    } else {
      showPermissionDeniedMessage();
    }
  }
};

const launchLibrary = async () => {
  const result = await ImagePicker.launchImageLibraryAsync({
    mediaTypes: 'images',
    quality: 0.8,
  });
  
  if (!result.canceled) {
    // Handle selected images
    console.log('Selected:', result.assets);
  }
};

Hook-Based Approach

import { useMediaLibraryPermissions, useCameraPermissions } from 'expo-image-picker';

function MediaPickerComponent() {
  const [libraryStatus, requestLibrary] = useMediaLibraryPermissions();
  const [cameraStatus, requestCamera] = useCameraPermissions();

  const pickFromLibrary = async () => {
    if (!libraryStatus?.granted) {
      await requestLibrary();
    }
    
    if (libraryStatus?.granted) {
      const result = await ImagePicker.launchImageLibraryAsync();
      // Handle result
    }
  };

  const takePhoto = async () => {
    if (!cameraStatus?.granted) {
      await requestCamera();
    }
    
    if (cameraStatus?.granted) {
      const result = await ImagePicker.launchCameraAsync();
      // Handle result
    }
  };

  return (
    <div>
      <button onClick={pickFromLibrary}>
        Choose from Library
      </button>
      <button onClick={takePhoto}>
        Take Photo
      </button>
    </div>
  );
}