@amazon-devices/expo-file-system 2.0.1758683737
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +2 -0
- package/CHANGELOG.md +317 -0
- package/CMakeLists.txt +52 -0
- package/LICENSE +7 -0
- package/README.kepler.md +260 -0
- package/README.md +46 -0
- package/THIRD_PARTY_NOTICES.txt +24 -0
- package/android/build.gradle +118 -0
- package/android/src/main/AndroidManifest.xml +17 -0
- package/android/src/main/java/expo/modules/filesystem/AppDirectoriesModule.kt +26 -0
- package/android/src/main/java/expo/modules/filesystem/CountingRequestBody.kt +52 -0
- package/android/src/main/java/expo/modules/filesystem/FilePermissionModule.kt +48 -0
- package/android/src/main/java/expo/modules/filesystem/FileSystemExceptions.kt +48 -0
- package/android/src/main/java/expo/modules/filesystem/FileSystemFileProvider.kt +5 -0
- package/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt +1110 -0
- package/android/src/main/java/expo/modules/filesystem/FileSystemPackage.kt +10 -0
- package/android/src/main/java/expo/modules/filesystem/FileSystemRecords.kt +92 -0
- package/android/src/main/res/xml/file_system_provider_paths.xml +5 -0
- package/app.plugin.js +1 -0
- package/build/ExponentFileSystem.d.ts +4 -0
- package/build/ExponentFileSystem.d.ts.map +1 -0
- package/build/ExponentFileSystem.js +5 -0
- package/build/ExponentFileSystem.js.map +1 -0
- package/build/ExponentFileSystem.kepler.d.ts +4 -0
- package/build/ExponentFileSystem.kepler.d.ts.map +1 -0
- package/build/ExponentFileSystem.kepler.js +112 -0
- package/build/ExponentFileSystem.kepler.js.map +1 -0
- package/build/ExponentFileSystem.web.d.ts +3 -0
- package/build/ExponentFileSystem.web.d.ts.map +1 -0
- package/build/ExponentFileSystem.web.js +3 -0
- package/build/ExponentFileSystem.web.js.map +1 -0
- package/build/ExponentFileSystemShim.d.ts +4 -0
- package/build/ExponentFileSystemShim.d.ts.map +1 -0
- package/build/ExponentFileSystemShim.js +21 -0
- package/build/ExponentFileSystemShim.js.map +1 -0
- package/build/FileSystem.d.ts +361 -0
- package/build/FileSystem.d.ts.map +1 -0
- package/build/FileSystem.js +616 -0
- package/build/FileSystem.js.map +1 -0
- package/build/FileSystem.types.d.ts +304 -0
- package/build/FileSystem.types.d.ts.map +1 -0
- package/build/FileSystem.types.js +47 -0
- package/build/FileSystem.types.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +3 -0
- package/build/index.js.map +1 -0
- package/build/types.d.ts +35 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/expo-module.config.json +11 -0
- package/ios/EXFilePermissionModule.h +16 -0
- package/ios/EXFilePermissionModule.m +68 -0
- package/ios/EXFileSystem.h +25 -0
- package/ios/EXFileSystem.m +1084 -0
- package/ios/EXFileSystemAssetLibraryHandler.h +6 -0
- package/ios/EXFileSystemAssetLibraryHandler.m +142 -0
- package/ios/EXFileSystemHandler.h +17 -0
- package/ios/EXFileSystemLocalFileHandler.h +7 -0
- package/ios/EXFileSystemLocalFileHandler.m +79 -0
- package/ios/EXSessionTasks/EXSessionCancelableUploadTaskDelegate.h +16 -0
- package/ios/EXSessionTasks/EXSessionCancelableUploadTaskDelegate.m +55 -0
- package/ios/EXSessionTasks/EXSessionDownloadTaskDelegate.h +13 -0
- package/ios/EXSessionTasks/EXSessionDownloadTaskDelegate.m +64 -0
- package/ios/EXSessionTasks/EXSessionHandler.h +19 -0
- package/ios/EXSessionTasks/EXSessionHandler.m +49 -0
- package/ios/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.h +18 -0
- package/ios/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.m +66 -0
- package/ios/EXSessionTasks/EXSessionTaskDelegate.h +32 -0
- package/ios/EXSessionTasks/EXSessionTaskDelegate.m +58 -0
- package/ios/EXSessionTasks/EXSessionTaskDispatcher.h +19 -0
- package/ios/EXSessionTasks/EXSessionTaskDispatcher.m +96 -0
- package/ios/EXSessionTasks/EXSessionUploadTaskDelegate.h +8 -0
- package/ios/EXSessionTasks/EXSessionUploadTaskDelegate.m +52 -0
- package/ios/EXSessionTasks/EXTaskHandlersManager.h +21 -0
- package/ios/EXSessionTasks/EXTaskHandlersManager.m +56 -0
- package/ios/Encoding.swift +88 -0
- package/ios/ExpoFileSystem.h +1 -0
- package/ios/ExpoFileSystem.podspec +32 -0
- package/ios/FileSystemBackgroundSessionHandler.swift +25 -0
- package/ios/FileSystemExceptions.swift +69 -0
- package/ios/FileSystemHelpers.swift +66 -0
- package/ios/FileSystemModule.swift +263 -0
- package/ios/FileSystemRecords.swift +74 -0
- package/ios/NSData+EXFileSystem.h +9 -0
- package/ios/NSData+EXFileSystem.m +19 -0
- package/ios/NetworkingHelpers.swift +84 -0
- package/ios/Tests/EXFileSystemSpec.swift +55 -0
- package/jest.config.js +3 -0
- package/kepler/ExponentFileSystem.cpp +498 -0
- package/kepler/ExponentFileSystem.h +60 -0
- package/kepler/KeplerInit.cpp +28 -0
- package/kepler/NetworkingRequestHandler.cpp +47 -0
- package/kepler/test/FileSystem.cpp +425 -0
- package/package.json +1 -0
- package/plugin/build/withFileSystem.d.ts +3 -0
- package/plugin/build/withFileSystem.js +12 -0
- package/plugin/src/withFileSystem.ts +13 -0
- package/plugin/tsconfig.json +9 -0
- package/plugin/tsconfig.tsbuildinfo +1 -0
- package/react-native.config.js +21 -0
- package/src/ExponentFileSystem.kepler.ts +167 -0
- package/src/ExponentFileSystem.ts +7 -0
- package/src/ExponentFileSystem.web.ts +2 -0
- package/src/ExponentFileSystemShim.ts +23 -0
- package/src/FileSystem.ts +756 -0
- package/src/FileSystem.types.ts +339 -0
- package/src/index.ts +2 -0
- package/src/types.ts +34 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#import <ExpoFileSystem/EXSessionTaskDispatcher.h>
|
|
4
|
+
#import <ExpoFileSystem/EXSessionResumableDownloadTaskDelegate.h>
|
|
5
|
+
|
|
6
|
+
@interface EXSessionTaskDispatcher ()
|
|
7
|
+
|
|
8
|
+
@property (nonatomic, strong) NSMutableDictionary<NSURLSessionTask *, EXSessionTaskDelegate *> *tasks;
|
|
9
|
+
@property (nonatomic) BOOL isActive;
|
|
10
|
+
@property (nonatomic, weak, nullable) id<EXSessionHandler> sessionHandler;
|
|
11
|
+
|
|
12
|
+
@end
|
|
13
|
+
|
|
14
|
+
@implementation EXSessionTaskDispatcher
|
|
15
|
+
|
|
16
|
+
- (instancetype)initWithSessionHandler:(nullable id<EXSessionHandler>)sessionHandler;
|
|
17
|
+
{
|
|
18
|
+
if (self = [super init]) {
|
|
19
|
+
_tasks = [NSMutableDictionary dictionary];
|
|
20
|
+
_isActive = true;
|
|
21
|
+
_sessionHandler = sessionHandler;
|
|
22
|
+
}
|
|
23
|
+
return self;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#pragma mark - public methods
|
|
27
|
+
|
|
28
|
+
- (void)registerTaskDelegate:(EXSessionTaskDelegate *)delegate forTask:(NSURLSessionTask *)task
|
|
29
|
+
{
|
|
30
|
+
_tasks[task] = delegate;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
- (void)deactivate
|
|
34
|
+
{
|
|
35
|
+
_isActive = false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#pragma mark - dispatcher
|
|
39
|
+
|
|
40
|
+
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
|
|
41
|
+
{
|
|
42
|
+
if (_isActive) {
|
|
43
|
+
EXSessionTaskDelegate *exTask = _tasks[downloadTask];
|
|
44
|
+
if (exTask) {
|
|
45
|
+
[exTask URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];
|
|
46
|
+
[_tasks removeObjectForKey:downloadTask];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
|
|
52
|
+
{
|
|
53
|
+
if (_isActive) {
|
|
54
|
+
EXSessionTaskDelegate *exTask = _tasks[task];
|
|
55
|
+
if (exTask) {
|
|
56
|
+
[exTask URLSession:session task:task didCompleteWithError:error];
|
|
57
|
+
[_tasks removeObjectForKey:task];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
|
63
|
+
didWriteData:(int64_t)bytesWritten
|
|
64
|
+
totalBytesWritten:(int64_t)totalBytesWritten
|
|
65
|
+
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
|
|
66
|
+
{
|
|
67
|
+
if (_isActive) {
|
|
68
|
+
EXSessionTaskDelegate *exTask = _tasks[downloadTask];
|
|
69
|
+
[exTask URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
|
|
74
|
+
{
|
|
75
|
+
if (_isActive) {
|
|
76
|
+
EXSessionTaskDelegate *exTask = _tasks[dataTask];
|
|
77
|
+
[exTask URLSession:session dataTask:dataTask didReceiveData:data];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
|
|
82
|
+
[_sessionHandler invokeCompletionHandlerForSessionIdentifier:session.configuration.identifier];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
|
|
86
|
+
didSendBodyData:(int64_t)bytesSent
|
|
87
|
+
totalBytesSent:(int64_t)totalBytesSent
|
|
88
|
+
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
|
|
89
|
+
{
|
|
90
|
+
if (_isActive) {
|
|
91
|
+
EXSessionTaskDelegate *exTask = _tasks[task];
|
|
92
|
+
[exTask URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#import <ExpoFileSystem/EXSessionUploadTaskDelegate.h>
|
|
4
|
+
|
|
5
|
+
@interface EXSessionUploadTaskDelegate ()
|
|
6
|
+
|
|
7
|
+
@property (strong, nonatomic) NSMutableData *responseData;
|
|
8
|
+
|
|
9
|
+
@end
|
|
10
|
+
|
|
11
|
+
@implementation EXSessionUploadTaskDelegate
|
|
12
|
+
|
|
13
|
+
- (instancetype)initWithResolve:(EXPromiseResolveBlock)resolve reject:(EXPromiseRejectBlock)reject
|
|
14
|
+
{
|
|
15
|
+
if (self = [super initWithResolve:resolve reject:reject]) {
|
|
16
|
+
_responseData = [NSMutableData new];
|
|
17
|
+
}
|
|
18
|
+
return self;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
|
|
22
|
+
{
|
|
23
|
+
if (!data.length) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
[_responseData appendData:data];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
|
|
30
|
+
{
|
|
31
|
+
if (error) {
|
|
32
|
+
self.reject(@"ERR_FILESYSTEM_CANNOT_UPLOAD",
|
|
33
|
+
[NSString stringWithFormat:@"Unable to upload the file: '%@'", error.description],
|
|
34
|
+
error);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// We only set EXSessionUploadTaskDelegates as delegates of upload tasks
|
|
39
|
+
// so it should be safe to assume that this is what we will receive here.
|
|
40
|
+
NSURLSessionUploadTask *uploadTask = (NSURLSessionUploadTask *)task;
|
|
41
|
+
self.resolve([self parseServerResponse:uploadTask.response]);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
- (NSDictionary *)parseServerResponse:(NSURLResponse *)response
|
|
45
|
+
{
|
|
46
|
+
NSMutableDictionary *result = [[super parseServerResponse:response] mutableCopy];
|
|
47
|
+
// TODO: add support for others response types (different encodings, files)
|
|
48
|
+
result[@"body"] = EXNullIfNil([[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding]);
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#import <Foundation/Foundation.h>
|
|
4
|
+
|
|
5
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
6
|
+
|
|
7
|
+
@interface EXTaskHandlersManager : NSObject
|
|
8
|
+
|
|
9
|
+
- (NSURLSessionTask * _Nullable)taskForId:(NSString *)uuid;
|
|
10
|
+
|
|
11
|
+
- (NSURLSessionDownloadTask * _Nullable)downloadTaskForId:(NSString *)uuid;
|
|
12
|
+
|
|
13
|
+
- (NSURLSessionUploadTask * _Nullable)uploadTaskForId:(NSString *)uuid;
|
|
14
|
+
|
|
15
|
+
- (void)registerTask:(NSURLSessionTask *)task uuid:(NSString *)uuid;
|
|
16
|
+
|
|
17
|
+
- (void)unregisterTask:(NSString *)uuid;
|
|
18
|
+
|
|
19
|
+
@end
|
|
20
|
+
|
|
21
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#import <ExpoFileSystem/EXTaskHandlersManager.h>
|
|
4
|
+
|
|
5
|
+
@interface EXTaskHandlersManager ()
|
|
6
|
+
|
|
7
|
+
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSURLSessionTask *> *resumableDownloads;
|
|
8
|
+
|
|
9
|
+
@end
|
|
10
|
+
|
|
11
|
+
@implementation EXTaskHandlersManager
|
|
12
|
+
|
|
13
|
+
- (instancetype)init
|
|
14
|
+
{
|
|
15
|
+
if (self = [super init]) {
|
|
16
|
+
_resumableDownloads = [NSMutableDictionary dictionary];
|
|
17
|
+
}
|
|
18
|
+
return self;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
- (void)registerTask:(NSURLSessionTask *)task uuid:(NSString *)uuid
|
|
22
|
+
{
|
|
23
|
+
_resumableDownloads[uuid] = task;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
- (NSURLSessionTask * _Nullable)taskForId:(NSString *)uuid
|
|
27
|
+
{
|
|
28
|
+
return _resumableDownloads[uuid];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
- (NSURLSessionDownloadTask * _Nullable)downloadTaskForId:(NSString *)uuid
|
|
32
|
+
{
|
|
33
|
+
NSURLSessionTask *task = [self taskForId:uuid];
|
|
34
|
+
if ([task isKindOfClass:[NSURLSessionDownloadTask class]]) {
|
|
35
|
+
return (NSURLSessionDownloadTask *)task;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return nil;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
- (NSURLSessionUploadTask * _Nullable)uploadTaskForId:(NSString *)uuid
|
|
42
|
+
{
|
|
43
|
+
NSURLSessionTask *task = [self taskForId:uuid];
|
|
44
|
+
if ([task isKindOfClass:[NSURLSessionUploadTask class]]) {
|
|
45
|
+
return (NSURLSessionDownloadTask *)task;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return nil;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
- (void)unregisterTask:(NSString *)uuid
|
|
52
|
+
{
|
|
53
|
+
[_resumableDownloads removeObjectForKey:uuid];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Copyright 2023-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import ExpoModulesCore
|
|
4
|
+
|
|
5
|
+
enum Encoding: String, Enumerable {
|
|
6
|
+
// Equivalents of String.Encoding
|
|
7
|
+
case ascii
|
|
8
|
+
case nextstep
|
|
9
|
+
case japaneseeuc
|
|
10
|
+
case utf8
|
|
11
|
+
case isolatin1
|
|
12
|
+
case symbol
|
|
13
|
+
case nonlossyascii
|
|
14
|
+
case shiftjis
|
|
15
|
+
case isolatin2
|
|
16
|
+
case unicode
|
|
17
|
+
case windowscp1251
|
|
18
|
+
case windowscp1252
|
|
19
|
+
case windowscp1253
|
|
20
|
+
case windowscp1254
|
|
21
|
+
case windowscp1250
|
|
22
|
+
case iso2022jp
|
|
23
|
+
case macosroman
|
|
24
|
+
case utf16
|
|
25
|
+
case utf16bigendian
|
|
26
|
+
case utf16littleendian
|
|
27
|
+
case utf32
|
|
28
|
+
case utf32bigendian
|
|
29
|
+
case utf32littleendian
|
|
30
|
+
|
|
31
|
+
// Without equivalents in String.Encoding
|
|
32
|
+
case base64
|
|
33
|
+
|
|
34
|
+
func toStringEncoding() -> String.Encoding? {
|
|
35
|
+
switch self {
|
|
36
|
+
case .ascii:
|
|
37
|
+
return .ascii
|
|
38
|
+
case .nextstep:
|
|
39
|
+
return .nextstep
|
|
40
|
+
case .japaneseeuc:
|
|
41
|
+
return .japaneseEUC
|
|
42
|
+
case .utf8:
|
|
43
|
+
return .utf8
|
|
44
|
+
case .isolatin1:
|
|
45
|
+
return .isoLatin1
|
|
46
|
+
case .symbol:
|
|
47
|
+
return .symbol
|
|
48
|
+
case .nonlossyascii:
|
|
49
|
+
return .nonLossyASCII
|
|
50
|
+
case .shiftjis:
|
|
51
|
+
return .shiftJIS
|
|
52
|
+
case .isolatin2:
|
|
53
|
+
return .isoLatin2
|
|
54
|
+
case .unicode:
|
|
55
|
+
return .unicode
|
|
56
|
+
case .windowscp1251:
|
|
57
|
+
return .windowsCP1251
|
|
58
|
+
case .windowscp1252:
|
|
59
|
+
return .windowsCP1252
|
|
60
|
+
case .windowscp1253:
|
|
61
|
+
return .windowsCP1253
|
|
62
|
+
case .windowscp1254:
|
|
63
|
+
return .windowsCP1254
|
|
64
|
+
case .windowscp1250:
|
|
65
|
+
return .windowsCP1250
|
|
66
|
+
case .iso2022jp:
|
|
67
|
+
return .iso2022JP
|
|
68
|
+
case .macosroman:
|
|
69
|
+
return .macOSRoman
|
|
70
|
+
case .utf16:
|
|
71
|
+
return .utf16
|
|
72
|
+
case .utf16bigendian:
|
|
73
|
+
return .utf16BigEndian
|
|
74
|
+
case .utf16littleendian:
|
|
75
|
+
return .utf16LittleEndian
|
|
76
|
+
case .utf32:
|
|
77
|
+
return .utf32
|
|
78
|
+
case .utf32bigendian:
|
|
79
|
+
return .utf32BigEndian
|
|
80
|
+
case .utf32littleendian:
|
|
81
|
+
return .utf32LittleEndian
|
|
82
|
+
|
|
83
|
+
// Cases that don't have their own equivalent in String.Encoding
|
|
84
|
+
case .base64:
|
|
85
|
+
return nil
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Copyright 2023-present 650 Industries. All rights reserved.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'ExpoFileSystem'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.description = package['description']
|
|
10
|
+
s.license = package['license']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.homepage = package['homepage']
|
|
13
|
+
s.platforms = { :ios => '13.0', :tvos => '13.0'}
|
|
14
|
+
s.swift_version = '5.4'
|
|
15
|
+
s.source = { :git => 'https://github.com/expo/expo.git' }
|
|
16
|
+
s.static_framework = true
|
|
17
|
+
|
|
18
|
+
s.dependency 'ExpoModulesCore'
|
|
19
|
+
|
|
20
|
+
# Swift/Objective-C compatibility
|
|
21
|
+
s.pod_target_xcconfig = {
|
|
22
|
+
'DEFINES_MODULE' => 'YES'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
s.source_files = "**/*.{h,m,swift}"
|
|
26
|
+
|
|
27
|
+
s.exclude_files = 'Tests/'
|
|
28
|
+
s.test_spec 'Tests' do |test_spec|
|
|
29
|
+
test_spec.dependency 'ExpoModulesTestCore'
|
|
30
|
+
test_spec.source_files = 'Tests/**/*.{m,swift}'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Copyright 2023-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import ExpoModulesCore
|
|
4
|
+
|
|
5
|
+
public final class FileSystemBackgroundSessionHandler: ExpoAppDelegateSubscriber, EXSessionHandlerProtocol {
|
|
6
|
+
public typealias BackgroundSessionCompletionHandler = () -> Void
|
|
7
|
+
|
|
8
|
+
private var completionHandlers: [String: BackgroundSessionCompletionHandler] = [:]
|
|
9
|
+
|
|
10
|
+
public func invokeCompletionHandler(forSessionIdentifier identifier: String) {
|
|
11
|
+
guard let completionHandler = completionHandlers[identifier] else {
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
DispatchQueue.main.async {
|
|
15
|
+
completionHandler()
|
|
16
|
+
}
|
|
17
|
+
completionHandlers.removeValue(forKey: identifier)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// MARK: - ExpoAppDelegateSubscriber
|
|
21
|
+
|
|
22
|
+
public func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
|
|
23
|
+
completionHandlers[identifier] = completionHandler
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Copyright 2023-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import ExpoModulesCore
|
|
4
|
+
|
|
5
|
+
final class FileNotExistsException: GenericException<String> {
|
|
6
|
+
override var reason: String {
|
|
7
|
+
"File '\(param)' does not exist"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
final class DirectoryNotExistsException: GenericException<String> {
|
|
12
|
+
override var reason: String {
|
|
13
|
+
"Directory '\(param)' does not exist"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
final class FileNotReadableException: GenericException<String> {
|
|
18
|
+
override var reason: String {
|
|
19
|
+
"File '\(param)' is not readable"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
final class FileNotWritableException: GenericException<String> {
|
|
24
|
+
override var reason: String {
|
|
25
|
+
"File '\(param)' is not writable"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
final class FileWriteFailedException: GenericException<String> {
|
|
30
|
+
override var reason: String {
|
|
31
|
+
"Writing to '\(param)' file has failed"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
final class FileCannotDeleteException: GenericException<String> {
|
|
36
|
+
override var reason: String {
|
|
37
|
+
"File '\(param)' could not be deleted"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
final class InvalidFileUrlException: GenericException<URL> {
|
|
42
|
+
override var reason: String {
|
|
43
|
+
"'\(param.absoluteString)' is not a file URL"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
final class UnsupportedSchemeException: GenericException<String?> {
|
|
48
|
+
override var reason: String {
|
|
49
|
+
"Unsupported URI scheme: '\(String(describing: param))'"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
final class HeaderEncodingFailedException: GenericException<String> {
|
|
54
|
+
override var reason: String {
|
|
55
|
+
"Unable to encode headers for request '\(param)' to UTF8"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
final class DownloadTaskNotFoundException: GenericException<String> {
|
|
60
|
+
override var reason: String {
|
|
61
|
+
"Cannot find a download task with id: '\(param)'"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
final class CannotDetermineDiskCapacity: Exception {
|
|
66
|
+
override var reason: String {
|
|
67
|
+
"Unable to determine free disk storage capacity"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Copyright 2023-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import ExpoModulesCore
|
|
4
|
+
|
|
5
|
+
internal func ensureFileDirectoryExists(_ fileUrl: URL) throws {
|
|
6
|
+
let directoryPath = fileUrl.deletingLastPathComponent()
|
|
7
|
+
|
|
8
|
+
if !FileManager.default.fileExists(atPath: directoryPath.path) {
|
|
9
|
+
throw DirectoryNotExistsException(directoryPath.path)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
internal func readFileAsBase64(path: String, options: ReadingOptions) throws -> String {
|
|
14
|
+
let file = FileHandle(forReadingAtPath: path)
|
|
15
|
+
|
|
16
|
+
guard let file else {
|
|
17
|
+
throw FileNotExistsException(path)
|
|
18
|
+
}
|
|
19
|
+
if let position = options.position, position != 0 {
|
|
20
|
+
// TODO: Handle these errors?
|
|
21
|
+
try? file.seek(toOffset: UInt64(position))
|
|
22
|
+
}
|
|
23
|
+
if let length = options.length {
|
|
24
|
+
return file.readData(ofLength: length).base64EncodedString(options: .endLineWithLineFeed)
|
|
25
|
+
}
|
|
26
|
+
return file.readDataToEndOfFile().base64EncodedString(options: .endLineWithLineFeed)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
internal func writeFileAsBase64(path: String, string: String) throws {
|
|
30
|
+
let data = Data(base64Encoded: string, options: .ignoreUnknownCharacters)
|
|
31
|
+
|
|
32
|
+
if !FileManager.default.createFile(atPath: path, contents: data) {
|
|
33
|
+
throw FileWriteFailedException(path)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
internal func removeFile(path: String, idempotent: Bool = false) throws {
|
|
38
|
+
if FileManager.default.fileExists(atPath: path) {
|
|
39
|
+
do {
|
|
40
|
+
try FileManager.default.removeItem(atPath: path)
|
|
41
|
+
} catch {
|
|
42
|
+
throw FileCannotDeleteException(path)
|
|
43
|
+
.causedBy(error)
|
|
44
|
+
}
|
|
45
|
+
} else if !idempotent {
|
|
46
|
+
throw FileCannotDeleteException(path)
|
|
47
|
+
.causedBy(FileNotExistsException(path))
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
internal func getResourceValues(from directory: URL?, forKeys: Set<URLResourceKey>) throws -> URLResourceValues? {
|
|
52
|
+
do {
|
|
53
|
+
return try directory?.resourceValues(forKeys: forKeys)
|
|
54
|
+
} catch {
|
|
55
|
+
throw CannotDetermineDiskCapacity().causedBy(error)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
internal func ensurePathPermission(_ appContext: AppContext?, path: String, flag: EXFileSystemPermissionFlags) throws {
|
|
60
|
+
guard let permissionsManager: EXFilePermissionModuleInterface = appContext?.legacyModule(implementing: EXFilePermissionModuleInterface.self) else {
|
|
61
|
+
throw Exceptions.PermissionsModuleNotFound()
|
|
62
|
+
}
|
|
63
|
+
guard permissionsManager.getPathPermissions(path).contains(flag) else {
|
|
64
|
+
throw flag == .read ? FileNotReadableException(path) : FileNotWritableException(path)
|
|
65
|
+
}
|
|
66
|
+
}
|