存储
通过 PhotosPicker 将图片上传到 Supabase Storage。
上传示例是一个 Example(示例) 功能:选择照片,将其上传到限定于当前登录用户的私有 Supabase Storage 桶,并显示逐任务进度。当你要添加自己的文件功能时,可照搬它。
工作原理
UploadsRepository 直接与 Supabase Storage 通信(没有单独的数据源——没有需要隔离的行映射),
并返回一个 AsyncStream<UploadStatus>,让视图渲染实时进度:
enum UploadStatus: Sendable {
case progress(Double)
case completed(UploadedFile)
case failed(String)
}流程:UploadView 中的 PhotosPicker 把所选图片数据交给 UploadViewModel,后者调用
UploadsRepository.upload(data:fileName:contentType:userId:),并依据发出的 UploadStatus
值驱动 UI。
文件去向
上传写入 sample-uploads 桶,位于按用户划分的路径下,以便 RLS 按文件夹限定访问:
sample-uploads/<user-id>/<timestamp>-<short-uuid>-<sanitized-filename>用户 ID 会被转为小写并作为第一段路径。文件名会被清洗为 [A-Za-z0-9.-_],上传使用
upsert: false(每次上传都是一个新对象)。
iOS 应用仅使用 Storage——它不写入 sample_uploads 表行(Expo 原版会写)。若你需要
可查询的上传索引,可加一张表并在 completed 后插入,照搬
数据层 的仓库形态。
存储桶与策略
创建私有桶(在 Supabase 配置 中也有):
insert into storage.buckets (id, name, public, file_size_limit)
values ('sample-uploads', 'sample-uploads', false, 52428800) -- 50 MB
on conflict (id) do nothing;然后添加 storage.objects 策略,按每行的首段路径是否匹配调用者 UID 来放行——这正是让
按用户划分的文件夹保持私有的机制:
create policy "Users can read own sample upload objects"
on storage.objects for select to authenticated
using (bucket_id = 'sample-uploads'
and (storage.foldername(name))[1] = auth.uid()::text);
create policy "Users can upload own sample upload objects"
on storage.objects for insert to authenticated
with check (bucket_id = 'sample-uploads'
and (storage.foldername(name))[1] = auth.uid()::text);
create policy "Users can update own sample upload objects"
on storage.objects for update to authenticated
using (bucket_id = 'sample-uploads'
and (storage.foldername(name))[1] = auth.uid()::text)
with check (bucket_id = 'sample-uploads'
and (storage.foldername(name))[1] = auth.uid()::text);
create policy "Users can delete own sample upload objects"
on storage.objects for delete to authenticated
using (bucket_id = 'sample-uploads'
and (storage.foldername(name))[1] = auth.uid()::text);注销账户时的清理
delete-account Edge Function 会列出 sample-uploads/<user-id>/ 下的全部内容,并在删除
auth 用户之前移除它们,因此不会留下孤立对象。没有该桶的项目会被视作「无需清理」。参见
身份认证。
显示图片
应用其他地方显示远程图片时,使用 RemoteImage——它是对 Kingfisher 的轻量封装,负责异步
加载、缓存与占位/错误状态。参见 UI 组件。
换成你自己的存储桶
- 构建
UploadsRepository时传入bucketName:即可更改桶名(默认为sample-uploads)。 - 为你的桶 id 重建这四条
storage.objects策略。 - 保留
<user-id>/…路径前缀,foldername的 RLS 检查才继续生效;或重写策略以匹配你自己的 布局。 - 对于公共资源,创建一个
public桶并去掉 SELECT 策略——但绝不要把按用户划分的桶设为公开。
