From 647bbd120a2e5389b9d60ffaa8d1d0a4c51f0531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kosmaty?= Date: Thu, 2 Apr 2020 15:59:11 +0200 Subject: [PATCH] [expo-file-system] Apply requested changes --- packages/expo-file-system/CHANGELOG.md | 2 +- .../modules/filesystem/FileSystemModule.java | 14 +- packages/expo-file-system/build/FileSystem.js | 2 +- .../expo-file-system/build/FileSystem.js.map | 2 +- .../build/FileSystem.types.js | 10 ++ .../build/FileSystem.types.js.map | 2 +- .../ios/EXFileSystem/EXFileSystem.h | 2 +- .../ios/EXFileSystem/EXFileSystem.m | 146 ++++++++++++------ .../EXSessionDownloadTaskDelegate.h | 20 +-- .../EXSessionDownloadTaskDelegate.m | 41 ++--- .../EXSessionResumableDownloadTaskDelegate.h | 23 ++- .../EXSessionResumableDownloadTaskDelegate.m | 49 +++--- .../EXSessionTasks/EXSessionTaskDelegate.h | 18 ++- .../EXSessionTasks/EXSessionTaskDelegate.m | 6 +- .../EXSessionUploadTaskDelegate.h | 5 +- .../EXSessionUploadTaskDelegate.m | 13 +- packages/expo-file-system/src/FileSystem.ts | 2 +- .../expo-file-system/src/FileSystem.types.ts | 11 +- 18 files changed, 202 insertions(+), 166 deletions(-) diff --git a/packages/expo-file-system/CHANGELOG.md b/packages/expo-file-system/CHANGELOG.md index fe7f92bf59a02..dba7ab5eaa4a1 100644 --- a/packages/expo-file-system/CHANGELOG.md +++ b/packages/expo-file-system/CHANGELOG.md @@ -4,7 +4,7 @@ ### 🛠 Breaking changes -- `FileSystem.downloadAsync` and `FileSystem.DownloadResumable` now works in the background - they won't reject when the user backgrounds the application. ([#7380](https://github.com/expo/expo/pull/7380) [@lukmccall](https://github.com/lukmccall)) +- `FileSystem.downloadAsync` and `FileSystem.DownloadResumable` works in the background from now on - they won't reject when the application is moved to the background. ([#7380](https://github.com/expo/expo/pull/7380) by [@lukmccall](https://github.com/lukmccall)) - `FileSystem.getContentUriAsync` now returns a string. ([#7192](https://github.com/expo/expo/pull/7192) by [@lukmccall](https://github.com/lukmccall)) ### 🎉 New features diff --git a/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.java b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.java index a01b271920e8c..202a5a781471c 100644 --- a/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.java +++ b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.java @@ -37,8 +37,6 @@ import java.io.OutputStreamWriter; import java.math.BigInteger; import java.net.CookieHandler; -import java.nio.file.LinkOption; -import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; @@ -83,7 +81,6 @@ public FileSystemModule(Context context) { } catch (IOException e) { e.printStackTrace(); } - } @Override @@ -491,9 +488,14 @@ public void downloadAsync(String url, final String uriStr, final Map headers = (Map) options.get(HEADER_KEY); - for (String key : headers.keySet()) { - requestBuilder.addHeader(key, headers.get(key).toString()); + try { + final Map headers = (Map) options.get(HEADER_KEY); + for (String key : headers.keySet()) { + requestBuilder.addHeader(key, (String) headers.get(key)); + } + } catch (ClassCastException exception) { + promise.reject("ERR_FILESYSTEM_INVALID_HEADERS", "Invalid headers dictionary. Keys and values should be strings.", exception); + return; } } getOkHttpClient().newCall(requestBuilder.build()).enqueue(new Callback() { diff --git a/packages/expo-file-system/build/FileSystem.js b/packages/expo-file-system/build/FileSystem.js index f91b3fff95519..700ba0a0fe1ec 100644 --- a/packages/expo-file-system/build/FileSystem.js +++ b/packages/expo-file-system/build/FileSystem.js @@ -164,7 +164,7 @@ export class DownloadResumable { if (this._subscription) { return; } - this._subscription = this._emitter.addListener('Exponent.downloadProgress', (event) => { + this._subscription = this._emitter.addListener('expo-file-system.downloadProgress', (event) => { if (event.uuid === this._uuid) { const callback = this._callback; if (callback) { diff --git a/packages/expo-file-system/build/FileSystem.js.map b/packages/expo-file-system/build/FileSystem.js.map index d1bdc2a264bad..d5fa52219c22f 100644 --- a/packages/expo-file-system/build/FileSystem.js.map +++ b/packages/expo-file-system/build/FileSystem.js.map @@ -1 +1 @@ -{"version":3,"file":"FileSystem.js","sourceRoot":"","sources":["../src/FileSystem.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter, Subscription, UnavailabilityError } from '@unimodules/core';\nimport { Platform } from 'react-native';\nimport uuidv4 from 'uuid/v4';\n\nimport ExponentFileSystem from './ExponentFileSystem';\nimport {\n DownloadOptions,\n DownloadPauseState,\n DownloadProgressCallback,\n DownloadProgressData,\n DownloadResult,\n EncodingType,\n FileInfo,\n FileSystemDownloadResult,\n FileSystemHttpMethods,\n FileSystemSessionType,\n FileSystemUploadOptions,\n FileSystemUploadResult,\n ProgressEvent,\n ReadingOptions,\n WritingOptions,\n} from './FileSystem.types';\n\nif (!ExponentFileSystem) {\n console.warn(\n \"No native ExponentFileSystem module found, are you sure the expo-file-system's module is linked properly?\"\n );\n}\n// Prevent webpack from pruning this.\nconst _unused = new EventEmitter(ExponentFileSystem); // eslint-disable-line\n\nexport {\n DownloadOptions,\n DownloadPauseState,\n DownloadProgressCallback,\n DownloadProgressData,\n DownloadResult,\n EncodingType,\n FileInfo,\n FileSystemDownloadResult,\n FileSystemHttpMethods,\n FileSystemSessionType,\n FileSystemUploadOptions,\n FileSystemUploadResult,\n ProgressEvent,\n ReadingOptions,\n WritingOptions,\n};\n\nfunction normalizeEndingSlash(p: string | null): string | null {\n if (p != null) {\n return p.replace(/\\/*$/, '') + '/';\n }\n return null;\n}\n\nexport const documentDirectory = normalizeEndingSlash(ExponentFileSystem.documentDirectory);\nexport const cacheDirectory = normalizeEndingSlash(ExponentFileSystem.cacheDirectory);\n\nexport const { bundledAssets, bundleDirectory } = ExponentFileSystem;\n\nexport async function getInfoAsync(\n fileUri: string,\n options: { md5?: boolean; size?: boolean } = {}\n): Promise {\n if (!ExponentFileSystem.getInfoAsync) {\n throw new UnavailabilityError('expo-file-system', 'getInfoAsync');\n }\n return await ExponentFileSystem.getInfoAsync(fileUri, options);\n}\n\nexport async function readAsStringAsync(\n fileUri: string,\n options?: ReadingOptions\n): Promise {\n if (!ExponentFileSystem.readAsStringAsync) {\n throw new UnavailabilityError('expo-file-system', 'readAsStringAsync');\n }\n return await ExponentFileSystem.readAsStringAsync(fileUri, options || {});\n}\n\nexport async function getContentUriAsync(fileUri: string): Promise {\n if (Platform.OS === 'android') {\n if (!ExponentFileSystem.getContentUriAsync) {\n throw new UnavailabilityError('expo-file-system', 'getContentUriAsync');\n }\n return await ExponentFileSystem.getContentUriAsync(fileUri);\n } else {\n return new Promise(function(resolve, reject) {\n resolve(fileUri);\n });\n }\n}\n\nexport async function writeAsStringAsync(\n fileUri: string,\n contents: string,\n options: WritingOptions = {}\n): Promise {\n if (!ExponentFileSystem.writeAsStringAsync) {\n throw new UnavailabilityError('expo-file-system', 'writeAsStringAsync');\n }\n return await ExponentFileSystem.writeAsStringAsync(fileUri, contents, options);\n}\n\nexport async function deleteAsync(\n fileUri: string,\n options: { idempotent?: boolean } = {}\n): Promise {\n if (!ExponentFileSystem.deleteAsync) {\n throw new UnavailabilityError('expo-file-system', 'deleteAsync');\n }\n return await ExponentFileSystem.deleteAsync(fileUri, options);\n}\n\nexport async function deleteLegacyDocumentDirectoryAndroid(): Promise {\n if (Platform.OS !== 'android' || documentDirectory == null) {\n return;\n }\n const legacyDocumentDirectory = `${documentDirectory}ExperienceData/`;\n return await deleteAsync(legacyDocumentDirectory, { idempotent: true });\n}\n\nexport async function moveAsync(options: { from: string; to: string }): Promise {\n if (!ExponentFileSystem.moveAsync) {\n throw new UnavailabilityError('expo-file-system', 'moveAsync');\n }\n return await ExponentFileSystem.moveAsync(options);\n}\n\nexport async function copyAsync(options: { from: string; to: string }): Promise {\n if (!ExponentFileSystem.copyAsync) {\n throw new UnavailabilityError('expo-file-system', 'copyAsync');\n }\n return await ExponentFileSystem.copyAsync(options);\n}\n\nexport async function makeDirectoryAsync(\n fileUri: string,\n options: { intermediates?: boolean } = {}\n): Promise {\n if (!ExponentFileSystem.makeDirectoryAsync) {\n throw new UnavailabilityError('expo-file-system', 'makeDirectoryAsync');\n }\n return await ExponentFileSystem.makeDirectoryAsync(fileUri, options);\n}\n\nexport async function readDirectoryAsync(fileUri: string): Promise {\n if (!ExponentFileSystem.readDirectoryAsync) {\n throw new UnavailabilityError('expo-file-system', 'readDirectoryAsync');\n }\n return await ExponentFileSystem.readDirectoryAsync(fileUri, {});\n}\n\nexport async function getFreeDiskStorageAsync(): Promise {\n if (!ExponentFileSystem.getFreeDiskStorageAsync) {\n throw new UnavailabilityError('expo-file-system', 'getFreeDiskStorageAsync');\n }\n return await ExponentFileSystem.getFreeDiskStorageAsync();\n}\n\nexport async function getTotalDiskCapacityAsync(): Promise {\n if (!ExponentFileSystem.getTotalDiskCapacityAsync) {\n throw new UnavailabilityError('expo-file-system', 'getTotalDiskCapacityAsync');\n }\n return await ExponentFileSystem.getTotalDiskCapacityAsync();\n}\n\nexport async function downloadAsync(\n uri: string,\n fileUri: string,\n options: DownloadOptions = {}\n): Promise {\n if (!ExponentFileSystem.downloadAsync) {\n throw new UnavailabilityError('expo-file-system', 'downloadAsync');\n }\n return await ExponentFileSystem.downloadAsync(uri, fileUri, options);\n}\n\nexport async function uploadAsync(\n url: string,\n fileUri: string,\n options: FileSystemUploadOptions = {}\n): Promise {\n if (!ExponentFileSystem.uploadAsync) {\n throw new UnavailabilityError('expo-file-system', 'uploadAsync');\n }\n return await ExponentFileSystem.uploadAsync(url, fileUri, options);\n}\n\nexport function createDownloadResumable(\n uri: string,\n fileUri: string,\n options?: DownloadOptions,\n callback?: DownloadProgressCallback,\n resumeData?: string\n): DownloadResumable {\n return new DownloadResumable(uri, fileUri, options, callback, resumeData);\n}\n\nexport class DownloadResumable {\n _uuid: string;\n _url: string;\n _fileUri: string;\n _options: DownloadOptions;\n _resumeData?: string;\n _callback?: DownloadProgressCallback;\n _subscription?: Subscription | null;\n _emitter: EventEmitter;\n\n constructor(\n url: string,\n fileUri: string,\n options: DownloadOptions = {},\n callback?: DownloadProgressCallback,\n resumeData?: string\n ) {\n this._uuid = uuidv4();\n this._url = url;\n this._fileUri = fileUri;\n this._options = options;\n this._resumeData = resumeData;\n this._callback = callback;\n this._subscription = null;\n this._emitter = new EventEmitter(ExponentFileSystem);\n }\n\n async downloadAsync(): Promise {\n if (!ExponentFileSystem.downloadResumableStartAsync) {\n throw new UnavailabilityError('expo-file-system', 'downloadResumableStartAsync');\n }\n this._addSubscription();\n return await ExponentFileSystem.downloadResumableStartAsync(\n this._url,\n this._fileUri,\n this._uuid,\n this._options,\n this._resumeData\n );\n }\n\n async pauseAsync(): Promise {\n if (!ExponentFileSystem.downloadResumablePauseAsync) {\n throw new UnavailabilityError('expo-file-system', 'downloadResumablePauseAsync');\n }\n const pauseResult = await ExponentFileSystem.downloadResumablePauseAsync(this._uuid);\n this._removeSubscription();\n if (pauseResult) {\n this._resumeData = pauseResult.resumeData;\n return this.savable();\n } else {\n throw new Error('Unable to generate a savable pause state');\n }\n }\n\n async resumeAsync(): Promise {\n if (!ExponentFileSystem.downloadResumableStartAsync) {\n throw new UnavailabilityError('expo-file-system', 'downloadResumableStartAsync');\n }\n this._addSubscription();\n return await ExponentFileSystem.downloadResumableStartAsync(\n this._url,\n this._fileUri,\n this._uuid,\n this._options,\n this._resumeData\n );\n }\n\n savable(): DownloadPauseState {\n return {\n url: this._url,\n fileUri: this._fileUri,\n options: this._options,\n resumeData: this._resumeData,\n };\n }\n\n _addSubscription(): void {\n if (this._subscription) {\n return;\n }\n this._subscription = this._emitter.addListener(\n 'Exponent.downloadProgress',\n (event: ProgressEvent) => {\n if (event.uuid === this._uuid) {\n const callback = this._callback;\n if (callback) {\n callback(event.data);\n }\n }\n }\n );\n }\n\n _removeSubscription(): void {\n if (!this._subscription) {\n return;\n }\n this._emitter.removeSubscription(this._subscription);\n this._subscription = null;\n }\n}\n"]} \ No newline at end of file +{"version":3,"file":"FileSystem.js","sourceRoot":"","sources":["../src/FileSystem.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter, Subscription, UnavailabilityError } from '@unimodules/core';\nimport { Platform } from 'react-native';\nimport uuidv4 from 'uuid/v4';\n\nimport ExponentFileSystem from './ExponentFileSystem';\nimport {\n DownloadOptions,\n DownloadPauseState,\n DownloadProgressCallback,\n DownloadProgressData,\n DownloadResult,\n EncodingType,\n FileInfo,\n FileSystemDownloadResult,\n FileSystemHttpMethods,\n FileSystemSessionType,\n FileSystemUploadOptions,\n FileSystemUploadResult,\n ProgressEvent,\n ReadingOptions,\n WritingOptions,\n} from './FileSystem.types';\n\nif (!ExponentFileSystem) {\n console.warn(\n \"No native ExponentFileSystem module found, are you sure the expo-file-system's module is linked properly?\"\n );\n}\n// Prevent webpack from pruning this.\nconst _unused = new EventEmitter(ExponentFileSystem); // eslint-disable-line\n\nexport {\n DownloadOptions,\n DownloadPauseState,\n DownloadProgressCallback,\n DownloadProgressData,\n DownloadResult,\n EncodingType,\n FileInfo,\n FileSystemDownloadResult,\n FileSystemHttpMethods,\n FileSystemSessionType,\n FileSystemUploadOptions,\n FileSystemUploadResult,\n ProgressEvent,\n ReadingOptions,\n WritingOptions,\n};\n\nfunction normalizeEndingSlash(p: string | null): string | null {\n if (p != null) {\n return p.replace(/\\/*$/, '') + '/';\n }\n return null;\n}\n\nexport const documentDirectory = normalizeEndingSlash(ExponentFileSystem.documentDirectory);\nexport const cacheDirectory = normalizeEndingSlash(ExponentFileSystem.cacheDirectory);\n\nexport const { bundledAssets, bundleDirectory } = ExponentFileSystem;\n\nexport async function getInfoAsync(\n fileUri: string,\n options: { md5?: boolean; size?: boolean } = {}\n): Promise {\n if (!ExponentFileSystem.getInfoAsync) {\n throw new UnavailabilityError('expo-file-system', 'getInfoAsync');\n }\n return await ExponentFileSystem.getInfoAsync(fileUri, options);\n}\n\nexport async function readAsStringAsync(\n fileUri: string,\n options?: ReadingOptions\n): Promise {\n if (!ExponentFileSystem.readAsStringAsync) {\n throw new UnavailabilityError('expo-file-system', 'readAsStringAsync');\n }\n return await ExponentFileSystem.readAsStringAsync(fileUri, options || {});\n}\n\nexport async function getContentUriAsync(fileUri: string): Promise {\n if (Platform.OS === 'android') {\n if (!ExponentFileSystem.getContentUriAsync) {\n throw new UnavailabilityError('expo-file-system', 'getContentUriAsync');\n }\n return await ExponentFileSystem.getContentUriAsync(fileUri);\n } else {\n return new Promise(function(resolve, reject) {\n resolve(fileUri);\n });\n }\n}\n\nexport async function writeAsStringAsync(\n fileUri: string,\n contents: string,\n options: WritingOptions = {}\n): Promise {\n if (!ExponentFileSystem.writeAsStringAsync) {\n throw new UnavailabilityError('expo-file-system', 'writeAsStringAsync');\n }\n return await ExponentFileSystem.writeAsStringAsync(fileUri, contents, options);\n}\n\nexport async function deleteAsync(\n fileUri: string,\n options: { idempotent?: boolean } = {}\n): Promise {\n if (!ExponentFileSystem.deleteAsync) {\n throw new UnavailabilityError('expo-file-system', 'deleteAsync');\n }\n return await ExponentFileSystem.deleteAsync(fileUri, options);\n}\n\nexport async function deleteLegacyDocumentDirectoryAndroid(): Promise {\n if (Platform.OS !== 'android' || documentDirectory == null) {\n return;\n }\n const legacyDocumentDirectory = `${documentDirectory}ExperienceData/`;\n return await deleteAsync(legacyDocumentDirectory, { idempotent: true });\n}\n\nexport async function moveAsync(options: { from: string; to: string }): Promise {\n if (!ExponentFileSystem.moveAsync) {\n throw new UnavailabilityError('expo-file-system', 'moveAsync');\n }\n return await ExponentFileSystem.moveAsync(options);\n}\n\nexport async function copyAsync(options: { from: string; to: string }): Promise {\n if (!ExponentFileSystem.copyAsync) {\n throw new UnavailabilityError('expo-file-system', 'copyAsync');\n }\n return await ExponentFileSystem.copyAsync(options);\n}\n\nexport async function makeDirectoryAsync(\n fileUri: string,\n options: { intermediates?: boolean } = {}\n): Promise {\n if (!ExponentFileSystem.makeDirectoryAsync) {\n throw new UnavailabilityError('expo-file-system', 'makeDirectoryAsync');\n }\n return await ExponentFileSystem.makeDirectoryAsync(fileUri, options);\n}\n\nexport async function readDirectoryAsync(fileUri: string): Promise {\n if (!ExponentFileSystem.readDirectoryAsync) {\n throw new UnavailabilityError('expo-file-system', 'readDirectoryAsync');\n }\n return await ExponentFileSystem.readDirectoryAsync(fileUri, {});\n}\n\nexport async function getFreeDiskStorageAsync(): Promise {\n if (!ExponentFileSystem.getFreeDiskStorageAsync) {\n throw new UnavailabilityError('expo-file-system', 'getFreeDiskStorageAsync');\n }\n return await ExponentFileSystem.getFreeDiskStorageAsync();\n}\n\nexport async function getTotalDiskCapacityAsync(): Promise {\n if (!ExponentFileSystem.getTotalDiskCapacityAsync) {\n throw new UnavailabilityError('expo-file-system', 'getTotalDiskCapacityAsync');\n }\n return await ExponentFileSystem.getTotalDiskCapacityAsync();\n}\n\nexport async function downloadAsync(\n uri: string,\n fileUri: string,\n options: DownloadOptions = {}\n): Promise {\n if (!ExponentFileSystem.downloadAsync) {\n throw new UnavailabilityError('expo-file-system', 'downloadAsync');\n }\n return await ExponentFileSystem.downloadAsync(uri, fileUri, options);\n}\n\nexport async function uploadAsync(\n url: string,\n fileUri: string,\n options: FileSystemUploadOptions = {}\n): Promise {\n if (!ExponentFileSystem.uploadAsync) {\n throw new UnavailabilityError('expo-file-system', 'uploadAsync');\n }\n return await ExponentFileSystem.uploadAsync(url, fileUri, options);\n}\n\nexport function createDownloadResumable(\n uri: string,\n fileUri: string,\n options?: DownloadOptions,\n callback?: DownloadProgressCallback,\n resumeData?: string\n): DownloadResumable {\n return new DownloadResumable(uri, fileUri, options, callback, resumeData);\n}\n\nexport class DownloadResumable {\n _uuid: string;\n _url: string;\n _fileUri: string;\n _options: DownloadOptions;\n _resumeData?: string;\n _callback?: DownloadProgressCallback;\n _subscription?: Subscription | null;\n _emitter: EventEmitter;\n\n constructor(\n url: string,\n fileUri: string,\n options: DownloadOptions = {},\n callback?: DownloadProgressCallback,\n resumeData?: string\n ) {\n this._uuid = uuidv4();\n this._url = url;\n this._fileUri = fileUri;\n this._options = options;\n this._resumeData = resumeData;\n this._callback = callback;\n this._subscription = null;\n this._emitter = new EventEmitter(ExponentFileSystem);\n }\n\n async downloadAsync(): Promise {\n if (!ExponentFileSystem.downloadResumableStartAsync) {\n throw new UnavailabilityError('expo-file-system', 'downloadResumableStartAsync');\n }\n this._addSubscription();\n return await ExponentFileSystem.downloadResumableStartAsync(\n this._url,\n this._fileUri,\n this._uuid,\n this._options,\n this._resumeData\n );\n }\n\n async pauseAsync(): Promise {\n if (!ExponentFileSystem.downloadResumablePauseAsync) {\n throw new UnavailabilityError('expo-file-system', 'downloadResumablePauseAsync');\n }\n const pauseResult = await ExponentFileSystem.downloadResumablePauseAsync(this._uuid);\n this._removeSubscription();\n if (pauseResult) {\n this._resumeData = pauseResult.resumeData;\n return this.savable();\n } else {\n throw new Error('Unable to generate a savable pause state');\n }\n }\n\n async resumeAsync(): Promise {\n if (!ExponentFileSystem.downloadResumableStartAsync) {\n throw new UnavailabilityError('expo-file-system', 'downloadResumableStartAsync');\n }\n this._addSubscription();\n return await ExponentFileSystem.downloadResumableStartAsync(\n this._url,\n this._fileUri,\n this._uuid,\n this._options,\n this._resumeData\n );\n }\n\n savable(): DownloadPauseState {\n return {\n url: this._url,\n fileUri: this._fileUri,\n options: this._options,\n resumeData: this._resumeData,\n };\n }\n\n _addSubscription(): void {\n if (this._subscription) {\n return;\n }\n this._subscription = this._emitter.addListener(\n 'expo-file-system.downloadProgress',\n (event: ProgressEvent) => {\n if (event.uuid === this._uuid) {\n const callback = this._callback;\n if (callback) {\n callback(event.data);\n }\n }\n }\n );\n }\n\n _removeSubscription(): void {\n if (!this._subscription) {\n return;\n }\n this._emitter.removeSubscription(this._subscription);\n this._subscription = null;\n }\n}\n"]} \ No newline at end of file diff --git a/packages/expo-file-system/build/FileSystem.types.js b/packages/expo-file-system/build/FileSystem.types.js index 5ed08f8cb5eb1..015bb7dbdf49a 100644 --- a/packages/expo-file-system/build/FileSystem.types.js +++ b/packages/expo-file-system/build/FileSystem.types.js @@ -1,6 +1,16 @@ export var FileSystemSessionType; (function (FileSystemSessionType) { + /* + * Using this mode means that the downloading/uploading session on the native side will work even if the application is moved to the `background`. + * + * If the task completes when the application is in the `background`, the promise might be resolved immediately. + * However, javascript execution will be stopped after a couple of seconds and it will be resumed when the application is moved to the `foreground` again. + */ FileSystemSessionType[FileSystemSessionType["BACKGROUND"] = 0] = "BACKGROUND"; + /* + * Using this mode means that downloading/uploading session on the native side will be killed once the application becomes inactive (e.g. when it goes to `background`). + * Bringing the application to the `foreground` again would trigger promise rejection. + */ FileSystemSessionType[FileSystemSessionType["FOREGROUND"] = 1] = "FOREGROUND"; })(FileSystemSessionType || (FileSystemSessionType = {})); export var EncodingType; diff --git a/packages/expo-file-system/build/FileSystem.types.js.map b/packages/expo-file-system/build/FileSystem.types.js.map index 5a0c7698825f9..7be814cbad00a 100644 --- a/packages/expo-file-system/build/FileSystem.types.js.map +++ b/packages/expo-file-system/build/FileSystem.types.js.map @@ -1 +1 @@ -{"version":3,"file":"FileSystem.types.js","sourceRoot":"","sources":["../src/FileSystem.types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,qBAGX;AAHD,WAAY,qBAAqB;IAC/B,6EAAc,CAAA;IACd,6EAAc,CAAA;AAChB,CAAC,EAHW,qBAAqB,KAArB,qBAAqB,QAGhC;AAsED,MAAM,CAAN,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,6BAAa,CAAA;IACb,iCAAiB,CAAA;AACnB,CAAC,EAHW,YAAY,KAAZ,YAAY,QAGvB;AAED,MAAM,CAAN,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,iEAAQ,CAAA;IACR,+DAAO,CAAA;IACP,mEAAS,CAAA;AACX,CAAC,EAJW,qBAAqB,KAArB,qBAAqB,QAIhC","sourcesContent":["export enum FileSystemSessionType {\n BACKGROUND = 0,\n FOREGROUND = 1,\n}\n\nexport type DownloadOptions = {\n md5?: boolean;\n cache?: boolean;\n headers?: { [name: string]: string };\n /*\n * iOS only\n */\n sessionType?: FileSystemSessionType;\n};\n\nexport type FileSystemHttpResult = {\n headers: { [name: string]: string };\n status: number;\n mimeType: string | null;\n};\n\nexport type FileSystemDownloadResult = FileSystemHttpResult & {\n uri: string;\n md5?: string;\n};\n\n/**\n * @deprecated Use FileSystemDownloadResult instead.\n */\nexport type DownloadResult = FileSystemDownloadResult;\n\nexport type FileSystemUploadOptions = {\n headers?: { [name: string]: string };\n httpMethod?: FileSystemHttpMethods;\n sessionType?: FileSystemSessionType;\n};\n\nexport type FileSystemUploadResult = FileSystemHttpResult & {\n body: string;\n};\n\nexport type DownloadProgressCallback = (data: DownloadProgressData) => void;\n\nexport type DownloadProgressData = {\n totalBytesWritten: number;\n totalBytesExpectedToWrite: number;\n};\n\nexport type DownloadPauseState = {\n url: string;\n fileUri: string;\n options: DownloadOptions;\n resumeData?: string;\n};\n\nexport type FileInfo =\n | {\n exists: true;\n uri: string;\n size: number;\n isDirectory: boolean;\n modificationTime: number;\n md5?: string;\n }\n | {\n exists: false;\n uri: string;\n size: undefined;\n isDirectory: false;\n modificationTime: undefined;\n md5: undefined;\n };\n\nexport enum EncodingType {\n UTF8 = 'utf8',\n Base64 = 'base64',\n}\n\nexport enum FileSystemHttpMethods {\n POST = 0,\n PUT = 1,\n PATCH = 2,\n}\n\nexport type ReadingOptions = {\n encoding?: EncodingType | 'utf8' | 'base64';\n position?: number;\n length?: number;\n};\n\nexport type WritingOptions = {\n encoding?: EncodingType | 'utf8' | 'base64';\n};\n\nexport type ProgressEvent = {\n uuid: string;\n data: {\n totalBytesWritten: number;\n totalBytesExpectedToWrite: number;\n };\n};\n\ntype PlatformMethod = (...args: any[]) => Promise;\n\nexport interface ExponentFileSystemModule {\n readonly name: 'ExponentFileSystem';\n readonly documentDirectory: string | null;\n readonly cacheDirectory: string | null;\n readonly bundledAssets: string | null;\n readonly bundleDirectory: string | null;\n readonly getInfoAsync?: PlatformMethod;\n readonly readAsStringAsync?: PlatformMethod;\n readonly writeAsStringAsync?: PlatformMethod;\n readonly deleteAsync?: PlatformMethod;\n readonly moveAsync?: PlatformMethod;\n readonly copyAsync?: PlatformMethod;\n readonly makeDirectoryAsync?: PlatformMethod;\n readonly readDirectoryAsync?: PlatformMethod;\n readonly downloadAsync?: PlatformMethod;\n readonly uploadAsync?: PlatformMethod;\n readonly downloadResumableStartAsync?: PlatformMethod;\n readonly downloadResumablePauseAsync?: PlatformMethod;\n readonly getContentUriAsync?: PlatformMethod;\n readonly getFreeDiskStorageAsync?: PlatformMethod;\n readonly getTotalDiskCapacityAsync?: PlatformMethod;\n startObserving?: () => void;\n stopObserving?: () => void;\n addListener: (eventName: string) => void;\n removeListeners: (count: number) => void;\n}\n"]} \ No newline at end of file +{"version":3,"file":"FileSystem.types.js","sourceRoot":"","sources":["../src/FileSystem.types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,qBAaX;AAbD,WAAY,qBAAqB;IAC/B;;;;;OAKG;IACH,6EAAc,CAAA;IACd;;;OAGG;IACH,6EAAc,CAAA;AAChB,CAAC,EAbW,qBAAqB,KAArB,qBAAqB,QAahC;AAsED,MAAM,CAAN,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,6BAAa,CAAA;IACb,iCAAiB,CAAA;AACnB,CAAC,EAHW,YAAY,KAAZ,YAAY,QAGvB;AAED,MAAM,CAAN,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,iEAAQ,CAAA;IACR,+DAAO,CAAA;IACP,mEAAS,CAAA;AACX,CAAC,EAJW,qBAAqB,KAArB,qBAAqB,QAIhC","sourcesContent":["export enum FileSystemSessionType {\n /*\n * Using this mode means that the downloading/uploading session on the native side will work even if the application is moved to the `background`.\n *\n * If the task completes when the application is in the `background`, the promise might be resolved immediately.\n * However, javascript execution will be stopped after a couple of seconds and it will be resumed when the application is moved to the `foreground` again.\n */\n BACKGROUND = 0,\n /*\n * Using this mode means that downloading/uploading session on the native side will be killed once the application becomes inactive (e.g. when it goes to `background`).\n * Bringing the application to the `foreground` again would trigger promise rejection.\n */\n FOREGROUND = 1,\n}\n\nexport type DownloadOptions = {\n md5?: boolean;\n cache?: boolean;\n headers?: { [name: string]: string };\n /*\n * iOS only\n */\n sessionType?: FileSystemSessionType;\n};\n\nexport type FileSystemHttpResult = {\n headers: { [name: string]: string };\n status: number;\n mimeType: string | null;\n};\n\nexport type FileSystemDownloadResult = FileSystemHttpResult & {\n uri: string;\n md5?: string;\n};\n\n/**\n * @deprecated Use FileSystemDownloadResult instead.\n */\nexport type DownloadResult = FileSystemDownloadResult;\n\nexport type FileSystemUploadOptions = {\n headers?: { [name: string]: string };\n httpMethod?: FileSystemHttpMethods;\n sessionType?: FileSystemSessionType;\n};\n\nexport type FileSystemUploadResult = FileSystemHttpResult & {\n body: string;\n};\n\nexport type DownloadProgressCallback = (data: DownloadProgressData) => void;\n\nexport type DownloadProgressData = {\n totalBytesWritten: number;\n totalBytesExpectedToWrite: number;\n};\n\nexport type DownloadPauseState = {\n url: string;\n fileUri: string;\n options: DownloadOptions;\n resumeData?: string;\n};\n\nexport type FileInfo =\n | {\n exists: true;\n uri: string;\n size: number;\n isDirectory: boolean;\n modificationTime: number;\n md5?: string;\n }\n | {\n exists: false;\n uri: string;\n size: undefined;\n isDirectory: false;\n modificationTime: undefined;\n md5: undefined;\n };\n\nexport enum EncodingType {\n UTF8 = 'utf8',\n Base64 = 'base64',\n}\n\nexport enum FileSystemHttpMethods {\n POST = 0,\n PUT = 1,\n PATCH = 2,\n}\n\nexport type ReadingOptions = {\n encoding?: EncodingType | 'utf8' | 'base64';\n position?: number;\n length?: number;\n};\n\nexport type WritingOptions = {\n encoding?: EncodingType | 'utf8' | 'base64';\n};\n\nexport type ProgressEvent = {\n uuid: string;\n data: {\n totalBytesWritten: number;\n totalBytesExpectedToWrite: number;\n };\n};\n\ntype PlatformMethod = (...args: any[]) => Promise;\n\nexport interface ExponentFileSystemModule {\n readonly name: 'ExponentFileSystem';\n readonly documentDirectory: string | null;\n readonly cacheDirectory: string | null;\n readonly bundledAssets: string | null;\n readonly bundleDirectory: string | null;\n readonly getInfoAsync?: PlatformMethod;\n readonly readAsStringAsync?: PlatformMethod;\n readonly writeAsStringAsync?: PlatformMethod;\n readonly deleteAsync?: PlatformMethod;\n readonly moveAsync?: PlatformMethod;\n readonly copyAsync?: PlatformMethod;\n readonly makeDirectoryAsync?: PlatformMethod;\n readonly readDirectoryAsync?: PlatformMethod;\n readonly downloadAsync?: PlatformMethod;\n readonly uploadAsync?: PlatformMethod;\n readonly downloadResumableStartAsync?: PlatformMethod;\n readonly downloadResumablePauseAsync?: PlatformMethod;\n readonly getContentUriAsync?: PlatformMethod;\n readonly getFreeDiskStorageAsync?: PlatformMethod;\n readonly getTotalDiskCapacityAsync?: PlatformMethod;\n startObserving?: () => void;\n stopObserving?: () => void;\n addListener: (eventName: string) => void;\n removeListeners: (count: number) => void;\n}\n"]} \ No newline at end of file diff --git a/packages/expo-file-system/ios/EXFileSystem/EXFileSystem.h b/packages/expo-file-system/ios/EXFileSystem/EXFileSystem.h index f2226f5b5aeac..92f7ca132344e 100644 --- a/packages/expo-file-system/ios/EXFileSystem/EXFileSystem.h +++ b/packages/expo-file-system/ios/EXFileSystem/EXFileSystem.h @@ -7,7 +7,7 @@ #import #import -@interface EXFileSystem : UMExportedModule +@interface EXFileSystem : UMExportedModule @property (nonatomic, readonly) NSString *documentDirectory; @property (nonatomic, readonly) NSString *cachesDirectory; diff --git a/packages/expo-file-system/ios/EXFileSystem/EXFileSystem.m b/packages/expo-file-system/ios/EXFileSystem/EXFileSystem.m index c0ee56c77b646..a62d6dfd4a2aa 100644 --- a/packages/expo-file-system/ios/EXFileSystem/EXFileSystem.m +++ b/packages/expo-file-system/ios/EXFileSystem/EXFileSystem.m @@ -18,7 +18,7 @@ #import #import -NSString * const EXDownloadProgressEventName = @"Exponent.downloadProgress"; +NSString * const EXDownloadProgressEventName = @"expo-file-system.downloadProgress"; typedef NS_ENUM(NSInteger, EXFileSystemSessionType) { EXFileSystemBackgroundSession = 0, @@ -33,6 +33,7 @@ typedef NS_ENUM(NSInteger, EXFileSystemHTTPMethod) { @interface EXFileSystem () +@property (nonatomic, strong) NSMutableArray *sessions; @property (nonatomic, strong) NSMutableDictionary *resumableDownloads; @property (nonatomic, weak) UMModuleRegistry *moduleRegistry; @property (nonatomic, weak) id eventEmitter; @@ -63,7 +64,8 @@ - (instancetype)initWithDocumentDirectory:(NSString *)documentDirectory cachesDi _cachesDirectory = cachesDirectory; _bundleDirectory = bundleDirectory; _resumableDownloads = [NSMutableDictionary dictionary]; - + _sessions = [NSMutableArray new]; + [EXFileSystem ensureDirExistsWithPath:_documentDirectory]; [EXFileSystem ensureDirExistsWithPath:_cachesDirectory]; } @@ -112,6 +114,13 @@ - (void)stopObserving { } +- (void)dealloc +{ + for (NSURLSession *session in _sessions) { + [session invalidateAndCancel]; + } +} + - (NSDictionary *)encodingMap { /* @@ -531,16 +540,22 @@ - (NSDictionary *)encodingMap nil); return; } + if (![self _checkHeadersDictionary:options[@"headers"]]) { + reject(@"ERR_FILESYSTEM_INVALID_HEADERS", + @"Invalid headers dictionary. Keys and values should be strings.", + nil); + return; + } - EXSessionDownloadTaskDelegate* taskDelegate = [[EXSessionDownloadTaskDelegate alloc] initWithResolve:resolve - reject:reject - localFileUrl:localUri - serverUrl:url - md5Option:[options[@"md5"] boolValue] ?: false]; + EXSessionDownloadTaskDelegate* taskDelegate = [[EXSessionDownloadTaskDelegate alloc] initWithSessionRegister:self + resolve:resolve + reject:reject + localFileUrl:localUri + serverUrl:url + md5Option:[options[@"md5"] boolValue] ?: false]; - NSURLSession *session = [self _createSession:taskDelegate withOptions:options]; + NSURLSession *session = [self _createSession:taskDelegate options:options]; NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url]; - [task resume]; } @@ -564,12 +579,27 @@ - (NSDictionary *)encodingMap nil); return; } + if (![self _checkHeadersDictionary:options[@"headers"]]) { + reject(@"ERR_FILESYSTEM_INVALID_HEADERS_DICTIONARY", + @"Invalid headers dictionary. Keys and values should be strings.", + nil); + return; + } - EXSessionUploadTaskDelegate* taskDelegate = [[EXSessionUploadTaskDelegate alloc] initWithResolve:resolve reject:reject]; + EXSessionUploadTaskDelegate* taskDelegate = [[EXSessionUploadTaskDelegate alloc] initWithSessionRegister:self resolve:resolve reject:reject]; - NSURLSession *session = [self _createSession:taskDelegate withOptions:options]; + NSURLSession *session = [self _createSession:taskDelegate options:options]; NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]]; - [urlRequest setHTTPMethod:[self _importHttpMethod:options[@"httpMethod"]]]; + if (options[@"httpMethod"]) { + NSString *httpMethod = [self _importHttpMethod:options[@"httpMethod"]]; + if (!httpMethod) { + reject(@"ERR_FILESYSTEM_INVALID_HTTP_METHOD", + [NSString stringWithFormat:@"Invalid http method %@", options[@"httpMethod"]], + nil); + return; + } + [urlRequest setHTTPMethod:httpMethod]; + } NSURLSessionUploadTask *task = [session uploadTaskWithRequest:urlRequest fromFile:fileUri]; [task resume]; @@ -606,6 +636,14 @@ - (NSDictionary *)encodingMap nil); return; } + + if (![self _checkHeadersDictionary:options[@"headers"]]) { + reject(@"ERR_FILESYSTEM_INVALID_HEADERS_DICTIONARY", + @"Invalid headers dictionary. Keys and values should be strings.", + nil); + return; + } + NSData *resumeData = data ? [[NSData alloc] initWithBase64EncodedString:data options:0] : nil; [self _downloadResumableCreateSessionWithUrl:url fileUrl:localUrl @@ -637,6 +675,8 @@ - (NSDictionary *)encodingMap reject(@"E_UNABLE_TO_PAUSE", @"There was an error producing resume data", nil); + [self unregister:session uuid:uuid]; + [session invalidateAndCancel]; } }]; } @@ -662,7 +702,18 @@ - (NSDictionary *)encodingMap #pragma mark - Internal methods -- (NSURLSession *)_createSession:(id)delegate withOptions:(NSDictionary *)options +- (BOOL)_checkHeadersDictionary:(NSDictionary * _Nullable)headers +{ + for (id key in [headers allKeys]) { + if (![key isKindOfClass:[NSString class]] || ![headers[key] isKindOfClass:[NSString class]]) { + return false; + } + } + + return true; +} + +- (NSURLSession *)_createSession:(id)delegate options:(NSDictionary *)options { EXFileSystemSessionType sessionType = [options[@"sessionType"] intValue] ?: EXFileSystemBackgroundSession; NSDictionary *headers = options[@"headers"]; @@ -681,10 +732,11 @@ - (NSURLSession *)_createSession:(id)delegate withOptions: if (headers != nil) { sessionConfiguration.HTTPAdditionalHeaders = headers; } - - return [NSURLSession sessionWithConfiguration:sessionConfiguration - delegate:delegate - delegateQueue:[NSOperationQueue mainQueue]]; + NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration + delegate:delegate + delegateQueue:[NSOperationQueue mainQueue]]; + [_sessions addObject:session]; + return session; } - (BOOL)_checkIfFileExists:(NSString *)path @@ -692,26 +744,17 @@ - (BOOL)_checkIfFileExists:(NSString *)path return [[NSFileManager defaultManager] fileExistsAtPath:path]; } -- (NSMutableDictionary *)_parseServerResponse:(NSURLResponse *)response +- (NSString * _Nullable)_importHttpMethod:(NSNumber *)httpMethod { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - result[@"status"] = @([httpResponse statusCode]); - result[@"headers"] = [httpResponse allHeaderFields]; - result[@"mineType"] = UMNullIfNil([httpResponse MIMEType]); - return result; -} - -- (NSString *)_importHttpMethod:(NSNumber *)httpMethod -{ - if ([httpMethod isEqual:@(EXFileSystemPutMethod)]) { - return @"PUT"; - } - if ([httpMethod isEqual:@(EXFileSystemPatchMethod)]) { - return @"PATCH"; + switch ([httpMethod intValue]) { + case EXFileSystemPostMethod: + return @"POST"; + case EXFileSystemPutMethod: + return @"PUT"; + case EXFileSystemPatchMethod: + return @"PATCH"; } - - return @"POST"; + return nil; } - (void)_downloadResumableCreateSessionWithUrl:(NSURL *)url @@ -722,10 +765,6 @@ - (void)_downloadResumableCreateSessionWithUrl:(NSURL *)url resolve:(UMPromiseResolveBlock)resolve reject:(UMPromiseRejectBlock)reject { - NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:uuid]; - sessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData; - sessionConfiguration.URLCache = nil; - UM_WEAKIFY(self); EXDownloadDelegateOnWriteCallback onWrite = ^(NSURLSessionDownloadTask *task, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) { UM_ENSURE_STRONGIFY(self); @@ -740,18 +779,17 @@ - (void)_downloadResumableCreateSessionWithUrl:(NSURL *)url } }; - EXSessionResumableDownloadTaskDelegate *downloadDelegate = [[EXSessionResumableDownloadTaskDelegate alloc] initWithResolve:resolve - reject:reject - localFileUrl:fileUrl - serverUrl:url - md5Option:[options[@"md5"] boolValue] ?: false - onWriteCallback:onWrite - uuid:(NSString *)uuid - resumableTaskRegister:self]; + EXSessionResumableDownloadTaskDelegate *downloadDelegate = [[EXSessionResumableDownloadTaskDelegate alloc] initWithSessionRegister:self + resolve:resolve + reject:reject + localFileUrl:fileUrl + serverUrl:url + md5Option:[options[@"md5"] boolValue] ?: false + onWriteCallback:onWrite + uuid:uuid]; - NSURLSession *session = [self _createSession:downloadDelegate withOptions:options]; + NSURLSession *session = [self _createSession:downloadDelegate options:options]; self.resumableDownloads[uuid] = session; - NSURLSessionDownloadTask *downloadTask; if (resumeData) { downloadTask = [session downloadTaskWithResumeData:resumeData]; @@ -858,8 +896,14 @@ - (NSNumber *)freeDiskStorage { #pragma mark - EXSessionTaskRegister -- (void)onTaskCompleted:(NSString *)uuid { - [_resumableDownloads removeObjectForKey:uuid]; +- (void)unregister:(NSURLSession *)session +{ + [_sessions removeObject:session]; } +- (void)unregister:(NSURLSession *)session uuid:(NSString *)uuid +{ + [self unregister:session]; + [self.resumableDownloads removeObjectForKey:uuid]; +} @end diff --git a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionDownloadTaskDelegate.h b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionDownloadTaskDelegate.h index 546bc336f8add..a8faedf9f8ef0 100644 --- a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionDownloadTaskDelegate.h +++ b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionDownloadTaskDelegate.h @@ -2,22 +2,14 @@ #import -typedef void (^EXDownloadDelegateOnWriteCallback)(NSURLSessionDownloadTask *task, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite); - @interface EXSessionDownloadTaskDelegate : EXSessionTaskDelegate -- (instancetype)initWithResolve:(UMPromiseResolveBlock)resolve - reject:(UMPromiseRejectBlock)reject - localFileUrl:(NSURL *)localFileUrl - serverUrl:(NSURL *)serverUrl - md5Option:(BOOL)md5Option; - -- (instancetype)initWithResolve:(UMPromiseResolveBlock)resolve - reject:(UMPromiseRejectBlock)reject - localFileUrl:(NSURL *)localFileUrl - serverUrl:(NSURL *)serverUrl - md5Option:(BOOL)md5Option - onWriteCallback:(EXDownloadDelegateOnWriteCallback)onWrite; +- (instancetype)initWithSessionRegister:(id)sessionRegister + resolve:(UMPromiseResolveBlock)resolve + reject:(UMPromiseRejectBlock)reject + localFileUrl:(NSURL *)localFileUrl + serverUrl:(NSURL *)serverUrl + md5Option:(BOOL)md5Option; - (void)handleDidFinishDownloadingToURL:(NSURL *)location task:(NSURLSessionDownloadTask *)downloadTask; diff --git a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionDownloadTaskDelegate.m b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionDownloadTaskDelegate.m index afb7fead3dd71..2a80dfa109839 100644 --- a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionDownloadTaskDelegate.m +++ b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionDownloadTaskDelegate.m @@ -8,19 +8,19 @@ @interface EXSessionDownloadTaskDelegate () @property (strong, nonatomic) NSURL *serverUrl; @property (strong, nonatomic) NSURL *localFileUrl; @property (nonatomic) BOOL md5Option; -@property (strong, nonatomic) EXDownloadDelegateOnWriteCallback onWrite; @end @implementation EXSessionDownloadTaskDelegate -- (instancetype)initWithResolve:(UMPromiseResolveBlock)resolve - reject:(UMPromiseRejectBlock)reject - localFileUrl:(NSURL *)localFileUrl - serverUrl:(NSURL *)serverUrl - md5Option:(BOOL)md5Option +- (instancetype)initWithSessionRegister:(id)sessionRegister + resolve:(UMPromiseResolveBlock)resolve + reject:(UMPromiseRejectBlock)reject + localFileUrl:(NSURL *)localFileUrl + serverUrl:(NSURL *)serverUrl + md5Option:(BOOL)md5Option; { - if (self = [super initWithResolve:resolve reject:reject]) { + if (self = [super initWithSessionRegister:sessionRegister resolve:resolve reject:reject]) { _serverUrl = serverUrl; _localFileUrl = localFileUrl; _md5Option = md5Option; @@ -29,34 +29,10 @@ - (instancetype)initWithResolve:(UMPromiseResolveBlock)resolve return self; } -- (instancetype)initWithResolve:(UMPromiseResolveBlock)resolve - reject:(UMPromiseRejectBlock)reject - localFileUrl:(NSURL *)localFileUrl - serverUrl:(NSURL *)serverUrl - md5Option:(BOOL)md5Option - onWriteCallback:(EXDownloadDelegateOnWriteCallback)onWrite; -{ - if (self = [self initWithResolve:resolve - reject:reject - localFileUrl:localFileUrl - serverUrl:serverUrl - md5Option:md5Option]) { - _onWrite = onWrite; - } - - return self; -} - -- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite -{ - if (_onWrite) { - _onWrite(downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); - } -} - - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { [self handleDidFinishDownloadingToURL:location task:downloadTask]; + [self.sessionRegister unregister:session]; } - (void)handleDidFinishDownloadingToURL:(NSURL *)location task:(NSURLSessionDownloadTask *)downloadTask @@ -91,6 +67,7 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didComp self.reject(@"ERR_FILE_SYSTEM_UNABLE_TO_DOWNLOAD", [NSString stringWithFormat:@"Unable to download file. %@", error.description], error); + [self.sessionRegister unregister:session]; } } diff --git a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.h b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.h index 789bcfe3e0e64..2a43fd1728b8f 100644 --- a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.h +++ b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.h @@ -2,22 +2,17 @@ #import - -@protocol EXResumableTaskRegister - -- (void)onTaskCompleted:(NSString *)uuid; - -@end +typedef void (^EXDownloadDelegateOnWriteCallback)(NSURLSessionDownloadTask *task, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite); @interface EXSessionResumableDownloadTaskDelegate : EXSessionDownloadTaskDelegate -- (instancetype)initWithResolve:(UMPromiseResolveBlock)resolve - reject:(UMPromiseRejectBlock)reject - localFileUrl:(NSURL *)localFileUrl - serverUrl:(NSURL *)serverUrl - md5Option:(BOOL)md5Option - onWriteCallback:(EXDownloadDelegateOnWriteCallback)onWrite - uuid:(NSString *)uuid - resumableTaskRegister:(id)taskRegister; +- (instancetype)initWithSessionRegister:(id)sessionRegister + resolve:(UMPromiseResolveBlock)resolve + reject:(UMPromiseRejectBlock)reject + localFileUrl:(NSURL *)localFileUrl + serverUrl:(NSURL *)serverUrl + md5Option:(BOOL)md5Option + onWriteCallback:(EXDownloadDelegateOnWriteCallback)onWrite + uuid:(NSString *)uuid; @end diff --git a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.m b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.m index 3a5bd6c52a7f6..4b6a44e1d653b 100644 --- a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.m +++ b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.m @@ -4,36 +4,42 @@ @interface EXSessionResumableDownloadTaskDelegate () -@property (strong, nonatomic) NSString *taskUUID; -@property (weak, nonatomic) id taskRegister; +@property (strong, nonatomic, readonly) EXDownloadDelegateOnWriteCallback onWrite; +@property (strong, nonatomic, readonly) NSString *uuid; @end - @implementation EXSessionResumableDownloadTaskDelegate -- (instancetype)initWithResolve:(UMPromiseResolveBlock)resolve - reject:(UMPromiseRejectBlock)reject - localFileUrl:(NSURL *)localFileUrl - serverUrl:(NSURL *)serverUrl - md5Option:(BOOL)md5Option - onWriteCallback:(EXDownloadDelegateOnWriteCallback)onWrite - uuid:(NSString *)uuid - resumableTaskRegister:(id)taskRegister +- (instancetype)initWithSessionRegister:(id)sessionRegister + resolve:(UMPromiseResolveBlock)resolve + reject:(UMPromiseRejectBlock)reject + localFileUrl:(NSURL *)localFileUrl + serverUrl:(NSURL *)serverUrl + md5Option:(BOOL)md5Option + onWriteCallback:(EXDownloadDelegateOnWriteCallback)onWrite + uuid:(NSString *)uuid; { - if (self = [super initWithResolve:resolve - reject:reject - localFileUrl:localFileUrl - serverUrl:serverUrl - md5Option:md5Option - onWriteCallback:onWrite]) { - _taskUUID = uuid; - _taskRegister = taskRegister; + if (self = [self initWithSessionRegister:sessionRegister + resolve:resolve + reject:reject + localFileUrl:localFileUrl + serverUrl:serverUrl + md5Option:md5Option]) { + _onWrite = onWrite; + _uuid = uuid; } return self; } +- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite +{ + if (_onWrite) { + _onWrite(downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + } +} + - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { if (error) { @@ -44,16 +50,15 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didComp self.reject(@"ERR_FILE_SYSTEM_UNABLE_TO_DOWNLOAD", [NSString stringWithFormat:@"Unable to download file. %@", error.description], error); + [self.sessionRegister unregister:session uuid:_uuid]; } - - [_taskRegister onTaskCompleted:_taskUUID]; } } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { [super handleDidFinishDownloadingToURL:location task:downloadTask]; - [_taskRegister onTaskCompleted:_taskUUID]; + [self.sessionRegister unregister:session uuid:_uuid]; } @end diff --git a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionTaskDelegate.h b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionTaskDelegate.h index 73261a6a2231e..672c8872ba5b9 100644 --- a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionTaskDelegate.h +++ b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionTaskDelegate.h @@ -3,16 +3,22 @@ #import #import -@class EXSessionTaskDelegate; +@protocol EXSessionRegister + +- (void)unregister:(NSURLSession *)session; +- (void)unregister:(NSURLSession *)session uuid:(NSString *)uuid; + +@end @interface EXSessionTaskDelegate : NSObject -@property (nonatomic, strong) NSString *uuid; -@property (nonatomic, strong) UMPromiseResolveBlock resolve; -@property (nonatomic, strong) UMPromiseRejectBlock reject; +@property (nonatomic, strong, readonly) UMPromiseResolveBlock resolve; +@property (nonatomic, strong, readonly) UMPromiseRejectBlock reject; +@property (nonatomic, strong, readonly) id sessionRegister; -- (instancetype)initWithResolve:(UMPromiseResolveBlock)resolve - reject:(UMPromiseRejectBlock)reject; +- (instancetype)initWithSessionRegister:(id)sessionRegister + resolve:(UMPromiseResolveBlock)resolve + reject:(UMPromiseRejectBlock)reject; - (NSMutableDictionary *)parseServerResponse:(NSURLResponse *)response; diff --git a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionTaskDelegate.m b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionTaskDelegate.m index a2473cc0788d5..f0233049c2249 100644 --- a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionTaskDelegate.m +++ b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionTaskDelegate.m @@ -4,10 +4,12 @@ @implementation EXSessionTaskDelegate -- (instancetype)initWithResolve:(UMPromiseResolveBlock)resolve - reject:(UMPromiseRejectBlock)reject +- (instancetype)initWithSessionRegister:(id)sessionRegister + resolve:(UMPromiseResolveBlock)resolve + reject:(UMPromiseRejectBlock)reject { if (self = [super init]) { + _sessionRegister = sessionRegister; _resolve = resolve; _reject = reject; } diff --git a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionUploadTaskDelegate.h b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionUploadTaskDelegate.h index 5ade084296d7f..e229aafd9e8c3 100644 --- a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionUploadTaskDelegate.h +++ b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionUploadTaskDelegate.h @@ -4,8 +4,9 @@ @interface EXSessionUploadTaskDelegate : EXSessionTaskDelegate -- (instancetype)initWithResolve:(UMPromiseResolveBlock)resolve - reject:(UMPromiseRejectBlock)reject; +- (instancetype)initWithSessionRegister:(id)taskRegister + resolve:(UMPromiseResolveBlock)resolve + reject:(UMPromiseRejectBlock)reject; @end diff --git a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionUploadTaskDelegate.m b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionUploadTaskDelegate.m index 50ac41d1a33bc..40acfe86e9dbe 100644 --- a/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionUploadTaskDelegate.m +++ b/packages/expo-file-system/ios/EXFileSystem/EXSessionTasks/EXSessionUploadTaskDelegate.m @@ -8,13 +8,13 @@ @interface EXSessionUploadTaskDelegate () @end - @implementation EXSessionUploadTaskDelegate -- (instancetype)initWithResolve:(UMPromiseResolveBlock)resolve - reject:(UMPromiseRejectBlock)reject +- (instancetype)initWithSessionRegister:(id)sessionRegister + resolve:(UMPromiseResolveBlock)resolve + reject:(UMPromiseRejectBlock)reject { - if (self = [super initWithResolve:resolve reject:reject]) { + if (self = [super initWithSessionRegister:sessionRegister resolve:resolve reject:reject]) { _responseData = [[NSMutableData alloc] init]; } @@ -35,13 +35,16 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didComp self.reject(@"ERR_FILE_SYSTEM_UNABLE_TO_UPLOAD_FILE.", [NSString stringWithFormat:@"Unable to upload the file. '%@'", error.description], error); + [self.sessionRegister unregister:session]; return; } + NSURLSessionUploadTask *uploadTask = (NSURLSessionUploadTask *)task; NSMutableDictionary *result = [self parseServerResponse:uploadTask.response]; result[@"body"] = [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding]; - self.resolve(result); + + [self.sessionRegister unregister:session]; } @end diff --git a/packages/expo-file-system/src/FileSystem.ts b/packages/expo-file-system/src/FileSystem.ts index 7d53db272b8ee..958904beda1ad 100644 --- a/packages/expo-file-system/src/FileSystem.ts +++ b/packages/expo-file-system/src/FileSystem.ts @@ -281,7 +281,7 @@ export class DownloadResumable { return; } this._subscription = this._emitter.addListener( - 'Exponent.downloadProgress', + 'expo-file-system.downloadProgress', (event: ProgressEvent) => { if (event.uuid === this._uuid) { const callback = this._callback; diff --git a/packages/expo-file-system/src/FileSystem.types.ts b/packages/expo-file-system/src/FileSystem.types.ts index 79cea62ddcc4b..af11418b3565b 100644 --- a/packages/expo-file-system/src/FileSystem.types.ts +++ b/packages/expo-file-system/src/FileSystem.types.ts @@ -1,15 +1,14 @@ export enum FileSystemSessionType { /* - * The session will work even if the user backgrounds an application. + * Using this mode means that the downloading/uploading session on the native side will work even if the application is moved to the `background`. * - * If a task complete when the application is inactive, the promise might resolve immediately. - * However, js code will be stopped after a couple of seconds and it will be resume when the user comes back to the application. + * If the task completes when the application is in the `background`, the promise might be resolved immediately. + * However, javascript execution will be stopped after a couple of seconds and it will be resumed when the application is moved to the `foreground` again. */ BACKGROUND = 0, - /* - * The session will be killed when an application is inactive. - * When the user comes back to the application, the promise will be rejected. + * Using this mode means that downloading/uploading session on the native side will be killed once the application becomes inactive (e.g. when it goes to `background`). + * Bringing the application to the `foreground` again would trigger promise rejection. */ FOREGROUND = 1, }