Android 10 (API seviyesi 29), kullanıcıların gizliliğini daha iyi korumak için bir dizi özellik ve davranış değişikliği sunar. Bu değişiklikler, kullanıcıların verileri ve uygulamalara sağladıkları yetenekler üzerinde sahip oldukları şeffaflığı ve kontrolü genişletir. Bu özellikler, uygulamanızın bağlı olduğu belirli davranışların veya verilerin, platformun eski sürümlerine kıyasla farklı davranabileceği anlamına gelebilir. Uygulamanız, kullanıcı verilerini işlemek için mevcut en iyi uygulamaları izliyorsa, uygulamanız üzerindeki etkiler minimum düzeyde olmalıdır.
Uygulama dosyalarına ve medyaya yönelik harici depolama erişimi
Varsayılan olarak, Android 10 ve sonraki sürümleri hedefleyen uygulamalara harici depolamaya veya kapsamlı depolamaya kapsamlı erişim verilir. Bu tür uygulamalar, depolamayla ilgili herhangi bir kullanıcı izni istemeye gerek kalmadan harici bir depolama aygıtında aşağıdaki dosya türlerini görebilir: ·getExternalFilesDir (TPath.GetPublicPath) kullanılarak erişilen uygulamaya özel dizindeki dosyalar. ·Uygulamanın medya mağazasında oluşturduğu fotoğraflar, videolar ve ses klipleri.
Kapsamlı depolama ile harici depolama cihazlarına kaydedilmiş dosyaları paylaşma, ulaşma ve değiştirme hakkında daha fazla bilgi için harici depolama dosyaları yönetme ve medya dosyalarını ulaşma ve değiştirme kılavuzlarına bakın. https://developer.android.com/about/vers...cy/changes
Android 11 (API 30) Gizlilik ve Güvenlik Android 11'i hedefleyen uygulamaların, yalnızca kendi oluşturdukları harici depolama alanındaki dosyalara ("scoped storage") erişmeye izni vardır. Ayrıca uygulamaya özel bir dizinde bulunan dosyalara ek olarak; ana dizindeki "Müzik", "Resimler" veya "Video" dizinleri erişime dahildir. Diğer herhangi bir dosyaya ancak ve ancak "Depolama Erişim Çerçevesi / Storage Access Framework" aracılığıyla ve kullanıcı izni yoluyla erişilebilir. Uygulamada belirlenen konum izni sayesinde üretilen EXIF konum verisinin başarıyla işlenmiş olmasından emin olmak için Android 11, video ve fotoğraf kayıt "niyetlerini / intents" yalnızca sistem kamera uygulamasına olmak üzere sınırlar. https://tr.wikipedia.org/wiki/Android_11 Android 11, kullanıcı gizliliğini geliştirmek için aşağıdakiler dahil olmak üzere değişiklikler ve kısıtlamalar getirmiştir:
Kapsamlı depolama mecburiyeti : Harici depolama dizinlerine erişim, uygulamaya özel bir dizin ve uygulamanın oluşturduğu belirli ortam türleriyle sınırlıdır.
İzinlerin otomatik olarak sıfırlanması : Kullanıcılar bir uygulamayla birkaç aydır etkileşimde bulunmadıysa, sistem uygulamanın hassas izinlerini otomatik olarak sıfırlar.
Arka planda konum erişimi : Uygulamalara arka planda konum izni vermek için kullanıcıların sistem ayarlarına yönlendirilmesi gerekir.
Paket görünürlüğü : Bir uygulama, cihazda yüklü uygulamaların listesini sorguladığında, döndürülen liste filtrelenir.
Arka planda konum erişimi ve resim, video ve ses dosyalarına ulaşma için yeni izinler
Google Play, Tüm dosyalara erişim adlı özel uygulama erişimi de dahil olmak üzere yüksek riskli ya da hassas izinlerin kullanımını kısıtlıyor. Bu, yalnızca Android 11'i hedefleyen (API düzeyi 30) uygulamalar ve Android 11'de eklenen MANAGE_EXTERNAL_STORAGE iznini beyan eden uygulamalar için geçerlidir. Ayrıca bu politika, READ_EXTERNAL_STORAGE izninin kullanımını etkilemez.
Uygulamanız MANAGE_EXTERNAL_STORAGE iznine erişilmesini gerektirmiyorsa uygulamanızı başarılı bir şekilde yayınlayabilmek için bu izni uygulamanızın manifest dosyasından kaldırmanız gerekir. Politikaya uygun alternatiflerin uygulanması hakkında ayrıntılı bilgiyi aşağıda bulabilirsiniz.
Uygulamanız kabul edilebilir kullanım ile ilgili politika gereksinimlerini karşılıyorsa veya istisna olarak tutulmaya uygunsa Play Console'daki Beyan Formu'nu kullanarak bunu ve diğer yüksek riskli izinleri bildirmeniz gerekir.
Politika gereksinimlerini karşılamayan veya Beyan Formu gönderilmeyen uygulamalar Google Play'den kaldırılabilir.
Tüm dosyalara erişim iznine yalnızca uygulamanız, gizliliği daha fazla koruyan en iyi uygulamaları verimli bir şekilde kullanamadığında (ör. Depolama Erişim Çerçevesi veya Media Store API kullanımı) erişmelisiniz.
Buna ek olarak, uygulamanın izin kullanımı, izin verilen kullanımlar kapsamına girmeli ve uygulamanın temelişleviyle doğrudan bağlantılı olmalıdır. Temel işlev, uygulamanın asıl amacı olarak tanımlanır. Bu temel işlev olmadan uygulama "çalışmaz" veya kullanışlı olmaz. Temel işlevin yanı sıra bu temel işlevi oluşturan tüm temel özellikler, uygulamanın açıklamasında belirgin bir şekilde belgelenmeli ve tanıtılmalıdır. https://support.google.com/googleplay/an...7955?hl=tr
Paylaşılan depolamaya genel bakış
Diğer uygulamalar tarafından erişilebilen veya erişilmesi gereken ve kullanıcı uygulamanızın yüklemesini kaldırsa bile kaydedilen kullanıcı verileri için paylaşılan depolamayı kullanır. Android, paylaşılabilir veri türlerini depolamak ve bunlara erişmek için aşağıdaki API'ler sağlar:
Medya içeriği: Sistem, bu tür dosyalar için standart genel dizinler sağlar, böylece kullanıcının tüm fotoğrafları için ortak bir konumu, tüm müzik ve ses dosyaları için başka bir ortak konumu vb. vardır. Uygulamanız, platformu MediaStore API'sini kullanarak bu içeriğe erişebilir.
Belgeler ve diğer dosyalar: Sistem, PDF belgeleri ve EPUB biçimini kullanan kitaplar gibi diğer dosya türlerini içeren özel bir dizine sahiptir. Uygulamanız, platformun Depolama Erişim Çerçevesini (SAF) kullanarak bu dosyalara erişebilir.
Veritabanları: Android 11 (API düzeyi 30) ve sonraki sürümlerde sistem, birden fazla uygulamanın kullanabileceği büyük Veritabanlarıni önbelleğe alır. Bu Veritabanları, makine öğrenimi ve medya oynatma gibi kullanma vakalarını destekleyebilir. Uygulamalar, BlobStoreManager API'yi kullanarak bu paylaşılan Veritabanlarıne erişebilir.
Bu API'ler hakkında daha fazla bilgi için aşağıdaki kılavuzlara bakınız:
Android 10 ve 11 gizlilik ve güvenlik değişikliklerinden sonra harici depolamaya erişim kapsamlı hale getirilmiş olup, artık dosyalara ulaşmanın 4 ana yolu mevcuttur: 1.Depolama Erişim Çerçevesi / Storage Access Framework (SAF) 2.MediaStore API 3.All Files Access API 4.Paylaşmalı Veritabanları API
All Files Access API (ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION izni ve ACTION_MANAGE_STORAGE niyeti) sadece dosya yöneticisi ve antivirus türü uygulamalar için çıkarılmış olup, diğer tüm uygulamalar Google Play Store tarafından reddedilmektedir.
Paylaşmalı Veritabanları / Databases (BlobStoreManager) API de sadece Android 11 SDK 30 ve üstünde çalışmakta olup, Android 10 ve önceki sürümlerde çalışmamaktadır.
Dolayısıyla bu iki API konuya dahil edilmemiştir. Depolama Erişim Çerçevesi / Storage Access Framework (SAF)
Android 4.4 (API seviyesi 19), Storage Access Framework (SAF) sınıfını sunmuştur. SAF, kullanıcıların tercih ettikleri tüm belge depolama sağlayıcılarında belgelere, resimlere ve diğer dosyalara göz atmasını ve bunları açmasını kolaylaştırır. Standart, kullanımı kolay bir kullanıcı arayüzü, kullanıcıların dosyalara göz atmasına ve uygulamalar ve sağlayıcılar arasında tutarlı bir şekilde son bilgilere erişmesine olanak tanır. Bulut veya yerel depolama hizmetleri, DocumentsProvider hizmetlerini kapsayan bir uygulama uygulayarak bu ekosisteme katılabilir. Bir sağlayıcının belgelerine erişmesi gereken istemci uygulamaları, yalnızca birkaç satır kodla SAF ile entegre olabilir. SAF aşağıdakileri ihtiva eder:
Belge sağlayıcı —Bir depolama hizmetinin (Google Drive gibi) yönettiği dosyaları ortaya çıkarmasına izin veren bir içerik sağlayıcı. Bir belge sağlayıcı, sınıfın bir alt DocumentsProvider sınıfı olarak uygulanır. Belge sağlayıcı şeması, geleneksel bir dosya hiyerarşisine dayanır, ancak belge sağlayıcınızın verileri fiziksel olarak nasıl depolayacağı size bağlıdır. Android platformu, İndirilenler, Görüntüler ve Videolar gibi çeşitli yerleşik belge sağlayıcıları içerir.
Seçici —Kullanıcıların, istemci uygulamasının arama kriterlerini karşılayan tüm belge sağlayıcılarından belgelere erişmesine olanak tanıyan bir sistem kullanıcı arabirimi.
SAF'ın sunduğu özelliklerden bazıları şunlardır:
Kullanıcıların yalnızca tek bir uygulamadan değil, tüm belge sağlayıcılardan gelen içeriğe göz atmasına olanak tanır.
Uygulamanızın, bir belge sağlayıcıya ait belgelere uzun vadeli, kalıcı erişime sahip olmasını mümkün kılar. Bu erişim sayesinde kullanıcılar sağlayıcıya dosya ekleyebilir, düzenleyebilir, kaydedebilir ve silebilir.
Yalnızca sürücü takılıyken görünen USB depolama sağlayıcıları gibi birden çok kullanıcı hesabını ve geçici kökleri destekler.
Genel bakış SAF, DocumentsProvider sınıfın bir alt sınıfı olan bir içerik sağlayıcı etrafında toplanır. Bir belge sağlayıcı içinde veriler, geleneksel bir dosya hiyerarşisi olarak yapılandırılmıştır:
Şekil 1. Belge sağlayıcı veri modeli. Bir Kök, tek bir Belgeye işaret eder ve ardından tüm ağacın yayılmasını başlatır. Aşağıdakilere dikkat ediniz:
Her belge sağlayıcı, bir belge ağacını keşfetmeye başlama noktaları olan bir veya daha fazla 'kök' bildirir. Her kökün benzersiz bir değeri vardır COLUMN_ROOT_ID ve bu kökün altındaki içeriği temsil eden bir belgeye (bir dizine) işaret eder. Kökler, birden çok hesap, geçici USB depolama aygıtı veya kullanıcı oturum açma/oturum kapatma gibi kullanım durumlarını desteklemek için tasarım gereği dinamiktir.
Her kökün altında tek bir belge bulunur. Bu belge 1'den N'ye kadar belgeye işaret eder ve bunların her biri sırayla 1'den N'ye kadar belgeye işaret edebilir.
Her depolama arka ucu, benzersiz bir COLUMN_DOCUMENT_ID. Cihaz yeniden başlatmaları arasında kalıcı URI izinleri için kullanıldığından, belge kimlikleri benzersiz olmalı ve yayınlandıktan sonra değişmemelidir.
Belgeler, açılabilir bir dosya (belirli bir MIME türüyle) veya ek belgeler içeren bir dizin ( MIME_TYPE_DIR MIME türüyle) olabilir.
Kontrol akışı Yukarıda belirtildiği gibi, belge sağlayıcı veri modeli, geleneksel bir dosya hiyerarşisine dayanmaktadır. Ancak DocumentsProvider API kullanarak erişebildiğiniz sürece verilerinizi fiziksel olarak istediğiniz gibi saklayabilirsiniz. Örneğin, verileriniz için etiket tabanlı bulut depolamayı kullanabilirsiniz. Şekil 2, bir fotoğraf uygulamasının depolanan verilere erişmek için SAF'ı nasıl kullanabileceğini gösterir:
Şekil2. Depolama Erişim Çerçevesi akış şeması Aşağıdakilere dikkat ediniz:
SAF'ta sağlayıcılar ve müşteriler doğrudan etkileşime girmez. İstemci, dosyalarla etkileşim (yani, dosyaları okumak, düzenlemek, oluşturmak veya silmek) için izin ister.
Bir uygulamanın (bu örnekte, bir fotoğraf uygulaması) ACTION_OPEN_DOCUMENT veya ACTION_CREATE_DOCUMENT niyeti etkileşimi. Niyet /intent şartları daha da hassaslaştırmak için filtreler içerebilir; örneğin, "image” MIME türüne sahip tüm açılabilir dosyaları verir.
Niyet harekete geçtiğinde, sistem seçici her kayıtlı sağlayıcıya gider ve kullanıcıya eşleşen içerik köklerini gösterir.
Seçici, temeldeki belge sağlayıcıları çok farklı olsa bile, kullanıcılara belgelere erişmek için standart bir arabirim sağlar. Örneğin, şekil 2 bir Google Drive sağlayıcısını, bir USB sağlayıcısını ve bir bulut sağlayıcısını göstermektedir.
Şekil 3, görüntüleri arayan bir kullanıcının İndirilenler klasörünü seçtiği bir seçiciyi göstermektedir. Ayrıca, istemci uygulamasının kullanabileceği tüm kökleri de gösterir.
Şekil 3. (Sistem Dosya) Seçici Kullanıcı İndirilenler klasörünü seçtikten sonra resimler görüntülenir. Şekil 4, bu işlemin sonucunu göstermektedir. Kullanıcı artık bu görüntülerle sağlayıcının ve istemci uygulamasının desteklediği şekillerde etkileşim kurabilir.
Şekil 4. Sistem seçicide görüntülendiği şekliyle İndirilenler klasöründe saklanan resimler
İstemci uygulaması yazma Android 4.3 ve önceki sürümlerde, uygulamanızın başka bir uygulamadan dosya almasını istiyorsanız, ACTION_PICK veya ACTION_GET_CONTENT gibi bir niyeti çağırılması gerekir. Kullanıcı daha sonra içinden bir dosya seçeceği tek bir uygulama seçmeli ve seçilen uygulama, kullanıcının mevcut dosyalara göz atması ve aralarından seçim yapması için bir kullanıcı arabirimi sağlamalıdır. Android 4.4 (API düzeyi 19) ve sonraki sürümlerde, ACTION_OPEN_DOCUMENT kullanıcının diğer uygulamaların kullanıma sunduğu tüm dosyalara göz atmasına olanak tanıyan, sistem kontrollü bir seçici kullanıcı arabirimini görüntüleyen niyeti kullanma ek seçeneğiniz vardır. Bu tek kullanıcı arayüzünden kullanıcı, desteklenen uygulamalardan herhangi birinden bir dosya seçebilir. Android 5.0 (API düzeyi 21) ve sonraki sürümlerde, kullanıcının bir istemci uygulamasının erişmesi için bir dizin seçmesine olanak tanıyan ACTION_OPEN_DOCUMENT_TREE niyetini de kullanabilirsiniz. Not: ACTION_OPEN_DOCUMENT niyetinin ACTION_GET_CONTENT‘in yerine geçmesi amaçlanmamıştır. Kullanma Vakası uygulamanızın ihtiyaçlarına bağlıdır:
ACTION_GET_CONTENT Uygulamanızın yalnızca verileri okumasını veya içe aktarmasını istiyorsanız kullanın. Bu yaklaşımla uygulama, resim dosyası gibi verilerin bir kopyasını içe aktarır.
ACTION_OPEN_DOCUMENT Uygulamanızın bir belge sağlayıcıya ait belgelere uzun süreli, kalıcı erişime sahip olmasını istiyorsanız kullanın. Bir örnek, kullanıcıların bir belge sağlayıcıda depolanan görüntüleri düzenlemesine izin veren bir fotoğraf düzenleme uygulaması olabilir.
Paylaşılan depolama alanından belgelere ve diğer dosyalara erişme
Android 4.4 (API düzeyi 19) ve sonraki sürümleri çalıştıran cihazlarda, uygulamanız Depolama Erişim Çerçevesini kullanarak harici depolama birimleri ve bulut tabanlı depolama dahil olmak üzere bir belge sağlayıcıyla etkileşim kurabilir. Bu çerçeve, kullanıcıların bir belge sağlayıcı seçmek için bir sistem seçiciyle etkileşime girmesine ve uygulamanızın oluşturacağı, açacağı veya değiştireceği belirli belgeleri ve diğer dosyaları seçmesine olanak tanır. Kullanıcı, uygulamanızın erişebileceği dosyaları veya dizinleri seçmeye dahil olduğundan, bu mekanizma herhangi bir sistem izni gerektirmez ve kullanıcı denetimi ve gizliliği artırılır. Ayrıca, uygulamaya özel bir dizinin dışında ve medya deposunun dışında depolanan bu dosyalar, uygulamanızın yüklemesi kaldırıldıktan sonra cihazda kalır. Çerçeveyi kullanmak aşağıdaki adımları içerir:
Bir uygulama, depolamayla ilgili bir eylem içeren bir niyeti çağırır. Bu eylem, çerçevenin kullanıma sunduğu belirli bir kullanma vakasına karşılık gelir.
Kullanıcı, bir belge sağlayıcısına göz atmasına ve depolamayla ilgili eylemin gerçekleştiği bir konum veya belge seçmesine olanak tanıyan bir Sistem Seçici gösterilir.
Uygulama, kullanıcının seçtiği konumu veya belgeyi temsil eden bir URI'ye okuma ve yazma erişimi kazanır. Bu URI'yi kullanarak uygulama, seçilen konumda işlemler gerçekleştirebilir.
Not: Uygulamanız harici bir depolama birimindeki medya dosyalarına erişiyorsa, bu tür dosyalara erişmek için uygun bir arabirim sağlayan medya deposunu kullanmayı düşünün. Ancak uygulamanız medya deposunu kullanıyorsa, diğer uygulamaların medya dosyalarına erişmek için READ_EXTERNAL_STORAGE iznini istemeniz gerekir. Android 9 (API düzeyi 28) veya daha eski sürümleri çalıştıran cihazlarda, READ_EXTERNAL_STORAGE uygulamanızın oluşturduğu medya dosyaları da dahil olmak üzere herhangi bir medya dosyasına erişim izni istemesi gerekir. Bu kılavuz, çerçevenin dosyalar ve diğer belgelerle çalışmak için desteklediği farklı kullanım durumlarını açıklar. Ayrıca, kullanıcı tarafından seçilen konumda işlemlerin nasıl gerçekleştirileceğini de açıklar.
Belgelere ve diğer dosyalara erişmek için vakaları kullanın
Storage Access Framework, dosyalara ve diğer belgelere erişmek için aşağıdaki Kullanma Vakalarını destekler. Yeni bir dosya oluşturun ACTION_CREATE_DOCUMENT niyet eylemi, kullanıcıların belirli bir yerde bir dosyayı kaydetmesi için izin verir. Bir belge veya dosya açın ACTION_OPEN_DOCUMENT niyet eylemi, kullanıcıların belirli bir belgeyi açması veya dosyayı seçmesi için izin verir. Bir dizinin içeriğine erişim izni verin ACTION_OPEN_DOCUMENT_TREE Android 5.0 (API düzeyi 21) ve sonraki sürümlerde bulunan niyet eylemi, kullanıcıların belirli bir dizini seçmesine olanak tanıyarak uygulamanızın bu dizindeki tüm dosyalara ve alt dizinlere erişmesine izin verir. Aşağıdaki bölümler, her bir kullanma vakasının nasıl yapılandırılacağına ilişkin rehberlik sağlar.
Yeni bir dosya oluşturun
ACTION_CREATE_DOCUMENTSistem dosyası seçiciyi yüklemek ve kullanıcının bir dosyanın içeriğini yazacağı konumu seçmesine izin vermek için niyet eylemini (intent action) kullanır. Bu işlem, diğer işletim sistemlerinin kullandığı "farklı kaydet" iletişim kutularında kullanılana benzer. Not: ACTION_CREATE_DOCUMENTmevcut bir dosyanın üzerine yazılamaz. Uygulamanız aynı ada sahip bir dosyayı kaydetmeye çalışırsa, sistem dosya adının sonuna parantez içinde bir sayı ekler.
Uygulamanız yeni dosyayı örneğin confirmation.pdf, zaten o ada sahip dosya bulunan bir dizinde kaydetmeye çalışırsa, sistem yeni dosyayı confirmation(1).pdf adıyla kaydeder. Niyeti yapılandırırken, dosyanın adını ve MIME türünü belirtin. İsteğe bağlı olarak, EXTRA_INITIAL_URI ekstra niyeti kullanarak, dosya seçicinin ilk yüklediğinde görüntülemesi gereken dosyanın veya dizinin URI'sini belirtin. Aşağıdaki kod parçacığı, bir dosya oluşturma niyetinin nasıl oluşturulacağını ve çağrılacağını gösterir:
// PDF belgesi oluşturma için talep kodu.
const Dosya_Olustur : integer = 11; //CREATE_FILE = 1
procedure PdfDosyasiOlustur(seciciBaslangicUri : JNet_Uri);
var
Intent : JIntent;
begin
Intent := TJIntent.Create;
Intent.setAction(TJIntent.JavaClass.ACTION_CREATE_DOCUMENT);
Intent.addCategory(TJIntent.JavaClass.CATEGORY_OPENABLE);
Intent.setType(StringToJString('application/pdf'));
Intent.putExtra(TJIntent.JavaClass.EXTRA_TITLE,StringToJString('fatura.pdf'));
// İsteğe bağlı olarak, uygulamanız dosyayı oluşturduğunda
// sistem dosya seçici tarafından açılacak dizin için bir URI belirleyin.
Intent.putExtra(TJDocumentsContract.JavaClass.EXTRA_INITIAL_URI,
JParcelable(seciciBaslangicUri));
MainActivity.startActivityForResult(Intent, Dosya_Olustur);
end;
Bir dosya açın
Uygulamanız, kullanıcıların benzerleriyle paylaşmak veya başka belgelere aktarmak isteyebilecekleri verileri girdiği depolama birimi olarak belgeleri kullanabilir. Birkaç örnek, bir kullanıcının bir üretkenlik belgesi açmasını veya bir EPUB dosyası olarak kaydedilmiş bir kitabı açmasını içerir. Bu durumlarda, ACTION_OPEN_DOCUMENT sistemin dosya seçici uygulamasını açan niyeti çağırarak kullanıcının açılacak dosyayı seçmesine izin verin. Yalnızca uygulamanızın desteklediği dosya türlerini göstermek için bir MIME türü belirtin. Ayrıca, isteğe bağlı olarak, EXTRA_INITIAL_URI ekstra niyetini kullanarak dosya seçicinin ilk yüklendiğinde görüntülemesi gereken dosyanın URI'sini belirtebilirsiniz. Aşağıdaki kod parçacığı, bir PDF belgesi açma niyetinin nasıl oluşturulacağını ve çağrılacağını gösterir:
// Bir PDF belgesi seçmek için talep kodu.
// const Pdf_Dosyasi_Sec : integer = 22; //PICK_PDF_FILE = 2
procedure PdfDosyasiOlustur(seciciBaslangicUri : JNet_Uri);
var
Intent: JIntent;
begin
Intent := TJIntent.Create;
Intent.setAction(TJIntent.JavaClass.ACTION_OPEN_DOCUMENT);
Intent.addCategory(TJIntent.JavaClass.CATEGORY_OPENABLE);
Intent.setType(StringToJString('application/pdf'));
// İsteğe bağlı olarak, sistem dosya seçici yüklendiğinde
// gösterilecek dosya için bir URI belirleyin.
Intent.putExtra(TJDocumentsContract.JavaClass.EXTRA_INITIAL_URI,
JParcelable(seciciBaslangicUri));
TAndroidHelper.Activity.startActivityForResult(Intent, Pdf_Dosyasi_Sec);
end;
Bir dizinin içeriğine erişim izni verin
Not: Bu bölümde açıklanan niyet eylemi (intent action), Android 5.0 (API düzeyi 21) ve sonraki sürümlerde mevcuttur.
Dosya yönetimi ve medya oluşturma uygulamaları, genellikle bir dizin hiyerarşisindeki dosya gruplarını yönetir. Uygulamanızda bu özelliği sağlamak için, Android 11'den (API düzeyi 30) başlayan bazı istisnalar dışında, kullanıcının bir dizin ağacının tamamına erişim vermesine izin veren ACTION_OPEN_DOCUMENT_TREEniyet eylemini kullanın. Uygulamanız daha sonra seçilen dizindeki ve alt dizinlerindeki herhangi bir dosyaya erişebilir. ACTION_OPEN_DOCUMENT_TREE uygulamasını kullanırken, uygulamanız yalnızca kullanıcının seçtiği dizindeki dosyalara erişim kazanır. Kullanıcı tarafından seçilen bu dizinin dışında bulunan diğer uygulamaların dosyalarına erişiminiz yok. Bu kullanıcı kontrollü erişim, kullanıcıların uygulamanızla tam olarak hangi içeriği paylaşacaklarını seçmelerine imkan sağlar. İsteğe bağlı olarak, EXTRA_INITIAL_URI ilave niyetini kullanarak dosya seçicinin ilk yüklendiğinde görüntülemesi gereken dizinin URI'sini belirtebilirsiniz. Aşağıdaki kod parçacığı, bir dizin açma niyetinin nasıl oluşturulacağını ve çağrılacağını gösterir:
procedure DizinAc(YuklenecekUri : JNet_Uri);
// Sistem dosya seçici kullanarak bir dizin seçin
var
Intent : JIntent;
begin
Intent := TJIntent.Create;
Intent.setAction(TJIntent.JavaClass.ACTION_OPEN_DOCUMENT_TREE);
// İsteğe bağlı olarak, sistem dosya seçici yüklendiğinde
// açılacak dizin için bir URI belirleyin.
Intent.putExtra(TJDocumentsContract.JavaClass.EXTRA_INITIAL_URI,
JParcelable(YuklenecekUri));
Mainactivity.startActivityForResult(Intent, Dizin_Agaci_Ac);
end;
Dikkat: ACTION_OPEN_DOCUMENT_TREEkullanılarak erişilen dizindeki çok sayıda dosyayı yinelerseniz, uygulamanızın performansı düşebilir.
Erişim kısıtlamaları Android 11 (API düzeyi 30) ve sonraki sürümlerde, ACTION_OPEN_DOCUMENT_TREE aşağıdaki dizinlere erişim istemek için niyet eylemini kullanamazsınız:
Dahili depolama biriminin kök dizini.
Kartın öykünmesi veya çıkarılabilir olmasına bakılmaksızın, aygıt üreticisinin güvenilir olduğunu düşündüğü her bir SD kart sürücüsünün kök dizini. Güvenilir sürücü, bir uygulamanın çoğu zaman başarıyla erişebildiği birimdir.
Download
dizini.
Ayrıca, Android 11 (API düzeyi 30) ve sonraki sürümlerde, ACTION_OPEN_DOCUMENT_TREE niyet eylemini kullanıcının aşağıdaki dizinlerden tek tek dosyaları seçmesini istemek için kullanamazsınız:
Android/data/
dizini ve tüm alt dizinleri.
Android/obb/
dizini ve tüm alt dizinleri.
İşlemleri seçilen yerde gerçekleştirin Kullanıcı sistemin dosya seçicisini kullanarak bir dosya veya dizin seçtikten sonra, aşağıdaki kodu onActivityResult kullanarak seçilen öğenin URI'sini alabilirsiniz:
procedure TForm1.IletiFaaliyetiYakala(const Sender: TObject; const M: TMessage);
begin
if M is TMessageResultNotification then
OnActivityResult(
TMessageResultNotification(M).RequestCode,
TMessageResultNotification(M).ResultCode,
TMessageResultNotification(M).Value);
end;
procedure TForm1.OnActivityResult(RequestCode, ResultCode: Integer;
Data: JIntent);
var
Uri: Jnet_Uri;
begin
if ResultCode = TJActivity.JavaClass.RESULT_OK then
begin
// Sonuç verisi kullanıcının seçtiği
// belge veya dizin için bir URI içerir.
Uri := nil;
if Assigned(Data) then
begin
Uri := Data.getData;
if RequestCode = sizin-talep-kodunuz then
begin
// URI’sini kullanarak belge üzerinde işlemler gerçekleştirin.
end;
end;
end;
Uygulamanız, seçilen öğenin URI'sine bir referans alarak, öğe üzerinde birkaç işlem gerçekleştirebilir. Örneğin, öğenin meta verilerine erişebilir, öğeyi yerinde düzenleyebilir ve silebilirsiniz. Aşağıdaki bölümler, kullanıcının seçtiği dosyalar üzerindeki eylemlerin nasıl tamamlanacağını gösterir.
Bir sağlayıcının desteklediği işlemleri belirleyin
Farklı içerik sağlayıcılar, belgeler üzerinde, belgeyi kopyalama veya belgenin küçük resmini görüntüleme gibi farklı işlemlerin gerçekleştirilmesine izin verir. Belirli bir sağlayıcının hangi işlemleri desteklediğini belirlemek için Document.COLUMN_FLAGSdeğerini tetkik edin. Uygulamanızın kullanıcı arayüzü, yalnızca sağlayıcının desteklediği seçenekleri gösterebilir.
Kalıcı izinler
Uygulamanız okumak veya yazmak için bir dosya açtığında sistem, uygulamanıza bu dosya için kullanıcının cihazı yeniden başlatılana kadar süren bir URI izni verir. Bununla birlikte, uygulamanızın bir resim düzenleme uygulaması olduğunu ve kullanıcıların en son düzenledikleri 5 resme doğrudan uygulamanızdan erişmesini istediğinizi varsayalım. Kullanıcının cihazı yeniden başlatıldıysa, dosyaları bulması için kullanıcıyı sistem seçiciye geri göndermeniz gerekir. Cihaz yeniden başlatmalarında dosyalara erişimi korumak ve daha iyi bir kullanıcı deneyimi oluşturmak için uygulamanız, aşağıdaki kod parçacığında gösterildiği gibi, sistemin sunduğu kalıcı URI iznini "alabilir":
// TakeFlags: integer;
Intent := TJIntent.Create;
TakeFlags := Intent.getFlags
and (TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION
or TJIntent.JavaClass.FLAG_GRANT_WRITE_URI_PERMISSION);
// En yeni veriyi tetkik et
TAndroidHelper.Activity.getContentResolver.takePersistableUriPermission
(Uri, TakeFlags);
Dikkat: takePersistableUriPermission çağırıldıktan sonra bile, ilişkili belge taşınır veya silinirse, uygulamanız URI'ye erişimi korumaz. Bu durumlarda, URI'ye yeniden erişim sağlamak için tekrar izin istemeniz gerekir.
Belge meta verilerini inceleyin
Bir belgenin URI'sine sahip olduğunuzda, onun meta verilerine erişim kazanırsınız. Bu kod parçacığı, URI tarafından belirtilen bir belgenin meta verilerini alır:
procedure GoruntuMetaVerisiDokumu(uri : JNet_Uri); (* dumpImageMetaData *)
// Sorgu, tek bir belgeye uygulandığı için, sadece tek satır döndürür.
// Alanları filtreleme, sıralama veya seçmeye ihtiyaç yoktur.
// Çünkü tüm alanları bir belge için istiyoruz.
var
displayName, size : JString;
sizeIndex : integer;
cursor : JCursor;
begin
cursor := TAndroidHelper.Activity.getContentResolver.query(uri,nil,nil,nil,nil,nil);
try
if (cursor<>nil) then
if (cursor.moveToFirst) then
begin
displayName := cursor.getString (cursor.getColumnIndex
(TJOpenableColumns.JavaClass.DISPLAY_NAME));
Memo1.Lines.Add({TAG.ToString +} 'Görünen Ad: ' +
JStringToString (displayName));
sizeIndex:=cursor.getColumnIndex(TJOpenableColumns.JavaClass.SIZE);
size := nil;
if not (cursor.isNull(sizeIndex)) then
size := cursor.getString(sizeIndex)
else
size:=StringToJString ('Bilinmiyor');
Memo1.Lines.Add({TAG.ToString +} 'Boyut: ' + JStringToString (size));
end;
finally
cursor.close;
end;
end;
Belge açın
Bir belgenin URI'sine referans vererek, daha sonraki işlemler için bir belge açabilirsiniz. Bu bölüm, bir bit eşlem ve bir giriş akışı açma örneklerini gösterir. bit eşlem / bitmap Aşağıdaki kod parçacığı, Bitmap URI'si verilen bir dosyanın nasıl açılacağını gösterir :
function UridenBiteslemAl (uri : JNet_Uri): JBitmap; (* getBitmapFromUri *)
var
fileDescriptor : JFileDescriptor;
parcelFileDescriptor : JParcelFileDescriptor;
image : JBitmap;
begin
Result := nil;
try
parcelFileDescriptor := TAndroidHelper.Activity
.getContentResolver.openFileDescriptor(uri,StringToJString('r'));
fileDescriptor := parcelFileDescriptor.getFileDescriptor;
image := TJBitmapFactory.JavaClass.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close;
result := image;
except
on E: Exception do
ShowMessage(e.Message);
end;
Not: Bu işlemi UI iş parçacığında değil arka plan iş parçacığında tamamlamanız gerekir. Bitmap'i açtıktan sonra, onu bir ImageControl içinde gösterebilirsiniz. Giriş akışı/ Inputstream Aşağıdaki kod parçacığı, URI'si verilen bir InputStream nesnesinin nasıl açılacağını gösterir. Bu pasajda, dosyanın satırları bir dizgeye okunuyor:
function TForm1.MetinDosyasiOkuyucu(Uri : JNet_Uri): string; (* readTextFromUri *)
const
bufferSize = 4096*2;
var
inputStream : JInputStream;
b : TJavaArray<Byte>;
ms: TMemoryStream;
sl: TStringList;
bufflen: Integer;
begin
result := '';
try
inputStream := TAndroidHelper.Context.getContentResolver.openInputStream(Uri);
ms := TMemoryStream.Create;
bufflen := inputStream.available;
b := TJavaArray<Byte>.Create(bufflen);
inputStream.read(b);
ms.Write(b.Data^, bufflen);
ms.position := 0;
sl := TStringList.Create;
sl.LoadFromStream(ms);
result := sl.Text;
sl.Free;
b.Free;
ms.Free;
inputStream.Close;
except
on E: Exception do
Application.ShowException(E);
end;
end;
Belge düzenleyin
Bir metin belgesini yerinde düzenlemek için Depolama Erişim Çerçevesini kullanabilirsiniz. Not:DocumentFile sınıfının canWrite yöntemi uygulamanızın mutlaka bir belgeyi düzenleyebileceğini göstermez. Çünkü Document.COLUMN_FLAGS eğer FLAG_SUPPORTS_DELETE veya FLAG_SUPPORTS_WRITE içeriyorsa true döndürür. Uygulamanızın belirli bir belgeyi düzenleyip düzenleyemeyeceğini belirlemek için doğrudan FLAG_SUPPORTS_WRITE değerini sorgulayın. Aşağıdaki kod parçacığı, verilen URI tarafından temsil edilen belgenin içeriğinin üzerine yazar:
procedure MetinBelgesiDegistir(uri : JNet_Uri); (* alterDocument *)
var
pfd : JParcelFileDescriptor;
fileOutputStream : JFileOutputStream;
begin
try
pfd := TAndroidHelper.Activity.getContentResolver
.openFileDescriptor(uri,StringToJString('w'));
fileOutputStream := TJFileOutputStream.JavaClass.init(pfd.getFileDescriptor);
fileOutputStream.write(StringToJString('Üzerine yazıldı ' + timetostr(Now)).getBytes);
fileOutputStream.close;
pfd.close;
except
on E: Exception do
ShowMessage(e.Message);
end;
end;
getMediaUri yöntemi verilen belgeler sağlayıcısına URI'siyle eşdeğer bir medya deposu URI’si sağlar. 2 URI, aynı temel öğeye atıfta bulunur. Medya deposu URI'sini kullanarak, paylaşılan depodan medya dosyalarına daha kolay erişebilirsiniz. Not: Bu yöntem herhangi bir yeni izin vermez. Uygulamanızın, belirli bir belge sağlayıcı URI'sine (ör. belgeyi açarak) erişmek için gerekli izinlere zaten sahip olması gerekir. ExternalStorageProvider URI'leri getMediaUri yöntemini destekler. Android 12 (API düzeyi 31) ve sonraki sürümlerde, MediaDocumentsProvider URI'leri de bu yöntemi destekler.
Sanal bir dosya açın
Android 7.0 (API düzeyi 25) ve sonraki sürümlerde uygulamanız, Storage Access Framework'ün kullanıma sunduğu sanal dosyaları kullanabilir. Sanal dosyaların ikili gösterimi olmamasına rağmen, uygulamanız içeriklerini farklı bir dosya türüne zorlayarak veya ACTION_VIEWniyet eylemini kullanarak bu dosyaları görüntüleyerek açabilir. Sanal dosyaları açmak için, istemci uygulamanızın bunları işlemek için özel bir mantık içermesi gerekir. Dosyanın bayt temsilini almak istiyorsanız, örneğin dosyayı önizlemek için, belge sağlayıcısından alternatif bir MIME türü talep etmeniz gerekir. Not: Bir uygulama, openInputStream yöntemini kullanarak bir sanal dosyayı doğrudan açamayacağından, ACTION_OPEN_DOCUMENT veya ACTION_OPEN_DOCUMENT_TREE eylemi içeren niyeti oluştururken CATEGORY_OPENABLE kategorisini kullanmayın. Kullanıcı bir seçim yaptıktan sonra, aşağıdaki kod parçacığında gösterildiği gibi, dosyanın sanal olup olmadığını belirlemek için sonuç verilerindeki URI'yi kullanın:
function SanalDosyami(Uri : JNet_Uri): boolean; (* isVirtualFile *)
var
flags : integer;
cursor : JCursor;
s : TJavaObjectArray<JString>;
begin
if (not TJDocumentsContract.JavaClass.isDocumentUri(TAndroidHelper.Context,Uri)) then
begin
result := false;
exit;
end;
s := TJavaObjectArray<JString>.Create(0);
s[0] := TJDocumentsContract_Document.JavaClass.COLUMN_FLAGS;
cursor := TAndroidHelper.Activity.getContentResolver.query(uri,s,nil,nil,nil);
flags:=0;
if (cursor.moveToFirst) then
flags:=cursor.getInt(0);
cursor.close;
result := (flags and TJDocumentsContract_Document.JavaClass.FLAG_VIRTUAL_DOCUMENT) <> 0;
end;
Belgenin sanal bir dosya olduğunu doğruladıktan sonra, dosyayı "image/png" benzeri MIME türüne çevirebilirsiniz. Aşağıdaki kod parçacığı, bir sanal dosyanın bir görüntü olarak gösterilip gösterilmeyeceğinin nasıl kontrol edileceğini gösterir ve eğer öyleyse, sanal dosyadan bir girdi akışı alır:
function SanalDosyaIcinGirisAkisiAl(Uri : JNet_Uri; mimeTypeFilter : String): JInputStream;
var (* getInputStreamForVirtualFile *)
openableMimeTypes : TJavaObjectArray<JString>;
resolver : JContentResolver;
begin
resolver := TAndroidHelper.Activity.getContentResolver;
openableMimeTypes := resolver.getStreamTypes(uri,StringToJString(mimeTypeFilter));
if ((openableMimeTypes = nil) or (openableMimeTypes.Length < 1)) then
begin
Teblig('Dosya bulunamadı!');
result := nil;
exit;
end;
result := resolver.openTypedAssetFileDescriptor(uri,openableMimeTypes[0],nil)
.createInputStream;
end;
https://developer.android.com/training/d...ents-files MediaStore API MediaProvider ve uygulamalar arasındaki sözleşme sınıfıdır. Desteklenen URI'ler ve sütunlar için tanımları içerir. Medya sağlayıcısı, herhangi bir bağlı depolama cihazlarındaki Audio, Videove Imagesgibi yaygın medya tipleri için dizinlenmiş bir koleksiyon sağlar. Her koleksiyon, temel alınan içeriğin birincil MIME türüne göre düzenlenir; örneğin, image/* içeriği Images altındaki dizine eklenir. Files kolleksiyonu tüm koleksiyonlar boyunca geniş bir görünüm sağlar ve MIME türüne göre filtre uygulamaz. createWriteRequest, createDeleteRequest, createTrashRequest, createFavoriteRequest sınıflarını kullanır. https://developer.android.com/reference/...MediaStore
Daha zenginleştirilmiş bir kullanıcı deneyimi sağlamak için birçok uygulama, kullanıcıların harici bir depolama biriminde bulunan medyaya katkıda bulunmasına ve bu medyaya erişmesine olanak tanır. Çerçeve, bu medya dosyalarının daha kolay alınmasına ve güncellenmesine izin veren, medya deposu adı verilen medya koleksiyonlarına optimize edilmiş bir dizin sağlar. Uygulamanızın yüklemesi kaldırıldıktan sonra bile bu dosyalar kullanıcının cihazında kalır. Not: Uygulamanız, kullanıcıya yalnızca uygulamanız içinde değer sağlayan medya dosyaları ile çalışıyorsa, bunları harici depolama içindeki uygulamaya özel dizinlerde depolamak en iyisidir. Medya deposu soyutlamasıyla etkileşim kurmak için, uygulamanızın bağlamından (context) aldığınız bir ContentResolver nesnesini kullanın:
var
projection, selectionArgs: TJavaObjectArray<JString>;
selection, sortOrder: JString;
cursor: JCursor;
begin
selection := where-şartı-bulunan-sql-seçme-değişkeni
projection := alınacak-medya-veritabanı-sütunları //TJavaObjectArray<JString>.Create(3);
//projection.Items[0] := TJAudio_AlbumColumns.JavaClass.ALBUM;
//projection.Items[1] := TJAudio_AlbumColumns.JavaClass.ARTIST;
//projection.Items[2] := StringToJString('_id');
selectionArgs := seçme-şartı-değişken-değerleri
sortOrder := order by-sıralama-şartı
cursor := MainActivity.getContentResolver.query(
TJAudio_Albums.JavaClass.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder);
while (cursor.moveToNext) do
begin
// Projeksiyondan medya kalemini temsil eden bir URI almak için bir ID sütünü kullanın
end;
cursor.close;
end;
Sistem kendiliğinden harici bir depolama birimini tarar ve medya dosyalarını aşağıdaki iyi tanımlanmış koleksiyonlara ekler: • Görüntüler fotoğraf ve ekran görüntüleri de dahil olmak üzere, DCIM/ve Pictures/dizinlerinde saklanır. Sistem bu dosyaları MediaStore.Images tablosuna ekler. • Videolar DCIM/, Movies/, ve Pictures/ dizinlerinde saklanır. Sistem bu dosyaları MediaStore.Video tablosuna ekler. • Ses dosyaları saklanır, Alarms/, Audiobooks/, Music/, Notifications/, Podcasts/, ve Ringtones/dizinleri. Ayrıca sistem, Music/veya Movies/dizinlerindeki ses çalma listelerini ve dizindeki ses kayıtlarını tanır Recordings/. Sistem bu dosyaları MediaStore.Audio tablosuna ekler. Kayıtlar dizini, Android 11 (API düzeyi 30) ve önceki sürümlerde kullanılamaz. • İndirilen dosyalar Download dizininde depolanan Android 10 (API düzeyi 29) ve sonraki sürümleri çalıştıran cihazlarda bu dosyalar MediaStore.Downloads tabloda depolanır. Bu tablo, Android 9 (API düzeyi 28) ve daha düşük sürümlerde mevcut değildir. Medya deposunda MediaStore.Files içeriği, uygulamanızın Android 10 veya sonraki sürümleri hedefleyen uygulamalarda bulunan kapsamlı depolama kullanıp kullanmadığına bağlıdır:
Kapsamlı depolama etkinleştirilirse koleksiyon yalnızca uygulamanızın oluşturduğu fotoğrafları, videoları ve ses dosyalarını gösterir. Çoğu geliştiricinin
MediaStore.Files diğer uygulamalardan medya dosyalarını görüntülemek için kullanması gerekmez, ancak bunu yapmak için özel bir gereksiniminiz varsa,
READ_EXTERNAL_STORAGE izin beyan edebilirsiniz. Ancak uygulamanızın oluşturmadığı dosyaları açmak için MediaStore API'lerini kullanmanız önerilir.
Kapsamlı depolama yoksa veya kullanılmıyorsa, koleksiyon her tür medya dosyasını gösterir.
Gerekli izinleri isteyin
Medya dosyaları üzerinde işlem yapmadan önce, uygulamanızın bu dosyalara erişmek için ihtiyaç duyduğu izinleri beyan ettiğinden emin olun. Ancak, uygulamanızın ihtiyaç duymadığı veya kullanmadığı izinleri beyan etmemesi gerektiğini unutmayın.
Depolama izni Uygulamanızdaki medya dosyalarına erişmek için izin modeli, uygulamanızın Android 10 veya sonraki sürümleri hedefleyen uygulamalarda bulunan kapsamlı depolamayı kullanıp kullanmadığına bağlıdır. Kapsamlı depolama etkinleştirilecek ise Uygulamanız kapsamlı depolama kullanıyorsa, yalnızca Android 9 (API düzeyi 28) veya daha eski sürümleri çalıştıran cihazlar için depolamayla ilgili izinler istemelidir. Bu şartı, uygulamanızın bildirim dosyasındaki izin bildirimine android:maxSdkVersion özniteliği ekleyerek sağlayabilirsiniz :
Android 10 veya sonraki sürümleri çalıştıran cihazlar için depolamayla ilgili izinleri gereksiz yere istemeyin. Uygulamanız, koleksiyon da dahil olmak üzere iyi tanımlanmış medya koleksiyonlarına MediaStore.Downloads depolamayla ilgili herhangi bir izin istemeden katkıda bulunabilir. Örneğin bir kamera uygulaması geliştiriyorsanız , medya deposuna yazdığınız görüntülerin sahibi uygulamanız olduğundan depolamayla ilgili izinler istemeniz gerekmez. Diğer uygulamaların oluşturduğu dosyalara erişmek için aşağıdaki koşulların her birinin doğru olması gerekir:
Uygulamanıza READ_EXTERNAL_STORAGE izin verilmiş olmalıdır.
Dosyalar, aşağıdaki iyi tanımlanmış medya koleksiyonlarından birinde bulunmalıdır:
Not: Bir dosya olarak MediaStore.Images, MediaStore.Videoya da MediaStore.Audio sorguları kullanarak görüntülenebilir olduğu gibi, MediaStore.Files sorgusu ile de görüntülenebilir.
Uygulamanız MediaStore.Downloads, uygulamanızın oluşturmadığı koleksiyon içindeki bir dosyaya erişmek istiyorsa, Depolama Erişim Çerçevesini kullanmanız gerekir. Bu çerçevenin nasıl kullanılacağı hakkında daha fazla bilgi edinmek için belgelere ve diğer dosyalara nasıl erişileceğine ilişkin kılavuza bakın. Kapsamlı depolama devre dışı ise Uygulamanız Android 9 veya önceki sürümleri çalıştıran bir cihazda kullanılıyorsa veya uygulamanız geçici olarak kapsamlı depolamayı devre dışı bıraktıysaREAD_EXTERNAL_STORAGE medya dosyalarına erişim izni istemeniz gerekir. Medya dosyalarını değiştirmek istiyorsanız, WRITE_EXTERNAL_STORAGE izin de istemeniz gerekir. Not: Uygulamanızın kullanma vakası kapsamlı depolamaya dahil olmuyorsa, bir özellik talebi bildirin ve geçici olarak kapsamlı depolamadan çıkın. Medya konum izni Uygulamanız Android 10 (API düzeyi 29) veya sonraki bir sürümünü hedefliyorsa, uygulamanızın fotoğraflardan düzenlenmemiş Exif meta verilerini alabilmesi ACCESS_MEDIA_LOCATION için uygulamanızın bildiriminde izni bildirmeniz ve ardından bu izni çalışma zamanında istemeniz gerekir. Dikkat: Çalışma zamanında ACCESS_MEDIA_LOCATION izin talep ettiğiniz için, uygulamanızın fotoğraflardan redaksiyona tabi tutulmamış Exif meta verilerine erişebileceğinin garantisi yoktur. Uygulamanız, bu bilgilere erişmek için açık kullanıcı onayı gerektirir. Medya depolamadaki değişilikliklerin tetkiki Medya dosyalarına daha güvenilir bir şekilde erişmek için, özellikle uygulamanız URI'leri veya medya deposundaki verileri önbelleğe alıyorsa, medya deposu sürümünün medya verilerinizi en son senkronize ettiğiniz zamana göre değişip değişmediğini kontrol edin. Güncellemeler için bu kontrolügerçekleştirmek için getVersion çağırın. Döndürülen sürüm, medya deposu önemli ölçüde değiştiğinde değişen benzersiz bir dizedir. Döndürülen sürüm, son eşitlenen sürümden farklıysa, uygulamanızın medya önbelleğini yeniden tarayın ve yeniden eşitleyin. Bu kontrolü uygulama süreci başlangıç zamanında tamamlayın. Medya deposunu her sorguladığınızda sürümü kontrol etmenize gerek yoktur. Sürüm numarasıyla ilgili herhangi bir uygulama ayrıntısını varsaymayın. Not: Medya deposu sürüm numarası, bir uygulamanın medya dosyası eklemesi gibi uygulama tarafındaki değişikliklerin bir sonucu olarak değişmez. Medya dosyalarındaki güncellemeleri algılamanıza yardımcı olacak ayrı bir yöntem vardır. Medya kolleksiyonu sorgulama 5 dakika veya daha uzun süre gibi belirli bir dizi koşulu karşılayan medyayı bulmak için aşağıdaki kod parçacığında gösterilene benzer bir SQL benzeri seçim ifadesi kullanın: // Uygulamanızın oluşturmadığı video dosyalarına ulaşmak için READ_EXTERNAL_STORAGE izni gereklidir // Java kodu eksik Delphi kütüphaneleri sebebi ile çevirilemedi Uygulamanızda böyle bir sorgu gerçekleştirirken aşağıdakileri aklınızda bulundurunuz:
Query yöntemini çalışan bir iş parçacığında çağırın.
Sütun dizinlerini önbelleğe alın, böylece sorgu sonucundan bir satırı her işlediğinizde çağırmanız gerekmez.
Kimliği, kod parçacığında gösterildiği gibi içerik URI'sine ekleyin.
Android 10 ve sonraki sürümleri çalıştıran cihazlar, MediaStoreAPI'de tanımlanan sütun adlarını gerektirir. Uygulamanızdaki bağımlı bir kitaplık, API'de tanımsız bir sütun adı bekliyorsa, örneğin uygulamanızın işleminde sütun adını dinamik olarak çevirmek için CursorWrapper "MimeType" kullanın.
Dosya küçük resimleri (thumbnails) yükleme Uygulamanız birden fazla medya dosyası gösteriyorsa ve kullanıcının bu dosyalardan birini seçmesini isterse, dosyaların kendisi yerine dosyaların önizleme sürümlerini (veya küçük resimlerini) yüklemek daha verimlidir. Belirli bir medya dosyasının loadThumbnail küçük resmini yüklemek için, aşağıdaki kod parçacığında gösterildiği gibi, yüklemek istediğiniz küçük resmin boyutunu kullanın ve iletin: // java kodu Medya dosyası açma Bir medya dosyasını açmak için kullandığınız belirli mantık, medya içeriğinin en iyi dosya tanımlayıcı, dosya akışı veya doğrudan dosya yolu olarak temsil edilip edilmediğine bağlıdır: Dosya tanımlayıcı / File descriptor Dosya tanımlayıcı kullanarak bir medya dosyasını açmak için aşağıdaki kod parçacığında gösterilene benzer bir mantık kullanın:
// ParcelFileDescriptor kullanarak belli bir medya öğesini açın.
procedure DosyaAc_FileDescriptor(Uri : JNet_Uri);
var
pfd : JParcelFileDescriptor;
readOnlyMode : JString;
resolver : JContentResolver;
begin
resolver := TAndroidHelper.Context.getContentResolver;
// "r" salt okunur, "rw" oku-yaz
// "rwt" mevcut dosya muhteviyatını kısaltma ve üzerine yazma.
readOnlyMode := stringtoJString('r');
try
pfd := resolver.openFileDescriptor(Uri, readOnlyMode);
// "pfd" üzerinde işlemler yapın.
Memo1.Lines.Add(jstringtostring( pfd.toString));
except
on E: Exception do
Application.ShowException(E);
end;
end;
Dosya akışı / File stream Dosya akışı kullanarak bir medya dosyasını açmak için aşağıdaki kod parçacığında gösterilene benzer bir mantık kullanın:
// InputStream kullanarak belli bir medya öğesi açın.
procedure DosyaAc_FileStream(Uri : JNet_Uri);
var
jis: JInputStream;
resolver : JContentResolver;
begin
resolver := TAndroidHelper.Context.getContentResolver;
try
jis := resolver.openInputStream(Uri);
// "jis" üzerinde işlemler yapın.
Memo1.Lines.Add(jstringtostring( jis.toString));
except
on E: Exception do
Application.ShowException(E);
end;
end;
Direk dosya dizinleri / paths Uygulamanızın üçüncü taraf medya kitaplıklarıyla daha sorunsuz çalışmasına yardımcı olmak için Android 11 (API düzeyi 30) ve sonraki sürümleri MediaStore, paylaşılan depolama alanından medya dosyalarına erişmek için API dışındaki API'leri kullanmanıza olanak tanır. Bunun yerine, aşağıdaki API'lerden birini kullanarak medya dosyalarına doğrudan erişebilirsiniz: • File API. • Yerel kütüphaneler, örneğin fopen. Eğer herhangi bir depolama ilgili izinleri yoksa, uygulamaya özgü dizine yanı sıra uygulamanıza atfedilir medya dosyaları kendi içinde dosyalara FileAPI kullanarak erişebilir Uygulamanız FileAPI'yi kullanarak bir dosyaya erişmeye çalışırsa ve gerekli izinlere sahip değilse, bir FileNotFoundException oluşur. Android'i 10 (API seviyesi 29) çalışan bir cihazda erişim Paylaşılan depolama diğer dosyaları için, uygulamanızın manifest dosyasında geçici kapsamına sahip depolama çıkma amacıyla requestLegacyExternalStorage için true ayarı önerilir. Android 10'da yerel dosya yöntemlerini kullanarak medya dosyalarına erişmek için ayrıca READ_EXTERNAL_STORAGE izin istemeniz gerekir. Medya içeriğine ulaşırken dikkat edilecekler Medya içeriğine erişirken, aşağıdaki bölümlerde ele alınan hususları aklınızda bulundurun. Önbellek verisi / Cached data Uygulamanız URI'leri veya medya deposundaki verileri önbelleğe alıyorsa, medya deposunda güncelleme olup olmadığını düzenli olarak kontrol edin. Bu kontrol, uygulama tarafında, önbelleğe alınmış verilerinizin sistem tarafında, sağlayıcı verileriyle senkronize kalmasını sağlar. Performans Doğrudan dosya yollarını kullanarak medya dosyalarının sıralı okumalarını gerçekleştirdiğinizde, performans MediaStore API'nin performansıyla karşılaştırılabilir. Ancak, doğrudan dosya yollarını kullanarak medya dosyalarının rastgele okuma ve yazma işlemlerini gerçekleştirdiğinizde, işlem iki kata kadar daha yavaş olabilir. Bu durumlarda, bunun yerine MediaStore API'yi kullanmanızı öneririz. Veri sütunu / DATA column Mevcut bir medya dosyasına eriştiğinizde DATA, mantığınızdaki sütunun değerini kullanabilirsiniz. Bunun nedeni, bu değerin geçerli bir dosya yoluna sahip olmasıdır. Ancak, dosyanın her zaman kullanılabilir olduğunu varsaymayın. Oluşabilecek dosya tabanlı G/Ç hatalarını işlemeye hazır olun. Öte yandan bir medya dosyası oluşturmak veya güncellemek için DATA sütunun değerini kullanmayın. Bunun yerine DISPLAY_NAMEve RELATIVE_PATH sütunlarının değerlerini kullanın. Depolama sürücüleri Android 10 veya sonraki sürümleri hedefleyen uygulamalar, sistemin her bir harici depolama birimine atadığı benzersiz ada erişebilir. Bu adlandırma sistemi, içeriği verimli bir şekilde düzenlemenize ve dizine eklemenize yardımcı olur ve yeni medya dosyalarının nerede saklandığını kontrol etmenizi sağlar. Aşağıdaki hacimlerin akılda tutulması özellikle yararlıdır: • VOLUME_EXTERNAL Hacim, cihazdaki tüm paylaşılan depolama hacimlerinin bir görünüm sağlar. Bu sentetik cildin içeriğini okuyabilirsiniz, ancak içeriği değiştiremezsiniz. • VOLUME_EXTERNAL_PRIMARY Hacim cihazında, birincil ortak depolama hacmi temsil eder. Bu cildin içeriğini okuyabilir ve değiştirebilirsiniz. MediaStore.getExternalVolumeNames ile diğer sürücüleri keşfedebilirsiniz: // Java kodu eksik Delphi kütüphaneleri sebebi ile çevirilemedi Medyanın yakalandığı konum Bazı fotoğraflar ve videolar, meta verilerinde bir fotoğrafın çekildiği veya bir videonun kaydedildiği yeri gösteren konum bilgileri içerir. Uygulamanızda bu konum bilgilerine erişmek için fotoğraf konum bilgileri için bir API ve video konum bilgileri için başka bir API kullanın. Fotoğraflar Uygulamanız kapsamlı depolama kullanıyorsa sistem varsayılan olarak konum bilgilerini gizler. Bu bilgilere erişmek için aşağıdaki adımları tamamlayın:
MediaStore (SDK seviyesi 29 ve sonrasında geçerli olan) setRequireOriginal nesnesi ile arayarak fotoğrafın tam baytları almak ve aşağıdaki kod parçacığında gösterildiği gibi, fotoğrafın URI’sine geçmek için:
// Java kodu. Delphi 11 & sdk 29 gerekli. Videolar Bir videonun meta verisindeki konumbilgilerine erişmek MediaMetadataRetriever için aşağıdaki kod parçacığında gösterildiği gibi sınıfı kullanın. Uygulamanızın bu sınıfı kullanmak için herhangi bir ek izin istemesi gerekmez. // Java kodu eksik Delphi kütüphaneleri sebebi ile çevirilemedi Paylaşma Bazı uygulamalar, kullanıcıların medya dosyalarını birbirleriyle paylaşmalarına izin verir. Örneğin, sosyal medya uygulamaları, kullanıcılara fotoğrafları ve videoları arkadaşlarıyla paylaşma olanağı verir. Medya dosyalarını paylaşmak için içerik sağlayıcı oluşturma kılavuzunda önerildiği gibi bir content:// URI kullanınız. Medya dosyalarının uygulama nitelikleri Kapsamlı depolama Android 10 veya üstü hedeflendiğinde, sistem o bir uygulaması için etkin olup nitelikleri herhangi bir depolama izin istediniz henüz zaman uygulamanızın erişebilmesi dosyaları belirler her medya dosyasına bir uygulamayı. Her dosya yalnızca bir uygulamaya atfedilebilir. Bu nedenle, uygulamanız fotoğraflar, videolar veya ses dosyaları medya koleksiyonunda depolanan bir medya dosyası oluşturursa uygulamanızın dosyaya erişimi olur. Ancak kullanıcı uygulamanızı kaldırır ve yeniden yüklerse, READ_EXTERNAL_STORAGE uygulamanızın orijinal olarak oluşturduğu dosyalara erişmek için istekte bulunmanız gerekir. Bu izin isteği, sistem dosyanın yeni yüklenen sürümden ziyade uygulamanın önceden yüklenen sürümüyle ilişkilendirildiğini düşündüğü için gereklidir. Öğe ekleme Mevcut bir koleksiyona medya öğesi eklemek için aşağıdakine benzer bir kod arayın. Bu kod parçacığı, VOLUME_EXTERNAL_PRIMARY Android 10 veya sonraki sürümleri çalıştıran cihazlarda birime erişir. Bunun nedeni, bu cihazlarda, depolama birimleri bölümünde açıklandığı gibi yalnızca birincil birimse bir birimin içeriğini değiştirebilmenizdir. // Java kodu eksik Delphi kütüphaneleri sebebi ile çevirilemedi Medya dosyaları bekleme durumunu yenileme Uygulamanız medya dosyalarına yazma gibi potansiyel olarak zaman alıcı işlemler gerçekleştiriyorsa, işlenirken dosyaya özel erişime sahip olmak yararlıdır. Android 10 veya sonraki sürümleri çalıştıran cihaz larda, uygulamanız, IS_PENDING bayrağın değerini 1 olarak ayarlayarak bu özel erişimi elde edebilir. Aşağıdaki kod parçacığı, önceki kod parçacığını temel alır. Aşağıdaki parça IS_PENDING, MediaStore.Audio koleksiyona karşılık gelen dizinde uzun bir şarkı saklarken bayrağın nasıl kullanılacağını gösterir: // Java kodu eksik Delphi kütüphaneleri sebebi ile çevirilemedi Dosya konumu için ipucu (hint) verme Uygulamanız medyayı Android 10 çalıştıran bir cihazda depoladığında, medya varsayılan olarak türüne göre düzenlenir. Örneğin, MediaStore.Images yeni görüntü dosyaları varsayılan olarak koleksiyona Environment.DIRECTORY_PICTURES karşılık gelen dizine yerleştirilir. Uygulamanız, Pictures/MyVacationPictures adlı bir fotoğraf albümü gibi dosyaların saklanması gereken belirli bir konumun farkındaysa MediaColumns.RELATIVE_PATH, sisteme yeni yazılan dosyaların nerede saklanacağı konusunda bir ipucu sağlayacak şekilde ayarlayabilirsiniz. Not: Genel amaçlı dosyaları, medya dışı dosyalar da dahil olmak üzere , Documents/klasörde veya klasörde depolamak mümkün olsa da, Download/bu kullanım durumları için Depolama Erişim Çerçevesini (SAF) kullanmak daha iyidir. Bir öğenin güncellenmesi Uygulamanızın sahip olduğu bir medya dosyasını güncellemek için aşağıdakine benzer bir kod çalıştırın: // Java kodu eksik Delphi kütüphaneleri sebebi ile çevirilemedi
Kapsamlı depolama kullanılamıyorsa veya etkinleştirilmediyse, önceki kod parçacığında gösterilen işlem, uygulamanızın sahip olmadığı dosyalar için de çalışır. Not: Bir arama sırasında MediaColumns.RELATIVE_PATH veya MediaColumns.DISPLAY_NAME öğesini update değiştirerek diskteki dosyaları taşıyabilirsiniz. Yerel kodun güncellenmesi
Medya dosyalarını yerel kitaplıkları kullanarak yazmanız gerekiyorsa, Java tabanlı veya Kotlin tabanlı kodunuzdan dosyanın ilişkili dosya tanımlayıcısını yerel kodunuza iletin.
Aşağıdaki kod parçacığı, bir medya nesnesinin dosya tanımlayıcısının uygulamanızın yerel koduna nasıl geçirileceğini gösterir: // Java kodu eksik Delphi kütüphaneleri sebebi ile çevirilemedi Başka uygulamaların medya dosyalarının güncellenmesi Uygulamanız kapsamlı depolama kullanıyorsa, normalde farklı bir uygulamanın medya deposuna katkıda bulunduğu bir medya dosyasını güncelleyemez. Ancak, RecoverableSecurityException platformun attığını yakalayarak dosyayı değiştirmek için kullanıcı onayını almak hala mümkündür. Ardından, aşağıdaki kod parçacığında gösterildiği gibi, kullanıcının uygulamanıza söz konusu öğeye yazma erişimi vermesini isteyebilirsiniz: // Java kodu eksik Delphi kütüphaneleri sebebi ile çevirilemedi
Uygulamanızın oluşturmadığı bir medya dosyasını değiştirmesi gerektiğinde bu işlemi tamamlayın. Alternatif olarak, uygulamanız Android 11 veya sonraki sürümlerde çalışıyorsa, kullanıcıların uygulamanıza bir grup medya dosyasına yazma erişimi vermesine izin verebilirsiniz. Medya dosyası gruplarınıncreateWriteRequest nasıl yönetileceği ile ilgili bölümde açıklandığı gibi yöntemi çağırın. Uygulamanız kapsamına sahip depolama kapsamında değildir başka kullanma vakasında varsa, bir özellik isteği dosya ve geçici kapsamına sahip depolama çıkma. Bir öğenin kaldırılması Uygulamanızın medya deposunda artık ihtiyaç duymadığı bir öğeyi kaldırmak için aşağıdaki kod parçacığında gösterilene benzer bir mantık kullanın: // Java kodu eksik Delphi kütüphaneleri sebebi ile çevirilemedi Kapsamlı depolama kullanılamıyorsa veya etkin değilse, diğer uygulamaların sahip olduğu dosyaları kaldırmak için önceki kod parçacığını kullanabilirsiniz. Kapsamlı depolama etkinleştirilirse, medya öğelerini güncelleme bölümünde açıklandığı gibi, uygulamanızın kaldırmak istediği her dosya için bir tane RecoverableSecurityException yakalamanız gerekir. Uygulamanız Android 11 veya sonraki sürümlerde çalışıyorsa, kullanıcıların kaldırılacak bir medya dosyası grubu seçmesine izin verebilirsiniz. Medya dosyası gruplarının nasıl yönetileceği ile ilgili bölümde açıklandığı gibi createTrashRequest veya createDeleteRequest yöntemini çağırın. Uygulamanız kapsamına sahip depolama kapsamında değildir başka kullanma vakasında varsa, bir özellik isteği dosya ve geçici kapsamına sahip depolama çıkma. Medya dosyalarındaki değişikliklerin tespiti Uygulamanızın, önceki bir zamana kıyasla, uygulamaların eklediği veya değiştirdiği medya dosyalarını içeren depolama birimlerini tanımlaması gerekebilir. Bu değişiklikleri en güvenilir şekilde algılamak için ilgili depolama hacmini getGeneration ile kontrol edilir. Media store sürümü değişmediği sürece bu yöntemin dönüş değeri monoton olarak zamanla artar. Özelli kle DATE_ADDEDDATE_MODIFIED setLastModified ve getGeneration gibi medya sütunlarındaki tarihlerden daha sağlamdır. Bunun nedeni, bir uygulama aradığında veya kullanıcı sistem saatini değiştirdiğinde bu medya sütunu değerlerinin değişebilmesidir. Dikkat: getGenerationgüncellemeler için medya deposu denetimi. Medya deposu sürümü değiştiyse, tam bir senkronizasyon geçişi gerçekleştirin. Medya dosya grupları yönetimi Android 11 ve sonraki sürümlerde, kullanıcıdan bir grup medya dosyası seçmesini isteyebilir, ardından bu medya dosyalarını tek bir işlemle güncelleyebilirsiniz. Bu yöntemler, cihazlar arasında daha iyi tutarlılık sunar ve yöntemler, kullanıcıların medya koleksiyonlarını yönetmesini kolaylaştırır. Bu "toplu güncelleme" işlevini sağlayan yöntemler şunları içerir: createWriteRequest Kullanıcının, uygulamanıza belirtilen medya dosyaları grubuna yazma erişimi vermesini isteyin. createFavoriteRequest Kullanıcının belirtilen medya dosyalarını cihazda "favori" ortamlarından bazıları olarak işaretlemesini isteyin. Bu dosyaya okuma erişimi olan herhangi bir uygulama, kullanıcının dosyayı "favori" olarak işaretlediğini görebilir. createTrashRequest Kullanıcıdan, belirtilen medya dosyalarını cihazın çöp kutusuna yerleştirmesini isteyin. Çöp kutusundaki öğeler, sistem tarafından tanımlanan bir süre sonunda kalıcı olarak silinir. Not: Uygulamanız, cihaz OEM'inin önceden yüklenmiş galeri uygulamasıysa, bir iletişim kutusu göstermeden dosyaları çöp kutusuna yerleştirebilirsiniz. Bunu yapmak IS_TRASHED için doğrudan ayarlayın. createDeleteRequest Kullanıcıdan belirtilen medya dosyalarını önceden çöp kutusuna atmadan kalıcı olarak silmesini isteyin. Bu yöntemlerden herhangi birini çağırdıktan sonra sistem bir PendingIntent nesne oluşturur. Uygulamanız bu niyetini çağırdıktan sonra, kullanıcılar uygulamanızın belirtilen medya dosyalarını güncellemesi veya silmesi için onaylarını isteyen bir iletişim kutusu görür. Örneğin, createWriteRequest ile bir çağrının nasıl yapılandırılacağı aşağıda açıklanmıştır: // Java kodu eksik Delphi kütüphaneleri sebebi ile çevirilemedi Kullanıcının yanıtını değerlendirin. Kullanıcı onay verdiyse, medya işlemine devam edin. Aksi takdirde, kullanıcıya uygulamanızın neden izne ihtiyacı olduğunu açıklayın: procedure TForm1.OnActivityResult(RequestCode, ResultCode: Integer; ... Yine aynıgenel tasarım createFavoriteRequest, createTrashRequest ve createDeleteRequest kullanabilir. Medya yönetim izni Kullanıcılar, medya dosyalarında sık düzenlemeler yapmak gibi medya yönetimini gerçekleştirmek için belirli bir uygulamaya güvenebilir. Uygulamanız Android 11 veya sonraki bir sürümü hedefliyorsa ve cihazın varsayılan galeri uygulaması değilse, uygulamanız bir dosyayı her değiştirmeye veya silmeye çalıştığında kullanıcıya bir onay iletişim kutusu göstermelisiniz. Uygulamanız Android 12 (API düzeyi 31) veya sonraki bir sürümünü hedefliyorsa, kullanıcılardan Medya yönetimi özel iznine uygulamanıza erişim vermesini isteyebilirsiniz. Bu izin, uygulamanızın her dosya işlemi için kullanıcıdan bilgi istemesine gerek kalmadan aşağıdakilerin her birini yapmasına olanak tanır: ·createWriteRequest kullanarak dosyaları değiştirin. ·createTrashRequest kullanarak dosyaları çöp kutusuna ve çöp kutusundan taşıyın. ·createDeleteRequest kullanarak dosyaları silin. Bunu yapmak için aşağıdaki adımları tamamlayın: 1.Uygulamanızın bildirim dosyasındaki MANAGE_MEDIA izni ve READ_EXTERNAL_STORAGE iznini bildirin. createWriteRequest onay diyaloğu göstermeden aramak için ACCESS_MEDIA_LOCATION iznini de bildirin. 2.Uygulamanızda, uygulamanıza neden medya yönetimi erişimi vermek isteyebileceklerini açıklamak için kullanıcıya bir kullanıcı arayüzü gösterin. 3.ACTION_REQUEST_MANAGE_MEDIA intent niyet eylemini çağırın. Bu, kullanıcıları sistem ayarlarında Medya yönetimi uygulamaları ekranına götürür. Buradan, kullanıcılar özel uygulamaya erişim izni verebilir. Medya deposuna alternatif gerektiren olayları kullanın Uygulamanız öncelikle aşağıdaki rollerden birini gerçekleştiriyorsa MediaStore API'lere alternatif düşünebilirsiniz: Diğer dosya türleri ile çalışın Uygulamanız, EPUB veya PDF dosya uzantısını kullanan dosyalar gibi yalnızca medya içeriği içermeyen belgeler ve dosyalarla çalışıyorsa, belgelerin ve diğer dosyaların ACTION_OPEN_DOCUMENT ile nasıl depolanacağı ve bunlara nasıl erişileceğiyle ilgili kılavuzda açıklandığı gibi intent eylemini kullanın. Tamamlayıcı uygulamalarda dosya paylaşımı Bir mesajlaşma uygulaması ve bir profil uygulaması gibi bir tamamlayıcı uygulama paketi sağladığınız durumlarda, content:// URI'leri kullanarak dosya paylaşımını ayarlayın. Ayrıca bu iş akışını en iyi güvenlik uygulaması olarak öneriyoruz. https://developer.android.com/training/d...ared/media Güncel Delphi - Android Dosya Kayıt Bilgileri
Standart RTL Android Dizin Fonksiyonları Fonksiyon * Android Hafızası (Java) Android Klasörü TPath.GetDocumentsPathGetFilesDir -> Dahili Hafıza /data/data/<application ID>/files TPath.GetCachePathGetCacheDir -> Dahili Hafıza /data/data/<application ID>/cache TPath.GetLibraryPathGetLibraryPath /data/app-lib/<application ID>-1 TPath.GetPublicPathGetExternalFilesDir -> Harici /storage/emulated/0/Android/data/<application ID>/files TPath.GetTempPathGetExternalFilesDir+'/tmp/' /storage/emulated/0/Android/data/<application ID>/files/tmp TPath.GetPicturesPathGetExternalPicturesDir -> Harici Hafıza /storage/emulated/0/Android/data/<application ID>/files/Pictures TPath.GetCameraPathGetExternalCameraDir -> Harici Hafıza /storage/emulated/0/Android/data/<application ID>/files/DCIM TPath.GetMusicPathGetExternalMusicDir -> Harici Hafıza /storage/emulated/0/Android/data/<application ID>/files/Music TPath.GetMoviesPathGetExternalMoviesDir -> Harici Hafıza /storage/emulated/0/Android/data/<application ID>/files/Movies TPath.GetAlarmsPathGetExternalAlarmsDir -> Harici Hafıza /storage/emulated/0/Android/data/<application ID>/files/Alarms TPath.GetRingtonesPath GetExternalRingtonesDir -> Harici Hafıza /storage/emulated/0/Android/data/<application ID>/files/Ringtones TPath.GetDownloadsPathGetExternalDownloadsDir -> Harici Hafıza /storage/emulated/0/Android/data/<application ID>/files/Download TPath.GetSharedDocumentsPath**GetExternalFilesDir -> Harici Hafıza /storage/emulated/0/Documents TPath.GetSharedDownloadsPathGetSharedDownloadsDir -> Paylaşılan Harici Hafıza /storage/emulated/0/Download TPath.GetSharedCameraPathGetSharedCameraDir -> Paylaşılan Harici Hafıza /storage/emulated/0/DCIM TPath.GetSharedAlarmsPathGetSharedAlarmsDir -> Paylaşılan Harici Hafıza /storage/emulated/0/Alarms TPath.GetSharedPicturesPathGetSharedPicturesDir -> Paylaşılan Harici Hafıza /storage/emulated/0/Pictures TPath.GetSharedMusicPathGetSharedMusicDir -> Paylaşılan Harici Hafıza /storage/emulated/0/Music TPath.GetSharedMoviesPathGetSharedMoviesDir -> Paylaşılan Harici Hafıza /storage/emulated/0/Movies TPath.GetSharedRingTonesPathGetSharedRingtonesDir -> Paylaşılan Harici Hafıza /storage/emulated/0/Ringtones
* System.SysUtils.pas ile birlikte gelen “GetHomePath” fonksiyonu, “TPath.GetDocumentsPath”ile aynı sonuç olan uygulama klasörünü (GetFilesDir -> Dahili Hafıza) vermektedir.
** TPath.GetSharedDocumentsPath : Cihazda fazladan harici bir depolama yeri daha (mesela SD kart) varsa, bu dizin bu harici depolama içindeki klasör adını vermektedir. Yoksa, cihaz depolaması içindeki herhangi bir yeri (/storage/emulated/0/Documents) vermektedir. https://docwiki.embarcadero.com/RADStudi..._Platforms
Android Sürümlerinde Dosya Kayıt Depolama Değişiklikleri
┌──┬──┬───┬──────┬──────────────────────────────────────────────┐
| # | Kod|SDK | Yayın | Değişiklik |
├──┼──┼───┼──────┼──────────────────────────────────────────────┤
| 1 | - | 1 | 23.09.08 | Intent, System picker (Action_*) ilk sürüm içinde başladı |
| 4.4 | K | 19 | 31.10.13 | FileProvider (Content API), DocumentsContract, DocumentProvider sınıfları |
| 7 | N | 25 | 04.10.16 | FileProvider kullanmak mecburi (Bu sürümü hedefleyince) |
| 8 | O | 26 | 21.03.17 | Ağustos 2018’de Google Play Store’da hedef sürüm 8.0 yayın şartı |
| 10 | Q | 29 | 03.09.19 | Kapsamlı depolama (scoped storage). Gizlilik ve güvenlik artırıldı |
| 11 | R | 30 | 09.09.20 | Ağustos 2021’de Android API 30 hedefleme (Google Play Store yayın şartı) |
└──┴──┴───┴──────┴──────────────────────────────────────────────┘
Android 4.3 ve öncesinde, uygulamanızdan başka bir uygulamanın dosyasına ulaşmak için, ACTION_PICK ya da ACTION_GET_CONTENT gibi bir intent çağırmanız ve kullanıcının mevcut bir dosyayı seçmesi için de bir arabirim gerekiyordu.
Android 4.4 (API seviyesi 19) ve üstünde, ilave bir seçenek olarak ACTION_OPEN_DOCUMENT niyetine sahipsiniz ki bu da mevcut tüm dosyaları listeleyen sistem kontrollü seçici arabirimini göstermektedir.
Android 5.0 (API seviyesi 21) ve üstünde, ACTION_OPEN_DOCUMENT_TREE niyeti tüm dizinleri gösteren arabirime ulaşmanızı sağlamaktadır. https://developer.android.com/guide/topi...t-provider
Delphi sürümlerinde Android Desteği
RAD Studio Delphi’nin Android 10’u destekleyen sürümlerden itibaren Android Java kütüphanelerinde (Androidapi.JNI.GraphicsContentViewText, Androidapi.IOUtils, Androidapi.JNI.Media, Androidapi.JNI.Provider, Androidapi.JNI.App, Androidapi.Helpers, Androidapi.JNI.JavaTypes, Androidapi.JNI.Net, Androidapi.JNI.Os, Androidapi.JNI.Provider) Kapsamlı depolama, SAF ve MediaStore komutları da XE8’den itibaren RAD Studio beraberinde sağlanmakta.
Delphi Android ─────────────── XE5 2.33 – 4.4 10 Seattle 4.03 – 5 10.1 Berlin 4.03 – 7 10.2 Tokyo 4.1 – 8 10.3 Rio 5.1 – 10 10.4 Sydney 6 – 11 11 Alexandria 8.1 – 11
RAD Studio 11.0 Alexandria ile Android 30 API desteği (Google Play Store’un 2021 şartı) yerleşik olarak gelmektedir.
Uygulamada Kapsamlı Depolama
İkaz:Android cihazlarda Dosya yöneticisi (Dosyalarım vs.) altında depolama dizinlerini Dahili depolama, SD kart, Ağ deplaması olarak gösteriyor. Halbuki bizim yüklediğimiz, cihazda çalışan uygulamalar depolamaları böyle algılamıyor. Uygulamalarımıza göre Dahili Depolama kum havuzu (sandbox) koruması altında olan, Dosya yöneticisi ve diğer uygulamalar tarafından görülemeyen klasörlerdir. Harici Depolama da uygulamamızın klasörleri dışında olan Paylaşılan Harici klasörlerdir. Dolayısıyla aşağıdaki açıklamalarda Dosya yöneticisi ve uygulamalarımız için Dahili ve Harici Depolama kavramlarını karıştırmayıp, uygulama açısından anlaşılmalıdır.
Dahili depolama için Android 11’de de fark yok. Android 10 ve öncesinde olduğu gibi, aynı şekilde dosyalara ulaşmak sınırsız. Yine izin gerekmiyor.
Dosya paylaşma aynı şekilde, yani yine Content API (FileProvider) ve “Intent.setAction(TJIntent.JavaClass.ACTION_SEND);” niyeti ile çağırma şekli devam etmekte. FileProvider için Delphi 10.3 Rio’dan itibaren yerleşik gelen Project Options->Application->Entitlement List kısmındaki "Secure File Sharing" seçeneğini işaretlemeli, 10.3 önceki sürümlerinde ise Android’de Dosya Depolama ve Paylaşma > “Dosya paylaşımı için FileProvider kullanma” altında anlatıldığı şekilde ilave edilerek bu API kullanmaya devam edilmelidir.
Android’de Dosya Depolama ve Paylaşma bulunan örnek projedeki (Android 10 SDK 29 veya altı hedeflendiğinde) çalışan harici depolama komutları, ör: “Memo1.Lines.SaveToFile(TPath.Combine(TPath.GetSharedDownloadsPath, 'memo1Harici.txt'));” Android 11 SDK 30’u hedeflendiği anda, aynı uygulamada “Cannot create file “(storage/emulated/0/Download/memo1Harici.txt”. Permission denied” hatası veriyor. “DeleteFile” komutu İndirilenler / GetSharedDownloadsPath altındaki dosyaları silmiyor. Bu durum sadece “Download” değil tüm Paylaşılan Harici klasörler için geçerli. Buların sebebi, yukarıdaki konularda bahsedildiği gibi, Android 11 kısıtlamaları.
Android 10 öncesi ile Android 11 ile mecburi olan Kapsamlı Depolama sonrasındaki dosya kayıt depolama değişiklikleri ve güncel durum:
“requestLegacyExternalStorage” Kapsamlı Depolamadan çıkarılmış olup artık ulaşmak isteyen uygulamalar G.P.Store’da reddediliyor. Uygulamanızı yayınlamak istiyorsanız AndroidManifest.template.xml’de şu değişikliği yapınız:
android:requestLegacyExternalStorage="false">
All Files Access API (ACTION_MANAGE_STORAGE), Google Play Store tarafından reddediliyor, ama bu izin varsa (ve uygulama yayınlanmayacaksa) Android 11 öncesinde olduğu gibi dosya okuyup kaydedebiliyor. Buna ihtiyaç duyarsanız “AndroidManifest.template.xml” altına <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> ekleyip, çalışma zamanında da “ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION” izni isteyip ACTION_MANAGE_STORAGE intentini çağırmanız gerekiyor.
Paylaşmalı Veritabanları / Databases BlobStoreManager API sadece Android 11 SDK 30 ve üstünde çalışıp, Android 10 ve önceki sürümlerde çalışmamakta, bugün için çok az cihaz desteklediği için incelemeye alınmadı.
Paylaşmalı (harici) depolamaya SAF ve MediaStore ile ulaşma:
Şekil 1 Android Depolama sürüm 10 öncesi ve üstü
URI Alma: Yukarıdaki eğitim kodlarından sadece ilk üçü olan Kullanma Vakaları örnekleri, hem dosya Uri’lerini hem de bunlara ulaşma izni almaktadır. OnActivityResult ile bunların eylemleri yakalanarak harici dosya URI’lerine ulaşma tanıtılmaktadır.
Diğer örneklerin tümü ise bu 3 kullanma vakaları eylemleri ile elde edilen URI’ler ile nasıl işlem yapılacağını anlatmakta. Dosya Uri’sini bilmiyorsanız bunları kullanamıyorsunuz.
Ayrıca eski ACTION_GET_CONTENT niyeti de, ACTION_OPEN_DOCUMENT’in benzeri şekilde, Sistem Seçiciyi çağırıp Uri almak için kullanılabilmektedir; fakat kalıcı ulaşma izni sağlamamaktadır.
MediaStore.Files ile de medya depolamasındaki dosyaların Uri’si alınabilmektedir, fakat “Medya mağazasında ayrıca MediaStore.Files içeriği, uygulamanızın Android 10 veya sonraki sürümleri hedefleyen uygulamalarda bulunan kapsamlı depolama kullanıp kullanmadığına bağlıdır” ibaresinden dolayı bu konu muhteviyatına alınmadı. MediaStore.Downloads ve getMediaUri sınıfları da yine harici depolama dosya Uri’lerine ulaşmayı sağlasa da yalnızca SDK 29 ve üstü destek vermektedir.
Eğer vaka kullanmadan, direk olarak bildiğiniz bir dosya Uri’sini (ör: content://com.android.providers.downloads.documents/documents/16874) herhangi kodla dosya üzerinde işlem yapmak isterseniz, “java.lang.SecurityException: Permission Denial: reading ... requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs” hata iletisi alıp, dosyaya ulaşamıyorsunuz.
Özet olarak, Kapsamlı Depolamada harici depolama dosya kayıt uygulamaları, Uri darboğazında. Üstelik SDK 29 öncesi eski sürümleri kullanan piyasadaki Android cihazların tamamını kapsamak istiyorsanız, SAF kullanma vakaları kullanmak zorundasınız, bunların dışında çıkış yolu yok. Android Developer konferans, video, duyurularında Kapsamlı Depolamaya geçme amaçlarının gereksiz izinlerini kaldırmak olduğunu iddia ediyorlar, fakat gerçekte geliştiricileri ve kullanıcılar açısından tam tersi bir durum gerçekleşmiş durumda.
Örnek kodlar (SAF eğitim konusundakilerin tümü ve MediaStore konusundakilerin çoğu) SDK seviyesi 1-24 arasında olup, Delphi 10.x sürümleri tarafından desteklenmektedir.
SDK seviyeleri 29 ve 30 olan MediaStore’daki “Downloads”, “getMediaUri” sınıfları, Dosya küçük resimleri (thumbnails) yükleme > loadThumbnail, Mevcut bir koleksiyona medya öğesi eklemek / Add an item > VOLUME_EXTERNAL_PRIMARY, Medya dosyaları bekleme durumunu yenileme / Toggle pending status for media files > IS_PENDING flag, Başka uygulamaların medya dosyalarının güncellenmesi / Update other apps' media files > RecoverableSecurityException, - Medya dosya gruplarını yönetin / Manage groups of media files > createWriteRequest createTrashRequest createFavoriteRequest” için Delphi 11 gereklidir.
Dosya paylaşma için, harici klasörde ise yine önce önce Uri alıp, dahili klasöre kopyalamalısınız. Kopyalamak için de Akış (JInputStream, JFileOutputStream) komutlarını kullanmanız gerekmektedir. SAF ile alınmış Uri varsa Harici depolamada; yeni dosya açma, okuma, kaydetme, kopyalama amaçları için kullanabilirsiniz. Akışlar Sistem Dosya Seçiciyi açmaz.
Harici Depolama İçin Yürürlükten Kalkanlar:
// HariciDosya := TPath.Combine(TPath.GetSharedDownloadsPath,'delphican.txt');
Memo1.Lines.SaveToFile(HariciDosya);
TFile.Copy(DahiliDosya, HariciDosya);
DeleteFile(HariciDosya);
Uri := TJnet_Uri.JavaClass.fromFile(TJFile.JavaClass.init(StringToJString(HariciDosya)));
Uri := TJnet_Uri.JavaClass.parse(StringToJString('file:///' + HariciDosya));
JinputStream1 := TJFileInputStream.JavaClass.init(StringToJString(HariciDosya));
Uri := TJFileProvider.JavaClass.getUriForFile(TAndroidHelper.Context,
LAuthority, TJFile.JavaClass.init(StringToJString(HariciDosya)));
Intent := TJFileProvider.JavaClass.getUriForFile(TJnet_Uri.JavaClass.fromFile
(TJFile.JavaClass.init(StringToJString(HariciDosya))));
Uri := TAndroidHelper.JFileToJURI (TJFile.JavaClass.init(StringToJString(dosya)));
Uri := TJFileProvider.JavaClass.getUriForFile(Context, LAuthority, AFile);
Özetle tüm File, Content, FileProvider eylem ve niyetleri ile Harici dizinlere (scoped / depreciated) ulaşılamıyor.
(Not: ACTION_OPEN_DOCUMENT_TREE ile dosyanın bulunduğu dizine ulaşma izni alınırsa, bu komutlarla ulaşılabilir, fakat bu niyet Delphi 10’da çalışmadığı için denenemedi.)
Depolama Erişimi Çerçevesi / Storage Access Framework SAF kullanmak için Project -> Uses Permissions altından herhangi bir İzin gerekmemektedir, hepsi kapatılabilir. Proje içinden de “PermissionsService.RequestPermissions” vs. ile herhangi bir İzin çağrılmadan kullanılabilir. Örnek projedeki tüm izinler kapatılmıştır.
SAF ile dosyalara ulaşmak için sadece Kullanma Vakaları (ACTION_CREATE_DOCUMENT, ACTION_OPEN_DOCUMENT, ACTION_OPEN_DOCUMENT_TREE) niyetlerini çağırmak kâfidir. Yalnız bunların herbiri, eski TFile.Copy’den farklı olarak, Sistem Seçici / System Picker arabirimini açmaktadır.
ACTION _CREATE_DOCUMENT farklı kaydet benzeri bir arabirim ile yeni dosya kaydetmek için, ACTION_OPEN_DOCUMENT ise mevcut dosyaları açıp, göstermek, değiştirmek için kullanılır. ACTION_OPEN_DOCUMENT_TREE sadece dizinlere değil altındaki tüm dosyalara da ulaşma amaçlıdır.
SAF kullanırken AndroidManifest.template.xml içinde intent-filter kısmı Delphi ile hazır halde geliyor, başka niyet eklemeye lüzum yok.
SAF Durum Vakaları; tüm Delphi 10 sürümleri ile yerleşik geldiği için, SDK 30’u hedefleyen Delphi projelerinde sadece gerekli Android kütüphaneleri ve örnek kodlar ile çağırılarak, hemen kullanılabilir durumdadır.
Medya deposu / MediaStore ile ses, görüntü, video dosyalarına ve sürüm 11 üstünde İndirilenlere yazma sınırlandırılmamıştır: Ör. Resmi izinsiz olarak kaydedebilirsiniz.
Media kolleksiyonları sadece İzin ile okunabilir.
Görüntü konum verisi için ACCESS_MEDIA_LOCATION gereklidir.
PDF, metin, vb. dosyalara ulaşmak “Sistem Seçici” System Picker ile mümkündür.
Kolleksiyon dışında okuma yazma için “Sistem Seçici” gereklidir.
Project -> Uses Permissions altında WRITE_EXTERNAL_STORAGE seçeneği SDK 29 üstünde kapatılmalıdır. READ_EXTERNAL_STORAGE okuma için gereklidir.
MediaStore Uri sınıfları, SDK 29 üstündeki dosyalara ulaşma amacıyla için çıkarıldığı için, Delphi 11 öncesi kütüphanelerinde mevcut değil. Dolayısıyla yukarıdaki MediaStore eğitim kodlarının çoğu sadece Java’dan Object Pascal’a aktarılamadı.
Çalışma zamanında da cihazın SDK seviyesine bakılarak, (SDK<28) yazma izni istenmeli veya (SDK>=29) için istenmemelidir.
MediaStore’da da harici depolamada okuma izni gerekiyor, yazma izni gerekmiyor. Android 10 öncesi sürümlerle uyumluluk için Project -> Uses Permissions altında WRITE_EXTERNAL_STORAGE seçeneğini kaldırıp, Manifest’te şunu ekleyiniz:
Dosya kopyalama artık harici depolamadan tek komutla (TFile.Copy) gerçekleştirilemiyor. Önce Kullanma Vaka (ACTION_OPEN_DOCUMENT veya ACTION_CREATE_DOCUMENT) niyetini çağırıyoruz. Sonra “IletiFaaliyetiYakala” ve “OnActivityResult” ile talep kodunu yakalıyoruz. En son Uri ve akışlar (JInputStream, JFileOutputStream) ile yeni açtığımız dosyaya yazıyoruz.
Örnek proje içerisindeki bazı kısımlar çalışmayabilir. Delphi ve Android sürümleri ile bildirilirse ileride güncellenebilir. Hepimize faydalı olması dileği ile..
güzel bir çalışma olmuş, bende cameradan resim çekme için ihtiyaca oldu, delphi demo olan sistem ile devam etmiştim. yeni sisteme için iyi bir kayak sağlamışsınız
var
Intent: JIntent;
begin
Intent := TJIntent.Create;
Intent.setAction(TJIntent.JavaClass.ACTION_OPEN_DOCUMENT); // ACTION_GET_CONTENT);
Intent.addCategory(TJIntent.JavaClass.CATEGORY_OPENABLE);
Intent.setType(StringToJString('*/*'));
TAndroidHelper.Activity.startActivityForResult(Intent, 77);
End;
procedure OnActivityResult(RequestCode, ResultCode: Integer;
Data: JIntent);
var
Uri: JNet_Uri;
Ad: string;
AItem: TSkinListViewItem;
UriString: JString;
begin
if ResultCode = TJActivity.JavaClass.RESULT_OK then
begin
Uri := nil;
ad:='';
if Assigned(Data) then
begin
if (Data = nil) then
begin
exit;
end;
Uri := Data.getData;
Ad := jstringtostring(Uri.getPath);// gerçek dosya adı
if RequestCode = 77 then
begin
// kayıt
end;
end;
end;
end;
Android de seçtiğim dosyanın gerçek yolunu nasıl alabilirim. Uri.getPath ile "/document/primaryocuments/XXXXXX.pdf" diye bir yol çıkıyor sonra bu yolu kullanamıyorum.
Ben : /storage/emulated/0/Documents/xxxx.pdf olarak istiyorum.
Merhaba @elixir84
DosyaAdi fonksiyonunu değiştirin. Dosyanın gerçek yolunu "Documents/xxxx.pdf" şeklinde alacaksınız.
function TForm1.DosyaAdi(Uri: JNet_Uri): string;
var
C: JCursor;
I: integer;
begin
C := TAndroidHelper.Activity.getContentResolver.query(Uri, nil,
StringToJString(''), nil, StringToJString(''));
C.moveToFirst;
Result := '';
for I := 0 to C.getColumnCount - 1 do
begin
if JStringToString(C.getColumnName(I)) = 'document_id' then
begin
Result := JStringToString(C.getString(I));
Break;
end;
end;
Result := StringReplace(Result, 'primary:', '', [rfReplaceAll]);
end;