@capacitor/camera 5.0.0-alpha.1 → 5.0.0-beta.1

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
@@ -3,6 +3,29 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [5.0.0-beta.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/camera@5.0.0-beta.0...@capacitor/camera@5.0.0-beta.1) (2023-04-21)
7
+
8
+
9
+ ### Features
10
+
11
+ * Update gradle to 8.0.2 and gradle plugin to 8.0.0 ([#1542](https://github.com/ionic-team/capacitor-plugins/issues/1542)) ([e7210b4](https://github.com/ionic-team/capacitor-plugins/commit/e7210b47867644f5983e37acdbf0247214ec232d))
12
+
13
+
14
+
15
+
16
+
17
+ # [5.0.0-beta.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/camera@5.0.0-alpha.1...@capacitor/camera@5.0.0-beta.0) (2023-03-31)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * **camera:** add proper permissions for Android 13 ([#1509](https://github.com/ionic-team/capacitor-plugins/issues/1509)) ([0dcbe56](https://github.com/ionic-team/capacitor-plugins/commit/0dcbe56bc554b1919c3e26d2f6b7ff8e5b7a0f5e))
23
+ * **camera:** prevent iOS crash with 0 limited images selected ([#1495](https://github.com/ionic-team/capacitor-plugins/issues/1495)) ([33f5c8e](https://github.com/ionic-team/capacitor-plugins/commit/33f5c8ebc7705c0e697caee4b2177ebc27d46311))
24
+
25
+
26
+
27
+
28
+
6
29
  # [5.0.0-alpha.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/camera@4.1.4...@capacitor/camera@5.0.0-alpha.1) (2023-03-16)
7
30
 
8
31
 
package/README.md CHANGED
@@ -24,6 +24,7 @@ Read about [Configuring `Info.plist`](https://capacitorjs.com/docs/ios/configura
24
24
  This API requires the following permissions be added to your `AndroidManifest.xml`:
25
25
 
26
26
  ```xml
27
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
27
28
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
28
29
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
29
30
  ```
@@ -17,7 +17,7 @@ buildscript {
17
17
  }
18
18
  }
19
19
  dependencies {
20
- classpath 'com.android.tools.build:gradle:7.2.1'
20
+ classpath 'com.android.tools.build:gradle:8.0.0'
21
21
  if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") {
22
22
  classpath 'io.github.gradle-nexus:publish-plugin:1.1.0'
23
23
  }
@@ -32,6 +32,7 @@ if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") {
32
32
  }
33
33
 
34
34
  android {
35
+ namespace "com.capacitorjs.plugins.camera"
35
36
  compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 33
36
37
  defaultConfig {
37
38
  minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
@@ -50,8 +51,8 @@ android {
50
51
  abortOnError false
51
52
  }
52
53
  compileOptions {
53
- sourceCompatibility JavaVersion.VERSION_11
54
- targetCompatibility JavaVersion.VERSION_11
54
+ sourceCompatibility JavaVersion.VERSION_17
55
+ targetCompatibility JavaVersion.VERSION_17
55
56
  }
56
57
  }
57
58
 
@@ -1,5 +1,4 @@
1
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
- package="com.capacitorjs.plugins.camera">
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
2
  <queries>
4
3
  <intent>
5
4
  <action android:name="android.media.action.IMAGE_CAPTURE" />
@@ -1,6 +1,7 @@
1
1
  package com.capacitorjs.plugins.camera;
2
2
 
3
3
  import android.Manifest;
4
+ import android.annotation.SuppressLint;
4
5
  import android.app.Activity;
5
6
  import android.content.ActivityNotFoundException;
6
7
  import android.content.ContentResolver;
@@ -18,6 +19,7 @@ import android.os.Parcelable;
18
19
  import android.provider.MediaStore;
19
20
  import android.util.Base64;
20
21
  import androidx.activity.result.ActivityResult;
22
+ import androidx.annotation.NonNull;
21
23
  import androidx.core.content.FileProvider;
22
24
  import com.getcapacitor.FileUtils;
23
25
  import com.getcapacitor.JSArray;
@@ -55,14 +57,23 @@ import org.json.JSONException;
55
57
  *
56
58
  * Adapted from https://developer.android.com/training/camera/photobasics.html
57
59
  */
60
+ @SuppressLint("InlinedApi")
58
61
  @CapacitorPlugin(
59
62
  name = "Camera",
60
63
  permissions = {
61
64
  @Permission(strings = { Manifest.permission.CAMERA }, alias = CameraPlugin.CAMERA),
65
+ // SDK VERSIONS 32 AND BELOW
62
66
  @Permission(
63
67
  strings = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE },
64
68
  alias = CameraPlugin.PHOTOS
65
- )
69
+ ),
70
+ /*
71
+ SDK VERSIONS 33 AND ABOVE
72
+ This alias is a placeholder and the PHOTOS alias will be updated to use these permissions
73
+ so that the end user does not need to explicitly use separate aliases depending
74
+ on the SDK version.
75
+ */
76
+ @Permission(strings = { Manifest.permission.READ_MEDIA_IMAGES }, alias = CameraPlugin.MEDIA)
66
77
  }
67
78
  )
68
79
  public class CameraPlugin extends Plugin {
@@ -70,6 +81,7 @@ public class CameraPlugin extends Plugin {
70
81
  // Permission alias constants
71
82
  static final String CAMERA = "camera";
72
83
  static final String PHOTOS = "photos";
84
+ static final String MEDIA = "media";
73
85
 
74
86
  // Message constants
75
87
  private static final String INVALID_RESULT_TYPE_ERROR = "Invalid resultType option";
@@ -194,10 +206,16 @@ public class CameraPlugin extends Plugin {
194
206
  }
195
207
 
196
208
  private boolean checkPhotosPermissions(PluginCall call) {
197
- if (getPermissionState(PHOTOS) != PermissionState.GRANTED) {
198
- requestPermissionForAlias(PHOTOS, call, "cameraPermissionsCallback");
209
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
210
+ if (getPermissionState(PHOTOS) != PermissionState.GRANTED) {
211
+ requestPermissionForAlias(PHOTOS, call, "cameraPermissionsCallback");
212
+ return false;
213
+ }
214
+ } else if (getPermissionState(MEDIA) != PermissionState.GRANTED) {
215
+ requestPermissionForAlias(MEDIA, call, "cameraPermissionsCallback");
199
216
  return false;
200
217
  }
218
+
201
219
  return true;
202
220
  }
203
221
 
@@ -216,15 +234,33 @@ public class CameraPlugin extends Plugin {
216
234
  Logger.debug(getLogTag(), "User denied camera permission: " + getPermissionState(CAMERA).toString());
217
235
  call.reject(PERMISSION_DENIED_ERROR_CAMERA);
218
236
  return;
219
- } else if (settings.getSource() == CameraSource.PHOTOS && getPermissionState(PHOTOS) != PermissionState.GRANTED) {
220
- Logger.debug(getLogTag(), "User denied photos permission: " + getPermissionState(PHOTOS).toString());
221
- call.reject(PERMISSION_DENIED_ERROR_PHOTOS);
222
- return;
237
+ } else if (settings.getSource() == CameraSource.PHOTOS) {
238
+ PermissionState permissionState = (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
239
+ ? getPermissionState(PHOTOS)
240
+ : getPermissionState(MEDIA);
241
+ if (permissionState != PermissionState.GRANTED) {
242
+ Logger.debug(getLogTag(), "User denied photos permission: " + permissionState.toString());
243
+ call.reject(PERMISSION_DENIED_ERROR_PHOTOS);
244
+ return;
245
+ }
223
246
  }
224
247
  doShow(call);
225
248
  }
226
249
  }
227
250
 
251
+ @Override
252
+ protected void requestPermissionForAliases(@NonNull String[] aliases, @NonNull PluginCall call, @NonNull String callbackName) {
253
+ // If the SDK version is 33 or higher, use the MEDIA alias permissions instead.
254
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
255
+ for (int i = 0; i < aliases.length; i++) {
256
+ if (aliases[i].equals(PHOTOS)) {
257
+ aliases[i] = MEDIA;
258
+ }
259
+ }
260
+ }
261
+ super.requestPermissionForAliases(aliases, call, callbackName);
262
+ }
263
+
228
264
  private CameraSettings getSettings(PluginCall call) {
229
265
  CameraSettings settings = new CameraSettings();
230
266
  settings.setResultType(getResultType(call.getString("resultType")));
@@ -372,7 +408,12 @@ public class CameraPlugin extends Plugin {
372
408
  } else if (data.getExtras() != null) {
373
409
  Bundle bundle = data.getExtras();
374
410
  if (bundle.keySet().contains("selectedItems")) {
375
- ArrayList<Parcelable> fileUris = bundle.getParcelableArrayList("selectedItems");
411
+ ArrayList<Parcelable> fileUris;
412
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
413
+ fileUris = bundle.getParcelableArrayList("selectedItems", Parcelable.class);
414
+ } else {
415
+ fileUris = getLegacyParcelableArrayList(bundle, "selectedItems");
416
+ }
376
417
  if (fileUris != null) {
377
418
  for (Parcelable fileUri : fileUris) {
378
419
  if (fileUri instanceof Uri) {
@@ -402,6 +443,11 @@ public class CameraPlugin extends Plugin {
402
443
  }
403
444
  }
404
445
 
446
+ @SuppressWarnings("deprecation")
447
+ private ArrayList<Parcelable> getLegacyParcelableArrayList(Bundle bundle, String key) {
448
+ return bundle.getParcelableArrayList(key);
449
+ }
450
+
405
451
  private void processPickedImage(Uri imageUri, PluginCall call) {
406
452
  InputStream imageStream = null;
407
453
 
@@ -771,6 +817,11 @@ public class CameraPlugin extends Plugin {
771
817
  permissionStates.put(CAMERA, PermissionState.GRANTED);
772
818
  }
773
819
 
820
+ // If the SDK version is 33 or higher, update the PHOTOS state to match the MEDIA state.
821
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && permissionStates.containsKey(MEDIA)) {
822
+ permissionStates.put(PHOTOS, permissionStates.get(MEDIA));
823
+ }
824
+
774
825
  return permissionStates;
775
826
  }
776
827
 
@@ -798,9 +849,18 @@ public class CameraPlugin extends Plugin {
798
849
  int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
799
850
  editIntent.addFlags(flags);
800
851
  editIntent.putExtra(MediaStore.EXTRA_OUTPUT, editUri);
801
- List<ResolveInfo> resInfoList = getContext()
802
- .getPackageManager()
803
- .queryIntentActivities(editIntent, PackageManager.MATCH_DEFAULT_ONLY);
852
+
853
+ List<ResolveInfo> resInfoList;
854
+
855
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
856
+ resInfoList =
857
+ getContext()
858
+ .getPackageManager()
859
+ .queryIntentActivities(editIntent, PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
860
+ } else {
861
+ resInfoList = legacyQueryIntentActivities(editIntent);
862
+ }
863
+
804
864
  for (ResolveInfo resolveInfo : resInfoList) {
805
865
  String packageName = resolveInfo.activityInfo.packageName;
806
866
  getContext().grantUriPermission(packageName, editUri, flags);
@@ -811,6 +871,11 @@ public class CameraPlugin extends Plugin {
811
871
  }
812
872
  }
813
873
 
874
+ @SuppressWarnings("deprecation")
875
+ private List<ResolveInfo> legacyQueryIntentActivities(Intent intent) {
876
+ return getContext().getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
877
+ }
878
+
814
879
  @Override
815
880
  protected Bundle saveInstanceState() {
816
881
  Bundle bundle = super.saveInstanceState();
@@ -109,19 +109,20 @@ public class CameraPlugin: CAPPlugin {
109
109
  options.deliveryMode = .highQualityFormat
110
110
 
111
111
  let group = DispatchGroup()
112
-
113
- for index in 0...(assets.count - 1) {
114
- let asset = assets.object(at: index)
115
- let fullSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
116
-
117
- group.enter()
118
- imageManager.requestImage(for: asset, targetSize: fullSize, contentMode: .default, options: options) { image, _ in
119
- guard let image = image else {
112
+ if assets.count > 0 {
113
+ for index in 0...(assets.count - 1) {
114
+ let asset = assets.object(at: index)
115
+ let fullSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
116
+
117
+ group.enter()
118
+ imageManager.requestImage(for: asset, targetSize: fullSize, contentMode: .default, options: options) { image, _ in
119
+ guard let image = image else {
120
+ group.leave()
121
+ return
122
+ }
123
+ processedImages.append(self.processedImage(from: image, with: asset.imageData))
120
124
  group.leave()
121
- return
122
125
  }
123
- processedImages.append(self.processedImage(from: image, with: asset.imageData))
124
- group.leave()
125
126
  }
126
127
  }
127
128
 
@@ -4,7 +4,7 @@ class ImageSaver: NSObject {
4
4
 
5
5
  var onResult: ((Error?) -> Void) = {_ in }
6
6
 
7
- init(image: UIImage, onResult:@escaping ((Error?) -> Void)) {
7
+ init(image: UIImage, onResult: @escaping ((Error?) -> Void)) {
8
8
  self.onResult = onResult
9
9
  super.init()
10
10
  UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveResult), nil)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor/camera",
3
- "version": "5.0.0-alpha.1",
3
+ "version": "5.0.0-beta.1",
4
4
  "description": "The Camera API provides the ability to take a photo with the camera or choose an existing one from the photo album.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -79,5 +79,5 @@
79
79
  "publishConfig": {
80
80
  "access": "public"
81
81
  },
82
- "gitHead": "b980c4d862b72610560a6cedc69238021c5367cc"
82
+ "gitHead": "a837068f095735043d64f8c4bfa22a0e77dcda7a"
83
83
  }