Es mostren els missatges amb l'etiqueta de comentaris file. Mostrar tots els missatges
Es mostren els missatges amb l'etiqueta de comentaris file. Mostrar tots els missatges

dilluns, 5 de juny del 2017

Ionic 2. Backup stories part II

Well, in the previous entry I explain how to install the plugin and how decide according the system the origin of data and the destination. Every OS has a different file system and we must adapt us at your characteristics. In the two cases the origin it's similar and use  applicationStorageDirectory property for access both of them. The difference is in the directory that contains the database, Library/LocalDatabase/ in iOS and databases/ in Android.

In the case of the destination it's where the differences are more big. In Android I think the best place is the root of the external storage, either in the root or in a directory for the app in the root. The access for this location is easy and the user just have to plug your device and has already access to the files and directories. 

iOS is another thing. Reading the File System Programming Guide from Apple Developers here we can see that recommends Documents/ in the Data Container inside the sandbox for store the user-generated content. The contents of this directory is accessible with iTunes and iCloud when making a backup or through file sharing but not  as in Android with a file manager when plugs the device in a computer.

Having said this already we can implement our methods for make a backup and restore it. For the destination path we use two different properties externalRootDirectory for Android and documentsDirectory for iOS, you can see this in the previous entry. 

The idea for the implementation is easy, first we check if file exist in the destination path, if it exist we remove it because the plugin cannot rewrite it. After of remove the file or if the file doesn't exist we copy it . If the operation have success shows a success message and if it is rejected shows an error message.

The code for the backup

backup() { let path: string; let destPath: string; let dirMessage: string;
if (this.iOSDir.length > 1) { destPath = this.iOSDir; path = this.file.applicationStorageDirectory + 'Library/LocalDatabase/'; this.translate.get('IOSDOCUMENTSDIRECTORY') .subscribe(value => { dirMessage = value; }); } else { destPath = this.AndroidDir;< path = this.file.applicationStorageDirectory + 'databases/'; this.translate.get('ANDROIDDOCUMENTSDIRECTORY') .subscribe(value => { dirMessage = value; }); } //check if file exist, if it exist remove it and copy new file. //If the file doesn't exist copy it this.file.checkFile(destPath, this.fileName) .then(success => {
//if file exist first remove it this.file.removeFile(destPath, this.fileName) .then(success => { //Copy new instance of the file this.file.copyFile(path, this.fileName, destPath, this.fileName).then(success => { //translations this.translate.get('BACKUPSUCCESS') .subscribe(value => { this.alertMes = value; this.alertMessage(this.alertMes + dirMessage); });
}, error => { this.translate.get('BACKUPUNSUCCESS') .subscribe(value => { this.alertMes = value; this.alertMessage(this.alertMes); }); }); }, error => { this.translate.get('BACKUPUNSUCCESS') .subscribe(value => { this.alertMes = value; this.alertMessage(this.alertMes); }); }); }, error => { //first copy of file this.file.copyFile(path, this.fileName, destPath, this.fileName).then(success => { this.translate.get('BACKUPSUCCESS') .subscribe(value => { this.alertMes = value; this.alertMessage(this.alertMes + dirMessage); }); }, error => { this.translate.get('BACKUPUNSUCCESS') .subscribe(value => { this.alertMes = value; this.alertMessage(this.alertMes); }) }); }); }

And for restore

restoreBackup() { let path: string; let destPath: string; let dirMessage: string; if (this.iOSDir.length > 1) { path = this.iOSDir; destPath = this.file.applicationStorageDirectory + 'Library/LocalDatabase/'; } else { path = this.AndroidDir;
destPath = this.file.applicationStorageDirectory + 'databases/'; } //check if backup file exist this.file.checkFile(path, this.fileName).then(success => { //check if file exist, if it exist remove it and //copy new file. If the file doesn't exist copy it this.file.checkFile(destPath, this.fileName) .then(success => { //if file exist first remove it this.file.removeFile(destPath, this.fileName) .then(success => { //Copy new instance of the file this.file.copyFile(path, this.fileName, destPath, this.fileName).then(success => { //Close and reopen database this.dbService.closeDatabase().then(success => { this.dbService.openDatabase(); this.translate.get('RESTOREBACKUPSUCCESS') .subscribe(value => { this.alertMes = value; this.alertMessage(this.alertMes); }); }); }, error => { this.translate.get('RESTOREBACKUPUNSUCCESS') .subscribe(value => { this.alertMes = value; this.alertMessage(this.alertMes); }); }); }, error => { this.translate.get('RESTOREBACKUPUNSUCCESS') .subscribe(value => { this.alertMes = value; this.alertMessage(this.alertMes); }); }); }, error => { this.translate.get('RESTOREBACKUPUNSUCCESS') .subscribe(value => { this.alertMes = value; this.alertMessage(this.alertMes); }); }); }, error => { this.translate.get('BACKUPUNOTEXIST') .subscribe(value => { this.alertMes = value; this.alertMessage(this.alertMes + path); }); }); }

Basically for restore we do the same changing the origin and the destination of the file. The last operation when the file are copied is close the database and reopen it for what the changes are efectives in the app.

And that would be all for iOS and Android before to Marshmallow. Since Marshmallow it is necessary to check the permissions and this I leave it for the next entry.

dilluns, 29 de maig del 2017

Ionic 2. Backup stories part I

When I started this blog, the idea was to practice my English with the hope to improve it, I'm self taught and I think that it is a good way to do it. Normally I write about what I'm doing, and this time is how to do a backup in my app developed with Ionic 2. The point is all of my apps don't use any server to store data, they not ask for special permissions, only the internet access for serve ads and in this case in Android, permission for write in the external storage for save the backup. But this is the second question of this story, so let's start at the beginning.

My app stores the data in a database SQLite and it to do in two tables. The amount of data is not very large and I don't need any more. My first idea was to create a method  that makes a query of all the data and store it in a file in JSON format. Create the backup is really easy and restore it not too complicated. I looked in the Ionic documentation and it provides a File API in Ionic Native for read and write files. Here you can find more info about this.  Well, it seems that I already have all of I need so let's install it.

From a terminal inside the project directory

   ionic plugin add cordova-plugin-file


And
   npm install --save @ionic-native/file




And add the plugin in the app.module.ts. First import it and then we put it on the providers section

import { File } from '@ionic-native/file';

providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}, DbService, File, AdMob]

Well, it is ready to use.

But reading the documentation of the plugin I see which it have methods to check, delete and copy files. And I have thought SQLite stores the data in a file so for make a backup I only need copy this file and store it in another directory that finally is the same that should I do with the result of the query. Ok, it's already decided. I will copy the file in a directory accessible to the user.

Now the first step is find the file.  In my database service, I have wrote

openDatabase() { return this.db.openDatabase({ name: 'eDomestic.db', location: 'default', createFromLocation: 1 }) .catch(error => console.error('Error opening database', error)); }


But where is location: default. Well, in Android it is in /data/data/your-app/databases/ or using the plugin File.applicationStorageDirectory + 'databases/'. In iOS it is in /var/mobile/Applications/<UUID>/Library/LocalDatabase/  or using the plugin File.applicationStorageDirectory + 'Library/LocalDatabase/.

First we need to know what system we are using Android or iOS, for that

if (/(android)/i.test(navigator.userAgent)) { this.AndroidDir = this.file.externalRootDirectory; } else if (/(ipod|iphone|ipad)/i.test(navigator.userAgent)) { this.iOSDir = this.file.documentsDirectory; }

AndroidDir and iOSDir contains the destination for the backup. For the origin path

if (this.iOSDir.length > 1) { destPath = this.iOSDir; path = this.file.applicationStorageDirectory + 'Library/LocalDatabase/'; this.translate.get('IOSDOCUMENTSDIRECTORY') .subscribe(value => { dirMessage = value; }); } else { destPath = this.AndroidDir; path = this.file.applicationStorageDirectory + 'databases/'; this.translate.get('ANDROIDDOCUMENTSDIRECTORY') .subscribe(value => { dirMessage = value; }); }

Here, depending of what OS we are using we select a destination and origin or another. And now we can use the plugin for copy the file. But where save the file and why?

In the next entry I will continue explain the as and the why I do it like that.