Blok Mağazası

Birçok kullanıcı, Android işletim sistemli yeni bir cihaz kurarken hâlâ kendi kimlik bilgilerini yönetiyor. Bu manuel süreç zor olabilir ve genellikle kötü bir kullanıcı deneyimine neden olur. Google Play Hizmetleri tarafından desteklenen bir kitaplık olan Block Store API, uygulamaların kullanıcı şifrelerini kaydetmeyle ilişkili karmaşıklık veya güvenlik riski olmadan kullanıcı kimlik bilgilerini kaydetmelerine olanak tanıyarak bu sorunu çözmeyi amaçlar.

Block Store API, uygulamanızın yeni bir cihazda kullanıcıların kimliğini yeniden doğrulamak için daha sonra alabildiği verileri depolamasına olanak tanır. Bu sayede, uygulamanızı yeni cihazda ilk kez başlatırken kullanıcının oturum açma ekranı görmesine gerek kalmaz ve kullanıcıya daha akıcı bir deneyim sunulur.

Block Store'u kullanmanın avantajları arasında şunlar vardır:

  • Geliştiriciler için şifrelenmiş kimlik bilgisi depolama çözümü. Kimlik bilgileri mümkün olduğunda uçtan uca şifrelenir.
  • Kullanıcı adları ve şifreler yerine jeton kaydedin.
  • Oturum açma akışlarındaki zorlukları ortadan kaldırın.
  • Kullanıcıları karmaşık şifreleri yönetme yükünden kurtarın.
  • Google, kullanıcının kimliğini doğrular.

Başlamadan önce

Uygulamanızı hazırlamak için aşağıdaki bölümlerdeki adımları tamamlayın.

Uygulamanızı yapılandırma

Proje düzeyindeki build.gradle dosyanızda, Google'ın Maven deposunu hem buildscript hem de allprojects bölümünüze ekleyin:

buildscript {
  repositories {
    google()
    mavenCentral()
  }
}

allprojects {
  repositories {
    google()
    mavenCentral()
  }
}

Block Store API için Google Play Hizmetleri bağımlılığını, modülünüzün Gradle derleme dosyasına (genellikle app/build.gradle) ekleyin:

dependencies {
  implementation 'com.google.android.gms:play-services-auth-blockstore:16.4.0'
}

İşleyiş şekli

Block Store, geliştiricilerin 16 bayta kadar dizileri kaydetmesine ve geri yüklemesine olanak tanır. Bu, mevcut kullanıcı oturumuyla ilgili önemli bilgileri kaydetmenize olanak tanır ve bu bilgileri istediğiniz şekilde kaydetme esnekliği sunar. Bu veriler uçtan uca şifrelenebilir ve Block Store'u destekleyen altyapı, Yedekleme ve Geri Yükleme altyapısının üzerine inşa edilmiştir.

Bu kılavuzda, kullanıcı jetonunun Block Store'a kaydedilmesi kullanım alanı ele alınmaktadır. Aşağıdaki adımlarda, Block Store'u kullanan bir uygulamanın işleyiş şekli özetlenmiştir:

  1. Uygulamanızın kimlik doğrulama akışı sırasında veya daha sonra dilediğiniz zaman kullanıcının kimlik doğrulama jetonunu daha sonra almak için Block Store'da saklayabilirsiniz.
  2. Jeton yerel olarak depolanır ve mümkün olduğunda uçtan uca şifrelenmiş olarak bulutta yedeklenir.
  3. Kullanıcı yeni bir cihazda geri yükleme akışını başlattığında veriler aktarılır.
  4. Kullanıcı, geri yükleme akışı sırasında uygulamanızı geri yüklerse uygulamanız, yeni cihazdaki Block Store'dan kayıtlı jetonu alabilir.

Jetonu kaydetme

Bir kullanıcı uygulamanızda oturum açtığında, söz konusu kullanıcı için oluşturduğunuz kimlik doğrulama jetonunu Block Store'a kaydedebilirsiniz. Bu jetonu, giriş başına maksimum 4 KB olan benzersiz bir anahtar çifti değeri kullanarak saklayabilirsiniz. Jetonu saklamak için StoreBytesData.Builder örneğinde setBytes() ve setKey()'i çağırarak kullanıcının kimlik bilgilerini kaynak cihazda saklayın. Jeton, Block Store ile kaydedildikten sonra şifrelenir ve cihazda yerel olarak depolanır.

Aşağıdaki örnekte, kimlik doğrulama jetonunun yerel cihaza nasıl kaydedileceği gösterilmektedir:

Java

  BlockstoreClient client = Blockstore.getClient(this);
  byte[] bytes1 = new byte[] { 1, 2, 3, 4 };  // Store one data block.
  String key1 = "com.example.app.key1";
  StoreBytesData storeRequest1 = StoreBytesData.Builder()
          .setBytes(bytes1)
          // Call this method to set the key value pair the data should be associated with.
          .setKeys(Arrays.asList(key1))
          .build();
  client.storeBytes(storeRequest1)
    .addOnSuccessListener(result -> Log.d(TAG, "stored " + result + " bytes"))
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

  val client = Blockstore.getClient(this)

  val bytes1 = byteArrayOf(1, 2, 3, 4) // Store one data block.
  val key1 = "com.example.app.key1"
  val storeRequest1 = StoreBytesData.Builder()
    .setBytes(bytes1) // Call this method to set the key value with which the data should be associated with.
    .setKeys(Arrays.asList(key1))
    .build()
  client.storeBytes(storeRequest1)
    .addOnSuccessListener { result: Int ->
      Log.d(TAG,
            "Stored $result bytes")
    }
    .addOnFailureListener { e ->
      Log.e(TAG, "Failed to store bytes", e)
    }

Varsayılan jetonu kullanın

StoreBytes işlevi anahtar olmadan kullanıldığında varsayılan anahtar BlockstoreClient.DEFAULT_BYTES_DATA_KEY kullanılır.

Java

  BlockstoreClient client = Blockstore.getClient(this);
  // The default key BlockstoreClient.DEFAULT_BYTES_DATA_KEY.
  byte[] bytes = new byte[] { 9, 10 };
  StoreBytesData storeRequest = StoreBytesData.Builder()
          .setBytes(bytes)
          .build();
  client.storeBytes(storeRequest)
    .addOnSuccessListener(result -> Log.d(TAG, "stored " + result + " bytes"))
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

  val client = Blockstore.getClient(this);
  // the default key BlockstoreClient.DEFAULT_BYTES_DATA_KEY.
  val bytes = byteArrayOf(1, 2, 3, 4)
  val storeRequest = StoreBytesData.Builder()
    .setBytes(bytes)
    .build();
  client.storeBytes(storeRequest)
    .addOnSuccessListener { result: Int ->
      Log.d(TAG,
            "stored $result bytes")
    }
    .addOnFailureListener { e ->
      Log.e(TAG, "Failed to store bytes", e)
    }

Jetonu alma

Daha sonra, kullanıcı yeni bir cihazda geri yükleme akışını tamamladığında Google Play hizmetleri önce kullanıcıyı doğrular, ardından Block Store verilerinizi alır. Kullanıcı, geri yükleme akışının bir parçası olarak uygulama verilerinizi geri yüklemeyi zaten kabul ettiğinden ek izinler gerekmez. Kullanıcı uygulamanızı açtığında retrieveBytes() çağrısını yaparak jetonunuzu Block Store'dan isteyebilirsiniz. Ardından, alınan jeton kullanıcının yeni cihazda oturumunun açık kalması için kullanılabilir.

Aşağıdaki örnekte, belirli anahtarlara göre birden fazla jetonun nasıl alınacağı gösterilmektedir.

Java

BlockstoreClient client = Blockstore.getClient(this);

// Retrieve data associated with certain keys.
String key1 = "com.example.app.key1";
String key2 = "com.example.app.key2";
String key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY; // Used to retrieve data stored without a key

List requestedKeys = Arrays.asList(key1, key2, key3); // Add keys to array
RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder()
    .setKeys(requestedKeys)
    .build();

client.retrieveBytes(retrieveRequest)
    .addOnSuccessListener(
        result -> {
          Map<String, BlockstoreData> blockstoreDataMap = result.getBlockstoreDataMap();
          for (Map.Entry<String, BlockstoreData> entry : blockstoreDataMap.entrySet()) {
            Log.d(TAG, String.format(
                "Retrieved bytes %s associated with key %s.",
                new String(entry.getValue().getBytes()), entry.getKey()));
          }
        })
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

val client = Blockstore.getClient(this)

// Retrieve data associated with certain keys.
val key1 = "com.example.app.key1"
val key2 = "com.example.app.key2"
val key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY // Used to retrieve data stored without a key

val requestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array

val retrieveRequest = RetrieveBytesRequest.Builder()
  .setKeys(requestedKeys)
  .build()

client.retrieveBytes(retrieveRequest)
  .addOnSuccessListener { result: RetrieveBytesResponse ->
    val blockstoreDataMap =
      result.blockstoreDataMap
    for ((key, value) in blockstoreDataMap) {
      Log.d(ContentValues.TAG, String.format(
        "Retrieved bytes %s associated with key %s.",
        String(value.bytes), key))
    }
  }
  .addOnFailureListener { e: Exception? ->
    Log.e(ContentValues.TAG,
          "Failed to store bytes",
          e)
  }

Tüm jetonları alma.

Aşağıda, BlockStore'a kaydedilen tüm jetonların nasıl alınacağına dair bir örnek verilmiştir.

Java

BlockstoreClient client = Blockstore.getClient(this)

// Retrieve all data.
RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder()
    .setRetrieveAll(true)
    .build();

client.retrieveBytes(retrieveRequest)
    .addOnSuccessListener(
        result -> {
          Map<String, BlockstoreData> blockstoreDataMap = result.getBlockstoreDataMap();
          for (Map.Entry<String, BlockstoreData> entry : blockstoreDataMap.entrySet()) {
            Log.d(TAG, String.format(
                "Retrieved bytes %s associated with key %s.",
                new String(entry.getValue().getBytes()), entry.getKey()));
          }
        })
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

val client = Blockstore.getClient(this)

val retrieveRequest = RetrieveBytesRequest.Builder()
  .setRetrieveAll(true)
  .build()

client.retrieveBytes(retrieveRequest)
  .addOnSuccessListener { result: RetrieveBytesResponse ->
    val blockstoreDataMap =
      result.blockstoreDataMap
    for ((key, value) in blockstoreDataMap) {
      Log.d(ContentValues.TAG, String.format(
        "Retrieved bytes %s associated with key %s.",
        String(value.bytes), key))
    }
  }
  .addOnFailureListener { e: Exception? ->
    Log.e(ContentValues.TAG,
          "Failed to store bytes",
          e)
  }

Varsayılan anahtarın nasıl alınacağına dair bir örnek aşağıda verilmiştir.

Java

BlockStoreClient client = Blockstore.getClient(this);
RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder()
    .setKeys(Arrays.asList(BlockstoreClient.DEFAULT_BYTES_DATA_KEY))
    .build();
client.retrieveBytes(retrieveRequest);

Kotlin

val client = Blockstore.getClient(this)

val retrieveRequest = RetrieveBytesRequest.Builder()
  .setKeys(Arrays.asList(BlockstoreClient.DEFAULT_BYTES_DATA_KEY))
  .build()
client.retrieveBytes(retrieveRequest)

Jetonları silme

Jetonların BlockStore'dan silinmesi aşağıdaki nedenlerle gerekebilir:

  • Kullanıcı, oturumu kapatma kullanıcı akışında ilerler.
  • Jeton iptal edilmiş veya geçersiz.

Jetonları almakla benzer şekilde, silinmesi gereken bir anahtar dizisi ayarlayarak hangi jetonların silinmesi gerektiğini belirtebilirsiniz.

Aşağıdaki örnekte belirli anahtarların nasıl silineceği gösterilmektedir:

Java

BlockstoreClient client = Blockstore.getClient(this);

// Delete data associated with certain keys.
String key1 = "com.example.app.key1";
String key2 = "com.example.app.key2";
String key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY; // Used to delete data stored without key

List requestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array
DeleteBytesRequest deleteRequest = new DeleteBytesRequest.Builder()
      .setKeys(requestedKeys)
      .build();
client.deleteBytes(deleteRequest)

Kotlin

val client = Blockstore.getClient(this)

// Retrieve data associated with certain keys.
val key1 = "com.example.app.key1"
val key2 = "com.example.app.key2"
val key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY // Used to retrieve data stored without a key

val requestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array

val retrieveRequest = DeleteBytesRequest.Builder()
      .setKeys(requestedKeys)
      .build()

client.deleteBytes(retrieveRequest)

Tüm jetonları silme

Aşağıdaki örnekte, şu anda BlockStore'a kayıtlı tüm jetonların nasıl silineceği gösterilmektedir:

Java

// Delete all data.
DeleteBytesRequest deleteAllRequest = new DeleteBytesRequest.Builder()
      .setDeleteAll(true)
      .build();
client.deleteBytes(deleteAllRequest)
.addOnSuccessListener(result -> Log.d(TAG, "Any data found and deleted? " + result));

Kotlin

  val deleteAllRequest = DeleteBytesRequest.Builder()
  .setDeleteAll(true)
  .build()
retrieve bytes, the key BlockstoreClient.DEFAULT_BYTES_DATA_KEY can be used
in the RetrieveBytesRequest instance in order to get your saved data

The following example shows how to retrieve the default key.

Java

End-to-end encryption

In order for end-to-end encryption to be made available, the device must be running Android 9 or higher, and the user must have set a screen lock (PIN, pattern, or password) for their device. You can verify if encryption will be available on the device by calling isEndToEndEncryptionAvailable().

The following sample shows how to verify if encryption will be available during cloud backup:

client.isEndToEndEncryptionAvailable()
        .addOnSuccessListener { result ->
          Log.d(TAG, "Will Block Store cloud backup be end-to-end encrypted? $result")
        }

Bulut yedeklemesini etkinleştirme

Bulut yedeklemeyi etkinleştirmek için StoreBytesData nesnenize setShouldBackupToCloud() yöntemini ekleyin. setShouldBackupToCloud() doğru olarak ayarlandığında Block Store, depolanan baytları düzenli olarak buluta yedeklemektedir.

Aşağıdaki örnekte, bulut yedeklemenin yalnızca uçtan uca şifrelenmiş olduğunda nasıl etkinleştirileceği gösterilmektedir:

val client = Blockstore.getClient(this)
val storeBytesDataBuilder = StoreBytesData.Builder()
        .setBytes(/* BYTE_ARRAY */)

client.isEndToEndEncryptionAvailable()
        .addOnSuccessListener { isE2EEAvailable ->
          if (isE2EEAvailable) {
            storeBytesDataBuilder.setShouldBackupToCloud(true)
            Log.d(TAG, "E2EE is available, enable backing up bytes to the cloud.")

            client.storeBytes(storeBytesDataBuilder.build())
                .addOnSuccessListener { result ->
                  Log.d(TAG, "stored: ${result.getBytesStored()}")
                }.addOnFailureListener { e ->
                  Log.e(TAG, Failed to store bytes, e)
                }
          } else {
            Log.d(TAG, "E2EE is not available, only store bytes for D2D restore.")
          }
        }

Test etme

Geliştirme sırasında, geri yükleme akışlarını test etmek için aşağıdaki yöntemleri kullanın.

Aynı cihazda kaldırma/yeniden yükleme

Kullanıcı, yedekleme hizmetlerini etkinleştirirse (Ayarlar > Google > Yedekleme bölümünden kontrol edilebilir) Block Store verileri, uygulamanın kaldırılması/yeniden yüklenmesi sırasında korunur.

Test etmek için aşağıdaki adımları uygulayabilirsiniz:

  1. Block Store API'yi test uygulamanıza entegre edin.
  2. Verilerinizi depolamak için Block Store API'yi çağırmak üzere test uygulamasını kullanın.
  3. Test uygulamanızı kaldırıp aynı cihaza yeniden yükleyin.
  4. Verilerinizi almak için Block Store API'yi çağırmak üzere test uygulamasını kullanın.
  5. Alınan baytların, kaldırmadan önce depolananlarla aynı olduğunu doğrulayın.

Cihazlar arası

Çoğu durumda, hedef cihazın fabrika ayarlarına sıfırlanması gerekir. Ardından Android kablosuz geri yükleme akışını veya Google kabloyla geri yükleme'yi (desteklenen cihazlar için) girebilirsiniz.

Buluttan geri yükleme

  1. Block Store API'yi test uygulamanıza entegre edin. Test uygulamasının Play Store'a gönderilmesi gerekir.
  2. Kaynak cihazda, verilerinizi depolamak için Block Store API'yi çağırmak üzere test uygulamasını kullanın. Bu işlem sırasında shouldBackUpToCloud, true olarak ayarlanmalıdır.
  3. O ve sonraki sürümlerin yüklü olduğu cihazlarda Block Store bulut yedeklemesini manuel olarak tetikleyebilirsiniz: Ayarlar > Google > Yedekleme'ye gidin, "Şimdi Yedekle" düğmesini tıklayın.
    1. Block Store bulut yedeklemesinin başarılı olduğunu doğrulamak için şunları yapabilirsiniz:
      1. Yedekleme tamamlandıktan sonra "CloudSyncBpTkSvc" etiketine sahip günlük satırlarını arayın.
      2. Şuna benzer satırlar görürsünüz: "......, CloudSyncBpTkSvc: sync result: SUCCESS, ..., uploaded size: XXX bytes ...”
    2. Block Store bulut yedeklemesinden sonra 5 dakikalık bir "bekleme" süresi vardır. Bu 5 dakika içinde "Şimdi Yedekle" düğmesini tıklamak başka bir Block Store bulut yedeği tetiklemez.
  4. Hedef cihazı fabrika ayarlarına sıfırlayın ve buluttan geri yükleme akışını uygulayın. Kurtarma akışı sırasında test uygulamanızı geri yüklemeyi seçin. Bulut geri yükleme akışları hakkında daha fazla bilgi için Desteklenen bulut geri yükleme akışları başlıklı makaleyi inceleyin.
  5. Hedef cihazda, verilerinizi almak için Block Store API'yi çağırmak üzere test uygulamasını kullanın.
  6. Alınan baytların kaynak cihazda depolananlarla aynı olduğunu doğrulayın.

Cihaz Gereksinimleri

Uçtan Uca Şifreleme

  • Uçtan uca şifreleme, Android 9 (API 29) ve sonraki sürümlerin yüklü olduğu cihazlarda desteklenir.
  • Uçtan uca şifrelemenin etkinleştirilmesi ve kullanıcı verilerinin doğru şekilde şifrelenmesi için cihazda PIN, desen veya şifreyle ayarlanmış bir ekran kilidi olmalıdır.

Cihazdan cihaza veri kurtarma akışı

Cihazdan cihaza geri yükleme işlemi için bir kaynak cihaz ve hedef cihazınız olması gerekir. Bunlar, veri aktaran iki cihazdır.

Yedekleme için kaynak cihazlarda Android 6 (API 23) ve sonraki sürümlerin yüklü olması gerekir.

Geri yükleme özelliğini sunmak için Android 9 (API 29) ve sonraki sürümleri çalıştıran cihazları hedefleyin.

Cihazlar arası geri yükleme akışı hakkında daha fazla bilgiyi burada bulabilirsiniz.

Bulut Yedekleme ve Geri Yükleme Akış İşlemi

Bulut yedekleme ve geri yükleme için bir kaynak cihaz ve bir hedef cihaz gerekir.

Yedekleme için kaynak cihazlarda Android 6 (API 23) ve sonraki sürümlerin yüklü olması gerekir.

Target cihazları, tedarikçi firmalarına göre desteklenir. Pixel cihazlar bu özelliği Android 9 (API 29) sürümünden itibaren kullanabilir. Diğer tüm cihazlarda Android 12 (API 31) veya sonraki bir sürüm yüklü olmalıdır.