Since Backendless does not have native APIs to download files, today we’ll talk about how to implement this function in your Android application. In order to do that, we’ll need to combine the Backendless file listing API and android.app.DownloadManager. There are several alternatives to this approach, but the selected one requires less code to write and has a well-thought-out structure.
Once a developer uploads files to the Backendless Files system, each file gets a public URL that can either be obtained using Backendless Console or calculated using the following URL scheme:
https://api.backendless.com/<appId>/<rest-key>/files/<path>/<fileName>
This public URI is the full path to the file in your Backendless file system. The directory listing API returns a list of the FileInfo objects representing the files located in the directory, where each element in the collection contains the following properties:
In this guide, we’ll be dealing with listing and downloading all the files with the .html extension in the /web folder located in the root directory of your Backendless file system.
As for the Android app itself, we’ll need to:
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
public void filesListing(String path, String pattern) { Toast.makeText(this, "Loading files... Please wait", Toast.LENGTH_LONG).show(); Backendless.Files.listing( path, pattern, false, new AsyncCallback<List<FileInfo>>() { @Override public void handleResponse( List<FileInfo> fileInfos ) { for( FileInfo file:fileInfos) { allFiles.add(file); filesList.append("File name: " + file.getName()+ "\n" + "File path: " + file.getURL() + "\n\n"); } } @Override public void handleFault( BackendlessFault backendlessFault ) { Log.e("Listing error", "Error listing files: " + backendlessFault.getMessage()); } }); }
In this code sample, allFiles is a variable that stores the results of the listing operation, and filesList is a TextView class where we show all the existing files.
When the listing process is finished, we can start the download.
public void downloadFile(final FileInfo fileInfo) throws IOException { isStoragePermissionGranted(); new Thread() { @Override public void run() { try { Uri downloadUri = Uri.parse(fileInfo.getPublicUrl()); DownloadManager.Request request = new DownloadManager.Request(downloadUri); DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); request.setDestinationInExternalPublicDir("/Download", fileInfo.getName()); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); request.setVisibleInDownloadsUi(true); downloadManager.enqueue(request); } catch(Exception e){ e.printStackTrace(); } } }.start(); }
That’s all we need to make it work on Android devices with SDK < 23. On devices with SDK 23+, we’ll have to ask application users to grant permission to use their device storage. A method to check the device SDK and to ask for permission (if necessary) may look like this (in our code sample it is called before the download starts in Step 3):
public boolean isStoragePermissionGranted() { if (Build.VERSION.SDK_INT >= 23) { //permission is automatically granted on sdk<23 upon installation if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { Log.v("Permission status","Permission is granted"); return true; } else { Log.v("Permission status","Permission is revoked"); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); return false; } } else { Log.v("Permission status","Permission is granted"); return true; } }
We need to call this method in the download method of our download activity class. The result of the user choice should be handled in a separate callback, the same callback in which the download process should be restored:
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(grantResults[0]== PackageManager.PERMISSION_GRANTED){ Log.v("Permission status","Permission: "+ permissions[0]+ "was "+ grantResults[0]); //resume tasks needing this permission downloadFiles.callOnClick(); } }
Where downloadFiles is a button to start the download.
The whole test app interface will look like this:
Once you click the ALLOW button, the download process will be started.
That’s it!
The archive with this application can be found here: https://drive.google.com/open?id=1A4Mx3UEWK_ckgaSjaw0TWU5OvVq4ocLY
Don’t forget to add your Backendless AppId and Android API key in the Defaults class. Thanks for reading this post, hope you like it!