문제 해결 목적
supabase storage를 활용한 가계부 sqlite db 파일 백업 기능 구현
문제 해결 과정
2024.02.09 - [Flutter-플러터/플러터 공부] - 7external_path 패키지, 결국 supabase
7external_path 패키지, 결국 supabase
https://pub.dev/packages/external_path external_path | Flutter package A flutter plugin to get internal, external storage and external public directory path. pub.dev 문제 해결 목적 백업 서비스를 구현 중 입니다. 원래계획은 앱 외부
ownerdev88.tistory.com
원래 목표는 안드로이드 - google drive , IOS - icloud 를 이용한 백업 서비스를 생각했었습니다.
하지만 편한가계부 네이버 까페에 가보면 안드로이드 폰 -> 아이폰으로 변경한 고객님께서 데이터 백업 절차가 복잡하다는 글이 좀 있더라구요.
그래서 결국 supabase에 있는 storage 를 이용해서 백업 기능을 구현하게 되었습니다.
유데미에 있는 아래 강좌를 이용해서 구현했습니다.
SupabaseService 코드
static으로 각 함수를 바로 사용할 수 있게 했습니다.
supabase storage의 기본적인 사용법은 다음과 같습니다.
1. supabase storage 에서 bucket 을 만든다.
2. bucket의 정책을 설정한다. supabase 로그인 된 아이디 = auth.id 이런 정책
3. 이렇게 되면 supabase bucket은 각 유저의 아이디로 생성된 폴더가 생깁니다. 그 폴더 안에 유저의 db를 보관하는 시스템입니다.
4. supabase에 있는 db파일을 다시 앱에 적용시키기 위해서는 앱을 재시작 해야 합니다. 아래 패키지를 사용했습니다. 좋네요!!!
https://pub.dev/packages/restart_app
restart_app | Flutter package
A Flutter plugin that helps you to restart the whole Flutter app with a single function call by using native APIs.
pub.dev
import 'dart:io';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:money_tracker_test/model/needs/needs_model.dart';
import 'package:money_tracker_test/model/user/delete_user_model.dart';
import 'package:path_provider/path_provider.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:restart_app/restart_app.dart';
class SupabaseService {
// Supabase 클라이언트를 초기화하는 메소드
// 데이터 생성 (Create)
static Future<void> createNeed(Needs need) async {
final supabase = Supabase.instance.client;
try {
await supabase.from('needs').upsert([need.toJson()]);
} catch (e) {
// 예외 발생 시 로그 출력 또는 오류 처리
print('Supabase 데이터 생성 중 오류 발생: $e');
}
}
static Future<void> createdDeleteUser(DeleteUser deleteUser) async {
final supabase = Supabase.instance.client;
try {
await supabase.from("delete_user_confirm").upsert([deleteUser.toJson()]);
} catch (e) {
print('Supabase 데이터 생성 중 오류 발생: $e');
}
}
// 안드로이드에서 파일 경로를 가져오는 함수
static Future<String> getDatabasePathAndroid() async {
return "/data/user/0/com.jalam.dev.app/databases/moneytracker.db";
}
// iOS에서 파일 경로를 가져오는 함수
static Future<String> getDatabasePathIOS() async {
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
return '$appDocPath/moneytracker.db';
}
// 플랫폼에 따라 파일 경로를 가져오는 함수
static Future<String> getDatabasePath() async {
if (Platform.isAndroid) {
return getDatabasePathAndroid();
} else if (Platform.isIOS) {
return getDatabasePathIOS();
} else {
throw UnsupportedError('이 플랫폼은 지원되지 않습니다.');
}
}
//db 파일에 supabase storage 에 upload
static Future<String?> uploadDatabaseToStorage() async {
final supabase = Supabase.instance.client;
try {
String dbPath = await getDatabasePath();
File dbFile = File(dbPath);
final now = DateTime.now();
final formatter = DateFormat('yy.MM.dd.HHmmss');
final String formattedDate = formatter.format(now);
final String fileName = "${formattedDate}_moneytracker.db";
if (await dbFile.exists()) {
// 파일이 존재하면 업로드
await supabase.storage
.from('db_data')
.upload("${supabase.auth.currentUser!.id}/$fileName", dbFile);
print('Database uploaded to Supabase Storage');
} else {
print('Database file does not exist');
}
} catch (e) {
print('Error uploading database to Supabase Storage: $e');
}
return null;
}
//supabase storage에 있는 파일을 리스트화 ui
static Future getData() async {
final supabase = Supabase.instance.client;
final List<FileObject> result = await supabase.storage
.from("db_data")
.list(path: supabase.auth.currentUser!.id);
final List<Map<String, String>> mydata = [];
if (result.isEmpty) {
// 데이터가 없는 경우 빈 리스트 반환
return mydata;
} else {
for (var data in result) {
mydata.add({
"파일 이름": data.name,
});
}
}
print(mydata);
return mydata;
}
//supabase storage 삭제 기능
static Future<void> deleteData(String dataName) async {
final supabase = Supabase.instance.client;
try {
supabase.storage
.from("db_data")
.remove([supabase.auth.currentUser!.id + "/" + dataName]);
} catch (e) {
print('Error deleting database to Supabase Storage: $e');
}
}
//supabase storage에 있는 백업 파일을 누르면 restore
static Future<void> restoreDatabase(String fileName) async {
final supabase = Supabase.instance.client;
try {
// 로컬에서 데이터베이스 파일 경로 가져오기
final String dbPath = await getDatabasePath();
// Supabase Storage에서 파일 다운로드
final fileResponse = await supabase.storage
.from('db_data')
.download('${supabase.auth.currentUser!.id}/$fileName');
// 다운로드된 파일 저장
final File dbFile = File(dbPath);
await dbFile.writeAsBytes(fileResponse);
Restart.restartApp();
print('Database restored from Supabase Storage');
} catch (e) {
Get.snackbar('복원 실패', '백업 파일 복원 중 오류가 발생했습니다.');
print('Error restoring database from Supabase Storage: $e');
}
}
}
결과
1번 영상
IOS 시뮬레이터에서 백업 기능 구현
2번 영상
IOS 시뮬레이터에서 백업한 파일을 안드로이드 폰에서 다시 백업 진행
IOS 에서 생성된 데이터 -> 안드로이드에서 정상 작동 확인!
'Flutter-플러터 > 플러터 공부' 카테고리의 다른 글
Flutter - 가계부 월 고정 지출 반복적으로 입력 구현 (0) | 2024.03.02 |
---|---|
Flutter 앱 버전 체크해서 알람 만들기 (0) | 2024.02.23 |
Flutter supabase Apple login 구현 (0) | 2024.02.11 |
7external_path 패키지, 결국 supabase (0) | 2024.02.09 |
flutter build 패키지 이름 변경 - 안드로이드, IOS 공통 (0) | 2024.01.17 |