expo-image-picker 13.0.1 → 13.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,12 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 13.1.0 — 2022-04-25
14
+
15
+ ### 🎉 New features
16
+
17
+ - [plugin] Added ability to disable permissions. ([#17168](https://github.com/expo/expo/pull/17168) by [@EvanBacon](https://github.com/EvanBacon))
18
+
13
19
  ## 13.0.1 — 2022-04-20
14
20
 
15
21
  _This version does not introduce any user-facing changes._
package/README.md CHANGED
@@ -23,6 +23,8 @@ expo install expo-image-picker
23
23
 
24
24
  ### Configure for iOS
25
25
 
26
+ > This is only required for usage in bare React Native apps.
27
+
26
28
  Add `NSPhotoLibraryUsageDescription`, `NSCameraUsageDescription`, and `NSMicrophoneUsageDescription` keys to your `Info.plist`:
27
29
 
28
30
  ```xml
@@ -38,6 +40,8 @@ Run `npx pod-install` after installing the npm package.
38
40
 
39
41
  ### Configure for Android
40
42
 
43
+ > This is only required for usage in bare React Native apps.
44
+
41
45
  This package automatically adds the `CAMERA`, `READ_EXTERNAL_STORAGE`, and `WRITE_EXTERNAL_STORAGE` permissions. They are used when picking images from the camera directly, or from the camera roll.
42
46
 
43
47
  ```xml
@@ -47,13 +51,49 @@ This package automatically adds the `CAMERA`, `READ_EXTERNAL_STORAGE`, and `WRIT
47
51
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
48
52
  ```
49
53
 
50
- In `AndroidManifest.xml` add the following `activity` within `application`:
54
+ ## Config Plugin
51
55
 
52
- ```xml
53
- <activity
54
- android:name="com.canhub.cropper.CropImageActivity"
55
- android:theme="@style/Base.Theme.AppCompat">
56
- </activity>
56
+ > This plugin is applied automatically in EAS Build, only add the config plugin if you want to pass in extra properties.
57
+
58
+ After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`:
59
+
60
+ ```json
61
+ {
62
+ "expo": {
63
+ "plugins": ["expo-image-picker"]
64
+ }
65
+ }
66
+ ```
67
+
68
+ Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
69
+
70
+ ### API
71
+
72
+ The plugin provides props for extra customization. Every time you change the props or plugins, you'll need to rebuild (and `prebuild`) the native app. If no extra properties are added, defaults will be used.
73
+
74
+ - `photosPermission` (_string | false_): Sets the iOS `NSPhotoLibraryUsageDescription` permission message to the `Info.plist`. Setting `false` will skip adding the permission on iOS and **does not** skip the permission on Android. Defaults to `Allow $(PRODUCT_NAME) to access your photos`.
75
+ - `cameraPermission` (_string | false_): Sets the iOS `NSCameraUsageDescription` permission message to the `Info.plist`. Setting `false` will skip adding the permission on iOS and **does not** skip the permission on Android. Defaults to `Allow $(PRODUCT_NAME) to access your camera`.
76
+ - `microphonePermission` (_string | false_): Sets the iOS `NSCameraUsageDescription` permission message to the `Info.plist`. Setting `false` will skip adding the permission on iOS and skips adding the `android.permission.RECORD_AUDIO` Android permission. Defaults to `Allow $(PRODUCT_NAME) to access your photos`.
77
+
78
+ ### Example
79
+
80
+ ```json
81
+ {
82
+ "expo": {
83
+ "plugins": [
84
+ [
85
+ "expo-image-picker",
86
+ {
87
+ "photosPermission": "custom photos permission",
88
+ "cameraPermission": "Allow $(PRODUCT_NAME) to open the camera",
89
+
90
+ "//": "Disables the microphone permission",
91
+ "microphonePermission": false
92
+ }
93
+ ]
94
+ ]
95
+ }
96
+ }
57
97
  ```
58
98
 
59
99
  # Contributing
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven-publish'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '13.0.1'
6
+ version = '13.1.0'
7
7
 
8
8
  buildscript {
9
9
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
@@ -74,7 +74,7 @@ android {
74
74
  minSdkVersion safeExtGet("minSdkVersion", 21)
75
75
  targetSdkVersion safeExtGet("targetSdkVersion", 31)
76
76
  versionCode 22
77
- versionName "13.0.1"
77
+ versionName "13.1.0"
78
78
  }
79
79
  lintOptions {
80
80
  abortOnError false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-image-picker",
3
- "version": "13.0.1",
3
+ "version": "13.1.0",
4
4
  "description": "Provides access to the system's UI for selecting images and videos from the phone's library or taking a photo with the camera.",
5
5
  "main": "build/ImagePicker.js",
6
6
  "types": "build/ImagePicker.d.ts",
@@ -46,5 +46,5 @@
46
46
  "peerDependencies": {
47
47
  "expo": "*"
48
48
  },
49
- "gitHead": "2b35d9008fef42cb53473331c37693ca12e9bf12"
49
+ "gitHead": "8fa7ceccfeab2f5090019403d6472fb80d6d7eaf"
50
50
  }
@@ -1,8 +1,10 @@
1
- import { ConfigPlugin, AndroidConfig } from '@expo/config-plugins';
2
- export declare function setImagePickerManifestActivity(androidManifest: AndroidConfig.Manifest.AndroidManifest): AndroidConfig.Manifest.AndroidManifest;
3
- declare const _default: ConfigPlugin<void | {
4
- photosPermission?: string | undefined;
5
- cameraPermission?: string | undefined;
6
- microphonePermission?: string | undefined;
7
- }>;
1
+ import { ConfigPlugin, InfoPlist } from '@expo/config-plugins';
2
+ declare type Props = {
3
+ photosPermission?: string | false;
4
+ cameraPermission?: string | false;
5
+ microphonePermission?: string | false;
6
+ };
7
+ export declare function setImagePickerInfoPlist(infoPlist: InfoPlist, { cameraPermission, microphonePermission, photosPermission }: Props): InfoPlist;
8
+ export declare const withAndroidImagePickerPermissions: ConfigPlugin<Props | void>;
9
+ declare const _default: ConfigPlugin<void | Props>;
8
10
  export default _default;
@@ -1,56 +1,71 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setImagePickerManifestActivity = void 0;
3
+ exports.withAndroidImagePickerPermissions = exports.setImagePickerInfoPlist = void 0;
4
4
  const config_plugins_1 = require("@expo/config-plugins");
5
5
  const pkg = require('expo-image-picker/package.json');
6
6
  const CAMERA_USAGE = 'Allow $(PRODUCT_NAME) to access your camera';
7
7
  const MICROPHONE_USAGE = 'Allow $(PRODUCT_NAME) to access your microphone';
8
8
  const READ_PHOTOS_USAGE = 'Allow $(PRODUCT_NAME) to access your photos';
9
- function setImagePickerManifestActivity(androidManifest) {
10
- const app = config_plugins_1.AndroidConfig.Manifest.getMainApplicationOrThrow(androidManifest);
11
- if (!app.activity) {
12
- app.activity = [];
13
- }
14
- if (!app.activity.find(({ $ }) => $['android:name'] === 'com.canhub.cropper.CropImageActivity')) {
15
- app.activity.push({
16
- $: {
17
- 'android:name': 'com.canhub.cropper.CropImageActivity',
18
- 'android:theme': '@style/Base.Theme.AppCompat',
19
- },
20
- });
9
+ function setImagePickerInfoPlist(infoPlist, { cameraPermission, microphonePermission, photosPermission }) {
10
+ if (photosPermission === false) {
11
+ delete infoPlist.NSPhotoLibraryUsageDescription;
12
+ }
13
+ else {
14
+ infoPlist.NSPhotoLibraryUsageDescription =
15
+ photosPermission || infoPlist.NSPhotoLibraryUsageDescription || READ_PHOTOS_USAGE;
16
+ }
17
+ if (cameraPermission === false) {
18
+ delete infoPlist.NSCameraUsageDescription;
19
+ }
20
+ else {
21
+ infoPlist.NSCameraUsageDescription =
22
+ cameraPermission || infoPlist.NSCameraUsageDescription || CAMERA_USAGE;
21
23
  }
22
- return androidManifest;
24
+ if (microphonePermission === false) {
25
+ delete infoPlist.NSMicrophoneUsageDescription;
26
+ }
27
+ else {
28
+ infoPlist.NSMicrophoneUsageDescription =
29
+ microphonePermission || infoPlist.NSMicrophoneUsageDescription || MICROPHONE_USAGE;
30
+ }
31
+ return infoPlist;
23
32
  }
24
- exports.setImagePickerManifestActivity = setImagePickerManifestActivity;
25
- const withImagePickerManifestActivity = (config) => {
26
- // This plugin has no ability to remove the activity that it adds.
27
- return (0, config_plugins_1.withAndroidManifest)(config, async (config) => {
28
- config.modResults = setImagePickerManifestActivity(config.modResults);
29
- return config;
30
- });
33
+ exports.setImagePickerInfoPlist = setImagePickerInfoPlist;
34
+ const withAndroidImagePickerPermissions = (config, { cameraPermission, microphonePermission } = {}) => {
35
+ if (microphonePermission !== false) {
36
+ config = config_plugins_1.AndroidConfig.Permissions.withPermissions(config, ['android.permission.RECORD_AUDIO']);
37
+ }
38
+ // If the user manually sets any of the permissions to `false`, then we should block the permissions to ensure no
39
+ // package can add them.
40
+ config = config_plugins_1.AndroidConfig.Permissions.withBlockedPermissions(config, [
41
+ microphonePermission === false && 'android.permission.RECORD_AUDIO',
42
+ cameraPermission === false && 'android.permission.CAMERA',
43
+ ].filter(Boolean));
44
+ // NOTE(EvanBacon): It's unclear if we should block the WRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGE permissions since
45
+ // they're used for many other things besides image picker.
46
+ return config;
31
47
  };
48
+ exports.withAndroidImagePickerPermissions = withAndroidImagePickerPermissions;
32
49
  const withImagePicker = (config, { photosPermission, cameraPermission, microphonePermission } = {}) => {
33
- if (!config.ios)
34
- config.ios = {};
35
- if (!config.ios.infoPlist)
36
- config.ios.infoPlist = {};
37
- config.ios.infoPlist.NSPhotoLibraryUsageDescription =
38
- photosPermission || config.ios.infoPlist.NSPhotoLibraryUsageDescription || READ_PHOTOS_USAGE;
39
- config.ios.infoPlist.NSCameraUsageDescription =
40
- cameraPermission || config.ios.infoPlist.NSCameraUsageDescription || CAMERA_USAGE;
41
- config.ios.infoPlist.NSMicrophoneUsageDescription =
42
- microphonePermission || config.ios.infoPlist.NSMicrophoneUsageDescription || MICROPHONE_USAGE;
43
- return (0, config_plugins_1.withPlugins)(config, [
44
- [
45
- config_plugins_1.AndroidConfig.Permissions.withPermissions,
46
- [
47
- 'android.permission.CAMERA',
48
- 'android.permission.READ_EXTERNAL_STORAGE',
49
- 'android.permission.WRITE_EXTERNAL_STORAGE',
50
- 'android.permission.RECORD_AUDIO',
51
- ],
52
- ],
53
- withImagePickerManifestActivity,
54
- ]);
50
+ config = (0, config_plugins_1.withInfoPlist)(config, (config) => {
51
+ config.modResults = setImagePickerInfoPlist(config.modResults, {
52
+ photosPermission,
53
+ cameraPermission,
54
+ microphonePermission,
55
+ });
56
+ return config;
57
+ });
58
+ if (microphonePermission !== false) {
59
+ config = config_plugins_1.AndroidConfig.Permissions.withPermissions(config, ['android.permission.RECORD_AUDIO']);
60
+ }
61
+ // If the user manually sets any of the permissions to `false`, then we should block the permissions to ensure no
62
+ // package can add them.
63
+ config = config_plugins_1.AndroidConfig.Permissions.withBlockedPermissions(config, [
64
+ microphonePermission === false && 'android.permission.RECORD_AUDIO',
65
+ cameraPermission === false && 'android.permission.CAMERA',
66
+ ].filter(Boolean));
67
+ // NOTE(EvanBacon): It's unclear if we should block the WRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGE permissions since
68
+ // they're used for many other things besides image picker.
69
+ return config;
55
70
  };
56
71
  exports.default = (0, config_plugins_1.createRunOncePlugin)(withImagePicker, pkg.name, pkg.version);
@@ -1,9 +1,9 @@
1
1
  import {
2
+ AndroidConfig,
2
3
  ConfigPlugin,
3
4
  createRunOncePlugin,
4
- withAndroidManifest,
5
- withPlugins,
6
- AndroidConfig,
5
+ InfoPlist,
6
+ withInfoPlist,
7
7
  } from '@expo/config-plugins';
8
8
 
9
9
  const pkg = require('expo-image-picker/package.json');
@@ -12,60 +12,92 @@ const CAMERA_USAGE = 'Allow $(PRODUCT_NAME) to access your camera';
12
12
  const MICROPHONE_USAGE = 'Allow $(PRODUCT_NAME) to access your microphone';
13
13
  const READ_PHOTOS_USAGE = 'Allow $(PRODUCT_NAME) to access your photos';
14
14
 
15
- export function setImagePickerManifestActivity(
16
- androidManifest: AndroidConfig.Manifest.AndroidManifest
17
- ): AndroidConfig.Manifest.AndroidManifest {
18
- const app = AndroidConfig.Manifest.getMainApplicationOrThrow(androidManifest);
19
- if (!app.activity) {
20
- app.activity = [];
15
+ type Props = {
16
+ photosPermission?: string | false;
17
+ cameraPermission?: string | false;
18
+ microphonePermission?: string | false;
19
+ };
20
+
21
+ export function setImagePickerInfoPlist(
22
+ infoPlist: InfoPlist,
23
+ { cameraPermission, microphonePermission, photosPermission }: Props
24
+ ): InfoPlist {
25
+ if (photosPermission === false) {
26
+ delete infoPlist.NSPhotoLibraryUsageDescription;
27
+ } else {
28
+ infoPlist.NSPhotoLibraryUsageDescription =
29
+ photosPermission || infoPlist.NSPhotoLibraryUsageDescription || READ_PHOTOS_USAGE;
21
30
  }
22
- if (!app.activity.find(({ $ }) => $['android:name'] === 'com.canhub.cropper.CropImageActivity')) {
23
- app.activity.push({
24
- $: {
25
- 'android:name': 'com.canhub.cropper.CropImageActivity',
26
- 'android:theme': '@style/Base.Theme.AppCompat',
27
- },
28
- });
31
+ if (cameraPermission === false) {
32
+ delete infoPlist.NSCameraUsageDescription;
33
+ } else {
34
+ infoPlist.NSCameraUsageDescription =
35
+ cameraPermission || infoPlist.NSCameraUsageDescription || CAMERA_USAGE;
29
36
  }
30
- return androidManifest;
37
+ if (microphonePermission === false) {
38
+ delete infoPlist.NSMicrophoneUsageDescription;
39
+ } else {
40
+ infoPlist.NSMicrophoneUsageDescription =
41
+ microphonePermission || infoPlist.NSMicrophoneUsageDescription || MICROPHONE_USAGE;
42
+ }
43
+ return infoPlist;
31
44
  }
32
45
 
33
- const withImagePickerManifestActivity: ConfigPlugin = (config) => {
34
- // This plugin has no ability to remove the activity that it adds.
35
- return withAndroidManifest(config, async (config) => {
36
- config.modResults = setImagePickerManifestActivity(config.modResults);
46
+ export const withAndroidImagePickerPermissions: ConfigPlugin<Props | void> = (
47
+ config,
48
+ { cameraPermission, microphonePermission } = {}
49
+ ) => {
50
+ if (microphonePermission !== false) {
51
+ config = AndroidConfig.Permissions.withPermissions(config, ['android.permission.RECORD_AUDIO']);
52
+ }
53
+
54
+ // If the user manually sets any of the permissions to `false`, then we should block the permissions to ensure no
55
+ // package can add them.
56
+ config = AndroidConfig.Permissions.withBlockedPermissions(
57
+ config,
58
+ [
59
+ microphonePermission === false && 'android.permission.RECORD_AUDIO',
60
+ cameraPermission === false && 'android.permission.CAMERA',
61
+ ].filter(Boolean) as string[]
62
+ );
63
+
64
+ // NOTE(EvanBacon): It's unclear if we should block the WRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGE permissions since
65
+ // they're used for many other things besides image picker.
66
+
67
+ return config;
68
+ };
69
+
70
+ const withImagePicker: ConfigPlugin<Props | void> = (
71
+ config,
72
+ { photosPermission, cameraPermission, microphonePermission } = {}
73
+ ) => {
74
+ config = withInfoPlist(config, (config) => {
75
+ config.modResults = setImagePickerInfoPlist(config.modResults, {
76
+ photosPermission,
77
+ cameraPermission,
78
+ microphonePermission,
79
+ });
37
80
  return config;
38
81
  });
39
- };
40
82
 
41
- const withImagePicker: ConfigPlugin<
42
- {
43
- photosPermission?: string;
44
- cameraPermission?: string;
45
- microphonePermission?: string;
46
- } | void
47
- > = (config, { photosPermission, cameraPermission, microphonePermission } = {}) => {
48
- if (!config.ios) config.ios = {};
49
- if (!config.ios.infoPlist) config.ios.infoPlist = {};
50
- config.ios.infoPlist.NSPhotoLibraryUsageDescription =
51
- photosPermission || config.ios.infoPlist.NSPhotoLibraryUsageDescription || READ_PHOTOS_USAGE;
52
- config.ios.infoPlist.NSCameraUsageDescription =
53
- cameraPermission || config.ios.infoPlist.NSCameraUsageDescription || CAMERA_USAGE;
54
- config.ios.infoPlist.NSMicrophoneUsageDescription =
55
- microphonePermission || config.ios.infoPlist.NSMicrophoneUsageDescription || MICROPHONE_USAGE;
83
+ if (microphonePermission !== false) {
84
+ config = AndroidConfig.Permissions.withPermissions(config, ['android.permission.RECORD_AUDIO']);
85
+ }
56
86
 
57
- return withPlugins(config, [
87
+ // If the user manually sets any of the permissions to `false`, then we should block the permissions to ensure no
88
+ // package can add them.
89
+ config = AndroidConfig.Permissions.withBlockedPermissions(
90
+ config,
58
91
  [
59
- AndroidConfig.Permissions.withPermissions,
60
- [
61
- 'android.permission.CAMERA',
62
- 'android.permission.READ_EXTERNAL_STORAGE',
63
- 'android.permission.WRITE_EXTERNAL_STORAGE',
64
- 'android.permission.RECORD_AUDIO',
65
- ],
66
- ],
67
- withImagePickerManifestActivity,
68
- ]);
92
+ microphonePermission === false && 'android.permission.RECORD_AUDIO',
93
+ cameraPermission === false && 'android.permission.CAMERA',
94
+ ].filter(Boolean) as string[]
95
+ );
96
+
97
+ // NOTE(EvanBacon): It's unclear if we should block the WRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGE permissions since
98
+ // they're used for many other things besides image picker.
99
+
100
+ return config;
69
101
  };
70
102
 
71
103
  export default createRunOncePlugin(withImagePicker, pkg.name, pkg.version);