Skip to content

Commit fc8b5a1

Browse files
authored
Merge pull request #273 from sendbird/feat/support-expo-54-file-system
[CLNP-7734] feat: support expo-file-system in expo 54 or higher
2 parents 32a3925 + 1338aa7 commit fc8b5a1

File tree

3 files changed

+77
-5
lines changed

3 files changed

+77
-5
lines changed

packages/uikit-react-native/src/platform/createFileService.expo.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,20 +145,22 @@ const createExpoFileService = ({
145145
if (!granted) throw new Error('Permission not granted');
146146
}
147147

148-
const basePath = fsModule.documentDirectory || fsModule.cacheDirectory;
148+
const basePath =
149+
expoBackwardUtils.fileSystem.getDocumentDirectory(fsModule) ||
150+
expoBackwardUtils.fileSystem.getCacheDirectory(fsModule);
149151
if (!basePath) throw new Error('Cannot determine directory');
150152

151153
const downloadPath = `${basePath}/${options.fileName}`;
152154

153-
const response = await fsModule.downloadAsync(options.fileUrl, downloadPath);
155+
const response = await expoBackwardUtils.fileSystem.downloadFile(fsModule, options.fileUrl, downloadPath);
154156
if (getFileType(options.fileType || '').match(/video|image/)) {
155157
await mediaLibraryModule.saveToLibraryAsync(response.uri);
156158
}
157159
return response.uri;
158160
}
159161

160162
createRecordFilePath(customExtension = 'm4a'): { recordFilePath: string; uri: string } {
161-
const basePath = fsModule.cacheDirectory;
163+
const basePath = expoBackwardUtils.fileSystem.getCacheDirectory(fsModule);
162164
if (!basePath) throw new Error('Cannot determine directory');
163165

164166
const filename = `record-${Date.now()}.${customExtension}`;

packages/uikit-react-native/src/platform/createMediaService.expo.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ const createExpoMediaService = ({
122122
const { uri: compressedURI } = await imageManipulator.manipulateAsync(uri, [{ resize: resizingSize }], {
123123
compress: Math.min(Math.max(0, compressionRate), 1),
124124
});
125-
const fileInfo = await fsModule.getInfoAsync(uri);
125+
const fileInfo = await expoBackwardUtils.fileSystem.getFileInfo(fsModule, uri);
126126

127127
return { uri: compressedURI, size: expoBackwardUtils.toFileSize(fileInfo) };
128128
},

packages/uikit-react-native/src/utils/expoBackwardUtils.ts

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,36 @@ import type * as ExpoVideo from 'expo-video';
88
import type { FilePickerResponse } from '../platform/types';
99
import normalizeFile from './normalizeFile';
1010

11+
// Legacy expo-file-system API types (before SDK 54)
12+
interface ExpoFileSystemLegacy {
13+
documentDirectory: string | null;
14+
cacheDirectory: string | null;
15+
getInfoAsync(fileUri: string, options?: unknown): Promise<ExpoFs.FileInfo>;
16+
downloadAsync(uri: string, fileUri: string, options?: unknown): Promise<{ uri: string }>;
17+
}
18+
19+
// New expo-file-system API types (SDK 54+)
20+
interface ExpoDirectory {
21+
uri: string;
22+
}
23+
24+
interface ExpoFileSystemNew {
25+
File: {
26+
new (...uris: (string | unknown)[]): {
27+
info(options?: unknown): ExpoFs.FileInfo;
28+
};
29+
downloadFileAsync(url: string, destination: unknown, options?: unknown): Promise<{ uri: string }>;
30+
};
31+
Directory: new (...uris: (string | unknown)[]) => ExpoDirectory;
32+
Paths: {
33+
document: ExpoDirectory;
34+
cache: ExpoDirectory;
35+
};
36+
}
37+
38+
// Union type for both legacy and new expo-file-system
39+
type ExpoFileSystemModule = ExpoFileSystemLegacy | ExpoFileSystemNew | typeof ExpoFs;
40+
1141
const expoBackwardUtils = {
1242
imagePicker: {
1343
isCanceled(result: ExpoImagePicker.ImagePickerResult) {
@@ -82,12 +112,52 @@ const expoBackwardUtils = {
82112
},
83113
},
84114
toFileSize(info: ExpoFs.FileInfo) {
85-
if ('size' in info) {
115+
if ('size' in info && info.size !== undefined) {
86116
return info.size;
87117
} else {
88118
return 0;
89119
}
90120
},
121+
fileSystem: {
122+
isLegacyModule(fsModule: ExpoFileSystemModule): fsModule is ExpoFileSystemLegacy {
123+
try {
124+
return 'documentDirectory' in fsModule || 'cacheDirectory' in fsModule;
125+
} catch {
126+
return false;
127+
}
128+
},
129+
async getFileInfo(fsModule: ExpoFileSystemModule, uri: string): Promise<ExpoFs.FileInfo> {
130+
if (expoBackwardUtils.fileSystem.isLegacyModule(fsModule)) {
131+
return await fsModule.getInfoAsync(uri);
132+
} else {
133+
const file = new fsModule.File(uri);
134+
return file.info();
135+
}
136+
},
137+
getDocumentDirectory(fsModule: ExpoFileSystemModule): string | null {
138+
if (expoBackwardUtils.fileSystem.isLegacyModule(fsModule)) {
139+
return fsModule.documentDirectory || null;
140+
} else {
141+
return fsModule.Paths?.document?.uri || null;
142+
}
143+
},
144+
getCacheDirectory(fsModule: ExpoFileSystemModule): string | null {
145+
if (expoBackwardUtils.fileSystem.isLegacyModule(fsModule)) {
146+
return fsModule.cacheDirectory || null;
147+
} else {
148+
return fsModule.Paths?.cache?.uri || null;
149+
}
150+
},
151+
async downloadFile(fsModule: ExpoFileSystemModule, url: string, localUri: string): Promise<{ uri: string }> {
152+
if (expoBackwardUtils.fileSystem.isLegacyModule(fsModule)) {
153+
return await fsModule.downloadAsync(url, localUri);
154+
} else {
155+
const destination = new fsModule.File(localUri);
156+
const result = await fsModule.File.downloadFileAsync(url, destination as never);
157+
return { uri: result.uri };
158+
}
159+
},
160+
},
91161
};
92162

93163
export type ExpoAudioModule = typeof ExpoAV | typeof ExpoAudio;

0 commit comments

Comments
 (0)