Android Backup Service는 Android 앱에서 키-값 데이터의 클라우드 스토리지 백업 및 복원을 제공합니다. 키-값 백업 작업 중 앱의 백업 데이터가 기기의 백업 전송으로 전달됩니다. 기기가 기본 Google 백업 전송을 사용한다면 데이터는 보관처리를 위해 Android Backup Service로 전달됩니다.
데이터는 앱 사용자당 5MB로 제한됩니다. 백업 데이터를 저장하는 데 드는 비용은 없습니다.
Android의 백업 옵션 개요와 백업 및 복원해야 하는 데이터에 관한 안내는 데이터 백업 개요를 참고하세요.
키-값 백업 구현
앱 데이터를 백업하려면 백업 에이전트를 구현해야 합니다. 백업 관리자는 백업 및 복원 중에 백업 에이전트를 호출합니다.
백업 에이전트를 구현하려면 다음을 실행해야 합니다.
android:backupAgent
속성을 사용하여 매니페스트 파일에 백업 에이전트를 선언합니다.다음 중 하나를 진행하여 백업 에이전트를 정의합니다.
-
BackupAgent
클래스는 앱이 백업 관리자와 통신하는 데 사용하는 중앙 인터페이스를 제공합니다. 이 클래스를 직접 확장하려면onBackup()
과onRestore()
를 재정의하여 데이터 백업 및 복원 작업을 처리해야 합니다. -
BackupAgentHelper
클래스는BackupAgent
클래스의 간편한 래퍼를 제공하고 개발자가 작성해야 하는 코드의 양을 최소화합니다.BackupAgentHelper
에서는 특정 데이터 유형을 자동으로 백업 및 복원하는 도우미 객체를 하나 이상 사용해야 하므로onBackup()
과onRestore()
를 구현할 필요가 없습니다. 앱의 백업을 완전히 제어해야 하는 경우가 아니라면BackupAgentHelper
를 사용하여 앱 백업을 처리하는 것이 좋습니다.Android는 현재
SharedPreferences
와 내부 저장소의 전체 파일을 백업 및 복원하는 백업 도우미를 제공합니다.
-
매니페스트에 백업 에이전트 선언
백업 에이전트의 클래스 이름을 정했으면 <application>
태그의 android:backupAgent
속성을 사용하여 매니페스트에 클래스 이름을 선언합니다.
예:
<manifest ... > ... <application android:label="MyApplication" android:backupAgent="MyBackupAgent"> <meta-data android:name="com.google.android.backup.api_key" android:value="unused" /> <activity ... > ... </activity> </application> </manifest>
이전 기기를 지원하려면 API 키 <meta-data>
를 Android 매니페스트 파일에 추가하는 것이 좋습니다. Android Backup Service에서는 더 이상 서비스 키가 필요하지 않지만 일부 이전 기기에서는 아직도 백업 시 키를 확인할 수 있습니다. android:name
을 com.google.android.backup.api_key
로, android:value
를 unused
로 설정합니다.
android:restoreAnyVersion
속성은 현재 앱 버전과 관계없이 백업 데이터를 생성한 버전과 비교하여 앱 데이터를 복원할지를 나타내는 부울 값을 사용합니다. 기본값은 false
입니다. 자세한 내용은 복원 데이터 버전 확인을 참고하세요.
BackupAgentHelper 확장
SharedPreferences
또는 내부 저장소 둘 중 하나에서 받은 전체 파일을 백업하려면 BackupAgentHelper
를 사용하여 백업 에이전트를 빌드해야 합니다.
BackupAgentHelper
를 사용하여 백업 에이전트를 빌드하면 onBackup()
과 onRestore()
를 구현하지 않아도 되므로 BackupAgent
를 확장하는 것보다 필요한 코드가 훨씬 적습니다.
BackupAgentHelper
를 구현하려면 백업 도우미를 하나 이상 사용해야 합니다.
백업 도우미는 특정 데이터 유형의 백업 및 복원 작업을 실행하기 위해 BackupAgentHelper
에서 호출하는 특화된 구성요소입니다. Android 프레임워크는 현재 다음의 두 가지 도우미를 제공합니다.
SharedPreferencesBackupHelper
:SharedPreferences
파일을 백업FileBackupHelper
: 내부 저장소에서 파일을 백업
BackupAgentHelper
에 도우미를 여러 개 포함할 수 있지만, 데이터 유형별로 하나의 도우미만 필요합니다. 즉, SharedPreferences
파일이 여러 개 있더라도 하나의 SharedPreferencesBackupHelper
만 필요합니다.
BackupAgentHelper
에 추가하려는 각 도우미별로 onCreate()
메서드 내에서 다음을 실행해야 합니다.
- 원하는 도우미 클래스의 인스턴스를 인스턴스화합니다. 클래스 생성자에서 백업할 파일을 지정해야 합니다.
addHelper()
를 호출하여BackupAgentHelper
에 도우미를 추가합니다.
다음 섹션에서는 사용 가능한 각 도우미를 사용하여 백업 에이전트를 만드는 방법을 설명합니다.
SharedPreferences 백업
SharedPreferencesBackupHelper
를 인스턴스화할 때 하나 이상의 SharedPreferences
파일 이름을 포함해야 합니다.
예를 들어, user_preferences
라는 이름의 SharedPreferences
파일을 백업하기 위해 BackupAgentHelper
를 사용하는 백업 에이전트의 완성된 모습은 다음과 같습니다.
Kotlin
// The name of the SharedPreferences file const val PREFS = "user_preferences" // A key to uniquely identify the set of backup data const val PREFS_BACKUP_KEY = "prefs" class MyPrefsBackupAgent : BackupAgentHelper() { override fun onCreate() { // Allocate a helper and add it to the backup agent SharedPreferencesBackupHelper(this, PREFS).also { addHelper(PREFS_BACKUP_KEY, it) } } }
자바
public class MyPrefsBackupAgent extends BackupAgentHelper { // The name of the SharedPreferences file static final String PREFS = "user_preferences"; // A key to uniquely identify the set of backup data static final String PREFS_BACKUP_KEY = "prefs"; // Allocate a helper and add it to the backup agent @Override public void onCreate() { SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS); addHelper(PREFS_BACKUP_KEY, helper); } }
SharedPreferencesBackupHelper
는 SharedPreferences
파일을 백업하고 복원하는 데 필요한 모든 코드를 포함합니다.
백업 관리자가 onBackup()
과 onRestore()
를 호출할 때 BackupAgentHelper
는 백업 도우미를 호출하여 지정된 파일을 백업 및 복원합니다.
다른 파일 백업
FileBackupHelper
를 인스턴스화할 때 앱의 내부 저장소(getFilesDir()
에 의해 지정된 위치이며 openFileOutput()
이 파일을 쓰는 위치와 동일함)에 저장되는 파일 이름을 하나 이상 포함해야 합니다.
예를 들어, scores
와 stats
라는 이름의 파일 두 개를 백업하기 위해 BackupAgentHelper
를 사용하는 백업 에이전트는 다음과 같습니다.
Kotlin
// The name of the file const val TOP_SCORES = "scores" const val PLAYER_STATS = "stats" // A key to uniquely identify the set of backup data const val FILES_BACKUP_KEY = "myfiles" class MyFileBackupAgent : BackupAgentHelper() { override fun onCreate() { // Allocate a helper and add it to the backup agent FileBackupHelper(this, TOP_SCORES, PLAYER_STATS).also { addHelper(FILES_BACKUP_KEY, it) } } }
자바
public class MyFileBackupAgent extends BackupAgentHelper { // The name of the file static final String TOP_SCORES = "scores"; static final String PLAYER_STATS = "stats"; // A key to uniquely identify the set of backup data static final String FILES_BACKUP_KEY = "myfiles"; // Allocate a helper and add it to the backup agent @Override public void onCreate() { FileBackupHelper helper = new FileBackupHelper(this, TOP_SCORES, PLAYER_STATS); addHelper(FILES_BACKUP_KEY, helper); } }
FileBackupHelper
는 앱의 내부 저장소에 저장되는 파일을 백업 및 복원하는 데 필요한 모든 코드를 포함합니다.
하지만 내부 저장소의 파일을 읽고 쓰는 것은 스레드로부터 안전하지 않습니다. 백업 에이전트가 활동과 동시에 파일을 읽거나 쓰지 않도록 보장하려면 읽기 또는 쓰기를 실행할 때마다 동기화된 문을 사용해야 합니다. 예를 들어 파일을 읽고 쓰는 모든 활동에서 다음과 같이 동기화된 문의 고유 잠금으로 사용할 객체가 필요합니다.
Kotlin
// Object for intrinsic lock companion object { val sDataLock = Any() }
자바
// Object for intrinsic lock static final Object sDataLock = new Object();
그런 다음 파일을 읽거나 쓸 때마다 이 잠금을 사용하여 동기화된 문을 만듭니다. 예를 들어 게임에서 파일에 가장 최근의 점수를 기록하는 동기화된 문은 다음과 같습니다.
Kotlin
try { synchronized(MyActivity.sDataLock) { val dataFile = File(filesDir, TOP_SCORES) RandomAccessFile(dataFile, "rw").apply { writeInt(score) } } } catch (e: IOException) { Log.e(TAG, "Unable to write to file") }
자바
try { synchronized (MyActivity.sDataLock) { File dataFile = new File(getFilesDir(), TOP_SCORES); RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw"); raFile.writeInt(score); } } catch (IOException e) { Log.e(TAG, "Unable to write to file"); }
read 문은 동일한 잠금으로 동기화해야 합니다.
그런 다음, BackupAgentHelper
에서 onBackup()
과 onRestore()
를 재정의하여 동일한 고유 잠금으로 백업 및 복원 작업을 동기화해야 합니다. 예를 들어, 위의 MyFileBackupAgent
예는 다음의 메서드가 필요합니다.
Kotlin
@Throws(IOException::class) override fun onBackup( oldState: ParcelFileDescriptor, data: BackupDataOutput, newState: ParcelFileDescriptor ) { // Hold the lock while the FileBackupHelper performs back up synchronized(MyActivity.sDataLock) { super.onBackup(oldState, data, newState) } } @Throws(IOException::class) override fun onRestore( data: BackupDataInput, appVersionCode: Int, newState: ParcelFileDescriptor ) { // Hold the lock while the FileBackupHelper restores the file synchronized(MyActivity.sDataLock) { super.onRestore(data, appVersionCode, newState) } }
자바
@Override public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException { // Hold the lock while the FileBackupHelper performs back up synchronized (MyActivity.sDataLock) { super.onBackup(oldState, data, newState); } } @Override public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException { // Hold the lock while the FileBackupHelper restores the file synchronized (MyActivity.sDataLock) { super.onRestore(data, appVersionCode, newState); } }
BackupAgent 확장
대부분의 앱에서 직접 BackupAgent
클래스를 확장할 필요는 없지만 대신 BackupAgentHelper
를 확장하여 자동으로 파일을 백업 및 복원하는 내장된 도우미 클래스를 활용해야 합니다.
하지만 BackupAgent
를 직접 확장하여 다음 작업을 진행할 수 있습니다.
- 데이터 형식의 버전을 관리합니다. 예를 들어, 앱 데이터를 쓰는 형식을 수정할 필요가 있을 것으로 예상된다면 백업 에이전트를 빌드하여 복원 작업 동안 앱 버전을 교차 확인하고 기기의 버전이 백업 데이터의 버전과 다른 경우 필요한 모든 호환성 작업을 실행할 수 있습니다. 자세한 내용은 복원 데이터 버전 확인을 참고하세요.
- 백업할 데이터의 일부를 지정합니다. 전체 파일을 백업하는 대신, 백업할 데이터의 일부를 지정하고 그 부분을 기기에 복원할 방법을 지정할 수 있습니다. 이는 완성된 파일이라기보다는 고유한 항목으로 데이터를 읽고 쓰기 때문에 서로 다른 버전을 관리하는 데도 도움이 됩니다.
- 데이터베이스의 데이터를 백업합니다. 사용자가 앱을 다시 설치할 때 복원할 SQLite 데이터베이스가 있다면 백업 작업 동안 적절한 데이터를 읽도록 맞춤
BackupAgent
를 빌드해야 하고 그런 다음 복원 작업 중에 표를 생성하여 데이터를 삽입해야 합니다.
위의 작업을 실행할 필요가 없고 SharedPreferences
또는 내부 저장소에서 전체 파일을 백업하려면 BackupAgentHelper
확장을 참고하세요.
필수 메서드
BackupAgent
를 생성하려면 다음 콜백 메서드를 구현해야 합니다.
onBackup()
- 백업을 요청하면 백업 관리자가 이 메서드를 호출합니다. 이 메서드에서는 백업 실행에 설명한 대로 기기에서 앱 데이터를 읽고 백업하려는 데이터를 백업 관리자에 전달합니다.
onRestore()
백업 관리자는 복원 작업 중에 이 메서드를 호출합니다. 이 메서드는 복원 실행에 설명한 대로 앱이 데이터의 이전 상태를 복원하는 데 사용할 수 있는 백업 데이터를 전달합니다.
시스템은 사용자가 앱을 다시 설치할 때 이 메서드를 호출하여 모든 백업 데이터를 복원하지만 앱이 복원을 요청할 수도 있습니다.
백업 실행
백업 요청을 한다고 onBackup()
메서드가 즉시 호출되는 것은 아닙니다. 대신, 백업 관리자는 적당한 시간을 기다린 다음 마지막 백업이 실행된 이후로 백업을 요청한 모든 앱의 백업을 실행합니다. 이때 앱 데이터를 백업 관리자에 제공해야 하므로 앱 데이터가 클라우드 스토리지에 저장될 수 있습니다.
백업 관리자만 백업 에이전트의 onBackup()
메서드를 호출할 수 있습니다. 앱 데이터가 변경되고 백업을 실행하려고 할 때마다 dataChanged()
를 호출하여 백업 작업을 요청해야 합니다.
자세한 내용은 백업 요청을 참고하세요.
팁: 앱을 개발할 때 백업 관리자에서 bmgr
도구를 사용하여 즉시 백업 작업을 시작할 수 있습니다.
백업 관리자가 onBackup()
메서드를 호출하면 세 개의 매개변수가 전달됩니다.
oldState
- 열기 및 읽기 전용
ParcelFileDescriptor
로, 앱에서 제공한 마지막 백업 상태를 가리킵니다. 이 데이터는 클라우드 스토리지의 백업 데이터가 아니라 마지막으로onBackup()
이 호출되었을 때 백업된 데이터의 로컬 표현(newState
또는onRestore()
에서 정의됨)입니다.onRestore()
은 다음 섹션에서 다룹니다.onBackup()
을 사용하면 클라우드 스토리지의 기존 백업 데이터를 읽을 수 없기 때문에 이 로컬 표현을 사용하여 마지막 백업 이후 데이터가 변경되었는지 판단할 수 있습니다. data
BackupDataOutput
객체로, 백업 관리자로 백업 데이터를 전달하는 데 사용됩니다.newState
- 열기 및 읽기/쓰기
ParcelFileDescriptor
로,data
에 전달되는 데이터의 표현을 써야 하는 파일을 가리킵니다. 표현은 파일의 최종 수정된 타임스탬프만큼 간단하면 됩니다. 이 객체는 다음에 백업 관리자가onBackup()
메서드를 호출할 때oldState
로 반환됩니다.newState
에 백업 데이터를 쓰지 않는다면oldState
는 다음에 백업 관리자가onBackup()
을 호출할 때 빈 파일을 가리킵니다.
이러한 매개변수로 onBackup()
메서드를 구현하여 다음을 진행합니다.
oldState
와 현재 데이터를 비교하여 마지막 백업 이후로 데이터가 변경되었는지 확인합니다.oldState
에 있는 데이터를 읽는 방법은 처음에newState
에 데이터를 쓴 방법에 따라 다릅니다(3단계 참고). 파일의 상태를 기록하는 가장 쉬운 방법은 최종 수정한 타임스탬프를 사용하는 것입니다. 예를 들어, 다음과 같이oldState
의 타임스탬프를 읽고 비교할 수 있습니다.Kotlin
val instream = FileInputStream(oldState.fileDescriptor) val dataInputStream = DataInputStream(instream) try { // Get the last modified timestamp from the state file and data file val stateModified = dataInputStream.readLong() val fileModified: Long = dataFile.lastModified() if (stateModified != fileModified) { // The file has been modified, so do a backup // Or the time on the device changed, so be safe and do a backup } else { // Don't back up because the file hasn't changed return } } catch (e: IOException) { // Unable to read state file... be safe and do a backup }
자바
// Get the oldState input stream FileInputStream instream = new FileInputStream(oldState.getFileDescriptor()); DataInputStream in = new DataInputStream(instream); try { // Get the last modified timestamp from the state file and data file long stateModified = in.readLong(); long fileModified = dataFile.lastModified(); if (stateModified != fileModified) { // The file has been modified, so do a backup // Or the time on the device changed, so be safe and do a backup } else { // Don't back up because the file hasn't changed return; } } catch (IOException e) { // Unable to read state file... be safe and do a backup }
변경사항이 없고 백업할 필요가 없는 경우 3단계로 건너뜁니다.
oldState
와 비교하여 데이터가 변경되었다면 현재 데이터를data
에 써서 클라우드 스토리지에 백업합니다.데이터의 각 청크를
BackupDataOutput
에 항목으로 써야 합니다. 항목은 고유 키 문자열로 식별되는 평면화된 바이너리 데이터 레코드입니다. 따라서 백업하는 데이터 세트는 개념적으로 키-값 쌍의 조합입니다.백업 데이터 세트에 항목을 추가하려면 다음을 진행해야 합니다.
writeEntityHeader()
를 호출하여 쓰려는 데이터의 고유 문자열 키와 데이터 크기를 전달합니다.writeEntityData()
를 호출하여 데이터를 포함하는 바이트 버퍼와 버퍼에서 쓰려는 바이트 수(writeEntityHeader()
에 전달된 크기와 일치해야 함)를 전달합니다.
예를 들어, 다음의 코드는 일부 데이터를 바이트 스트림으로 평면화하고 단일 항목에 씁니다.
Kotlin
val buffer: ByteArray = ByteArrayOutputStream().run { DataOutputStream(this).apply { writeInt(playerName) writeInt(playerScore) } toByteArray() } val len: Int = buffer.size data.apply { writeEntityHeader(TOPSCORE_BACKUP_KEY, len) writeEntityData(buffer, len) }
자바
// Create buffer stream and data output stream for our data ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); DataOutputStream outWriter = new DataOutputStream(bufStream); // Write structured data outWriter.writeUTF(playerName); outWriter.writeInt(playerScore); // Send the data to the Backup Manager via the BackupDataOutput byte[] buffer = bufStream.toByteArray(); int len = buffer.length; data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len); data.writeEntityData(buffer, len);
백업할 각 데이터에 이 작업을 진행합니다. 데이터를 항목으로 나누는 방법은 개발자가 결정하게 됩니다. 개발자는 항목을 하나만 사용할 수도 있습니다.
2단계에서 백업을 실행했는지와 관계없이 현재 데이터의 표현을
newState
ParcelFileDescriptor
에 씁니다. 백업 관리자는 이 객체를 현재 백업된 데이터의 표현으로 로컬에 유지합니다. 백업 관리자는 다음에onBackup()
을 호출할 때oldState
로 이 표현을 다시 전달하므로 1단계에서 처리한 것처럼 다른 백업이 필요한지 판단할 수 있습니다. 현재 데이터 상태를 이 파일에 쓰지 않으면 다음 콜백이 호출될 때oldState
는 비어있게 됩니다.다음 예에서는 파일의 최종 수정된 타임스탬프를 사용하여 현재 데이터의 표현을
newState
에 저장합니다.Kotlin
val modified = dataFile.lastModified() FileOutputStream(newState.fileDescriptor).also { DataOutputStream(it).apply { writeLong(modified) } }
자바
FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor()); DataOutputStream out = new DataOutputStream(outstream); long modified = dataFile.lastModified(); out.writeLong(modified);
복원 실행
앱 데이터를 복원할 때가 되면 백업 관리자는 백업 에이전트의 onRestore()
메서드를 호출합니다. 이 메서드를 호출할 때 백업 관리자는 백업 데이터를 전달하므로 데이터를 기기에 복원할 수 있습니다.
백업 관리자만 onRestore()
를 호출할 수 있습니다. 이 메서드는 시스템이 앱을 설치하고 기존의 백업 데이터를 찾을 때 자동으로 호출됩니다.
백업 관리자가 onRestore()
메서드를 호출하면 세 개의 매개변수가 전달됩니다.
data
BackupDataInput
객체를 사용하여 백업 데이터를 읽을 수 있습니다.appVersionCode
- 앱의
android:versionCode
매니페스트 속성 값을 나타내는 정수이며 이 데이터가 백업됐을 때와 동일합니다. 이를 사용하여 현재 앱 버전을 교차 확인하고 데이터 형식이 호환되는지 판단할 수 있습니다. 이 값을 사용하여 서로 다른 버전의 복원 데이터를 처리하는 방법에 관한 자세한 내용은 복원 데이터 버전 확인 섹션을 참고하세요. newState
- 열기, 읽기/쓰기
ParcelFileDescriptor
로,data
에서 제공된 최종 백업 상태를 써야 하는 파일을 가리킵니다. 이 객체는 다음에onBackup()
이 호출될 때oldState
로 반환됩니다. 또한onBackup()
콜백에 동일한newState
객체를 써야 하는 것에 유의해야 하며 이렇게 하는 것은 기기가 복원된 후onBackup()
이 호출된 것이 처음이라고 해도onBackup()
에 주어진oldState
객체가 유효하다는 것을 보장합니다.
onRestore()
를 구현할 때 readNextHeader()
를 호출하여 data
에 따라 데이터 세트에서 모든 항목을 반복해야 합니다. 발견된 항목별로 다음을 실행합니다.
getKey()
를 사용하여 항목 키를 가져옵니다.항목 키와
BackupAgent
클래스 내에 static final 문자열로 선언했어야 하는 알려진 키 값의 목록을 비교합니다. 키가 알려진 키 문자열 중에 하나와 일치하면 다음과 같이 구문에 입력하여 항목 데이터를 추출하고 기기에 저장합니다.getDataSize()
를 사용하여 항목 데이터 크기를 가져오고 크기에 맞는 바이트 배열을 생성합니다.readEntityData()
를 호출하여 데이터가 전송될 바이트 배열을 전달하고 시작 오프셋과 읽어야 하는 크기를 지정합니다.- 이제 바이트 배열은 가득 찬 상태입니다. 원하는 대로 데이터를 읽고 기기에 씁니다.
데이터를 읽고 기기에 다시 쓴 후
onBackup()
중에 한 것과 마찬가지로 데이터의 상태를newState
매개변수에 씁니다.
예를 들어, 이전 섹션의 예에서 백업된 데이터를 복원하는 방법은 다음과 같습니다.
Kotlin
@Throws(IOException::class) override fun onRestore(data: BackupDataInput, appVersionCode: Int, newState: ParcelFileDescriptor) { with(data) { // There should be only one entity, but the safest // way to consume it is using a while loop while (readNextHeader()) { when(key) { TOPSCORE_BACKUP_KEY -> { val dataBuf = ByteArray(dataSize).also { readEntityData(it, 0, dataSize) } ByteArrayInputStream(dataBuf).also { DataInputStream(it).apply { // Read the player name and score from the backup data playerName = readUTF() playerScore = readInt() } // Record the score on the device (to a file or something) recordScore(playerName, playerScore) } } else -> skipEntityData() } } } // Finally, write to the state blob (newState) that describes the restored data FileOutputStream(newState.fileDescriptor).also { DataOutputStream(it).apply { writeUTF(playerName) writeInt(mPlayerScore) } } }
자바
@Override public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException { // There should be only one entity, but the safest // way to consume it is using a while loop while (data.readNextHeader()) { String key = data.getKey(); int dataSize = data.getDataSize(); // If the key is ours (for saving top score). Note this key was used when // we wrote the backup entity header if (TOPSCORE_BACKUP_KEY.equals(key)) { // Create an input stream for the BackupDataInput byte[] dataBuf = new byte[dataSize]; data.readEntityData(dataBuf, 0, dataSize); ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf); DataInputStream in = new DataInputStream(baStream); // Read the player name and score from the backup data playerName = in.readUTF(); playerScore = in.readInt(); // Record the score on the device (to a file or something) recordScore(playerName, playerScore); } else { // We don't know this entity key. Skip it. (Shouldn't happen.) data.skipEntityData(); } } // Finally, write to the state blob (newState) that describes the restored data FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor()); DataOutputStream out = new DataOutputStream(outstream); out.writeUTF(playerName); out.writeInt(mPlayerScore); }
이 예에서 onRestore()
에 전달된 appVersionCode
매개변수는 사용되지 않습니다. 그러나 사용자의 앱 버전이 실제로 더 낮아진 경우(예: 사용자의 앱 버전이 1.5에서 1.0으로 변경됨) 백업을 실행하기로 선택했다면 이 매개변수를 사용할 수도 있습니다. 자세한 내용은 다음 섹션을 참고하세요.
복원 데이터 버전 확인
백업 관리자가 클라우드 스토리지에 데이터를 저장할 때 매니페스트 파일의 android:versionCode
속성에 정의된 앱 버전을 자동으로 포함합니다. 백업 관리자는 백업 에이전트를 호출하여 데이터를 복원하기 전에 설치된 앱의 android:versionCode
를 보고 복원 데이터 세트에 기록된 값과 비교합니다. 복원 데이터 세트에 기록된 버전이 기기의 앱 버전보다 최신이면 사용자가 앱을 다운그레이드한 것입니다. 이 경우 이전 버전에는 복원 세트가 무의미하다고 간주하기 때문에 백업 관리자는 앱의 복원 작업을 취소하고 onRestore()
메서드를 호출하지 않습니다.
android:restoreAnyVersion
속성을 사용하여 이 동작을 재정의할 수 있습니다.
앱을 복원 세트 버전과 관계없이 복원하겠다고 나타내려면 이 속성을 true
로 설정합니다. 기본값은 false
입니다. 이 값을 true
로 설정하면 백업 관리자는 android:versionCode
를 무시하고 모든 경우에 onRestore()
메서드를 호출합니다. 이렇게 하면 수동으로 onRestore()
메서드에서 버전 차이를 확인하고 버전이 일치하지 않을 경우 데이터를 호환할 수 있게 하는 데 필요한 모든 단계를 실행할 수 있습니다.
복원 작업 중에 다양한 버전을 처리할 수 있도록 onRestore()
메서드는 복원 데이터 세트와 함께 포함된 버전 코드를 appVersionCode
매개변수로 전달합니다. 그런 다음 현재 앱의 버전 코드를 PackageInfo.versionCode
필드를 사용하여 쿼리할 수 있습니다. 예:
Kotlin
val info: PackageInfo? = try { packageManager.getPackageInfo(packageName, 0) } catch (e: PackageManager.NameNotFoundException) { null } val version: Int = info?.versionCode ?: 0
자바
PackageInfo info; try { String name = getPackageName(); info = getPackageManager().getPackageInfo(name, 0); } catch (NameNotFoundException nnfe) { info = null; } int version; if (info != null) { version = info.versionCode; }
그런 다음 PackageInfo
에서 얻은 version
과 onRestore()
에 전달된 appVersionCode
를 비교합니다.
백업 요청
dataChanged()
를 호출하여 언제든지 백업 작업을 요청할 수 있습니다. 이 메서드는 백업 에이전트를 사용하여 데이터를 백업하도록 백업 관리자에게 알려줍니다. 그러면 백업 관리자가 미래 어느 시점에 백업 에이전트의 onBackup()
메서드를 호출합니다. 일반적으로 데이터가 변경(예: 백업하려는 앱 환경설정을 사용자가 변경할 때)될 때마다 백업을 요청해야 합니다. 백업 관리자가 에이전트에 백업을 요청하기 전에 dataChanged()
를 여러 번 호출해도 에이전트는 onBackup()
호출을 한 번만 수신합니다.
복원 요청
앱이 정상적으로 작동하는 동안에는 복원 작업을 요청하지 않아도 됩니다. 앱이 설치되면 시스템은 자동으로 백업 데이터를 확인하고 복원을 실행합니다.
자동 백업으로 이전
앱을 전체 데이터 백업으로 전환하려면 매니페스트 파일의 <application>
요소에서 android:fullBackupOnly
를 true
로 설정하면 됩니다. Android 5.1(API 수준 22) 이하를 사용하는 기기에서 앱을 실행하면 앱은 매니페스트에서 이 값을 무시하고 계속 키-값 백업을 실행합니다. Android 6.0(API 수준 23) 이상을 사용하는 기기에서 앱을 실행하면 앱은 키-값 백업 대신 자동 백업을 실행합니다.
사용자 개인 정보 보호
Google은 사용자의 신뢰를 중요하게 생각하며 사용자의 개인 정보를 보호할 책임이 있습니다. Google은 백업 및 복원 기능을 제공하기 위해 Google 서버로/Google 서버에서 백업 데이터를 안전하게 전송합니다. Google은 이 데이터를 Google의 개인정보처리방침에 따라 개인 정보로 취급합니다.
또한 사용자는 Android 시스템의 백업 설정을 통해 데이터 백업 기능을 사용 중지할 수 있습니다. 사용자가 백업을 사용 중지하면 Android Backup Service는 저장된 백업 데이터를 모두 삭제합니다. 사용자는 기기에서 백업을 다시 사용 설정할 수 있지만 Android Backup Service는 이전에 삭제된 데이터를 복원하지 않습니다.