CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-expo-image-picker

Provides access to the system's UI for selecting images and videos from the phone's library or taking a photo with the camera.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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>
  );
}

docs

configuration.md

index.md

media-selection.md

permissions.md

tile.json