Package Exports
- react-native-photos-framework
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (react-native-photos-framework) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
react-native-photos-framework
###Description Load photos/videos and more from CameraRoll and iCloud. Uses Apples photos framework.
React Native comes with it's own CameraRoll library. This however uses ALAssetLibrary which is a deprecated API from Apple and can only load photos and videos stored on the users device. This is not what your user expects today. Most users photos live on iCloud and these won't show if you use ALAssetLibrary.
If you use this library/Photos framework you can display the users local resources and the users iCloud resources.
###Installation:
npm i react-native-photos-framework --save && react-native link react-native-photos-framework
NOTE: When running npm install this library will try to automatically add NSPhotoLibraryUsageDescription to your Info.plist.
Check that it is there after the install or update it's value from the default:
Using photo library to select pictures
##Library (Top level):
##Static methods:
###cleanCache
RNPhotosFramework.cleanCache().then(() => {
});Signature: RNPhotosFramework.cleanCache() : Promise. Cleans library caches. Will never have to be called. This framework handles this automatically. But if you experience some kind of issue, you can try calling it and see if the result differs.
###authorizationStatus
RNPhotosFramework.authorizationStatus().then(() => {
});Signature: RNPhotosFramework.authorizationStatus() : Promise<{status : string, isAuthorized : boolean}>.
Fetches the current authorization-status.
NOTE: You can receive the following statuses :
notDetermined //Before user has granted permission,
restricted //User is restricted by policy, cannot use Photos,
denied //User has denied permission,
authorized //User has granted permission
###requestAuthorization
RNPhotosFramework.requestAuthorization().then((statusObj) => {
if(statusObj.isAuthorized) {
...start using the library.
}
});Signature: RNPhotosFramework.requestAuthorization() : Promise<{status : string, isAuthorized : boolean}>.
This will prompt the user to grant access to the user library at first start.
If you do not call this method explicitly before using any of the other functions in this library. The grant-access-dialog will appear for the user automatically at the next first function-call into the library. But only one function call can automatically
trigger this dialog, so if another call comes into Photos Framework before the user has granted you access, that function-cal will fail. Therefore I urge you to call this method explicitly before you start using the rest of the library to not experience unexpected behaviour.
NOTE: you do not have to first check the authorizationStatus before calling this. If the user has granted access before, this will just return authorized-status.
NOTE: See available statuses in doc. about: authorizationStatus
##Working with Content:
fetchOptions
fetchOptions is a query-object which can be sent both when fetching albums with
getAlbums and when fetching assets with getAssets. Bellow you can see the available options
for fetchOptions. You can also read Apple's documentation around PHFetchOptions here.
(Many of the args map one-to-one with native data structures.)
| Prop | Default | Type | Description |
|---|---|---|---|
mediaTypes (Only for getAssets) |
- | array<string> |
Defines what mediaType the asset should be. Array combined with OR-operator. eg. ['photo', 'video'] will return both photos and videos. Converted in Native to PHAssetMediaType. Accepted values: photo, video, audio, unknown |
mediaSubTypes (Only for getAssets) |
- | array<string> |
Defines what subtype the asset should be. Array combined with OR-operator. eg. ['photoPanorama', 'photoHDR'] will return both panorama and HDR-assets. Converted in Native to PHAssetMediaSubtype. Accepted enum-values: none, photoPanorama, photoHDR, photoScreenshot, photoLive, videoStreamed, videoHighFrameRate, videoTimeLapse (mediaTypes and mediaSubTypes are combined with AND-operator) |
sourceTypes (Only for getAssets) |
- | array<string> |
Defines where the asset should come from originally. Array combined with OR-operator. Converted in Native to PHAssetSourceType. Accepted enum-values: none, userLibrary, cloudShared, itunesSynced. |
| includeHiddenAssets | false | boolean |
A Boolean value that determines whether the fetch result includes assets marked as hidden. |
| includeAllBurstAssets | false | boolean |
A Boolean value that determines whether the fetch result includes all assets from burst photo sequences. |
| fetchLimit | 0 | number |
The maximum number of objects to include in the fetch result. Remember to not use this in the wrong way combined with startIndex and endIndex. 0 means unlimited. |
| sortDescriptors | - | array<{key : <string>, ascending : <boolean>}> |
Multiple sortDescriptors which decide how the result should be sorted. |
Retrieving Assets (photos/videos/audio):
import RNPhotosFramework from 'react-native-photos-framework';
RNPhotosFramework.getAssets({
// You can call this function multiple times providing startIndex and endIndex as
// pagination
startIndex: 0,
endIndex: 100,
// Media types you wish to display. See table bellow for possible options. Where
// is the image located? See table bellow for possible options.
sourceTypes: ['userLibrary'],
fetchOptions : {
sortDescriptors : [
{
key: 'creationDate',
ascending: true,
}
]
},
//Start loading images into memory with these displayOptions (Not required)
prepareForSizeDisplay: {
width: 91.5,
height: 91.5
},
prepareScale: 2
}).then((response) => console.log(response.assets));
Props to getAssets
| Prop | Default | Type | Description |
|---|---|---|---|
| startIndex | 0 | number |
startIndex-offset for fetching |
| endIndex | 0 | number |
endIndex-offset stop for fetching |
| includeMetaData | false | boolean |
Include a lot of meta data about the asset (See bellow). You can also choose to get this metaData at a later point by calling asset.getMetaData (See bellow) |
| prepareForSizeDisplay | - | Rect(width, height) |
The size of the image you soon will display after running the query. This is highly optional and only there for optimizations of big lists. Prepares the images for display in Photos by using PHCachingImageManager |
| prepareScale | 2.0 | number |
The scale to prepare the image in. |
###Example of asset response with includeMetaData : true
creationDate : 1466766146
duration : 17.647 (video)
width : 1920
height : 1080
isFavorite : false
isHidden : false
localIdentifier : "3D5E6260-2B63-472E-A38A-3B543E936E8C/L0/001"
location : Object
mediaSubTypes : null
mediaType : "video"
modificationDate : 1466766146
sourceType : "userLibrary"
uri : "pk://3D5E6260-2B63-472E-A38A-3B543E936E8C/L0/001"Retrieving albums and enumerating their assets:
RNPhotosFramework.getAlbums({
type: 'album',
subType: 'any',
assetCount: 'exact',
fetchOptions: {
sortDescriptors : [
{
key: 'title',
ascending: true
}
],
includeHiddenAssets: false,
includeAllBurstAssets: false
}
}).then((queryResult) => {
const album = queryResult.albums[0];
return album.getAssets({
//The fetch-options from the outer query will apply here, if we get
startIndex: 0,
endIndex: 10,
prepareForSizeDisplay: {
width: 91.5,
height: 91.5
},
prepareScale: 2
}).then((response) => {
console.log(response.assets, 'The assets in the first album');
});
});Props to getAlbums
Get albums allow to query the Photos Framework for asset-albums. Both User-created ones and Smart-albums. Note that Apple creates a lot of dynamic, so called Smart Albums, like : 'Recently added', 'Favourites' etc.
NOTE: There is also another method called getAlbumsMany. This could be considered a low-level-method of the API. It is constructed so that this library can build more accessable methods on top of one joint native-call: like getUserTopAlbums in pure JS.
The getAlbumsMany-api can take multiple queries (array
| Prop | Default | Type | Description |
|---|---|---|---|
| type | album |
string |
Defines what type of album/collection you wish to retrieve. Converted in Native to PHAssetCollectionType. Accepted enum-values: album, smartAlbum, moment |
| subType | any |
string |
Defines what subType the album/collection you wish to retrieve should have. Converted in Native to PHAssetCollectionSubtype. Accepted enum-values: any, albumRegular, syncedEvent, syncedFaces, syncedAlbum, imported, albumMyPhotoStream, albumCloudShared, smartAlbumGeneric, smartAlbumPanoramas, smartAlbumVideos, smartAlbumFavorites, smartAlbumTimelapses, smartAlbumAllHidden, smartAlbumRecentlyAdded, smartAlbumBursts, smartAlbumSlomoVideos, smartAlbumUserLibrary, smartAlbumSelfPortraits, smartAlbumScreenshots |
| assetCount | none |
string/enum |
By default you wont get any asset-count from the collection. But you can choose to get estimated count of the collection or exact-count. Of course these have different performance-impacts. Remember that your of course fetchOptions affects this count. |
| includeMetaData | false | boolean |
Include some meta data about the album. You can also choose to get this metaData at a later point by calling album.getMetaData (See bellow) |
| noCache | false |
boolean |
If you set this flag to true. The result won't get cached or tracked for changes. |
| preCacheAssets | false |
boolean |
If you set this property to true all assets of all albums your query returned will be cached and change-tracking will start. |
Working with Albums:
##Static methods:
###createAlbum
RNPhotosFramework.createAlbum('test-album').then((album) => {
//You can now use the album like any other album:
return album.getAssets().then((photos) => {});
});Signature: RNPhotosFramework.createAlbum(albumTitle) : Promise
NOTE: Alums can have the same name. All resources in Photos are unique on their localIdentifier. You can use the bellow methods to tackle this:
###getAlbumsByTitle
RNPhotosFramework.getAlbumsByTitle('test-album').then((albums) => {});Signature: RNPhotosFramework.getAlbumsByTitle(albumTitle) : Promise<array
###getAlbumByLocalIdentifier and getAlbumByLocalIdentifiers
RNPhotosFramework.getAlbumByLocalIdentifier(localIdentifier).then((album) => {});Signature: RNPhotosFramework.getAlbumByLocalIdentifier(localIdentifier) : Promise
##Album instance-methods:
###addAssetToAlbum and addAssetsToAlbum
album.addAssetToAlbum(asset).then((status) => {});Signature: album.addAssetToAlbum(asset) : Promise
###removeAssetFromAlbum and removeAssetsFromAlbum
album.removeAssetFromAlbum(asset).then((status) => {});Signature: album.removeAssetFromAlbum(asset) : Promise
###updateTitle
album.updateTitle(newTitle).then((status) => {});Signature: album.updateTitle(string) : Promise
###delete
album.delete().then((status) => {});Signature: album.delete() : Promise
###getMetaData
album.getMetaData().then((mutatedAlbumWithMetaData) => {});Fetch meta data for a specific album. You can also include metadata on all albums in the first getAlbum-call
by explicitly setting option includeMetaData: true.
Working with Assets (Images/Photos):
When you retrieve assets from the API you will get back an Asset object.
There is nothing special about this object. I've defined it as a class so
that it can have some instance-methods. But it should be highly compatible with
native RN-elements like <Image source={asset.image}></Image>.
NOTE: Use the property .image on an asset for the
##Images/Photos
An Image/Photo-asset is fully compatible with RN's
##Asset instance-methods:
###getMetaData
asset.getMetaData().then((mutatedAssetWithMetaData) => {});Fetch meta data for a specific asset. You can also include metadata on all assets in the first getAsset-call by explicitly setting option includeMetaData: true.
###ImageLoader Concept:
NOTE about RN's concept of Image loaders:
RN has a plugin-like system for displaying Images/Photos.
This means that any library (like this library) can define it's own
ImageLoader. When RN later gets a request to display a <Image> it will query
all ImageLoaders loaded in the system and ask which loader can load a specific resource.
If the resource starts with `https://` for instance, RN's own network-image-loader will take care of loading that resource. While if the scheme of the resource is `asset-library://` another ImageLoader will load that Image.
This library defines it's own ImageLoader which can load images from iCloud. (RN actually already have a ImageLoader that can load iCloud images, but we define our own/extend their original loader so we can have some extra functionality on our loader. (See deliveryMode below)).
A ´uri´ that our loader can load is defined in scheme: `pk://` and localIdentifier eg: `9509A678-2A07-405F-B3C6-49FD806915CC/L0/001`
URI-example: pk://9509A678-2A07-405F-B3C6-49FD806915CC/L0/001###deliveryMode (Advanced) Apple's Photo Framework will download images from iCloud on demand, and will generally be very smart about caching and loading resources quickly. You can however define how an Image should be loaded. We have 3 different options in PHImageRequestOptionsDeliveryMode:
PHImageRequestOptionsDeliveryModeOpportunistic = 0, // client may get several image results when the call is asynchronous or will get one result when the call is synchronous
PHImageRequestOptionsDeliveryModeHighQualityFormat = 1, // client will get one result only and it will be as asked or better than asked (sync requests are automatically processed this way regardless of the specified mode)
PHImageRequestOptionsDeliveryModeFastFormat = 2 // client will get one result only and it may be degradedThis library defaults to loading assets with PHImageRequestOptionsDeliveryModeHighQualityFormat.
This can be considered to be the same as RN normally loads images. It will simply download the image in the size of your
But you can choose to use the other two deliveryMode's to. you do this by calling:
const newAssetWithAnotherDeliveryMode = asset.withOptions({
//one of opportunistic|highQuality|fast
deliveryMode : 'opportunistic'
});If you choose to use opportunistic here you will see a low-res-version of the image displayed
while the highQuality version of the resource is downloaded. NOTE: This library will call correct lifecycle callback's on your image-tag when this is used: the
<Image onPartialLoad={//Low-res-callback} onLoad={//High-res-callback} onProgress={//downloadCallback}>
#Creating Assets: You can use this library to save images and videos to the users iCloud library.
##Images/Photos Creating image-assets uses RN's ImageLoader-system behind the scenes and should therefore be able to accept/save any image/photo that you can display in RN.
###Static methods:
###createImageAsset
RCTCameraRollRNPhotosFrameworkManager.createImageAsset(imageWithUriProp);Signature: album.createImageAsset(params) : Promise
###createVideoAsset
RCTCameraRollRNPhotosFrameworkManager.createVideoAsset(videoWithUriProp);Signature: album.createVideoAsset(params) : Promise
###createAssets
RCTCameraRollRNPhotosFrameworkManager.createAssets({
images : [{ uri : 'https://some-uri-local-or-remote.jpg' }],
videos : [{ uri : 'https://some-uri-local-or-remote.jpg' }]
album : album //(OPTIONAL) some album that you want to add the asset to when it's been added to the library.
includeMetaData : true //The result of this function call will return new assets. should this have metadata on them? See docs of getAssets for more info.
});Signature: album.createAssets(params) : Promise<array
#Observing library changes You can register listeners for library-change-detection on different levels of the api.
##Library-level You can detect globally if the library changed by:
RNPhotosFramework.onLibraryChange(() => {
console.log('Library Change');
});No details provided
##AlbumQueryResult-level
You can register a listener that receives updates when any of the albums that result contains
changes (Not if their assets change, only the Albums get those messages, see bellow).
You currently receive the following events: AlbumTitleChanged (More to come).
albumQueryResult.onChange((details) => {
console.log(details);
});NOTE: If a change occures that affects one of the AlbumQueryResults albums that change will also be passed along to the album.
##Album-level On an album object you can do:
album.onChange((changeDetails) => {
console.log('album did change', changeDetails);
});The changeDetails for albums contains the following props:
{
type : string //AssetChange, AlbumTitleChanged
newTitle : string //If AlbumTitleChanged-event.
removedIndexes : array<number> //The removed indexes
changedIndexes : array<number> //The changed indexes
insertedIndexes : array<number> //The inserted indexes
hasIncrementalChanges : boolean // A Boolean value that indicates whether changes to the fetch result can be described incrementally.
hasMoves : boolean // A Boolean value that indicates whether objects have been rearranged in the fetch result.
}NOTE: You will have to decide for yourself if you want to do a full reload of the album or rearrange the assets you have in JS-memory according to the information in the changeDetails.
All of these change events is for information. This library will provide a way of getting new immutable collections out of the changes so you can rerender efficiently.