Android X: Scoped Storage

Header image of article "Scoped Storage"

Merhabalar, bu yazıda 3 Eylül’de Android 10 ile birlikte yayınlanan ve sosyal medyada biraz tartışmaya neden olan Scoped Storage özelliğini anlatacağım. Android 10 öncesinde Shared Storage yapısı kullanılmaktadır.

Cihaz üzerindeki her bir uygulamanın internal storage hafızası içerisinde yer alan private depolama alanı vardır. Bir uygulamanın private depolama alanına ulaşmak için android/data/uygulama_package_ismi dizinine giderek içindekileri görebilirsiniz.

Internal storage dışında geriye kalan alana da Shared Storage alanı denilmektedir yani depolama iznine sahip her uygulama hafızanın bu bölümüne erişebilir. Buna medya dosyaları dediğimiz müzik ve ses dosyaları gibi ve diğer uygulamaların dosyaları da dahildir. Ancak sorun şu ki, bu depolamaya erişim iznine sahip olan uygulamalar, buradaki dosyaların hepsine erişip de n’apacak? Gereken dosyayı alıp işlemini yaptıktan sonra o dizinde işi bitmiş demektir. Dizindeki bütün dosyalara erişim iznine sahip olması, bunun bir güvenlik problemi olduğunu gösteriyor gibi..

İkinci sorun ise, uygulama, depolama üzerinde bu kadar geniş bir alana yazma işlemi yapabileceği için uygulama tarafından kaydedilmek suretiyle oluşturulan dosyalar çok dağınık ve pasaklı bir şekilde kaydedilmektedir. Kullanıcı bu uygulamayı kaldırdığında da bu dosyalar orada kalır ve çok da fazla yer kaplar.

Bu nedenle, uygulamaların sadece ihtiyaç duydukları kadar okuma ve yazma gücüne erişim sağlayabilecekleri bir mekanizmaya ihtiyacımız var. İşte Scoped Storage ile bu ihtiyacımız giderilmiş oluyor.

Scoped Storage’ın ana fikri, erişimi sınırlandırmak amacıyla geniş depolamayı belirlenen koleksiyonlara bölmesidir.  Scoped Storage’ın üzerine kurulu olduğu temel prensipler vardır:

Better attribution: Sistemin hangi dosyanın hangi uygulama tarafından oluşturulduğunu bilmesi anlamına gelir. Bunun faydası, bir uygulamanın dosyalarının yönetimine daha iyi vâkıf olabilmenizdir. Ayrıca bir uygulamayı cihazdan kaldırdığınızda kullanıcı açıkça saklamak istemediği sürece, uygulamaya ilişkin tüm içerikler cihazdan silinir.

App data protection: Uygulamanın internal storage’ının uygulamaya özel olduğunu ve diğer uygulamalar tarafından erişilemediğini biliyoruz. Ancak external storage, depolama iznine sahip olan bütün tarafından erişilebilmektedir. Scoped Storage sayesinde external storage üzerindeki verilere diğer uygulamaların erişmesi kolay olmayacaktır.

Anlattığım prensipler gereği bu yapı, şimdi belirteceğim bazı temel özelliklere sahip olarak oluşturulmuştur.

Scoped Storage temel özellikleri nelerdir?

Unrestricted access: Her uygulamanın kendi deposuna, yani internal ve external depolamaya sınırsız erişimi vardır. Bu nedenle Android 10’da, SD kart üzerinde kendi uygulama dizininize dosya yazmak için depolama izni sağlamanız gerekmez.

Unrestricted media: Kendi uygulamalarınızın medya koleksiyonlarına ve dosya indirme dosyalarına katkıda bulunmak için sınırsız erişime sahipsiniz. Bu nedenle, medya koleksiyonunda herhangi bir görüntü, video veya başka bir medya dosyasını kaydetmek istiyorsanız izin almanıza gerek yoktur. Sizin tarafınızdan oluşturulan medya dosyalarını okuyabilir veya yazabilirsiniz ancak başka bir uygulamanın medya dosyasını okumak için kullanıcıdan “READ_EXTERNAL_STORAGE” iznini almanız gerekir. Ayrıca, “WRITE_EXTERNAL_STORAGE” izni bir sonraki Android sürümünde kullanımdan kaldırılacak ve bunu kullandıysanız uygulamanız sadece okuma erişimine sahip olacak.

Organized collection: Scoped Storage’da, medya dosyaları için resimler, videolar, vb. koleksiyonları ve de medya olmayan dosyalar için ‘downloads’ koleksiyonu gibi organize bir medya koleksiyon yapısı vardır.

Media location metadata: Android 10 ile ACCESS_MEDIA_LOCATION isminde yeni bir runtime permission türü tanımlandı. Eğer bir medya dosyasının lokasyon bilgisini görmek istiyorsanız bunun da izninin alınması gerekir. Örneğin, bir kamera tarafından çekilen resim görüntülenirken altında çekilen resmin konumu bilgisini de barındırır, işte bu konum bilgisine erişmek için izin sağlanmalıdır. Bu bir runtime permission türü olduğundan, kullanabilmek için manifest içerisinde iznin belirtilmesi gerekmektedir ve MediaStore değişkeninde görüntünün URI’ı verilerek setRequireOriginal() metodu çağrılarak orijinal dosya istenir.

// Get location data from the ExifInterface class.
val photoUri = MediaStore.setRequireOriginal(photoUri)
contentResolver.openInputStream(photoUri).use { stream ->
    ExifInterface(stream).run {
        // If lat/long is null, fall back to the coordinates (0, 0).
        val latLong = ?: doubleArrayOf(0.0, 0.0)
    }
}

System Picker: Medya dosyaları dışındaki diğer dosyalara erişebilmek için Storage Access Framework aracılığıyla erişilen System Picker aracı kullanılmak zorundadır.

Read/write from outside: Koleksiyonun dışındaki dosyaları okumak ve yazmak için, System Picker kullanmanız gerekir.

Not: Şuan uygulamanızda Scoped Storage kullanmaktaysanız Shared Storage içerisinde bulunan uygulamaya ait bütün dosyaları uygulamanızın dizinine taşımanız gerekmektedir. Aksi takdirde bu dosyalara erişimi kaybedersiniz.

Download Collection
Scoped Storage’da medya koleksiyonunda bir dosyanın nasıl okunup editlenebileceğini gördük. PDF veya doc gibi medya dosyası olmayan diğer dosya türleri için, Android 10’da Download Collection isminde bir koleksiyonu vardır. Media Collection’da olduğu gibi, uygulamanızın Download Collection’da medya dışı dosyaları düzenlemek veya okumak için herhangi bir izne sahip olmaya gerek yoktur.

Ancak Media Collection’da “READ_EXTERNAL_STORAGE” izni, başka bir uygulamanın sağladığı tüm medya dosyalarına okuma erişimi sağladığını biliyoruz. Download Collection’da, diğer uygulamalar tarafından oluşturulan medya dışı dosyaları okumak için, Storage Access Framework API’ı aracılığyla System Picker aracını kullanmanız gerekmekte. Kullanıcının uygulamaya gerekli izni vermesi bu araçla sağlanır. Kullanıcı erişimi verirse, uygulamanız bu dosyalara tam erişime sahip olur; yani, medya dışı dosyaları okuyabilir, yazabilir ve silebilirsiniz.

Special App Access
Scoped Storage ile uygulamanızın sadece sınırlı bir depolama alanına erişmesine izin verilir. Shared Storage’a uygulamanızın geniş erişime sahip olmasını isterseniz uygulamanıza özel bir erişim izni verilebilmektedir. Bu nedenle, uygulamanız için Google Play Konsolunda bir bildirim formu göndererek uygulamanızın Shared Storage’a tam erişim hakkına ihtiyacı olduğunu kanıtlamanız gerekir. Kullanıcı geniş erişim hakkın izin verdiği takdirde medya dışı dosyaları içeren MediaStore’un filtrelenmemiş hâlini kullanabilirsiniz. Ancak yine, uygulamanızın external uygulama dizinlerine erişimi hakkı olmayacaktır.

Güvenlik konusuna tekrar dönecek olursak, kullanıcı verilerinin korunması amacıyla, uygulamalar artık eskisi gibi dosya dizinine sınırsız erişim hakkına sahip olamayacak.

Özetleyecek olursak: Her uygulama kendi dosyalarına erişebilir hâlde olacak (eskisi gibi). Ancak, diğer uygulamalar tarafından oluşturulan fotoğraf, video ve ses dosyalarına erişmek istiyorsa, “READ_EXTERNAL_STORAGE” izni verilmesi zorunlu olacak. Diğer dosya türlerini kullanması gerektiği durumlarda ise, kullanıcı dosya seçerken bu dosya türünün yer alması için Storage Access Framework’ün kullanılması gerekecek.

Normal cihaz dosyalarına nasıl ulaşacağız?

Cihazdaki dosyalara erişmek için Storage Access Framework’ü (SAF) kullanmanız gereklidir. Aşağıdakileri kullanarak istenen niyete uygun şekilde kullanıcıya iletişim kutusu gösterilerek dizin seçmesi istenir:

  • ACTION_OPEN_DOCUMENT kullanılarak gerekli belgelerin seçilmesi istenir
  • ACTION_CREATE_DOCUMENT  kullanarak (üzerinde işlem yapılacak) bir dizinin seçilmesi istenir.
  • ACTION_OPEN_DOCUMENT_TREE kullanarak kaydedilmek istenen dosyalar için bir dizin seçilmesi istenir.

Android 10’da Scoped Storage kullanmak istemezsek?

Scoped storage kullanmak istemiyorsanız manifest içerisinde bunu belirterek eski sistemle yolunuza devam edebilirsiniz. targetSdkVersion 29 ile projenizi geliştirirken manifest içine aşağıdaki kodu ekleyip legacy sistemi kullanmaya devam edebilirsiniz, eski projeler bu şekilde çalışmaya devam eder. Fakat dediğimiz gibi Android 11 ile bu Scoped Storage kullanımı zorunlu olacak, yani uygulamanızın kodlarını yeni özelliğe güncellemenizde fayda var.

android:requestLegacyExternalStorage=”true

Örnek uygulama: Galeri uygulamasında Scoped Storage kullanımı
Yakında..

  1. Nicole Borelli‘nin MediaStore’u kullandığı Storage Samples reposu içerisine koyduğu örnek uygulama kodlarına buradan bakabilirsiniz.
  2. Ayrıca buradan da resmi github reposundaki MediaStore kullanımı örneğine bakabilirsiniz.
  3. Resmi dökümana buradan ulaşabilirsiniz.
  4. İlgili best practice’e buradan ulaşabilirsiniz.