This post discusses how to download files to your device from your API in an Ionic 3 application. By using the File and File Transfer plugins that are available for Ionic you can accomplish this task.
First, you install the necessary plugins — File and File Transfer. You can refer to Ionic’s documentation here to install them.
- https://ionicframework.com/docs/v3/native/file/
- https://ionicframework.com/docs/v3/native/file-transfer/
Make certain that you add the plugins to your providers in the main app module.
Next, you create a service to handle the download. Using a service takes advantage of Angular’s modularity and reusability. Remember to add the following service to your providers in the main app module.
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";
import { fromPromise } from "rxjs/observable/fromPromise";
import { FileTransfer, FileTransferObject } from '@ionic-native/file-transfer';
import { Platform, AlertController } from "ionic-angular";
import { File } from "@ionic-native/file";
import { AndroidPermissions } from '@ionic-native/android-permissions';
@Injectable()
export class DownloadService {
constructor(
private transfer: FileTransfer,
private file: File,
private platform: Platform,
private androidPermissions: AndroidPermissions,
private alertCtrl: AlertController
) {
}
public downloadFile(fileId: number, fileName: string): Observable<any> {
return fromPromise(this.performDownload(fileId, fileName, fileExtension));
}
protected async performDownload(fileId: number, fileName: string){
// We added this check since this is only intended to work on devices and emulators
if (!this.platform.is('cordova')) {
console.warn('Cannot download in local environment!');
return;
}
const fileTransfer: FileTransferObject = this.transfer.create();
let uri = encodeURI(`www.yourapi.com/file/download?id=fileId`);
let path = await this.getDownloadPath();
let fullFileName = fileName + '.' + fileExtension;
// Depending on your needs, you might want to use some form of authentication for your API endpoints
// In this case, we are using bearer tokens
let bearerToken = 'yourToken';
return fileTransfer.download(
uri,
path + fileName,
false,
{
headers: {
"Authorization": `Bearer ${bearerToken}`
}
}
).then(
result => {
this.showAlert(true, fileName);
},
error => {
this.showAlert(false, fileName);
}
)
}
public async getDownloadPath() {
if (this.platform.is('ios')) {
return this.file.documentsDirectory;
}
// To be able to save files on Android, we first need to ask the user for permission.
// We do not let the download proceed until they grant access
await this.androidPermissions.checkPermission(this.androidPermissions.PERMISSION.WRITE_EXTERNAL_STORAGE).then(
result => {
if (!result.hasPermission) {
return this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.WRITE_EXTERNAL_STORAGE);
}
}
);
return this.file.externalRootDirectory + "/Download/";
}
// Here we are using simple alerts to show the user if the download was successful or not
public showAlert(hasPassed: boolean, fileName: string) {
let title = hasPassed ? "Download complete!" : "Download failed!";
let subTitle = hasPassed ? `Successfully downloaded ${fileName}.` : `There was a problem while downloading ${fileName}`;
const alert = this.alertCtrl.create({
title: title,
subTitle: subTitle,
buttons: ['OK']
});
alert.present();
}
}
Next, you inject the download service into the page and add a function to be called from your template. That code looks as follows.
import { Component} from '@angular/core';
import { IonicPage, NavController } from 'ionic-angular';
import { DownloadService } from '../../providers/download/download-service';
@IonicPage()
@Component({
selector: 'page-downloads',
templateUrl: 'downloads.html',
})
export class DownloadsPage {
// Here we are injecting our download service into our page
constructor(private downloadService: DownloadService{ }
// This is the function that will trigger the download
public downloadFile(fileId: number, fileName: string) {
this.downloadService.downloadFile(fileId, fileName).subscribe();
}
}
Finally, add the necessary code to call the function from page template. The assumption is that you have a list of items to be downloaded.
<ion-list>
<ng-container *ngFor="let item of downloadableItems">
<button (click)="downloadFile(item.id, item.name)">
<div>
<h2>{{ content.name }}</h2>
</div>
</button>
</ng-container>
</ion-list>
In summary, you create a service to handle the download. Then, you inject the service into the page and add a function to be called from the template. Finally, you call the function. Now, you can successfully download files from an API to your device.