내 백업에서 모든 사진이 사라졌다

오프라인 기분 추적기(mood tracker)를 위한 백업 버튼을 만들었습니다.

데이터를 JSON 파일로 내보내는 방식이었습니다. 사용자는 이 파일을 저장해 새 휴대폰으로 옮길 수 있었습니다. 완벽해 보였습니다.

그러다 앱의 패키지 ID를 변경했습니다. 새 기기에 앱을 새로 설치하고 백업을 복원해 보았습니다.

텍스트 기록은 돌아왔습니다. 하지만 모든 사진이 사라졌습니다.

제 실수를 깨달았습니다. 그 백업은 진짜 백업이 아니었습니다. 그저 더 이상 존재하지 않는 파일들을 가리키는 포인터 목록일 뿐이었습니다.

앱은 디스크에 사진을 저장했고, 데이터베이스에는 파일 경로를 저장했습니다.

경로는 다음과 같았습니다: file:///data/user/0/com.example.app/files/entry_media/image.jpg

JSON을 내보낼 때 저는 그 경로만 저장했습니다. 같은 기기에서는 파일이 여전히 그 자리에 있기 때문에 가져오기가 정상적으로 작동합니다.

하지만 새 기기에서 해당 경로들은 아무것도 가리키지 않습니다. 사용자는 깨진 썸네일을 보게 되고, 앱이 자신의 추억을 삭제했다고 생각하게 됩니다.

만약 내보내기 기능이 파일 경로만 포함한다면, 그것은 휴대 가능한 백업이 아닙니다. 백업이 필요 없는 기기에서만 작동하는 백업일 뿐입니다.

진짜 백업은 실제 데이터를 포함해야 합니다.

프로세스를 변경했습니다. 이제 내보내기 시 각 사진을 읽어 JSON 내부의 Base64 문자열로 변환합니다.

이 방식에는 트레이드오프(trade-offs)가 있습니다: • 파일 크기가 약 33% 증가합니다. • 대용량 라이브러리의 경우 내보내기 중에 더 많은 메모리가 필요합니다.

저는 파일 크기보다 정확성을 선택했습니다. 용량이 큰 백업은 유용하지만, 모든 이미지를 잃어버리는 아주 작은 백업은 가치가 없습니다.

또한 속도와 안전성을 보장하기 위해 가져오기 처리 방식도 변경했습니다:

  1. 먼저 모든 사진을 새 기기의 디스크에 씁니다. 속도를 유지하기 위해 이 작업은 데이터베이스 트랜잭션 외부에서 수행됩니다.
  2. 단일 데이터베이스 트랜잭션을 실행하여 새로운 로컬 경로를 항목(entries)에 연결합니다.

또한 시스템이 부드럽게 실패(fail soft)하도록 설계했습니다. 사진 하나가 누락되었거나 읽을 수 없는 경우, 앱은 이를 건너뛰고 다음 사진으로 넘어갑니다. 이미지 하나가 깨졌다고 해서 전체 복원 프로세스가 중단되어서는 안 됩니다.

배운 점:

  • 올바른 방식으로 테스트하세요. 한 기기에서 내보낸 뒤, 데이터를 완전히 삭제하고, 새로 설치한 상태에서 가져오기를 해보세요. 같은 기기에서 다시 가져오기를 하면 버그가 드러나지 않습니다.
  • 바이트(bytes)를 옮기세요. 데이터가 기기 변경 후에도 유지되어야 한다면, 주소가 아닌 실제 데이터를 옮겨야 합니다.

Source: https://dev.to/diven_rastdus_c5af27d68f3/my-offline-apps-backup-lost-every-photo-on-a-new-phone-3d36