@capacitor/camera 5.0.0-alpha.1 → 5.0.0-beta.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 +12 -0
- package/README.md +1 -0
- package/android/build.gradle +2 -1
- package/android/src/main/AndroidManifest.xml +1 -2
- package/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.java +76 -11
- package/ios/Plugin/CameraPlugin.swift +12 -11
- package/ios/Plugin/ImageSaver.swift +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
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.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)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **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))
|
|
12
|
+
* **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))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
6
18
|
# [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
19
|
|
|
8
20
|
|
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
|
```
|
package/android/build.gradle
CHANGED
|
@@ -17,7 +17,7 @@ buildscript {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
dependencies {
|
|
20
|
-
classpath 'com.android.tools.build:gradle:7.
|
|
20
|
+
classpath 'com.android.tools.build:gradle:7.4.1'
|
|
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
|
|
@@ -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 (
|
|
198
|
-
|
|
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
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
|
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
|
-
|
|
802
|
-
|
|
803
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
|
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-
|
|
3
|
+
"version": "5.0.0-beta.0",
|
|
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": "
|
|
82
|
+
"gitHead": "d53b649da594ee7e30d7cff4f7cdb87ba6a436b5"
|
|
83
83
|
}
|