hunk.code_window: ## Build locally with Android Studio and Xcode
   > **warning** We do not recommend this method or modifying these **android/** and **ios/** directories directly, especially when creating a development build with EAS Build. For more information, see [Prebuild](/workflow/prebuild/).
   If you need to debug native code or you prefer to manage your native projects, you can build and distribute your project using the `npx expo run` commands. You'll need to set up or have access to Android Studio, Xcode, and related dependencies on your local computer.
   The [`npx expo run` commands](/workflow/expo-cli/#compiling) will create a new build, install it on your emulator/simulator or device, and start running it.
  
hunk.labels: keep keep keep replace keep keep keep keep
hunk.after_edit: > **warning** We do not recommend this method or modifying these **android** and **ios** directories directly, especially when creating a development build with EAS Build. For more information, see [Prebuild](/workflow/prebuild/).
  
hunk.file_path: docs/pages/develop/development-builds/development-workflows.mdx
hunk.type: replace
file: import {
    AndroidConfig,
    withProjectBuildGradle,
    ConfigPlugin,
    createRunOncePlugin,
    withInfoPlist,
  } from '@expo/config-plugins';
  import {
    createGeneratedHeaderComment,
    MergeResults,
    removeGeneratedContents,
  } from '@expo/config-plugins/build/utils/generateCode';
  
  const pkg = require('expo-camera/package.json');
  
  const CAMERA_USAGE = 'Allow $(PRODUCT_NAME) to access your camera';
  const MICROPHONE_USAGE = 'Allow $(PRODUCT_NAME) to access your microphone';
  
  // Because we need the package to be added AFTER the React and Google maven packages, we create a new allprojects.
  // It's ok to have multiple allprojects.repositories, so we create a new one since it's cheaper than tokenizing
  // the existing block to find the correct place to insert our camera maven.
  const gradleMaven = [
    `def expoCameraMavenPath = new File(["node", "--print", "require.resolve('expo-camera/package.json')"].execute(null, rootDir).text.trim(), "../android/maven")`,
    `allprojects { repositories { maven { url(expoCameraMavenPath) } } }`,
  ].join('\n');
  
  const withAndroidCameraGradle: ConfigPlugin = (config) => {
    return withProjectBuildGradle(config, (config) => {
      if (config.modResults.language === 'groovy') {
        config.modResults.contents = addCameraImport(config.modResults.contents).contents;
      } else {
        throw new Error('Cannot add camera maven gradle because the build.gradle is not groovy');
      }
      return config;
    });
  };
  
  export function addCameraImport(src: string): MergeResults {
    return appendContents({
      tag: 'expo-camera-import',
      src,
      newSrc: gradleMaven,
      comment: '//',
    });
  }
  
  // Fork of config-plugins mergeContents, but appends the contents to the end of the file.
  function appendContents({
    src,
    newSrc,
    tag,
    comment,
  }: {
    src: string;
    newSrc: string;
    tag: string;
    comment: string;
  }): MergeResults {
    const header = createGeneratedHeaderComment(newSrc, tag, comment);
    if (!src.includes(header)) {
      // Ensure the old generated contents are removed.
      const sanitizedTarget = removeGeneratedContents(src, tag);
      const contentsToAdd = [
        // @something
        header,
        // contents
        newSrc,
        // @end
        `${comment} @generated end ${tag}`,
      ].join('\n');
  
      return {
        contents: sanitizedTarget ?? src + contentsToAdd,
        didMerge: true,
        didClear: !!sanitizedTarget,
      };
    }
    return { contents: src, didClear: false, didMerge: false };
  }
  
  const withCamera: ConfigPlugin<
    {
      cameraPermission?: string;
      microphonePermission?: string;
    } | void
  > = (config, { cameraPermission, microphonePermission } = {}) => {
    config = withInfoPlist(config, (config) => {
      config.modResults.NSCameraUsageDescription =
        cameraPermission || config.modResults.NSCameraUsageDescription || CAMERA_USAGE;
  
      config.modResults.NSMicrophoneUsageDescription =
        microphonePermission || config.modResults.NSMicrophoneUsageDescription || MICROPHONE_USAGE;
  
      return config;
    });
  
    config = AndroidConfig.Permissions.withPermissions(config, [
      'android.permission.CAMERA',
      // Optional
      'android.permission.RECORD_AUDIO',
    ]);
  
    return withAndroidCameraGradle(config);
  };
  
  export default createRunOncePlugin(withCamera, pkg.name, pkg.version);
  