Files

You can use Kinvey to store and retrieve binary files of size up to 5TB. Files can be of any format.

The files are automatically enabled for download using a Content Delivery Network (CDN) for massive scale and performance.

Kinvey does not directly serve or accept files. Instead, the Kinvey Files API works by providing a short-lived URL to a third-party cloud storage service from which file(s) can be uploaded or downloaded. Currently, the third-party service used is Google Cloud Storage.

You would typically use the Files API to upload and download:

  • images
  • video files
  • other application-specific files.

Uploading

The library's File API supports uploading a java.io.File directly as well as streaming content from an InputStream.

When using custom values for _id, you should avoid values that are exactly 12 or 24 symbols in length. Such values are automatically converted to BSON ObjectID and are not stored as strings in the database, which can interfere with querying and other operations.

To ensure that no items with 12 or 24 symbols long _id are stored in the collection, you can create a pre-save hook that either prevents saving such items, or appends an additional symbol (for example, underscore) to the _id:

if (_id.length === 12 || _id.length === 24) {
  _id += "_";
}

java.io.File

To upload a file, use kinveyClient.getFileStore(StoreType).upload(). Pass the file content as the first argument, followed by an AsyncUploaderProgressListener<FileMetaData> for callbacks.

import com.kinvey.android.callback.AsyncUploaderProgressListener;

...

java.io.File file = new java.io.File(getFilesDir(), "chicken_fried_waffles.txt");
file.createNewFile();

boolean isCancelled = false;
FileStore fileStore = kinveyClient.getFileStore(StoreType.CACHE);
fileStore.upload(file, new AsyncUploaderProgressListener<FileMetaData>() {
    @Override
    public void onSuccess(FileMetaData fileMetaData) {
        // Place your code here
    }

    @Override
    public void onFailure(Throwable throwable) {
        // Place your error handler here
    }

    @Override
    public void progressChanged(MediaHttpUploader mediaHttpUploader) throws IOException {
        // Place your code here
    }

    @Override
    public void onCancelled() {
        // Place your code here
    }

    @Override
    public boolean isCancelled() {
        return isCancelled;
    }
});

Optionally, you can use a FileMetaData object as the first parameter to save additional metadata. This lets you set the File's unique _id, ACLs, mark files as public, and set any other custom attributes your app may need.

import com.kinvey.java.model.FileMetaData;
...

//create the FileMetaData object
FileMetaData metadata = new FileMetaData("myFileID");
//set the file to be pubicly accesible
metadata.setPublic(true);
//allow all users to see this file
metadata.setAcl(new KinveyMetaData.AccessControlList().setGloballyReadable(true));
metadata.setFileName("chicken_fried_waffles.txt");

java.io.File file = new java.io.File(getFilesDir(), "chicken_fried_waffles.txt");
file.createNewFile();

boolean isCancelled = false;
FileStore fileStore = kinveyClient.getFileStore(StoreType.CACHE);
fileStore.upload(file, metadata, new AsyncUploaderProgressListener<FileMetaData>() {
    @Override
    public void onSuccess(FileMetaData fileMetaData) {
        // Place your code here
    }

    @Override
    public void onFailure(Throwable throwable) {
        // Place your error handler here
    }

    @Override
    public void progressChanged(MediaHttpUploader mediaHttpUploader) throws IOException {
        // Place your code here
    }

    @Override
    public void onCancelled() {
        // Place your code here
    }

    @Override
    public boolean isCancelled() {
        return isCancelled;
    }
});

InputStream

Alternatively you can upload a file from an input stream.

FileInputStream fIn = new FileInputStream(new File ("eats_bacon.mpg"));

boolean isCancelled = false;
FileStore fileStore = kinveyClient.getFileStore(StoreType.CACHE);
fileStore.upload("myFileID", metadata, new AsyncUploaderProgressListener<FileMetaData>() {
    @Override
    public void onSuccess(FileMetaData fileMetaData) {
        // Place your code here
    }

    @Override
    public void onFailure(Throwable throwable) {
        // Place your error handler here
    }

    @Override
    public void progressChanged(MediaHttpUploader mediaHttpUploader) throws IOException {
        // Place your code here
    }

    @Override
    public void onCancelled() {
        // Place your code here
    }

    @Override
    public boolean isCancelled() {
        return isCancelled;
    }
});

You can also provide a FileMetaData object as the first argument when streaming from an InputStream.

import com.kinvey.java.model.FileMetaData;
...

FileInputStream fIn = new FileInputStream(new File ("eats_bacon.mpg"));
//create the FileMetaData object
FileMetaData metadata = new FileMetaData("myFileID");

boolean isCancelled = false;
FileStore fileStore = kinveyClient.getFileStore(StoreType.CACHE);
fileStore.upload(fIn, metadata, new AsyncUploaderProgressListener<FileMetaData>() {
    @Override
    public void onSuccess(FileMetaData fileMetaData) {
        // Place your code here
    }

    @Override
    public void onFailure(Throwable throwable) {
        // Place your error handler here
    }

    @Override
    public void progressChanged(MediaHttpUploader mediaHttpUploader) throws IOException {
        // Place your code here
    }

    @Override
    public void onCancelled() {
        // Place your code here
    }

    @Override
    public boolean isCancelled() {
        return isCancelled;
    }
});

Uploading publicly readable files

Use the method myFileMetaData.setPublic(true) if you want to upload a publicly-readable file. This means that the download link to the file will not expire until you delete the file through Kinvey. If a user uploads a file that you want other users to be able download, you will have to set the gr (globally readable) attribute to true in the _acl (access control list).

import com.kinvey.java.model.FileMetaData;
...

//create the FileMetaData object
FileMetaData myFileMetaData = new FileMetaData("myFileID");
//set the file to be pubicly accesible
myFileMetaData.setPublic(true);
//allow all users to see this file
myFileMetaData.setAcl(new KinveyMetaData.AccessControlList().setGloballyReadable(true));
metadata.setFileName("chicken_fried_waffles.txt");

java.io.File file = new java.io.File(getFilesDir(), "chicken_fried_waffles.txt");
file.createNewFile();

boolean isCancelled = false;
FileStore fileStore = kinveyClient.getFileStore(StoreType.CACHE);
fileStore.upload(metadata, file, new AsyncUploaderProgressListener<FileMetaData>() {
    @Override
    public void onSuccess(FileMetaData fileMetaData) {
        // Place your code here
    }

    @Override
    public void onFailure(Throwable throwable) {
        // Place your error handler here
    }

    @Override
    public void progressChanged(MediaHttpUploader mediaHttpUploader) throws IOException {
        // Place your code here
    }

    @Override
    public void onCancelled() {
        // Place your code here
    }

    @Override
    public boolean isCancelled() {
        return isCancelled;
    }
});

Downloading

For downloading files to an OutputStream, you can open a file output stream, by fileMetaData, then feed the file output stream to the file download.

FileOutputStream fos = new FileOutputStream("mug.png");
FileMetaData fileMetaDataForDownload = new FileMetaData();
fileMetaDataForDownload.setId("myFileID");
boolean isCancelled = false;
FileStore fileStore = kinveyClient.getFileStore(StoreType.CACHE);
fileStore.download(fileMetaDataForDownload, fos, new AsyncDownloaderProgressListener<FileMetaData>() {

    @Override
    public void onSuccess(FileMetaData fileMetaData) {
        // Place your code here
    }

    @Override
    public void onFailure(Throwable throwable) {
        // Place your error handler here
    }

    @Override
    public void progressChanged(MediaHttpDownloader mediaHttpDownloader) throws IOException {
        // Place your code here
    }

    @Override
    public void onCancelled() {
        // Place your code here
    }

    @Override
    public boolean isCancelled() {
        return isCancelled;
    }
});

Optionally, you can use a KinveyCachedClientCallback<FileMetaData> as the fives parameter to download file. This lets you get the File from cache. This callback is available only for StoreType.CACHE

FileOutputStream fos = new FileOutputStream("mug.png");
FileMetaData fileMetaDataForDownload = new FileMetaData();
fileMetaDataForDownload.setId("myFileID");
boolean isCancelled = false;
FileStore fileStore = kinveyClient.getFileStore(StoreType.CACHE);
fileStore.download(fileMetaDataForDownload, fos, new AsyncDownloaderProgressListener<FileMetaData>() {

    @Override
    public void onSuccess(FileMetaData fileMetaData) {
        // Place your code here
    }

    @Override
    public void onFailure(Throwable throwable) {
        // Place your error handler here
    }

    @Override
    public void progressChanged(MediaHttpDownloader mediaHttpDownloader) throws IOException {
        // Place your code here
    }

    @Override
    public void onCancelled() {
        // Place your code here
    }

    @Override
    public boolean isCancelled() {
        return isCancelled;
    }
}, new KinveyCachedClientCallback<FileMetaData>() {
    @Override
    public void onSuccess(FileMetaData fileMetaData) {
        // Place your code here
    }

    @Override
    public void onFailure(Throwable throwable) {
        // Place your error handler here
    }
});

MediaPlayer Streaming

You can use the URI in conjunction with Android's MediaPlayer to stream videos or audio files. This has the distinct advantage of not needing to load the entire resource into memory before handing it off to the media player or bitmap factory. This approach saves on both memory usage and battery life, as the file contents are streamed and accessed at the same time.

Query query = new Query();
query = query.equals("_id", "MyFileId");
FileStore fileStore = client.getFileStore(StoreType.CACHE);
fileStore.find(query, new KinveyClientCallback<FileMetaData[]>() {
    @Override
    public void onSuccess(FileMetaData[] fileMetaDatas) {
        MediaPlayer mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setDataSource(fileMetaDatas[0].getDownloadURL());
        mMediaPlayer.prepare();
        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

        // you have 1 hour from the time getDownloadUrl was initiated to begin
        // downloading with the temporary url
        mMediaPlayer.start();
    }

    @Override
    public void onFailure(Throwable throwable) {
    Log.e(TAG, "error downloading movie.mp4", t);
    }
});

Deleting

You can permanently remove a file using the remove() method.

FileStore fileStore = kinveyClient.getFileStore(StoreType.CACHE);
fileStore.remove(fileMetaData, new KinveyDeleteCallback() {
    @Override
    public void onSuccess(Integer integer) {
        // Place your code here
    }

    @Override
    public void onFailure(Throwable throwable) {
        // Place your error handler here
    }
});