Skip to content

Commit f29d630

Browse files
swiftyoneihadeed
authored andcommitted
fix(image-loader): use tempDirectory on iOS (#39)
* fix(image-loader): use tempDirectory on iOS The tempDirectory can be accessed from the WKWebView as well; no need for base64! * Revert "fix(image-loader): use tempDirectory on iOS" This reverts commit bea5839. * Specify the imageReturnType (base64/uri) If 'uri' is used the files will be copied to the temporary directory if the WKWebView engine is used. Files in this directory are not persistent, but accessible from within the WebView. If the files do not exist any longer they will automatically be copied again!
1 parent ccf3ccc commit f29d630

File tree

3 files changed

+113
-26
lines changed

3 files changed

+113
-26
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- Allows setting **maximum cache age** to delete old images automatically. This is optional and **disabled by default**.
1414
- Allows setting **maximum cache size** to control how much space your app takes out of the users' phones. This is optional and **disabled by default**.
1515
- Allows setting a **fallback image** to be displayed in case the image you're trying to show doesn't exist on the web. (optional)
16+
- Works with the **[WKWebView Engine](https://github.com/apache/cordova-plugin-wkwebview-engine)** (iOS), as the images are copied to the temporary directory, which is accessible form within the WebView
1617

1718
![Gif](https://github.com/ihadeed/ionic-image-loader-example/blob/master/gif.gif?raw=true)
1819

@@ -250,6 +251,14 @@ Example:
250251
this.imageLoaderConfig.setMaximumCacheAge(7 * 24 * 60 * 60 * 1000); // 7 days
251252
```
252253
---
254+
#### setImageReturnType(imageReturnType: string)
255+
Set the return type of cached images. By default this option is set to 'uri', which will return the native file URL. If you want to get a base64-encoded representation of the file set the return type to 'base64'.
256+
257+
Example:
258+
```typescript
259+
this.imageLoaderConfig.setImageReturnType('base64');
260+
```
261+
---
253262
254263
# Preloading images
255264
```typescript

src/providers/image-loader-config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ export class ImageLoaderConfig {
2727

2828
maxCacheAge: number = -1;
2929

30+
imageReturnType: string = 'uri';
31+
3032
private _cacheDirectoryName: string = 'image-loader-cache';
3133

3234
set cacheDirectoryName(name: string) {
@@ -142,4 +144,12 @@ export class ImageLoaderConfig {
142144
this.maxCacheAge = cacheAge;
143145
}
144146

147+
/**
148+
* Set the return type of cached images
149+
* @param imageReturnType {string} The return type; either 'base64' or 'uri'
150+
*/
151+
setImageReturnType(imageReturnType: string): void {
152+
this.imageReturnType = imageReturnType;
153+
}
154+
145155
}

src/providers/image-loader.ts

Lines changed: 94 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Injectable } from '@angular/core';
2-
import { File, FileEntry, FileReader, FileError } from '@ionic-native/file';
2+
import { File, FileEntry, FileError, DirectoryEntry } from '@ionic-native/file';
33
import { Transfer } from '@ionic-native/transfer';
44
import { ImageLoaderConfig } from "./image-loader-config";
55
import { Platform } from 'ionic-angular';
@@ -108,7 +108,23 @@ export class ImageLoader {
108108

109109
this.file.removeRecursively(this.file.cacheDirectory, this.config.cacheDirectoryName)
110110
.then(() => {
111-
this.initCache(true);
111+
if (this.isWKWebView) {
112+
113+
// also clear the temp files
114+
this.file.removeRecursively(this.file.tempDirectory, this.config.cacheDirectoryName)
115+
.catch((error) => {
116+
// Noop catch. Removing the tempDirectory might fail,
117+
// as it is not persistent.
118+
})
119+
.then(() => {
120+
this.initCache(true);
121+
});
122+
123+
} else {
124+
125+
this.initCache(true);
126+
127+
}
112128
})
113129
.catch(this.throwError.bind(this));
114130

@@ -284,7 +300,7 @@ export class ImageLoader {
284300
&& (Date.now() - metadata.modificationTime.getTime()) > this.config.maxCacheAge
285301
) {
286302
// file age exceeds maximum cache age
287-
return this.file.removeFile(this.file.cacheDirectory + this.config.cacheDirectoryName, file.name);
303+
return this.removeFile(file.name);
288304
} else {
289305

290306
// file age doesn't exceed maximum cache age, or maximum cache age isn't set
@@ -352,7 +368,7 @@ export class ImageLoader {
352368
if (typeof file == 'undefined') return maintain();
353369

354370
// delete the file then process next file if necessary
355-
this.file.removeFile(this.file.cacheDirectory + this.config.cacheDirectoryName, file.name)
371+
this.removeFile(file.name)
356372
.then(() => next())
357373
.catch(() => next()); // ignore errors, nothing we can do about it
358374
}
@@ -364,6 +380,24 @@ export class ImageLoader {
364380

365381
}
366382

383+
/**
384+
* Remove a file
385+
* @param file {string} The name of the file to remove
386+
*/
387+
private removeFile(file: string): Promise<any> {
388+
return this.file
389+
.removeFile(this.file.cacheDirectory + this.config.cacheDirectoryName, file)
390+
.then(() => {
391+
if (this.isWKWebView) {
392+
return this.file
393+
.removeFile(this.file.tempDirectory + this.config.cacheDirectoryName, file)
394+
.catch(() => {
395+
// Noop catch. Removing the files from tempDirectory might fail, as it is not persistent.
396+
});
397+
}
398+
});
399+
}
400+
367401
/**
368402
* Get the local path of a previously cached image if exists
369403
* @param url {string} The remote URL of the image
@@ -381,32 +415,58 @@ export class ImageLoader {
381415
const fileName = this.createFileName(url);
382416

383417
// get full path
384-
const dirPath = this.file.cacheDirectory + this.config.cacheDirectoryName;
418+
const dirPath = this.file.cacheDirectory + this.config.cacheDirectoryName,
419+
tempDirPath = this.file.tempDirectory + this.config.cacheDirectoryName;
385420

386421
// check if exists
387422
this.file.resolveLocalFilesystemUrl(dirPath + '/' + fileName)
388423
.then((fileEntry: FileEntry) => {
389424
// file exists in cache
390425

391-
// now check if iOS device & using WKWebView Engine
392-
if (this.isWKWebView) {
393-
394-
// Read FileEntry and return as data url
395-
fileEntry.file((file: any) => {
396-
const reader = new FileReader();
397-
398-
reader.onloadend = function() {
399-
resolve(this.result);
400-
};
401-
402-
reader.readAsDataURL(file);
403-
}, reject);
404-
405-
} else {
406-
407-
// return native path
408-
resolve(fileEntry.nativeURL);
409-
426+
if (this.config.imageReturnType === 'base64') {
427+
428+
// read the file as data url and return the base64 string.
429+
// should always be successful as the existence of the file
430+
// is alreay ensured
431+
this.file
432+
.readAsDataURL(dirPath, fileName)
433+
.then((base64: string) => {
434+
resolve(base64);
435+
})
436+
.catch(reject);
437+
438+
} else if (this.config.imageReturnType === 'uri') {
439+
440+
// now check if iOS device & using WKWebView Engine.
441+
// in this case only the tempDirectory is accessible,
442+
// therefore the file needs to be copied into that directory first!
443+
if (this.isWKWebView) {
444+
445+
// check if file already exists in temp directory
446+
this.file.resolveLocalFilesystemUrl(tempDirPath + '/' + fileName)
447+
.then((tempFileEntry: FileEntry) => {
448+
// file exists in temp directory
449+
// return native path
450+
resolve(tempFileEntry.nativeURL);
451+
})
452+
.catch(() => {
453+
// file does not yet exist in the temp directory.
454+
// copy it!
455+
this.file.copyFile(dirPath, fileName, tempDirPath, fileName)
456+
.then((tempFileEntry: FileEntry) => {
457+
// now the file exists in the temp directory
458+
// return native path
459+
resolve(tempFileEntry.nativeURL);
460+
})
461+
.catch(reject);
462+
});
463+
464+
} else {
465+
466+
// return native path
467+
resolve(fileEntry.nativeURL);
468+
469+
}
410470
}
411471
})
412472
.catch(reject); // file doesn't exist
@@ -441,7 +501,11 @@ export class ImageLoader {
441501
* @returns {Promise<boolean|FileError>} Returns a promise that resolves if exists, and rejects if it doesn't
442502
*/
443503
private get cacheDirectoryExists(): Promise<boolean> {
444-
return this.file.checkDir(this.file.cacheDirectory, this.config.cacheDirectoryName);
504+
return this.file
505+
.checkDir(this.file.cacheDirectory, this.config.cacheDirectoryName)
506+
.then(() => {
507+
return (this.isWKWebView ? this.file.checkDir(this.file.tempDirectory, this.config.cacheDirectoryName) : Promise.resolve());
508+
});
445509
}
446510

447511
/**
@@ -450,7 +514,11 @@ export class ImageLoader {
450514
* @returns {Promise<DirectoryEntry|FileError>} Returns a promise that resolves if the directory was created, and rejects on error
451515
*/
452516
private createCacheDirectory(replace: boolean = false): Promise<any> {
453-
return this.file.createDir(this.file.cacheDirectory, this.config.cacheDirectoryName, replace);
517+
return this.file
518+
.createDir(this.file.cacheDirectory, this.config.cacheDirectoryName, replace)
519+
.then(() => {
520+
return this.isWKWebView ? this.file.createDir(this.file.tempDirectory, this.config.cacheDirectoryName, replace) : Promise.resolve();
521+
});
454522
}
455523

456524
/**

0 commit comments

Comments
 (0)