Blok Mağazası

Birçok kullanıcı yeni bir Android cihaz kurarken kendi kimlik bilgilerini yönetmeye devam eder. Bu manuel işlem zorlayıcı 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 ilgili karmaşıklık veya güvenlik riski olmadan kullanıcı kimlik bilgilerini kaydetmelerini sağlayan bir yöntem sunarak bu sorunu çözmektedir.

Block Store API, uygulamanızın yeni bir cihazdaki kullanıcıların kimliğini yeniden doğrulamak için alabileceği verileri depolamasına olanak tanır. Bu sayede, kullanıcılar yeni cihazda uygulamanızı ilk kez açarken oturum açma ekranı görmeleri gerekmediği için daha sorunsuz bir deneyim sunulur.

Mağaza Girişi'ni kullanmanın avantajları şunlardı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 jetonları kaydedin.
  • Oturum açma akışlarındaki sorunları ortadan kaldırın.
  • Kullanıcıları karmaşık şifreleri yönetme zahmetinden 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ümlerde yer alan adımları tamamlayın.

Uygulamanızı yapılandırma

Proje düzeyindeki build.gradle dosyanıza Google Maven deposunu hem buildscript hem de allprojects bölümlerinize ekleyin:

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

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

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

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

İşleyiş şekli

Block Store, geliştiricilerin 16 baytlık dizileri kaydetmesine ve geri yüklemesine olanak tanır. Bu, geçerli kullanıcı oturumuyla ilgili önemli bilgileri kaydetmenize olanak tanır ve bu bilgileri istediğiniz şekilde kaydetme esnekliği sağlar. Bu veriler uçtan uca şifrelenebilir ve Engelleme Mağazası'nı destekleyen altyapı, Yedekle ve Geri Yükle altyapısının üzerine inşa edilmiştir.

Bu kılavuzda, bir kullanıcının jetonunu Store'da kaydetmeyle ilgili kullanım alanları ele alınmaktadır. Aşağıdaki adımlar, Mağaza Girişi'ni kullanan bir uygulamanın nasıl çalışacağını göstermektedir:

  1. Uygulamanızın kimlik doğrulama akışı sırasında veya daha sonra, daha sonra almak isterseniz kullanıcının kimlik doğrulama jetonunu Mağazada Engelle seçeneğinde saklayabilirsiniz.
  2. Jeton yerel olarak depolanır ve mümkün olduğunda uçtan uca şifrelenerek buluta yedeklenebilir.
  3. Kullanıcı yeni bir cihazda geri yükleme işlemi 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 cihazda Kayıtlı Mağaza'dan kaydedilen jetonu alabilir.

Jeton kaydediliyor

Bir kullanıcı uygulamanızda oturum açtığında, bu kullanıcı için oluşturduğunuz kimlik doğrulama jetonunu Mağazayı Engelle'ye kaydedebilirsiniz. Bu jetonu, giriş başına maksimum 4 KB'lık bir benzersiz anahtar çifti değeri kullanarak saklayabilirsiniz. Jetonu depolamak için kullanıcının kimlik bilgilerini kaynak cihazda depolamak amacıyla bir StoreBytesData.Builder örneğinde setBytes() ve setKey() çağrın. Jetonu Store Store'da kaydettikten sonra jeton şifrelenir ve yerel olarak cihazda 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

StoreBytes'i anahtar olmadan kullanarak kaydedilen veriler varsayılan BlockstoreClient.DEFAULT_BYTES_DATA_KEY anahtarını kullanı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)
    }

Jeton alınıyor

Daha sonra bir kullanıcı yeni bir cihazda geri yükleme akışını gerçekleştirdiğinde, Google Play Hizmetleri önce kullanıcıyı doğrular, ardından Blok Depolama verilerinizi alır. Kullanıcı, geri yükleme akışının bir parçası olarak uygulama verilerinizi geri yüklemeyi kabul etmiştir. Bu nedenle başka izin gerekmez. Kullanıcı uygulamanızı açtığında retrieveBytes() numaralı telefonu arayarak jetonunuzu Engelleme Mağazası'ndan isteyebilirsiniz. Alınan jeton daha sonra kullanıcının yeni cihazda oturumunu açık tutmak için kullanılabilir.

Aşağıdaki örnekte, belirli anahtarlara bağlı olarak 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 blockstoreDataMap = result.getBlockstoreDataMap();
          for (Map.Entry 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 alınıyor.

BlockStore'a kaydedilen tüm jetonların nasıl alınacağını gösteren bir örneği aşağıda bulabilirsiniz.

Java

BlockstoreClient client = Blockstore.getClient(this)

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

client.retrieveBytes(retrieveRequest)
    .addOnSuccessListener(
        result -> {
          Map blockstoreDataMap = result.getBlockstoreDataMap();
          for (Map.Entry 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)
  }

Aşağıda, varsayılan anahtarın nasıl alınacağına dair bir örnek 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 nedenlerden dolayı gerekli olabilir:

  • Kullanıcı, oturumu kapatma kullanıcı akışından geçer.
  • Jeton iptal edildi veya jetonu geçersiz.

Jetonları almanıza benzer şekilde, silinmesi gereken bir dizi anahtar ayarlayarak silinecek jetonları belirtebilirsiniz.

Aşağıda, belirli anahtarları silmeyle ilgili bir örnek verilmiştir.

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ı Sil

Aşağıdaki örnekte şu anda BlockStore'da kayıtlı olan tüm jetonlar silinmektedir:

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()
client.deleteBytes(deleteAllRequest)
  .addOnSuccessListener { result: Boolean ->
    Log.d(TAG,
          "Any data found and deleted? $result")
  }

Uçtan uca şifreleme

Uçtan uca şifrelemenin kullanılabilmesi için cihazın Android 9 veya sonraki bir sürümü çalıştırıyor olması ve kullanıcının cihazı için bir ekran kilidi (PIN, desen veya şifre) ayarlamış olması gerekir. isEndToEndEncryptionAvailable() numaralı telefonu arayarak cihazda şifrelemenin kullanılıp kullanılamayacağını doğrulayabilirsiniz.

Aşağıdaki örnekte, bulut yedekleme sırasında şifrelemenin kullanılıp kullanılamayacağını nasıl doğrulayacağınız gösterilmektedir:

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

Bulut yedeklemeyi etkinleştirin

Bulut yedeklemeyi etkinleştirmek için StoreBytesData nesnenize setShouldBackupToCloud() yöntemini ekleyin. setShouldBackupToCloud() ayarı doğru değerine ayarlandığında, "mağazayı Engelle" ayarı, depolanan baytları düzenli olarak buluta yedekler.

Aşağıdaki örnekte, yalnızca bulut yedeği uçtan uca şifrelendiğinde bulut yedeklemesinin 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

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

Aynı cihazı kaldırma/yeniden yükleme

Kullanıcı, Yedekleme hizmetlerini etkinleştirirse (Ayarlar > Google > Yedekleme'ye giderek kontrol edilebilir), Mağazayı Engelle verilerinin uygulama kaldırma/yeniden yükleme işlemleri genelinde saklanır.

Aşağıdaki adımları uygulayarak test edebilirsiniz:

  1. BlockStore API'yi test uygulamanıza entegre edin.
  2. Verilerinizi depolamak için BlockStore API'yi çağırmak üzere test uygulamasını kullanın.
  3. Test uygulamanızı kaldırıp uygulamanızı aynı cihazda yeniden yükleyin.
  4. Verilerinizi almak amacıyla BlockStore API'yi çağırmak için test uygulamasını kullanın.
  5. Alınan baytların, kaldırma işleminden önce depolanan baytlarla aynı olduğunu doğrulayın.

Cihazdan cihaza

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

Bulut geri yükleme

  1. Blockstore API'yi test uygulamanıza entegre edin. Test uygulamasının Play Store'a gönderilmesi gerekir.
  2. Kaynak cihazda, test uygulamanız ile verilerinizi depolayacak Blockstore API'yi çağırın.
  3. O ve üstü cihazlar için, Store'u Engelle bulut yedeğini manuel olarak tetikleyebilirsiniz: Ayarlar > Google > Yedekleme'ye gidin ve "Şimdi Yedekle" düğmesini tıklayın.
    1. Mağaza Girişi bulut yedekleme işleminin başarılı olduğunu doğrulamak için şunları yapabilirsiniz:
      1. Yedekleme tamamlandıktan sonra “CloudSyncBpTkSvc” etiketiyle günlük satırlarını arayın.
      2. Şuna benzer satırlar görürsünüz: "......, CloudSyncBpTkSvc: Sync sonuç: SUCCESS, ..., uploaded size: XXX bytes ..."
    2. Mağaza Girişi bulut yedeği oluşturulduktan sonra 5 dakikalık bir "soğutma" süresi uygulanır. Bu 5 dakika içinde "Şimdi Yedekle" düğmesini tıklamak başka bir Blok Mağaza bulut yedeğini tetiklemez.
  4. Hedef cihazı fabrika ayarlarına sıfırlayıp bulut geri yükleme sürecinden geçin. Geri yükleme 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ı makaleye göz atın.
  5. Hedef cihazda, verilerinizi almak amacıyla Blockstore API'yi çağırmak için 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ümleri çalıştıran cihazlarda desteklenir.
  • Uçtan uca şifrelemenin etkinleştirilmesi ve kullanıcı verilerinin doğru bir şekilde şifrelenmesi için cihazda bir PIN, desen veya şifre ayarlanmış bir ekran kilidi olmalıdır.

Cihazdan Cihaza Geri Yükleme Akışı

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

Kaynak cihazlarda yedekleme yapılabilmesi için Android 6 (API 23) ve sonraki bir sürümün yüklü olması gerekir.

Geri yükleyebilmek için Android 9 (API 29) ve sonraki sürümleri çalıştıran cihazları hedefleyin.

Cihazdan cihaza geri yükleme akışı hakkında daha fazla bilgiye buradan ulaşabilirsiniz.

Cloud Yedekleme ve Geri Yükleme Akışı

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

Kaynak cihazlarda yedekleme yapılabilmesi için Android 6 (API 23) ve sonraki bir sürümün yüklü olması gerekir.

Hedef cihazlar, tedarikçilerine bağlı olarak desteklenir. Pixel cihazlar bu özelliği Android 9 (API 29) sürümünden kullanabilir. Diğer tüm cihazlar Android 12 (API 31) veya sonraki sürümleri çalıştırıyor olmalıdır.