Clean up media-upload temp files on iOS (#11007)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
So Asano
2026-07-06 23:18:00 +09:00
committed by GitHub
parent be0fbdff82
commit e5d2ee3315
2 changed files with 32 additions and 2 deletions
+8 -1
View File
@@ -10,6 +10,7 @@ import {useMutation} from '@tanstack/react-query'
import {STATUS_PAGE_URL} from '#/lib/constants'
import {type CommonNavigatorParams} from '#/lib/routes/types'
import {purgeTemporaryImageFiles} from '#/state/gallery'
import * as SettingsList from '#/screens/Settings/components/SettingsList'
import {Atom_Stroke2_Corner0_Rounded as AtomIcon} from '#/components/icons/Atom'
import {BroomSparkle_Stroke2_Corner2_Rounded as BroomSparkleIcon} from '#/components/icons/BroomSparkle'
@@ -41,7 +42,13 @@ export function AboutSettingsScreen({}: Props) {
useMutation({
mutationFn: async () => {
const freeSpaceBefore = await FileSystem.getFreeDiskStorageAsync()
await Image.clearDiskCache()
await Promise.all([
// expo-image's disk cache
Image.clearDiskCache(),
// full-resolution media-upload leftovers (picker/manipulator copies);
// the only in-app way for iOS users to reclaim this space
purgeTemporaryImageFiles(),
])
const freeSpaceAfter = await FileSystem.getFreeDiskStorageAsync()
const spaceDiff = freeSpaceBefore - freeSpaceAfter
return spaceDiff * -1
+24 -1
View File
@@ -358,14 +358,37 @@ function blobToDataUri(blob: Blob): Promise<string> {
})
}
/**
* Caches that the OS image picker and manipulator write into when attaching
* media to a post. They live alongside our own `bsky-composer` dir under the OS
* cache directory. expo-image-picker copies every originally selected photo and
* video here, and expo-image-manipulator leaves intermediate full-resolution
* outputs here (compressImage makes several manipulateAsync passes, only the
* last of which gets moved into `bsky-composer`). Nothing else cleans these up,
* so on iOS - where the OS exposes no "clear cache" - they accumulate
* indefinitely, one full-resolution copy per attached item.
*/
const SYSTEM_MEDIA_CACHE_DIRS = ['ImagePicker', 'ImageManipulator']
/** Purge files that were created to accomodate image manipulation */
export async function purgeTemporaryImageFiles() {
const cacheDir = IS_NATIVE && getImageCacheDirectory()
if (!IS_NATIVE) {
return
}
const cacheDir = getImageCacheDirectory()
if (cacheDir) {
await deleteAsync(cacheDir, {idempotent: true})
await makeDirectoryAsync(cacheDir)
}
// We don't recreate these - the respective expo modules recreate them on
// demand the next time they run.
await Promise.all(
SYSTEM_MEDIA_CACHE_DIRS.map(dir =>
deleteAsync(joinPath(cacheDirectory!, dir), {idempotent: true}),
),
)
}
function joinPath(a: string, b: string) {