My Cordova nightmares: Accessing photos from the phone’s gallery

Gallery API, Promises, WKWebView, Cordova local webserver

Ronny Roeller
Jan 18, 2017 · 2 min read

You want your users to pick photos that they shot earlier? The good news: You can do this with Cordova. The bad news: Getting there will be nightmarish.

Here is what we learned on our — rather nightmarish — trip.

Gallery API

The Cordova-Gallery-API is a great library that provides access to the phone’s gallery. After some experimentation, we found SuryaL’s fork to be the most stable and feature-rich: https://github.com/SuryaL/cordova-gallery-api

These are the commands for a standard scenario:

  1. Find all albums on the phone (e.g. Camera Roll) via galleryAPI.getAlbums()
  2. Find all media items within one album via galleryAPI.getMedia()
  3. Request the thumbnail for one media item via galleryAPI.getMediaThumbnail()
  4. Request the high quality version of one media item via galleryAPI.getHQImageData()

Escaping callback hell

In best Cordova tradition, combining the calls catapults the programmer quickly into callback hell:

galleryAPI.getAlbums(
function(albums) {
albums.forEach(function(album) {
galleryAPI.getMedia(
album,
function(media) {
...
},
function(e) {
throw new Error(e);
}
);
}
}),
function(e) {
throw new Error(e);
}
);

We clearly don’t want to end up there. Luckily, there is an easy solution. Wrapping the gallery-api with promises let’s us sneak out of callback hell:

const getAlbums = () =>
new Promise((resolve, reject) => {
galleryAPI.getAlbums(
albums => resolve(albums),
e => reject(`Failed to get albums: ${e}`)
);
});

const getMedia = (album) =>
new Promise((resolve, reject) => {
galleryAPI.getMedia(
album,
items => resolve(items),
e => reject(`Failed to load items for album ${album.id}: ${e}`)
);
});

With promises in place, combining the calls reads very natural:

getAlbums()
.then(albums => getMedia(album))
.then(items => getMediaThumbnails())

Burned by WKWebView

But there was one more proof for us: For Android, we can simply stick the thumbnail URL returned by Gallery API into a <img> tag to show the file to the user. But WKWebView, the high performance WebView for iOS, refuses to load the photo from the device.

The trick is to install Cordova’s local webserver plugin and capture the cdvToken passed to your index.html as a parameter (e.g. index.html?cdvToken=xyz):

// Using https://medialize.github.io/URI.js/
const cdvToken = URI(window.location).query(true).cdvToken

Now, you just need to prefix the thumbnails provided by Gallery API with /local-filesystem, add the cdvToken, and your images are finally ready to render!

items.forEach(item => {
html += `<img src="/local-filesystem${item.thumbnail}?cdvToken=${cdvToken}"></img>`;
});

Solution - out of the box

Sounds complicated? Agreed. We therefore collected all pieces of the puzzles into a library and open sourced it: https://github.com/Collaborne/cordova-gallery-access

Check it out, and let us know what you think.

Happy coding!

Want to learn more about coding? Have a look to our other articles.


Photo: gags9999

NEXT Engineering

Ronny Roeller

Written by

CTO at @Next. Building agile SaaS platform to make innovation smart, simple and sticky. @stanforddschool @INSEAD

NEXT Engineering

Tech lessons learned while making innovation smart, simple and sticky.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade