diff --git a/README.md b/README.md index 2c58d38..6211e57 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,12 @@ type FetchResult = { `FilesSystem.hash(path: string, algorithm: 'MD5' | 'SHA-1' | 'SHA-224' | 'SHA-256' | 'SHA-384' | 'SHA-512'): Promise` - Hash the file content. +`FilesSystem.getAppGroupDir(groupName: string): Promise` +- Get the directory for your app group (iOS only). + - App groups are used on iOS/MacOS for storing content, which is shared between apps. + - This is e.g. useful for sharing data between your iOS app and a widget or a watch app. + + `FilesSystem.isDir(path: string): Promise` - Check if a path is a directory. diff --git a/ios/FileAccess.m b/ios/FileAccess.m index 1ab38f6..a137822 100644 --- a/ios/FileAccess.m +++ b/ios/FileAccess.m @@ -37,6 +37,10 @@ @interface RCT_EXTERN_REMAP_MODULE(RNFileAccess, FileAccess, NSObject) withResolver:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(getAppGroupDir:(NSString *)groupName + withResolver:(RCTPromiseResolveBlock)resolve + withRejecter:(RCTPromiseRejectBlock)reject) + RCT_EXTERN_METHOD(hash:(NSString *)path withAlgorithm:(NSString *)algorithm withResolver:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject) diff --git a/ios/FileAccess.swift b/ios/FileAccess.swift index d7eb69e..c22b54b 100644 --- a/ios/FileAccess.swift +++ b/ios/FileAccess.swift @@ -179,6 +179,16 @@ class FileAccess: NSObject { downloadTask.resume() } + @objc(getAppGroupDir:withResolver:withRejecter:) + func getAppGroupDir(groupName: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + guard let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupName) else { + reject("ERR", "Could not resolve app group directory. The group name '\(groupName)' is invalid.", nil) + return + } + + resolve(groupURL.path) + } + @objc(hash:withAlgorithm:withResolver:withRejecter:) func hash(path: String, algorithm: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { guard let data = NSData(contentsOfFile: path) else { diff --git a/jest/react-native-file-access.ts b/jest/react-native-file-access.ts index c4e2915..9a69400 100644 --- a/jest/react-native-file-access.ts +++ b/jest/react-native-file-access.ts @@ -1,5 +1,6 @@ /* global jest */ +import { Platform } from 'react-native'; import type { ExternalDir, FetchResult, @@ -103,6 +104,18 @@ class FileSystemMock { } ); + /** + * Return the local storage directory for app groups. + * + * This is an Apple only feature. + */ + public getAppGroupDir = jest.fn((groupName: string) => { + if (Platform.OS !== 'ios' && Platform.OS !== 'macos') { + throw new Error('AppGroups are available on Apple devices only'); + } + return `${Dirs.DocumentDir}/shared/AppGroup/${groupName}`; + }); + /** * Hash the file content. */ diff --git a/src/index.ts b/src/index.ts index e255df0..0038f70 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { NativeModules } from 'react-native'; +import { NativeModules, Platform } from 'react-native'; import { FileAccessNative } from './native'; import type { Encoding, @@ -92,6 +92,20 @@ export const FileSystem = { return FileAccessNative.fetch(resource, init); }, + /** + * Return the local storage directory for app groups. + * + * This is an Apple only feature. + */ + getAppGroupDir(groupName: string) { + if (Platform.OS !== 'ios' && Platform.OS !== 'macos') { + return Promise.reject( + new Error('AppGroups are available on Apple devices only') + ); + } + return FileAccessNative.getAppGroupDir(groupName); + }, + /** * Hash the file content. */ diff --git a/src/native.ts b/src/native.ts index 80bde91..6402675 100644 --- a/src/native.ts +++ b/src/native.ts @@ -29,6 +29,7 @@ type FileAccessType = { path?: string; } ): Promise; + getAppGroupDir(groupName: string): Promise; hash(path: string, algorithm: HashAlgorithm): Promise; isDir(path: string): Promise; ls(path: string): Promise;