expo-media-library 17.1.0-canary-20250131-5c4e588 → 17.1.0-canary-20250219-4a5dade
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 +1 -0
- package/android/build.gradle +3 -19
- package/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt +62 -25
- package/android/src/main/res/values/strings.xml +3 -0
- package/build/MediaLibrary.d.ts.map +1 -1
- package/build/MediaLibrary.js +11 -2
- package/build/MediaLibrary.js.map +1 -1
- package/ios/ExpoMediaLibrary.podspec +2 -1
- package/ios/MediaLibraryModule.swift +4 -0
- package/ios/SaveToLibraryDelegate.swift +2 -0
- package/package.json +5 -4
- package/src/MediaLibrary.ts +19 -2
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
- [Android] Started using expo modules gradle plugin. ([#34176](https://github.com/expo/expo/pull/34176) by [@lukmccall](https://github.com/lukmccall))
|
|
16
16
|
- [apple] Migrate remaining `expo-module.config.json` to unified platform syntax. ([#34445](https://github.com/expo/expo/pull/34445) by [@reichhartd](https://github.com/reichhartd))
|
|
17
|
+
- Add guards when using the module in expo go. ([#34738](https://github.com/expo/expo/pull/34738) by [@alanjhughes](https://github.com/alanjhughes))
|
|
17
18
|
|
|
18
19
|
## 17.0.4 - 2024-12-19
|
|
19
20
|
|
package/android/build.gradle
CHANGED
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
5
|
-
apply from: expoModulesCorePlugin
|
|
6
|
-
applyKotlinExpoModulesCorePlugin()
|
|
7
|
-
useCoreDependencies()
|
|
8
|
-
useDefaultAndroidSdkVersions()
|
|
9
|
-
useExpoPublishing()
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
apply plugin: 'expo-module-gradle-plugin'
|
|
14
|
-
} catch (e) {
|
|
15
|
-
if (!e instanceof UnknownPluginException) {
|
|
16
|
-
throw e
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
useLegacyExpoModulesCorePlugin()
|
|
1
|
+
plugins {
|
|
2
|
+
id 'com.android.library'
|
|
3
|
+
id 'expo-module-gradle-plugin'
|
|
20
4
|
}
|
|
21
5
|
|
|
22
6
|
group = 'host.exp.exponent'
|
|
@@ -57,6 +57,16 @@ class MediaLibraryModule : Module() {
|
|
|
57
57
|
private var imagesObserver: MediaStoreContentObserver? = null
|
|
58
58
|
private var videosObserver: MediaStoreContentObserver? = null
|
|
59
59
|
private var awaitingAction: Action? = null
|
|
60
|
+
private val isExpoGo by lazy {
|
|
61
|
+
context.resources.getString(R.string.is_expo_go).toBoolean()
|
|
62
|
+
}
|
|
63
|
+
private val allowedPermissionsList by lazy {
|
|
64
|
+
if (isExpoGo) {
|
|
65
|
+
listOf(GranularPermission.AUDIO)
|
|
66
|
+
} else {
|
|
67
|
+
listOf(GranularPermission.AUDIO, GranularPermission.PHOTO, GranularPermission.VIDEO)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
60
70
|
|
|
61
71
|
override fun definition() = ModuleDefinition {
|
|
62
72
|
Name("ExpoMediaLibrary")
|
|
@@ -72,7 +82,8 @@ class MediaLibraryModule : Module() {
|
|
|
72
82
|
Events(LIBRARY_DID_CHANGE_EVENT)
|
|
73
83
|
|
|
74
84
|
AsyncFunction("requestPermissionsAsync") { writeOnly: Boolean, permissions: List<GranularPermission>?, promise: Promise ->
|
|
75
|
-
val granularPermissions = permissions ?:
|
|
85
|
+
val granularPermissions = permissions ?: allowedPermissionsList
|
|
86
|
+
maybeThrowIfExpoGo(granularPermissions)
|
|
76
87
|
askForPermissionsWithPermissionsManager(
|
|
77
88
|
appContext.permissions,
|
|
78
89
|
MediaLibraryPermissionPromiseWrapper(granularPermissions, promise, WeakReference(context)),
|
|
@@ -81,7 +92,8 @@ class MediaLibraryModule : Module() {
|
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
AsyncFunction("getPermissionsAsync") { writeOnly: Boolean, permissions: List<GranularPermission>?, promise: Promise ->
|
|
84
|
-
val granularPermissions = permissions ?:
|
|
95
|
+
val granularPermissions = permissions ?: allowedPermissionsList
|
|
96
|
+
maybeThrowIfExpoGo(granularPermissions)
|
|
85
97
|
getPermissionsWithPermissionsManager(
|
|
86
98
|
appContext.permissions,
|
|
87
99
|
MediaLibraryPermissionPromiseWrapper(granularPermissions, promise, WeakReference(context)),
|
|
@@ -284,14 +296,15 @@ class MediaLibraryModule : Module() {
|
|
|
284
296
|
)
|
|
285
297
|
}
|
|
286
298
|
|
|
287
|
-
videosObserver =
|
|
288
|
-
.
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
299
|
+
videosObserver =
|
|
300
|
+
MediaStoreContentObserver(handler, MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO)
|
|
301
|
+
.also { videoObserver ->
|
|
302
|
+
contentResolver.registerContentObserver(
|
|
303
|
+
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
|
|
304
|
+
true,
|
|
305
|
+
videoObserver
|
|
306
|
+
)
|
|
307
|
+
}
|
|
295
308
|
}
|
|
296
309
|
|
|
297
310
|
OnStopObserving {
|
|
@@ -322,15 +335,16 @@ class MediaLibraryModule : Module() {
|
|
|
322
335
|
}
|
|
323
336
|
}
|
|
324
337
|
|
|
325
|
-
private inline fun withModuleScope(promise: Promise, crossinline block: () -> Unit) =
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
338
|
+
private inline fun withModuleScope(promise: Promise, crossinline block: () -> Unit) =
|
|
339
|
+
moduleCoroutineScope.launch {
|
|
340
|
+
try {
|
|
341
|
+
block()
|
|
342
|
+
} catch (e: CodedException) {
|
|
343
|
+
promise.reject(e)
|
|
344
|
+
} catch (e: ModuleDestroyedException) {
|
|
345
|
+
promise.reject(TAG, "MediaLibrary module destroyed", e)
|
|
346
|
+
}
|
|
332
347
|
}
|
|
333
|
-
}
|
|
334
348
|
|
|
335
349
|
private val isMissingPermissions: Boolean
|
|
336
350
|
get() = hasReadPermissions()
|
|
@@ -339,7 +353,10 @@ class MediaLibraryModule : Module() {
|
|
|
339
353
|
get() = hasWritePermissions()
|
|
340
354
|
|
|
341
355
|
@SuppressLint("InlinedApi")
|
|
342
|
-
private fun getManifestPermissions(
|
|
356
|
+
private fun getManifestPermissions(
|
|
357
|
+
writeOnly: Boolean,
|
|
358
|
+
granularPermissions: List<GranularPermission>
|
|
359
|
+
): Array<String> {
|
|
343
360
|
// ACCESS_MEDIA_LOCATION should not be requested if it's absent in android-manifest
|
|
344
361
|
// If only audio permission is requested, we don't need to request media location permissions
|
|
345
362
|
val shouldAddMediaLocationAccess =
|
|
@@ -347,7 +364,9 @@ class MediaLibraryModule : Module() {
|
|
|
347
364
|
MediaLibraryUtils.hasManifestPermission(context, ACCESS_MEDIA_LOCATION) &&
|
|
348
365
|
!(
|
|
349
366
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
|
|
350
|
-
granularPermissions.count() == 1 && granularPermissions.contains(
|
|
367
|
+
granularPermissions.count() == 1 && granularPermissions.contains(
|
|
368
|
+
GranularPermission.AUDIO
|
|
369
|
+
)
|
|
351
370
|
)
|
|
352
371
|
|
|
353
372
|
val shouldAddWriteExternalStorage =
|
|
@@ -356,7 +375,12 @@ class MediaLibraryModule : Module() {
|
|
|
356
375
|
|
|
357
376
|
val shouldAddGranularPermissions =
|
|
358
377
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
|
|
359
|
-
granularPermissions.all {
|
|
378
|
+
granularPermissions.all {
|
|
379
|
+
MediaLibraryUtils.hasManifestPermission(
|
|
380
|
+
context,
|
|
381
|
+
it.toManifestPermission()
|
|
382
|
+
)
|
|
383
|
+
}
|
|
360
384
|
|
|
361
385
|
val shouldIncludeGranular = shouldAddGranularPermissions && !writeOnly
|
|
362
386
|
return listOfNotNull(
|
|
@@ -368,7 +392,10 @@ class MediaLibraryModule : Module() {
|
|
|
368
392
|
}
|
|
369
393
|
|
|
370
394
|
@SuppressLint("InlinedApi")
|
|
371
|
-
private fun getGranularPermissions(
|
|
395
|
+
private fun getGranularPermissions(
|
|
396
|
+
shouldIncludeGranular: Boolean,
|
|
397
|
+
granularPermissions: List<GranularPermission>
|
|
398
|
+
): Array<String> {
|
|
372
399
|
return if (shouldIncludeGranular) {
|
|
373
400
|
listOfNotNull(
|
|
374
401
|
READ_MEDIA_IMAGES.takeIf { granularPermissions.contains(GranularPermission.PHOTO) },
|
|
@@ -381,9 +408,11 @@ class MediaLibraryModule : Module() {
|
|
|
381
408
|
}
|
|
382
409
|
|
|
383
410
|
private inline fun throwUnlessPermissionsGranted(isWrite: Boolean = true, block: () -> Unit) {
|
|
384
|
-
val missingPermissionsCondition =
|
|
411
|
+
val missingPermissionsCondition =
|
|
412
|
+
if (isWrite) isMissingWritePermission else isMissingPermissions
|
|
385
413
|
if (missingPermissionsCondition) {
|
|
386
|
-
val missingPermissionsMessage =
|
|
414
|
+
val missingPermissionsMessage =
|
|
415
|
+
if (isWrite) ERROR_NO_WRITE_PERMISSION_MESSAGE else ERROR_NO_PERMISSIONS_MESSAGE
|
|
387
416
|
throw PermissionsException(missingPermissionsMessage)
|
|
388
417
|
}
|
|
389
418
|
block()
|
|
@@ -395,7 +424,7 @@ class MediaLibraryModule : Module() {
|
|
|
395
424
|
|
|
396
425
|
private fun hasReadPermissions(): Boolean {
|
|
397
426
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
398
|
-
val permissions =
|
|
427
|
+
val permissions = allowedPermissionsList.map { it.toManifestPermission() }.toMutableList()
|
|
399
428
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
400
429
|
permissions.add(READ_MEDIA_VISUAL_USER_SELECTED)
|
|
401
430
|
}
|
|
@@ -413,6 +442,14 @@ class MediaLibraryModule : Module() {
|
|
|
413
442
|
}
|
|
414
443
|
}
|
|
415
444
|
|
|
445
|
+
private fun maybeThrowIfExpoGo(permissions: List<GranularPermission>) {
|
|
446
|
+
if (isExpoGo) {
|
|
447
|
+
if (permissions.contains(GranularPermission.PHOTO) || permissions.contains(GranularPermission.VIDEO)) {
|
|
448
|
+
throw PermissionsException("Due to changes in Androids permission requirements, Expo Go can no longer provide full access to the media library. To test the full functionality of this module, you can create a development build")
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
416
453
|
private fun hasWritePermissions() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
417
454
|
false
|
|
418
455
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaLibrary.d.ts","sourceRoot":"","sources":["../src/MediaLibrary.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,IAAI,oBAAoB,EAC1C,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EAGrB,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"MediaLibrary.d.ts","sourceRoot":"","sources":["../src/MediaLibrary.ts"],"names":[],"mappings":"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"}
|
package/build/MediaLibrary.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { PermissionStatus, createPermissionHook, UnavailabilityError, } from 'expo-modules-core';
|
|
2
2
|
import { Platform } from 'react-native';
|
|
3
3
|
import MediaLibrary from './ExpoMediaLibrary';
|
|
4
|
+
const isExpoGo = typeof expo !== 'undefined' && globalThis.expo?.modules?.ExpoGo;
|
|
5
|
+
let loggedExpoGoWarning = false;
|
|
6
|
+
if (isExpoGo && !loggedExpoGoWarning) {
|
|
7
|
+
console.warn('Due to changes in Androids permission requirements, Expo Go can no longer provide full access to the media library. To test the full functionality of this module, you can create a development build. https://docs.expo.dev/develop/development-builds/create-a-build');
|
|
8
|
+
loggedExpoGoWarning = true;
|
|
9
|
+
}
|
|
4
10
|
export { PermissionStatus, };
|
|
5
11
|
function arrayize(item) {
|
|
6
12
|
if (Array.isArray(item)) {
|
|
@@ -81,7 +87,7 @@ export async function isAvailableAsync() {
|
|
|
81
87
|
* effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.
|
|
82
88
|
* @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.
|
|
83
89
|
*/
|
|
84
|
-
export async function requestPermissionsAsync(writeOnly = false, granularPermissions
|
|
90
|
+
export async function requestPermissionsAsync(writeOnly = false, granularPermissions) {
|
|
85
91
|
if (!MediaLibrary.requestPermissionsAsync) {
|
|
86
92
|
throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync');
|
|
87
93
|
}
|
|
@@ -98,7 +104,7 @@ export async function requestPermissionsAsync(writeOnly = false, granularPermiss
|
|
|
98
104
|
* an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.
|
|
99
105
|
* @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.
|
|
100
106
|
*/
|
|
101
|
-
export async function getPermissionsAsync(writeOnly = false, granularPermissions
|
|
107
|
+
export async function getPermissionsAsync(writeOnly = false, granularPermissions) {
|
|
102
108
|
if (!MediaLibrary.getPermissionsAsync) {
|
|
103
109
|
throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync');
|
|
104
110
|
}
|
|
@@ -138,6 +144,9 @@ export const usePermissions = createPermissionHook({
|
|
|
138
144
|
* @platform ios
|
|
139
145
|
*/
|
|
140
146
|
export async function presentPermissionsPickerAsync(mediaTypes = ['photo', 'video']) {
|
|
147
|
+
if (Platform.OS === 'android' && isExpoGo) {
|
|
148
|
+
throw new UnavailabilityError('MediaLibrary', 'presentPermissionsPickerAsync is unavailable in Expo Go');
|
|
149
|
+
}
|
|
141
150
|
if (Platform.OS === 'android' && Platform.Version >= 34) {
|
|
142
151
|
await MediaLibrary.requestPermissionsAsync(false, mediaTypes);
|
|
143
152
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaLibrary.js","sourceRoot":"","sources":["../src/MediaLibrary.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n PermissionResponse as EXPermissionResponse,\n PermissionStatus,\n PermissionExpiration,\n PermissionHookOptions,\n createPermissionHook,\n UnavailabilityError,\n EventSubscription,\n} from 'expo-modules-core';\nimport { Platform } from 'react-native';\n\nimport MediaLibrary from './ExpoMediaLibrary';\n\n// @needsAudit\nexport type PermissionResponse = EXPermissionResponse & {\n /**\n * Indicates if your app has access to the whole or only part of the photo library. Possible values are:\n * - `'all'` if the user granted your app access to the whole photo library\n * - `'limited'` if the user granted your app access only to selected photos (only available on Android API 14+ and iOS 14.0+)\n * - `'none'` if user denied or hasn't yet granted the permission\n */\n accessPrivileges?: 'all' | 'limited' | 'none';\n};\n\n/**\n * Determines the type of media that the app will ask the OS to get access to.\n * @platform android 13+\n */\nexport type GranularPermission = 'audio' | 'photo' | 'video';\n\nexport type MediaTypeValue = 'audio' | 'photo' | 'video' | 'unknown' | 'pairedVideo';\n\n/**\n * Represents the possible types of media that the app will ask the OS to get access to when calling [`presentPermissionsPickerAsync()`](#medialibrarypresentpermissionspickerasyncmediatypes).\n * @platform android 14+\n * */\nexport type MediaTypeFilter = 'photo' | 'video';\n\nexport type SortByKey =\n | 'default'\n | 'mediaType'\n | 'width'\n | 'height'\n | 'creationTime'\n | 'modificationTime'\n | 'duration';\nexport type SortByValue = [SortByKey, boolean] | SortByKey;\n\nexport type MediaTypeObject = {\n audio: 'audio';\n photo: 'photo';\n video: 'video';\n unknown: 'unknown';\n};\n\nexport type SortByObject = {\n default: 'default';\n mediaType: 'mediaType';\n width: 'width';\n height: 'height';\n creationTime: 'creationTime';\n modificationTime: 'modificationTime';\n duration: 'duration';\n};\n\n// @needsAudit\nexport type Asset = {\n /**\n * Internal ID that represents an asset.\n */\n id: string;\n /**\n * Filename of the asset.\n */\n filename: string;\n /**\n * URI that points to the asset. `ph://*` (iOS), `file://*` (Android)\n */\n uri: string;\n /**\n * Media type.\n */\n mediaType: MediaTypeValue;\n /**\n * An array of media subtypes.\n * @platform ios\n */\n mediaSubtypes?: MediaSubtype[];\n /**\n * Width of the image or video.\n */\n width: number;\n /**\n * Height of the image or video.\n */\n height: number;\n /**\n * File creation timestamp.\n */\n creationTime: number;\n /**\n * Last modification timestamp.\n */\n modificationTime: number;\n /**\n * Duration of the video or audio asset in seconds.\n */\n duration: number;\n /**\n * Album ID that the asset belongs to.\n * @platform android\n */\n albumId?: string;\n};\n\n// @needsAudit\nexport type AssetInfo = Asset & {\n /**\n * Local URI for the asset.\n */\n localUri?: string;\n /**\n * GPS location if available.\n */\n location?: Location;\n /**\n * EXIF metadata associated with the image.\n */\n exif?: object;\n /**\n * Whether the asset is marked as favorite.\n * @platform ios\n */\n isFavorite?: boolean;\n /**\n * This field is available only if flag `shouldDownloadFromNetwork` is set to `false`.\n * Whether the asset is stored on the network (iCloud on iOS).\n * @platform ios\n */\n isNetworkAsset?: boolean; //iOS only\n /**\n * Display orientation of the image. Orientation is available only for assets whose\n * `mediaType` is `MediaType.photo`. Value will range from 1 to 8, see [EXIF orientation specification](http://sylvana.net/jpegcrop/exif_orientation.html)\n * for more details.\n * @platform ios\n */\n orientation?: number;\n /**\n * Contains information about the video paired with the image file.\n * This field is available if the `mediaType` is `\"photo\"`, and the `mediaSubtypes` includes `\"livePhoto\"`.\n * @platform ios\n */\n pairedVideoAsset?: Asset | null;\n};\n\n/**\n * Constants identifying specific variations of asset media, such as panorama or screenshot photos,\n * and time-lapse or high-frame-rate video. Maps to [these values](https://developer.apple.com/documentation/photokit/phassetmediasubtype#1603888).\n * */\nexport type MediaSubtype =\n | 'depthEffect'\n | 'hdr'\n | 'highFrameRate'\n | 'livePhoto'\n | 'panorama'\n | 'screenshot'\n | 'stream'\n | 'timelapse';\n\n// @needsAudit\nexport type MediaLibraryAssetInfoQueryOptions = {\n /**\n * Whether allow the asset to be downloaded from network. Only available in iOS with iCloud assets.\n * @default true\n */\n shouldDownloadFromNetwork?: boolean;\n};\n\n// @needsAudit\nexport type MediaLibraryAssetsChangeEvent = {\n /**\n * Whether the media library's changes could be described as \"incremental changes\".\n * `true` indicates the changes are described by the `insertedAssets`, `deletedAssets` and\n * `updatedAssets` values. `false` indicates that the scope of changes is too large and you\n * should perform a full assets reload (eg. a user has changed access to individual assets in the\n * media library).\n */\n hasIncrementalChanges: boolean;\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been inserted to the library.\n */\n insertedAssets?: Asset[];\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been deleted from the library.\n */\n deletedAssets?: Asset[];\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been updated or completed downloading from network\n * storage (iCloud on iOS).\n */\n updatedAssets?: Asset[];\n};\n\n// @docsMissing\nexport type Location = {\n latitude: number;\n longitude: number;\n};\n\n// @needsAudit\nexport type Album = {\n /**\n * Album ID.\n */\n id: string;\n /**\n * Album title.\n */\n title: string;\n /**\n * Estimated number of assets in the album.\n */\n assetCount: number;\n /**\n * The type of the assets album.\n * @platform ios\n */\n type?: AlbumType;\n /**\n * Apply only to albums whose type is `'moment'`. Earliest creation timestamp of all\n * assets in the moment.\n * @platform ios\n */\n startTime: number;\n /**\n * Apply only to albums whose type is `'moment'`. Latest creation timestamp of all\n * assets in the moment.\n * @platform ios\n */\n endTime: number;\n /**\n * Apply only to albums whose type is `'moment'`. Approximated location of all\n * assets in the moment.\n * @platform ios\n */\n approximateLocation?: Location;\n /**\n * Apply only to albums whose type is `'moment'`. Names of locations grouped\n * in the moment.\n * @platform ios\n */\n locationNames?: string[];\n};\n\n// @docsMissing\nexport type AlbumType = 'album' | 'moment' | 'smartAlbum';\n\n// @docsMissing\nexport type AlbumsOptions = {\n includeSmartAlbums?: boolean;\n};\n\n// @needsAudit\nexport type AssetsOptions = {\n /**\n * The maximum number of items on a single page.\n * @default 20\n */\n first?: number;\n /**\n * Asset ID of the last item returned on the previous page. To get the ID of the next page,\n * pass [`endCursor`](#pagedinfo) as its value.\n */\n after?: AssetRef;\n /**\n * [Album](#album) or its ID to get assets from specific album.\n */\n album?: AlbumRef;\n /**\n * An array of [`SortByValue`](#sortbyvalue)s or a single `SortByValue` value. By default, all\n * keys are sorted in descending order, however you can also pass a pair `[key, ascending]` where\n * the second item is a `boolean` value that means whether to use ascending order. Note that if\n * the `SortBy.default` key is used, then `ascending` argument will not matter. Earlier items have\n * higher priority when sorting out the results.\n * If empty, this method uses the default sorting that is provided by the platform.\n */\n sortBy?: SortByValue[] | SortByValue;\n /**\n * An array of [MediaTypeValue](#mediatypevalue)s or a single `MediaTypeValue`.\n * @default MediaType.photo\n */\n mediaType?: MediaTypeValue[] | MediaTypeValue;\n /**\n * `Date` object or Unix timestamp in milliseconds limiting returned assets only to those that\n * were created after this date.\n */\n createdAfter?: Date | number;\n /**\n * Similarly as `createdAfter`, but limits assets only to those that were created before specified\n * date.\n */\n createdBefore?: Date | number;\n};\n\n// @needsAudit\nexport type PagedInfo<T> = {\n /**\n * A page of [`Asset`](#asset)s fetched by the query.\n */\n assets: T[];\n /**\n * ID of the last fetched asset. It should be passed as `after` option in order to get the\n * next page.\n */\n endCursor: string;\n /**\n * Whether there are more assets to fetch.\n */\n hasNextPage: boolean;\n /**\n * Estimated total number of assets that match the query.\n */\n totalCount: number;\n};\n\n// @docsMissing\nexport type AssetRef = Asset | string;\n\n// @docsMissing\nexport type AlbumRef = Album | string;\n\nexport {\n PermissionStatus,\n PermissionExpiration,\n EXPermissionResponse,\n PermissionHookOptions,\n EventSubscription as Subscription,\n};\n\nfunction arrayize(item: any): any[] {\n if (Array.isArray(item)) {\n return item;\n }\n return item ? [item] : [];\n}\n\nfunction getId(ref: any): string | undefined {\n if (typeof ref === 'string') {\n return ref;\n }\n return ref ? ref.id : undefined;\n}\n\nfunction checkAssetIds(assetIds: any): void {\n if (assetIds.some((id) => !id || typeof id !== 'string')) {\n throw new Error('Asset ID must be a string!');\n }\n}\n\nfunction checkAlbumIds(albumIds: any): void {\n if (albumIds.some((id) => !id || typeof id !== 'string')) {\n throw new Error('Album ID must be a string!');\n }\n}\n\nfunction checkMediaType(mediaType: any): void {\n if (Object.values(MediaType).indexOf(mediaType) === -1) {\n throw new Error(`Invalid mediaType: ${mediaType}`);\n }\n}\n\nfunction checkSortBy(sortBy: any): void {\n if (Array.isArray(sortBy)) {\n checkSortByKey(sortBy[0]);\n\n if (typeof sortBy[1] !== 'boolean') {\n throw new Error('Invalid sortBy array argument. Second item must be a boolean!');\n }\n } else {\n checkSortByKey(sortBy);\n }\n}\n\nfunction checkSortByKey(sortBy: any): void {\n if (Object.values(SortBy).indexOf(sortBy) === -1) {\n throw new Error(`Invalid sortBy key: ${sortBy}`);\n }\n}\n\nfunction sortByOptionToString(sortBy: any) {\n if (Array.isArray(sortBy)) {\n return `${sortBy[0]} ${sortBy[1] ? 'ASC' : 'DESC'}`;\n }\n return `${sortBy} DESC`;\n}\n\nfunction dateToNumber(value?: Date | number): number | undefined {\n return value instanceof Date ? value.getTime() : value;\n}\n\n// @needsAudit\n/**\n * Possible media types.\n */\nexport const MediaType: MediaTypeObject = MediaLibrary.MediaType;\n\n// @needsAudit\n/**\n * Supported keys that can be used to sort `getAssetsAsync` results.\n */\nexport const SortBy: SortByObject = MediaLibrary.SortBy;\n\n// @needsAudit\n/**\n * Returns whether the Media Library API is enabled on the current device.\n * @return A promise which fulfils with a `boolean`, indicating whether the Media Library API is\n * available on the current device.\n */\nexport async function isAvailableAsync(): Promise<boolean> {\n return !!MediaLibrary && 'getAssetsAsync' in MediaLibrary;\n}\n\n// @needsAudit @docsMissing\n/**\n * Asks the user to grant permissions for accessing media in user's media library.\n * @param writeOnly\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an\n * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function requestPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions: GranularPermission[] = ['audio', 'photo', 'video']\n): Promise<PermissionResponse> {\n if (!MediaLibrary.requestPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await MediaLibrary.requestPermissionsAsync(writeOnly, granularPermissions);\n }\n return await MediaLibrary.requestPermissionsAsync(writeOnly);\n}\n\n// @needsAudit @docsMissing\n/**\n * Checks user's permissions for accessing media library.\n * @param writeOnly\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has\n * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function getPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions: GranularPermission[] = ['audio', 'photo', 'video']\n): Promise<PermissionResponse> {\n if (!MediaLibrary.getPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await MediaLibrary.getPermissionsAsync(writeOnly, granularPermissions);\n }\n return await MediaLibrary.getPermissionsAsync(writeOnly);\n}\n\n// @needsAudit\n/**\n * Check or request permissions to access the media library.\n * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions();\n * ```\n */\nexport const usePermissions = createPermissionHook<\n PermissionResponse,\n { writeOnly?: boolean; granularPermissions?: GranularPermission[] }\n>({\n // TODO(cedric): permission requesters should have an options param or a different requester\n getMethod: (options) => getPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n requestMethod: (options) =>\n requestPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n});\n\n// @needsAudit\n/**\n * Allows the user to update the assets that your app has access to.\n * The system modal is only displayed if the user originally allowed only `limited` access to their\n * media library, otherwise this method is a no-op.\n * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented.\n *\n * @return A promise that either rejects if the method is unavailable, or resolves to `void`.\n * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to.\n * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener).\n * If `hasIncrementalChanges` is `false`, the user changed their permissions.\n *\n * @platform android 14+\n * @platform ios\n */\nexport async function presentPermissionsPickerAsync(\n mediaTypes: MediaTypeFilter[] = ['photo', 'video']\n): Promise<void> {\n if (Platform.OS === 'android' && Platform.Version >= 34) {\n await MediaLibrary.requestPermissionsAsync(false, mediaTypes);\n return;\n }\n if (!MediaLibrary.presentPermissionsPickerAsync) {\n throw new UnavailabilityError('MediaLibrary', 'presentPermissionsPickerAsync');\n }\n return await MediaLibrary.presentPermissionsPickerAsync();\n}\n\n// @needsAudit\n/**\n * Creates an asset from existing file. The most common use case is to save a picture taken by [Camera](./camera).\n * This method requires `CAMERA_ROLL` permission.\n *\n * @example\n * ```js\n * const { uri } = await Camera.takePictureAsync();\n * const asset = await MediaLibrary.createAssetAsync(uri);\n * ```\n * @param localUri A URI to the image or video file. It must contain an extension. On Android it\n * must be a local path, so it must start with `file:///`\n * @return A promise which fulfils with an object representing an [`Asset`](#asset).\n */\nexport async function createAssetAsync(localUri: string): Promise<Asset> {\n if (!MediaLibrary.createAssetAsync) {\n throw new UnavailabilityError('MediaLibrary', 'createAssetAsync');\n }\n\n if (!localUri || typeof localUri !== 'string') {\n throw new Error('Invalid argument \"localUri\". It must be a string!');\n }\n const asset = await MediaLibrary.createAssetAsync(localUri);\n\n if (Array.isArray(asset)) {\n // Android returns an array with asset, we need to pick the first item\n return asset[0];\n }\n return asset;\n}\n\n// @needsAudit\n/**\n * Saves the file at given `localUri` to the user's media library. Unlike [`createAssetAsync()`](#medialibrarycreateassetasynclocaluri),\n * This method doesn't return created asset.\n * On __iOS 11+__, it's possible to use this method without asking for `CAMERA_ROLL` permission,\n * however then yours `Info.plist` should have `NSPhotoLibraryAddUsageDescription` key.\n * @param localUri A URI to the image or video file. It must contain an extension. On Android it\n * must be a local path, so it must start with `file:///`.\n */\nexport async function saveToLibraryAsync(localUri: string): Promise<void> {\n if (!MediaLibrary.saveToLibraryAsync) {\n throw new UnavailabilityError('MediaLibrary', 'saveToLibraryAsync');\n }\n return await MediaLibrary.saveToLibraryAsync(localUri);\n}\n\n// @needsAudit\n/**\n * Adds array of assets to the album.\n *\n * On Android, by default it copies assets from the current album to provided one, however it's also\n * possible to move them by passing `false` as `copyAssets` argument. In case they're copied you\n * should keep in mind that `getAssetsAsync` will return duplicated assets.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @param album An [Album](#album) or its ID.\n * @param copy __Android only.__ Whether to copy assets to the new album instead of move them.\n * Defaults to `true`.\n * @return Returns promise which fulfils with `true` if the assets were successfully added to\n * the album.\n */\nexport async function addAssetsToAlbumAsync(\n assets: AssetRef[] | AssetRef,\n album: AlbumRef,\n copy: boolean = true\n): Promise<boolean> {\n if (!MediaLibrary.addAssetsToAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'addAssetsToAlbumAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n const albumId = getId(album);\n\n checkAssetIds(assetIds);\n\n if (!albumId || typeof albumId !== 'string') {\n throw new Error('Invalid album ID. It must be a string!');\n }\n\n if (Platform.OS === 'ios') {\n return await MediaLibrary.addAssetsToAlbumAsync(assetIds, albumId);\n }\n return await MediaLibrary.addAssetsToAlbumAsync(assetIds, albumId, !!copy);\n}\n\n// @needsAudit\n/**\n * Removes given assets from album.\n *\n * On Android, album will be automatically deleted if there are no more assets inside.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @param album An [Album](#album) or its ID.\n * @return Returns promise which fulfils with `true` if the assets were successfully removed from\n * the album.\n */\nexport async function removeAssetsFromAlbumAsync(\n assets: AssetRef[] | AssetRef,\n album: AlbumRef\n): Promise<boolean> {\n if (!MediaLibrary.removeAssetsFromAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'removeAssetsFromAlbumAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n const albumId = getId(album);\n\n checkAssetIds(assetIds);\n return await MediaLibrary.removeAssetsFromAlbumAsync(assetIds, albumId);\n}\n\n// @needsAudit\n/**\n * Deletes assets from the library. On iOS it deletes assets from all albums they belong to, while\n * on Android it keeps all copies of them (album is strictly connected to the asset). Also, there is\n * additional dialog on iOS that requires user to confirm this action.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @return Returns promise which fulfils with `true` if the assets were successfully deleted.\n */\nexport async function deleteAssetsAsync(assets: AssetRef[] | AssetRef): Promise<boolean> {\n if (!MediaLibrary.deleteAssetsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'deleteAssetsAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n\n checkAssetIds(assetIds);\n return await MediaLibrary.deleteAssetsAsync(assetIds);\n}\n\n// @needsAudit\n/**\n * Provides more information about an asset, including GPS location, local URI and EXIF metadata.\n * @param asset An [Asset](#asset) or its ID.\n * @param options\n * @return An [AssetInfo](#assetinfo) object, which is an `Asset` extended by an additional fields.\n */\nexport async function getAssetInfoAsync(\n asset: AssetRef,\n options: MediaLibraryAssetInfoQueryOptions = { shouldDownloadFromNetwork: true }\n): Promise<AssetInfo> {\n if (!MediaLibrary.getAssetInfoAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAssetInfoAsync');\n }\n\n const assetId = getId(asset);\n\n checkAssetIds([assetId]);\n\n const assetInfo = await MediaLibrary.getAssetInfoAsync(assetId, options);\n\n if (Array.isArray(assetInfo)) {\n // Android returns an array with asset info, we need to pick the first item\n return assetInfo[0];\n }\n return assetInfo;\n}\n\n// @needsAudit\n/**\n * Queries for user-created albums in media gallery.\n * @return A promise which fulfils with an array of [`Album`](#asset)s. Depending on Android version,\n * root directory of your storage may be listed as album titled `\"0\"` or unlisted at all.\n */\nexport async function getAlbumsAsync({ includeSmartAlbums = false }: AlbumsOptions = {}): Promise<\n Album[]\n> {\n if (!MediaLibrary.getAlbumsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAlbumsAsync');\n }\n return await MediaLibrary.getAlbumsAsync({ includeSmartAlbums });\n}\n\n// @needsAudit\n/**\n * Queries for an album with a specific name.\n * @param title Name of the album to look for.\n * @return An object representing an [`Album`](#album), if album with given name exists, otherwise\n * returns `null`.\n */\nexport async function getAlbumAsync(title: string): Promise<Album> {\n if (!MediaLibrary.getAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAlbumAsync');\n }\n if (typeof title !== 'string') {\n throw new Error('Album title must be a string!');\n }\n return await MediaLibrary.getAlbumAsync(title);\n}\n\n// @needsAudit\n/**\n * Creates an album with given name and initial asset. The asset parameter is required on Android,\n * since it's not possible to create empty album on this platform. On Android, by default it copies\n * given asset from the current album to the new one, however it's also possible to move it by\n * passing `false` as `copyAsset` argument.\n * In case it's copied you should keep in mind that `getAssetsAsync` will return duplicated asset.\n * @param albumName Name of the album to create.\n * @param asset An [Asset](#asset) or its ID (required on Android).\n * @param copyAsset __Android Only.__ Whether to copy asset to the new album instead of move it.\n * Defaults to `true`.\n * @return Newly created [`Album`](#album).\n */\nexport async function createAlbumAsync(\n albumName: string,\n asset?: AssetRef,\n copyAsset: boolean = true\n): Promise<Album> {\n if (!MediaLibrary.createAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'createAlbumAsync');\n }\n\n const assetId = getId(asset);\n\n if (Platform.OS === 'android' && (typeof assetId !== 'string' || assetId.length === 0)) {\n // it's not possible to create empty album on Android, so initial asset must be provided\n throw new Error('MediaLibrary.createAlbumAsync must be called with an asset on Android.');\n }\n if (!albumName || typeof albumName !== 'string') {\n throw new Error('Invalid argument \"albumName\". It must be a string!');\n }\n if (assetId != null && typeof assetId !== 'string') {\n throw new Error('Asset ID must be a string!');\n }\n\n if (Platform.OS === 'ios') {\n return await MediaLibrary.createAlbumAsync(albumName, assetId);\n }\n return await MediaLibrary.createAlbumAsync(albumName, assetId, !!copyAsset);\n}\n\n// @needsAudit\n/**\n * Deletes given albums from the library. On Android by default it deletes assets belonging to given\n * albums from the library. On iOS it doesn't delete these assets, however it's possible to do by\n * passing `true` as `deleteAssets`.\n * @param albums An array of [`Album`](#asset)s or their IDs.\n * @param assetRemove __iOS Only.__ Whether to also delete assets belonging to given albums.\n * Defaults to `false`.\n * @return Returns a promise which fulfils with `true` if the albums were successfully deleted from\n * the library.\n */\nexport async function deleteAlbumsAsync(\n albums: AlbumRef[] | AlbumRef,\n assetRemove: boolean = false\n): Promise<boolean> {\n if (!MediaLibrary.deleteAlbumsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'deleteAlbumsAsync');\n }\n\n const albumIds = arrayize(albums).map(getId);\n\n checkAlbumIds(albumIds);\n if (Platform.OS === 'android') {\n return await MediaLibrary.deleteAlbumsAsync(albumIds);\n }\n return await MediaLibrary.deleteAlbumsAsync(albumIds, !!assetRemove);\n}\n\n// @needsAudit\n/**\n * Fetches a page of assets matching the provided criteria.\n * @param assetsOptions\n * @return A promise that fulfils with to [`PagedInfo`](#pagedinfo) object with array of [`Asset`](#asset)s.\n */\nexport async function getAssetsAsync(assetsOptions: AssetsOptions = {}): Promise<PagedInfo<Asset>> {\n if (!MediaLibrary.getAssetsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAssetsAsync');\n }\n\n const { first, after, album, sortBy, mediaType, createdAfter, createdBefore } = assetsOptions;\n\n const options = {\n first: first == null ? 20 : first,\n after: getId(after),\n album: getId(album),\n sortBy: arrayize(sortBy),\n mediaType: arrayize(mediaType || [MediaType.photo]),\n createdAfter: dateToNumber(createdAfter),\n createdBefore: dateToNumber(createdBefore),\n };\n\n if (first != null && typeof options.first !== 'number') {\n throw new Error('Option \"first\" must be a number!');\n }\n if (after != null && typeof options.after !== 'string') {\n throw new Error('Option \"after\" must be a string!');\n }\n if (album != null && typeof options.album !== 'string') {\n throw new Error('Option \"album\" must be a string!');\n }\n\n if (after != null && Platform.OS === 'android' && isNaN(parseInt(getId(after) as string, 10))) {\n throw new Error('Option \"after\" must be a valid ID!');\n }\n\n if (first != null && first < 0) {\n throw new Error('Option \"first\" must be a positive integer!');\n }\n\n options.sortBy.forEach(checkSortBy);\n options.mediaType.forEach(checkMediaType);\n options.sortBy = options.sortBy.map(sortByOptionToString);\n\n return await MediaLibrary.getAssetsAsync(options);\n}\n\n// @needsAudit\n/**\n * Subscribes for updates in user's media library.\n * @param listener A callback that is fired when any assets have been inserted or deleted from the\n * library. On Android it's invoked with an empty object. On iOS, it's invoked with [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent)\n * object.\n *\n * Additionally, only on iOS, the listener is also invoked when the user changes access to individual assets in the media library\n * using `presentPermissionsPickerAsync()`.\n * @return An [`Subscription`](#subscription) object that you can call `remove()` on when you would\n * like to unsubscribe the listener.\n */\nexport function addListener(\n listener: (event: MediaLibraryAssetsChangeEvent) => void\n): EventSubscription {\n return MediaLibrary.addListener(MediaLibrary.CHANGE_LISTENER_NAME, listener);\n}\n\n// @docsMissing\nexport function removeSubscription(subscription: EventSubscription): void {\n subscription.remove();\n}\n\n// @needsAudit\n/**\n * Removes all listeners.\n */\nexport function removeAllListeners(): void {\n MediaLibrary.removeAllListeners(MediaLibrary.CHANGE_LISTENER_NAME);\n}\n\n// @needsAudit\n/**\n * Fetches a list of moments, which is a group of assets taken around the same place\n * and time.\n * @return An array of [albums](#album) whose type is `moment`.\n * @platform ios\n */\nexport async function getMomentsAsync() {\n if (!MediaLibrary.getMomentsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getMomentsAsync');\n }\n\n return await MediaLibrary.getMomentsAsync();\n}\n\n// @needsAudit\n/**\n * Moves album content to the special media directories on **Android R** or **above** if needed.\n * Those new locations are in line with the Android `scoped storage` - so your application won't\n * lose write permission to those directories in the future.\n *\n * This method does nothing if:\n * - app is running on **iOS**, **web** or **Android below R**\n * - app has **write permission** to the album folder\n *\n * The migration is possible when the album contains only compatible files types.\n * For instance, movies and pictures are compatible with each other, but music and pictures are not.\n * If automatic migration isn't possible, the function rejects.\n * In that case, you can use methods from the `expo-file-system` to migrate all your files manually.\n *\n * # Why do you need to migrate files?\n * __Android R__ introduced a lot of changes in the storage system. Now applications can't save\n * anything to the root directory. The only available locations are from the `MediaStore` API.\n * Unfortunately, the media library stored albums in folders for which, because of those changes,\n * the application doesn't have permissions anymore. However, it doesn't mean you need to migrate\n * all your albums. If your application doesn't add assets to albums, you don't have to migrate.\n * Everything will work as it used to. You can read more about scoped storage in [the Android documentation](https://developer.android.com/about/versions/11/privacy/storage).\n *\n * @param album An [Album](#album) or its ID.\n * @return A promise which fulfils to `void`.\n */\nexport async function migrateAlbumIfNeededAsync(album: AlbumRef): Promise<void> {\n if (!MediaLibrary.migrateAlbumIfNeededAsync) {\n return;\n }\n\n return await MediaLibrary.migrateAlbumIfNeededAsync(getId(album));\n}\n\n// @needsAudit\n/**\n * Checks if the album should be migrated to a different location. In other words, it checks if the\n * application has the write permission to the album folder. If not, it returns `true`, otherwise `false`.\n * > Note: For **Android below R**, **web** or **iOS**, this function always returns `false`.\n * @param album An [Album](#album) or its ID.\n * @return Returns a promise which fulfils with `true` if the album should be migrated.\n */\nexport async function albumNeedsMigrationAsync(album: AlbumRef): Promise<boolean> {\n if (!MediaLibrary.albumNeedsMigrationAsync) {\n return false;\n }\n\n return await MediaLibrary.albumNeedsMigrationAsync(getId(album));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MediaLibrary.js","sourceRoot":"","sources":["../src/MediaLibrary.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n PermissionResponse as EXPermissionResponse,\n PermissionStatus,\n PermissionExpiration,\n PermissionHookOptions,\n createPermissionHook,\n UnavailabilityError,\n EventSubscription,\n} from 'expo-modules-core';\nimport { Platform } from 'react-native';\n\nimport MediaLibrary from './ExpoMediaLibrary';\n\nconst isExpoGo = typeof expo !== 'undefined' && globalThis.expo?.modules?.ExpoGo;\n\nlet loggedExpoGoWarning = false;\n\nif (isExpoGo && !loggedExpoGoWarning) {\n console.warn(\n 'Due to changes in Androids permission requirements, Expo Go can no longer provide full access to the media library. To test the full functionality of this module, you can create a development build. https://docs.expo.dev/develop/development-builds/create-a-build'\n );\n loggedExpoGoWarning = true;\n}\n\n// @needsAudit\nexport type PermissionResponse = EXPermissionResponse & {\n /**\n * Indicates if your app has access to the whole or only part of the photo library. Possible values are:\n * - `'all'` if the user granted your app access to the whole photo library\n * - `'limited'` if the user granted your app access only to selected photos (only available on Android API 14+ and iOS 14.0+)\n * - `'none'` if user denied or hasn't yet granted the permission\n */\n accessPrivileges?: 'all' | 'limited' | 'none';\n};\n\n/**\n * Determines the type of media that the app will ask the OS to get access to.\n * @platform android 13+\n */\nexport type GranularPermission = 'audio' | 'photo' | 'video';\n\nexport type MediaTypeValue = 'audio' | 'photo' | 'video' | 'unknown' | 'pairedVideo';\n\n/**\n * Represents the possible types of media that the app will ask the OS to get access to when calling [`presentPermissionsPickerAsync()`](#medialibrarypresentpermissionspickerasyncmediatypes).\n * @platform android 14+\n * */\nexport type MediaTypeFilter = 'photo' | 'video';\n\nexport type SortByKey =\n | 'default'\n | 'mediaType'\n | 'width'\n | 'height'\n | 'creationTime'\n | 'modificationTime'\n | 'duration';\nexport type SortByValue = [SortByKey, boolean] | SortByKey;\n\nexport type MediaTypeObject = {\n audio: 'audio';\n photo: 'photo';\n video: 'video';\n unknown: 'unknown';\n};\n\nexport type SortByObject = {\n default: 'default';\n mediaType: 'mediaType';\n width: 'width';\n height: 'height';\n creationTime: 'creationTime';\n modificationTime: 'modificationTime';\n duration: 'duration';\n};\n\n// @needsAudit\nexport type Asset = {\n /**\n * Internal ID that represents an asset.\n */\n id: string;\n /**\n * Filename of the asset.\n */\n filename: string;\n /**\n * URI that points to the asset. `ph://*` (iOS), `file://*` (Android)\n */\n uri: string;\n /**\n * Media type.\n */\n mediaType: MediaTypeValue;\n /**\n * An array of media subtypes.\n * @platform ios\n */\n mediaSubtypes?: MediaSubtype[];\n /**\n * Width of the image or video.\n */\n width: number;\n /**\n * Height of the image or video.\n */\n height: number;\n /**\n * File creation timestamp.\n */\n creationTime: number;\n /**\n * Last modification timestamp.\n */\n modificationTime: number;\n /**\n * Duration of the video or audio asset in seconds.\n */\n duration: number;\n /**\n * Album ID that the asset belongs to.\n * @platform android\n */\n albumId?: string;\n};\n\n// @needsAudit\nexport type AssetInfo = Asset & {\n /**\n * Local URI for the asset.\n */\n localUri?: string;\n /**\n * GPS location if available.\n */\n location?: Location;\n /**\n * EXIF metadata associated with the image.\n */\n exif?: object;\n /**\n * Whether the asset is marked as favorite.\n * @platform ios\n */\n isFavorite?: boolean;\n /**\n * This field is available only if flag `shouldDownloadFromNetwork` is set to `false`.\n * Whether the asset is stored on the network (iCloud on iOS).\n * @platform ios\n */\n isNetworkAsset?: boolean; //iOS only\n /**\n * Display orientation of the image. Orientation is available only for assets whose\n * `mediaType` is `MediaType.photo`. Value will range from 1 to 8, see [EXIF orientation specification](http://sylvana.net/jpegcrop/exif_orientation.html)\n * for more details.\n * @platform ios\n */\n orientation?: number;\n /**\n * Contains information about the video paired with the image file.\n * This field is available if the `mediaType` is `\"photo\"`, and the `mediaSubtypes` includes `\"livePhoto\"`.\n * @platform ios\n */\n pairedVideoAsset?: Asset | null;\n};\n\n/**\n * Constants identifying specific variations of asset media, such as panorama or screenshot photos,\n * and time-lapse or high-frame-rate video. Maps to [these values](https://developer.apple.com/documentation/photokit/phassetmediasubtype#1603888).\n * */\nexport type MediaSubtype =\n | 'depthEffect'\n | 'hdr'\n | 'highFrameRate'\n | 'livePhoto'\n | 'panorama'\n | 'screenshot'\n | 'stream'\n | 'timelapse';\n\n// @needsAudit\nexport type MediaLibraryAssetInfoQueryOptions = {\n /**\n * Whether allow the asset to be downloaded from network. Only available in iOS with iCloud assets.\n * @default true\n */\n shouldDownloadFromNetwork?: boolean;\n};\n\n// @needsAudit\nexport type MediaLibraryAssetsChangeEvent = {\n /**\n * Whether the media library's changes could be described as \"incremental changes\".\n * `true` indicates the changes are described by the `insertedAssets`, `deletedAssets` and\n * `updatedAssets` values. `false` indicates that the scope of changes is too large and you\n * should perform a full assets reload (eg. a user has changed access to individual assets in the\n * media library).\n */\n hasIncrementalChanges: boolean;\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been inserted to the library.\n */\n insertedAssets?: Asset[];\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been deleted from the library.\n */\n deletedAssets?: Asset[];\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been updated or completed downloading from network\n * storage (iCloud on iOS).\n */\n updatedAssets?: Asset[];\n};\n\n// @docsMissing\nexport type Location = {\n latitude: number;\n longitude: number;\n};\n\n// @needsAudit\nexport type Album = {\n /**\n * Album ID.\n */\n id: string;\n /**\n * Album title.\n */\n title: string;\n /**\n * Estimated number of assets in the album.\n */\n assetCount: number;\n /**\n * The type of the assets album.\n * @platform ios\n */\n type?: AlbumType;\n /**\n * Apply only to albums whose type is `'moment'`. Earliest creation timestamp of all\n * assets in the moment.\n * @platform ios\n */\n startTime: number;\n /**\n * Apply only to albums whose type is `'moment'`. Latest creation timestamp of all\n * assets in the moment.\n * @platform ios\n */\n endTime: number;\n /**\n * Apply only to albums whose type is `'moment'`. Approximated location of all\n * assets in the moment.\n * @platform ios\n */\n approximateLocation?: Location;\n /**\n * Apply only to albums whose type is `'moment'`. Names of locations grouped\n * in the moment.\n * @platform ios\n */\n locationNames?: string[];\n};\n\n// @docsMissing\nexport type AlbumType = 'album' | 'moment' | 'smartAlbum';\n\n// @docsMissing\nexport type AlbumsOptions = {\n includeSmartAlbums?: boolean;\n};\n\n// @needsAudit\nexport type AssetsOptions = {\n /**\n * The maximum number of items on a single page.\n * @default 20\n */\n first?: number;\n /**\n * Asset ID of the last item returned on the previous page. To get the ID of the next page,\n * pass [`endCursor`](#pagedinfo) as its value.\n */\n after?: AssetRef;\n /**\n * [Album](#album) or its ID to get assets from specific album.\n */\n album?: AlbumRef;\n /**\n * An array of [`SortByValue`](#sortbyvalue)s or a single `SortByValue` value. By default, all\n * keys are sorted in descending order, however you can also pass a pair `[key, ascending]` where\n * the second item is a `boolean` value that means whether to use ascending order. Note that if\n * the `SortBy.default` key is used, then `ascending` argument will not matter. Earlier items have\n * higher priority when sorting out the results.\n * If empty, this method uses the default sorting that is provided by the platform.\n */\n sortBy?: SortByValue[] | SortByValue;\n /**\n * An array of [MediaTypeValue](#mediatypevalue)s or a single `MediaTypeValue`.\n * @default MediaType.photo\n */\n mediaType?: MediaTypeValue[] | MediaTypeValue;\n /**\n * `Date` object or Unix timestamp in milliseconds limiting returned assets only to those that\n * were created after this date.\n */\n createdAfter?: Date | number;\n /**\n * Similarly as `createdAfter`, but limits assets only to those that were created before specified\n * date.\n */\n createdBefore?: Date | number;\n};\n\n// @needsAudit\nexport type PagedInfo<T> = {\n /**\n * A page of [`Asset`](#asset)s fetched by the query.\n */\n assets: T[];\n /**\n * ID of the last fetched asset. It should be passed as `after` option in order to get the\n * next page.\n */\n endCursor: string;\n /**\n * Whether there are more assets to fetch.\n */\n hasNextPage: boolean;\n /**\n * Estimated total number of assets that match the query.\n */\n totalCount: number;\n};\n\n// @docsMissing\nexport type AssetRef = Asset | string;\n\n// @docsMissing\nexport type AlbumRef = Album | string;\n\nexport {\n PermissionStatus,\n PermissionExpiration,\n EXPermissionResponse,\n PermissionHookOptions,\n EventSubscription as Subscription,\n};\n\nfunction arrayize(item: any): any[] {\n if (Array.isArray(item)) {\n return item;\n }\n return item ? [item] : [];\n}\n\nfunction getId(ref: any): string | undefined {\n if (typeof ref === 'string') {\n return ref;\n }\n return ref ? ref.id : undefined;\n}\n\nfunction checkAssetIds(assetIds: any): void {\n if (assetIds.some((id) => !id || typeof id !== 'string')) {\n throw new Error('Asset ID must be a string!');\n }\n}\n\nfunction checkAlbumIds(albumIds: any): void {\n if (albumIds.some((id) => !id || typeof id !== 'string')) {\n throw new Error('Album ID must be a string!');\n }\n}\n\nfunction checkMediaType(mediaType: any): void {\n if (Object.values(MediaType).indexOf(mediaType) === -1) {\n throw new Error(`Invalid mediaType: ${mediaType}`);\n }\n}\n\nfunction checkSortBy(sortBy: any): void {\n if (Array.isArray(sortBy)) {\n checkSortByKey(sortBy[0]);\n\n if (typeof sortBy[1] !== 'boolean') {\n throw new Error('Invalid sortBy array argument. Second item must be a boolean!');\n }\n } else {\n checkSortByKey(sortBy);\n }\n}\n\nfunction checkSortByKey(sortBy: any): void {\n if (Object.values(SortBy).indexOf(sortBy) === -1) {\n throw new Error(`Invalid sortBy key: ${sortBy}`);\n }\n}\n\nfunction sortByOptionToString(sortBy: any) {\n if (Array.isArray(sortBy)) {\n return `${sortBy[0]} ${sortBy[1] ? 'ASC' : 'DESC'}`;\n }\n return `${sortBy} DESC`;\n}\n\nfunction dateToNumber(value?: Date | number): number | undefined {\n return value instanceof Date ? value.getTime() : value;\n}\n\n// @needsAudit\n/**\n * Possible media types.\n */\nexport const MediaType: MediaTypeObject = MediaLibrary.MediaType;\n\n// @needsAudit\n/**\n * Supported keys that can be used to sort `getAssetsAsync` results.\n */\nexport const SortBy: SortByObject = MediaLibrary.SortBy;\n\n// @needsAudit\n/**\n * Returns whether the Media Library API is enabled on the current device.\n * @return A promise which fulfils with a `boolean`, indicating whether the Media Library API is\n * available on the current device.\n */\nexport async function isAvailableAsync(): Promise<boolean> {\n return !!MediaLibrary && 'getAssetsAsync' in MediaLibrary;\n}\n\n// @needsAudit @docsMissing\n/**\n * Asks the user to grant permissions for accessing media in user's media library.\n * @param writeOnly\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an\n * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function requestPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions?: GranularPermission[]\n): Promise<PermissionResponse> {\n if (!MediaLibrary.requestPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await MediaLibrary.requestPermissionsAsync(writeOnly, granularPermissions);\n }\n return await MediaLibrary.requestPermissionsAsync(writeOnly);\n}\n\n// @needsAudit @docsMissing\n/**\n * Checks user's permissions for accessing media library.\n * @param writeOnly\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has\n * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function getPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions?: GranularPermission[]\n): Promise<PermissionResponse> {\n if (!MediaLibrary.getPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await MediaLibrary.getPermissionsAsync(writeOnly, granularPermissions);\n }\n return await MediaLibrary.getPermissionsAsync(writeOnly);\n}\n\n// @needsAudit\n/**\n * Check or request permissions to access the media library.\n * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions();\n * ```\n */\nexport const usePermissions = createPermissionHook<\n PermissionResponse,\n { writeOnly?: boolean; granularPermissions?: GranularPermission[] }\n>({\n // TODO(cedric): permission requesters should have an options param or a different requester\n getMethod: (options) => getPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n requestMethod: (options) =>\n requestPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n});\n\n// @needsAudit\n/**\n * Allows the user to update the assets that your app has access to.\n * The system modal is only displayed if the user originally allowed only `limited` access to their\n * media library, otherwise this method is a no-op.\n * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented.\n *\n * @return A promise that either rejects if the method is unavailable, or resolves to `void`.\n * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to.\n * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener).\n * If `hasIncrementalChanges` is `false`, the user changed their permissions.\n *\n * @platform android 14+\n * @platform ios\n */\nexport async function presentPermissionsPickerAsync(\n mediaTypes: MediaTypeFilter[] = ['photo', 'video']\n): Promise<void> {\n if (Platform.OS === 'android' && isExpoGo) {\n throw new UnavailabilityError(\n 'MediaLibrary',\n 'presentPermissionsPickerAsync is unavailable in Expo Go'\n );\n }\n if (Platform.OS === 'android' && Platform.Version >= 34) {\n await MediaLibrary.requestPermissionsAsync(false, mediaTypes);\n return;\n }\n if (!MediaLibrary.presentPermissionsPickerAsync) {\n throw new UnavailabilityError('MediaLibrary', 'presentPermissionsPickerAsync');\n }\n return await MediaLibrary.presentPermissionsPickerAsync();\n}\n\n// @needsAudit\n/**\n * Creates an asset from existing file. The most common use case is to save a picture taken by [Camera](./camera).\n * This method requires `CAMERA_ROLL` permission.\n *\n * @example\n * ```js\n * const { uri } = await Camera.takePictureAsync();\n * const asset = await MediaLibrary.createAssetAsync(uri);\n * ```\n * @param localUri A URI to the image or video file. It must contain an extension. On Android it\n * must be a local path, so it must start with `file:///`\n * @return A promise which fulfils with an object representing an [`Asset`](#asset).\n */\nexport async function createAssetAsync(localUri: string): Promise<Asset> {\n if (!MediaLibrary.createAssetAsync) {\n throw new UnavailabilityError('MediaLibrary', 'createAssetAsync');\n }\n\n if (!localUri || typeof localUri !== 'string') {\n throw new Error('Invalid argument \"localUri\". It must be a string!');\n }\n const asset = await MediaLibrary.createAssetAsync(localUri);\n\n if (Array.isArray(asset)) {\n // Android returns an array with asset, we need to pick the first item\n return asset[0];\n }\n return asset;\n}\n\n// @needsAudit\n/**\n * Saves the file at given `localUri` to the user's media library. Unlike [`createAssetAsync()`](#medialibrarycreateassetasynclocaluri),\n * This method doesn't return created asset.\n * On __iOS 11+__, it's possible to use this method without asking for `CAMERA_ROLL` permission,\n * however then yours `Info.plist` should have `NSPhotoLibraryAddUsageDescription` key.\n * @param localUri A URI to the image or video file. It must contain an extension. On Android it\n * must be a local path, so it must start with `file:///`.\n */\nexport async function saveToLibraryAsync(localUri: string): Promise<void> {\n if (!MediaLibrary.saveToLibraryAsync) {\n throw new UnavailabilityError('MediaLibrary', 'saveToLibraryAsync');\n }\n return await MediaLibrary.saveToLibraryAsync(localUri);\n}\n\n// @needsAudit\n/**\n * Adds array of assets to the album.\n *\n * On Android, by default it copies assets from the current album to provided one, however it's also\n * possible to move them by passing `false` as `copyAssets` argument. In case they're copied you\n * should keep in mind that `getAssetsAsync` will return duplicated assets.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @param album An [Album](#album) or its ID.\n * @param copy __Android only.__ Whether to copy assets to the new album instead of move them.\n * Defaults to `true`.\n * @return Returns promise which fulfils with `true` if the assets were successfully added to\n * the album.\n */\nexport async function addAssetsToAlbumAsync(\n assets: AssetRef[] | AssetRef,\n album: AlbumRef,\n copy: boolean = true\n): Promise<boolean> {\n if (!MediaLibrary.addAssetsToAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'addAssetsToAlbumAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n const albumId = getId(album);\n\n checkAssetIds(assetIds);\n\n if (!albumId || typeof albumId !== 'string') {\n throw new Error('Invalid album ID. It must be a string!');\n }\n\n if (Platform.OS === 'ios') {\n return await MediaLibrary.addAssetsToAlbumAsync(assetIds, albumId);\n }\n return await MediaLibrary.addAssetsToAlbumAsync(assetIds, albumId, !!copy);\n}\n\n// @needsAudit\n/**\n * Removes given assets from album.\n *\n * On Android, album will be automatically deleted if there are no more assets inside.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @param album An [Album](#album) or its ID.\n * @return Returns promise which fulfils with `true` if the assets were successfully removed from\n * the album.\n */\nexport async function removeAssetsFromAlbumAsync(\n assets: AssetRef[] | AssetRef,\n album: AlbumRef\n): Promise<boolean> {\n if (!MediaLibrary.removeAssetsFromAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'removeAssetsFromAlbumAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n const albumId = getId(album);\n\n checkAssetIds(assetIds);\n return await MediaLibrary.removeAssetsFromAlbumAsync(assetIds, albumId);\n}\n\n// @needsAudit\n/**\n * Deletes assets from the library. On iOS it deletes assets from all albums they belong to, while\n * on Android it keeps all copies of them (album is strictly connected to the asset). Also, there is\n * additional dialog on iOS that requires user to confirm this action.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @return Returns promise which fulfils with `true` if the assets were successfully deleted.\n */\nexport async function deleteAssetsAsync(assets: AssetRef[] | AssetRef): Promise<boolean> {\n if (!MediaLibrary.deleteAssetsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'deleteAssetsAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n\n checkAssetIds(assetIds);\n return await MediaLibrary.deleteAssetsAsync(assetIds);\n}\n\n// @needsAudit\n/**\n * Provides more information about an asset, including GPS location, local URI and EXIF metadata.\n * @param asset An [Asset](#asset) or its ID.\n * @param options\n * @return An [AssetInfo](#assetinfo) object, which is an `Asset` extended by an additional fields.\n */\nexport async function getAssetInfoAsync(\n asset: AssetRef,\n options: MediaLibraryAssetInfoQueryOptions = { shouldDownloadFromNetwork: true }\n): Promise<AssetInfo> {\n if (!MediaLibrary.getAssetInfoAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAssetInfoAsync');\n }\n\n const assetId = getId(asset);\n\n checkAssetIds([assetId]);\n\n const assetInfo = await MediaLibrary.getAssetInfoAsync(assetId, options);\n\n if (Array.isArray(assetInfo)) {\n // Android returns an array with asset info, we need to pick the first item\n return assetInfo[0];\n }\n return assetInfo;\n}\n\n// @needsAudit\n/**\n * Queries for user-created albums in media gallery.\n * @return A promise which fulfils with an array of [`Album`](#asset)s. Depending on Android version,\n * root directory of your storage may be listed as album titled `\"0\"` or unlisted at all.\n */\nexport async function getAlbumsAsync({ includeSmartAlbums = false }: AlbumsOptions = {}): Promise<\n Album[]\n> {\n if (!MediaLibrary.getAlbumsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAlbumsAsync');\n }\n return await MediaLibrary.getAlbumsAsync({ includeSmartAlbums });\n}\n\n// @needsAudit\n/**\n * Queries for an album with a specific name.\n * @param title Name of the album to look for.\n * @return An object representing an [`Album`](#album), if album with given name exists, otherwise\n * returns `null`.\n */\nexport async function getAlbumAsync(title: string): Promise<Album> {\n if (!MediaLibrary.getAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAlbumAsync');\n }\n if (typeof title !== 'string') {\n throw new Error('Album title must be a string!');\n }\n return await MediaLibrary.getAlbumAsync(title);\n}\n\n// @needsAudit\n/**\n * Creates an album with given name and initial asset. The asset parameter is required on Android,\n * since it's not possible to create empty album on this platform. On Android, by default it copies\n * given asset from the current album to the new one, however it's also possible to move it by\n * passing `false` as `copyAsset` argument.\n * In case it's copied you should keep in mind that `getAssetsAsync` will return duplicated asset.\n * @param albumName Name of the album to create.\n * @param asset An [Asset](#asset) or its ID (required on Android).\n * @param copyAsset __Android Only.__ Whether to copy asset to the new album instead of move it.\n * Defaults to `true`.\n * @return Newly created [`Album`](#album).\n */\nexport async function createAlbumAsync(\n albumName: string,\n asset?: AssetRef,\n copyAsset: boolean = true\n): Promise<Album> {\n if (!MediaLibrary.createAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'createAlbumAsync');\n }\n\n const assetId = getId(asset);\n\n if (Platform.OS === 'android' && (typeof assetId !== 'string' || assetId.length === 0)) {\n // it's not possible to create empty album on Android, so initial asset must be provided\n throw new Error('MediaLibrary.createAlbumAsync must be called with an asset on Android.');\n }\n if (!albumName || typeof albumName !== 'string') {\n throw new Error('Invalid argument \"albumName\". It must be a string!');\n }\n if (assetId != null && typeof assetId !== 'string') {\n throw new Error('Asset ID must be a string!');\n }\n\n if (Platform.OS === 'ios') {\n return await MediaLibrary.createAlbumAsync(albumName, assetId);\n }\n return await MediaLibrary.createAlbumAsync(albumName, assetId, !!copyAsset);\n}\n\n// @needsAudit\n/**\n * Deletes given albums from the library. On Android by default it deletes assets belonging to given\n * albums from the library. On iOS it doesn't delete these assets, however it's possible to do by\n * passing `true` as `deleteAssets`.\n * @param albums An array of [`Album`](#asset)s or their IDs.\n * @param assetRemove __iOS Only.__ Whether to also delete assets belonging to given albums.\n * Defaults to `false`.\n * @return Returns a promise which fulfils with `true` if the albums were successfully deleted from\n * the library.\n */\nexport async function deleteAlbumsAsync(\n albums: AlbumRef[] | AlbumRef,\n assetRemove: boolean = false\n): Promise<boolean> {\n if (!MediaLibrary.deleteAlbumsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'deleteAlbumsAsync');\n }\n\n const albumIds = arrayize(albums).map(getId);\n\n checkAlbumIds(albumIds);\n if (Platform.OS === 'android') {\n return await MediaLibrary.deleteAlbumsAsync(albumIds);\n }\n return await MediaLibrary.deleteAlbumsAsync(albumIds, !!assetRemove);\n}\n\n// @needsAudit\n/**\n * Fetches a page of assets matching the provided criteria.\n * @param assetsOptions\n * @return A promise that fulfils with to [`PagedInfo`](#pagedinfo) object with array of [`Asset`](#asset)s.\n */\nexport async function getAssetsAsync(assetsOptions: AssetsOptions = {}): Promise<PagedInfo<Asset>> {\n if (!MediaLibrary.getAssetsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAssetsAsync');\n }\n\n const { first, after, album, sortBy, mediaType, createdAfter, createdBefore } = assetsOptions;\n\n const options = {\n first: first == null ? 20 : first,\n after: getId(after),\n album: getId(album),\n sortBy: arrayize(sortBy),\n mediaType: arrayize(mediaType || [MediaType.photo]),\n createdAfter: dateToNumber(createdAfter),\n createdBefore: dateToNumber(createdBefore),\n };\n\n if (first != null && typeof options.first !== 'number') {\n throw new Error('Option \"first\" must be a number!');\n }\n if (after != null && typeof options.after !== 'string') {\n throw new Error('Option \"after\" must be a string!');\n }\n if (album != null && typeof options.album !== 'string') {\n throw new Error('Option \"album\" must be a string!');\n }\n\n if (after != null && Platform.OS === 'android' && isNaN(parseInt(getId(after) as string, 10))) {\n throw new Error('Option \"after\" must be a valid ID!');\n }\n\n if (first != null && first < 0) {\n throw new Error('Option \"first\" must be a positive integer!');\n }\n\n options.sortBy.forEach(checkSortBy);\n options.mediaType.forEach(checkMediaType);\n options.sortBy = options.sortBy.map(sortByOptionToString);\n\n return await MediaLibrary.getAssetsAsync(options);\n}\n\n// @needsAudit\n/**\n * Subscribes for updates in user's media library.\n * @param listener A callback that is fired when any assets have been inserted or deleted from the\n * library. On Android it's invoked with an empty object. On iOS, it's invoked with [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent)\n * object.\n *\n * Additionally, only on iOS, the listener is also invoked when the user changes access to individual assets in the media library\n * using `presentPermissionsPickerAsync()`.\n * @return An [`Subscription`](#subscription) object that you can call `remove()` on when you would\n * like to unsubscribe the listener.\n */\nexport function addListener(\n listener: (event: MediaLibraryAssetsChangeEvent) => void\n): EventSubscription {\n return MediaLibrary.addListener(MediaLibrary.CHANGE_LISTENER_NAME, listener);\n}\n\n// @docsMissing\nexport function removeSubscription(subscription: EventSubscription): void {\n subscription.remove();\n}\n\n// @needsAudit\n/**\n * Removes all listeners.\n */\nexport function removeAllListeners(): void {\n MediaLibrary.removeAllListeners(MediaLibrary.CHANGE_LISTENER_NAME);\n}\n\n// @needsAudit\n/**\n * Fetches a list of moments, which is a group of assets taken around the same place\n * and time.\n * @return An array of [albums](#album) whose type is `moment`.\n * @platform ios\n */\nexport async function getMomentsAsync() {\n if (!MediaLibrary.getMomentsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getMomentsAsync');\n }\n\n return await MediaLibrary.getMomentsAsync();\n}\n\n// @needsAudit\n/**\n * Moves album content to the special media directories on **Android R** or **above** if needed.\n * Those new locations are in line with the Android `scoped storage` - so your application won't\n * lose write permission to those directories in the future.\n *\n * This method does nothing if:\n * - app is running on **iOS**, **web** or **Android below R**\n * - app has **write permission** to the album folder\n *\n * The migration is possible when the album contains only compatible files types.\n * For instance, movies and pictures are compatible with each other, but music and pictures are not.\n * If automatic migration isn't possible, the function rejects.\n * In that case, you can use methods from the `expo-file-system` to migrate all your files manually.\n *\n * # Why do you need to migrate files?\n * __Android R__ introduced a lot of changes in the storage system. Now applications can't save\n * anything to the root directory. The only available locations are from the `MediaStore` API.\n * Unfortunately, the media library stored albums in folders for which, because of those changes,\n * the application doesn't have permissions anymore. However, it doesn't mean you need to migrate\n * all your albums. If your application doesn't add assets to albums, you don't have to migrate.\n * Everything will work as it used to. You can read more about scoped storage in [the Android documentation](https://developer.android.com/about/versions/11/privacy/storage).\n *\n * @param album An [Album](#album) or its ID.\n * @return A promise which fulfils to `void`.\n */\nexport async function migrateAlbumIfNeededAsync(album: AlbumRef): Promise<void> {\n if (!MediaLibrary.migrateAlbumIfNeededAsync) {\n return;\n }\n\n return await MediaLibrary.migrateAlbumIfNeededAsync(getId(album));\n}\n\n// @needsAudit\n/**\n * Checks if the album should be migrated to a different location. In other words, it checks if the\n * application has the write permission to the album folder. If not, it returns `true`, otherwise `false`.\n * > Note: For **Android below R**, **web** or **iOS**, this function always returns `false`.\n * @param album An [Album](#album) or its ID.\n * @return Returns a promise which fulfils with `true` if the album should be migrated.\n */\nexport async function albumNeedsMigrationAsync(album: AlbumRef): Promise<boolean> {\n if (!MediaLibrary.albumNeedsMigrationAsync) {\n return false;\n }\n\n return await MediaLibrary.albumNeedsMigrationAsync(getId(album));\n}\n"]}
|
|
@@ -65,10 +65,12 @@ public class MediaLibraryModule: Module, PhotoLibraryObserverHandler {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
AsyncFunction("presentPermissionsPickerAsync") {
|
|
68
|
+
#if os(iOS)
|
|
68
69
|
guard let vc = appContext?.utilities?.currentViewController() else {
|
|
69
70
|
return
|
|
70
71
|
}
|
|
71
72
|
PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: vc)
|
|
73
|
+
#endif
|
|
72
74
|
}.runOnQueue(.main)
|
|
73
75
|
|
|
74
76
|
AsyncFunction("createAssetAsync") { (uri: URL, promise: Promise) in
|
|
@@ -110,6 +112,7 @@ public class MediaLibraryModule: Module, PhotoLibraryObserverHandler {
|
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
AsyncFunction("saveToLibraryAsync") { (localUrl: URL, promise: Promise) in
|
|
115
|
+
#if os(iOS)
|
|
113
116
|
if Bundle.main.infoDictionary?["NSPhotoLibraryAddUsageDescription"] == nil {
|
|
114
117
|
throw MissingPListKeyException("NSPhotoLibraryAddUsageDescription")
|
|
115
118
|
}
|
|
@@ -155,6 +158,7 @@ public class MediaLibraryModule: Module, PhotoLibraryObserverHandler {
|
|
|
155
158
|
promise.reject(SaveVideoException())
|
|
156
159
|
return
|
|
157
160
|
}
|
|
161
|
+
#endif
|
|
158
162
|
|
|
159
163
|
promise.reject(UnsupportedAssetException())
|
|
160
164
|
}
|
|
@@ -6,6 +6,7 @@ typealias SaveToLibraryCallback = (Any?, Error?) -> Void
|
|
|
6
6
|
class SaveToLibraryDelegate: NSObject {
|
|
7
7
|
var callback: SaveToLibraryCallback?
|
|
8
8
|
|
|
9
|
+
#if os(iOS)
|
|
9
10
|
func writeImage(_ image: UIImage, withCallback callback: @escaping SaveToLibraryCallback) {
|
|
10
11
|
self.callback = callback
|
|
11
12
|
UIImageWriteToSavedPhotosAlbum(
|
|
@@ -49,4 +50,5 @@ class SaveToLibraryDelegate: NSObject {
|
|
|
49
50
|
func triggerCallback(_ asset: Any?, with error: Error?) {
|
|
50
51
|
callback?(asset, error)
|
|
51
52
|
}
|
|
53
|
+
#endif
|
|
52
54
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-media-library",
|
|
3
|
-
"version": "17.1.0-canary-
|
|
3
|
+
"version": "17.1.0-canary-20250219-4a5dade",
|
|
4
4
|
"description": "Provides access to user's media library.",
|
|
5
5
|
"main": "build/MediaLibrary.js",
|
|
6
6
|
"types": "build/MediaLibrary.d.ts",
|
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
"preset": "expo-module-scripts"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"expo-module-scripts": "4.0.
|
|
41
|
+
"expo-module-scripts": "4.0.5-canary-20250219-4a5dade"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
|
-
"expo": "53.0.0-canary-
|
|
44
|
+
"expo": "53.0.0-canary-20250219-4a5dade",
|
|
45
45
|
"react-native": "*"
|
|
46
46
|
},
|
|
47
47
|
"codegenConfig": {
|
|
@@ -53,5 +53,6 @@
|
|
|
53
53
|
"RCTImageURLLoader": "MediaLibraryImageLoader"
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
}
|
|
56
|
+
},
|
|
57
|
+
"gitHead": "4a5daded61d3d8b9d501059039ac74c09c25675b"
|
|
57
58
|
}
|
package/src/MediaLibrary.ts
CHANGED
|
@@ -11,6 +11,17 @@ import { Platform } from 'react-native';
|
|
|
11
11
|
|
|
12
12
|
import MediaLibrary from './ExpoMediaLibrary';
|
|
13
13
|
|
|
14
|
+
const isExpoGo = typeof expo !== 'undefined' && globalThis.expo?.modules?.ExpoGo;
|
|
15
|
+
|
|
16
|
+
let loggedExpoGoWarning = false;
|
|
17
|
+
|
|
18
|
+
if (isExpoGo && !loggedExpoGoWarning) {
|
|
19
|
+
console.warn(
|
|
20
|
+
'Due to changes in Androids permission requirements, Expo Go can no longer provide full access to the media library. To test the full functionality of this module, you can create a development build. https://docs.expo.dev/develop/development-builds/create-a-build'
|
|
21
|
+
);
|
|
22
|
+
loggedExpoGoWarning = true;
|
|
23
|
+
}
|
|
24
|
+
|
|
14
25
|
// @needsAudit
|
|
15
26
|
export type PermissionResponse = EXPermissionResponse & {
|
|
16
27
|
/**
|
|
@@ -433,7 +444,7 @@ export async function isAvailableAsync(): Promise<boolean> {
|
|
|
433
444
|
*/
|
|
434
445
|
export async function requestPermissionsAsync(
|
|
435
446
|
writeOnly: boolean = false,
|
|
436
|
-
granularPermissions
|
|
447
|
+
granularPermissions?: GranularPermission[]
|
|
437
448
|
): Promise<PermissionResponse> {
|
|
438
449
|
if (!MediaLibrary.requestPermissionsAsync) {
|
|
439
450
|
throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync');
|
|
@@ -454,7 +465,7 @@ export async function requestPermissionsAsync(
|
|
|
454
465
|
*/
|
|
455
466
|
export async function getPermissionsAsync(
|
|
456
467
|
writeOnly: boolean = false,
|
|
457
|
-
granularPermissions
|
|
468
|
+
granularPermissions?: GranularPermission[]
|
|
458
469
|
): Promise<PermissionResponse> {
|
|
459
470
|
if (!MediaLibrary.getPermissionsAsync) {
|
|
460
471
|
throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync');
|
|
@@ -503,6 +514,12 @@ export const usePermissions = createPermissionHook<
|
|
|
503
514
|
export async function presentPermissionsPickerAsync(
|
|
504
515
|
mediaTypes: MediaTypeFilter[] = ['photo', 'video']
|
|
505
516
|
): Promise<void> {
|
|
517
|
+
if (Platform.OS === 'android' && isExpoGo) {
|
|
518
|
+
throw new UnavailabilityError(
|
|
519
|
+
'MediaLibrary',
|
|
520
|
+
'presentPermissionsPickerAsync is unavailable in Expo Go'
|
|
521
|
+
);
|
|
522
|
+
}
|
|
506
523
|
if (Platform.OS === 'android' && Platform.Version >= 34) {
|
|
507
524
|
await MediaLibrary.requestPermissionsAsync(false, mediaTypes);
|
|
508
525
|
return;
|