Konuyu Oyla:
  • Derecelendirme: 5/5 - 1 oy
  • 1
  • 2
  • 3
  • 4
  • 5
Android’de Dosya Depolama ve Paylaşma
#1
Android’de Dosya Depolama ve Paylaşma

Dosya kaydetme *
Android 2 çeşit depolamaya sahiptir: Dahili/varsayılan "Internal storage" ve harici depolama "External storage". İlk zamanlardan beri dahili depolama cihaz içinde ve harici de cihaz dışında olabildiği için, bugün de çok fazla bir fark yok. Sadece dahiliyi hariciden farkı kılan şey, izinler: Uygulamanız dahili için tüm izinlere sahip olup, buradaki dosyalar uygulamanıza aittir. Uygulamanızı kaldırırsanız, dahili depolamadaki dosyalarınız da birlikte silinecektir. Buna karşın harici depolama sizin izin vermenize ihtiyaç duyar ve dosyaları diğer uygulamalara da açıktır.

Dahili depolama
Dahili depolama için çok fazla söylecek bir şey yok: İstediğiniz gibi bu dosyalardan oluşturabilir, değiştirebilir ve silebilirsiniz. Kod ile dahili depolamaya ulaşmak için bu yolu kullanabilirsiniz:
TPath.GetDocumentsPath **

Harici depolama
Harici depolama kendi içinde 2 farklı tipe bölünebilir: Özel Private ve Genel Public harici depolama. Her ikisi de diğer uygulamalar için kullanıma açıktır; fakat kapsama alanı olarak özel dosyalar uygulamanıza kullandırılırken, genel dosyalar serbestçe paylaştırılır.
Harici depolamaya dosya kaydetmek için, şunları kullanabilirsiniz: NOT
GetPublicPath metodu biraz kafa karıştırıcı olabilir, zira özel Private harici depolama için kullanılır. Fakat yolu bu şekilde. Buradaki “public” ifadesi gerçekten de harici depolama içinde olan dosyalara işaret etmekte, ama genele açık harici depolama içinde olanlara değil.
Harici depolama için (Rad Studio yerine Xamarin’i hedef almasına rağmen, aynı muhteviyatı kullandığı için) buradan oldukça iyi bilgiler alabilirsiniz: https://docs.microsoft.com/en-us/xamarin/android/platform/files/external-storage
Ayrıca, dosyaları kaydebileceğiniz klasörler hakkında daha fazla bilgi için https://developer.android.com/training/data-storage/files inceleyebilirsiniz.

Harici depolama için izin alma
Harici depolamadan okuma veya yazma için, ilk olarak Android’den izin almalısınız. Eski Android sürümlerinde, manifest’e izinleri eklemek yeterliydi. Fakat Android 6 ve üstü için, kullanacağınız zamanlarda gerekli izinleri canlı olarak istemeniz gerekiyor.
Buradan ihtiyaç duyulabilecek izinleri bulabilirsiniz:
http://docwiki.embarcadero.com/RADStudio/Rio/en/Android_Permission_Model
Buradan da android izinleri hakkında daha fazla bilgi alabilirsiniz (yine Xamarin hedef alınmış olmasına rağmen kullanışlı): https://docs.microsoft.com/en-us/xamarin/android/app-fundamentals/permissions

Dosyaların paylaşılması
İki API hikayesi
Çok, çok uzun zamanlar önce Android’de dosya paylaşmanın yolu, dosyayı harici depolamaya kaydetmek ve sonra da dosyayı paylaşacak bir intent çağırmak idi. Bunun da pek çok sıkıntıları vardı, biri uygulama hem dosya paylaşırken ve bir yandan da uygulamayı zorla okuma/yazma harici depolama iznine sahip olmaya zorlamasıydı.
Bunu düzeltmek için, Android 4 (Ice Cream Sandwich) ve sonraki sürümlerden itibaren kullanılacak olan FileProvider sınıfını piyasaya sürdü.
Fakat FileProvider API’ye geçmek için fazla bir sebep yoktu, zira eski API sıkıntılarına rağmen hala çalışmaya devam etmekteydi.
Bu eski dosya paylaşma yolunu ortadan kaldıran Android 7 (Nougat) ile değişti: https://developer.android.com/about/versions/nougat/android-7.0-changes#perm
Şu anda da eski yolları değiştirmeye lüzum yok: Hala daha eski sürüm Android sürümlerini hedefliyorsanız, Android 7’de sıkıntısızca çalıştırabilirsiniz. Sadece yeni tutum doğrudan Android 7’yi hedefliyorsanız gerçekleşiyor.
NOT
Android sürümleri biraz karışık olabilir ve devam etmeden önce biraz açıklama yapmak faydalı olabilir.
Android’de hedef sürüm uygulamanızın kullanacağı minimum Android sürümü değildir. minSdkVersion tarafından verilen de minimum sürümdür. Halbuki hedef sürüm, uygulamanızın optimize edildiği****  sürümdür. Minimum sürüm olarak Android 4 sürümüne sahipken, aynı zamanda Android 7’yi hedef alabilirsiniz. Fakat Android 7’yi hedef alırsanız, Android 7 kuralları geçerli olacak ve dosya paylaşımının eski yolununu kullanan kodunuz da çalışmayacaktır. Eğer hedef olarak Android 4 alırsanız (ve minimum sürüm de Android 4 olursa), o zaman Android 7’de çalıştırsanız bile, Android 4 kuralları geçerli olur.
Bütün bunlar şu demek oluyor ki, Android 4’ü hedef alırsanız ve minimum SDK Android 4 ise, yeni Android 7 kurallarını dert etmek zorunda değilsiniz ve uygulamanız da Android 7’de çalışmaya devam eder. Eğer Android 7’yi hedef alırsanız, minimum desteklenen sürümünüz 4 olmasına rağmen, dosya paylaşımı için yeni yolu kullanmak zorundasınız.
Buradan Android sürümleri hakkında daha fazla bilgi alabilirsiniz: https://developer.android.com/guide/topics/manifest/uses-sdk-element?utm_campaign=adp_series_sdkversion_010616&utm_source=medium&utm_medium=blog#ApiLevels
Hikayemize geri dönecek olursak: Ağustos 2018’de tüm bunlar tekrar değişti. Google Play store’da yayına izin vermek için hedef sürüm olarak 8.0 veya üstünü istemeye başladı. Hedef olarak 8.0 seçtiğinizde (minimum sürüm daha düşük olsa bile), eski usul dosya paylaşımı Nougat ve üstü cihazlarda çalışmamaktadır. Eski hileler de artık işe yaramamaktadır ve bu da yeni sisteme geçmenin zamanı gelmiş demektir.

Dosya paylaşımı için FileProvider kullanma
Yeni usulde dosya paylaşma için FileProvider tanımlamanız gerekmektedir.
Muhteviyatı hakkında ayrıntılı bilgi almak için: https://developer.android.com/training/secure-file-sharing/
Bu bölümün kalanında da oluşturulan basit bir dosyanın paylaşımını inceleyeceğiz. Örnek için bkz: LangWars
1. adım - Fileprovider tanımlama
Bunu gerçekleştirmek için ihtiyacımız olan ilk şey  AndroidManifest.template.xml dosyasının değiştirilmesi ve bir provider eklemektir.
Projenizdeki AndroidManifest.template.xml dosyasını açın ve <application>  etiketinin altına <provider> ifadesini ilave edin:
   <application ...>
      ...
      <provider android:name="android.support.v4.content.FileProvider"
         android:grantUriPermissions="true"
         android:exported="false"
         android:authorities="%package%.fileprovider">
         <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_provider_paths" />
      </provider>
   </application>
ÖNEMLİ
Android manifest dosyasını elle değiştirdiğimiz için, Delphi’yi her seferinde güncellemeyi burada anlatıldığı şekilde güncellemeyi unutmuyoruz:
http://docwiki.embarcadero.com/RADStudio/Sydney/en/Preparing_an_Android_Application_for_Deployment#Re-creating_the_AndroidManifest.template.xml_File
2. adım - FileProvider'ın kullanacağı yolların tanımlanması
İlk adımda bir kaynak tanımlıyoruz:
Resource = "@xml/file_provider_paths"
Şimdi, provider’ın kullanacağı yolların hangileri olduğunu Android’e söyleyecek, bu kaynağı oluşturmamız gerekiyor. Bunun için, file_provider_paths.xml isimli bir dosya oluşturmamız gerekiyor. Bu örnekte bir "res" klasörüne koyacağız, fakat siz istediğiniz yere koyabilirsiniz.
 
Örneğimizde dahili hafızanın ana data klasörüne depolayacağız, ki onu da provider’daki yollara ekleyebilelim. file_provider_paths.xml dosyası:
<?xml version="1.0" encoding="utf-8" ?>
<paths>
  <files-path name="files" path="." />
</paths>
Eğer bir dosyayı harici depolama içindeki veya farklı bir yoldaki bir dosyayı paylaşacaksanız, burayı ona göre değiştirmeniz gerekiyor. Bu dosyaya yazabilecekleriniz hakkında daha fazla için bakınız https://developer.android.com/reference/android/support/v4/content/FileProvider#SpecifyFiles
3. adım - Yolları gösteren dosyanın kaynak olarak yüklenmesi
Şimdi 2. adımda oluşturduğumuz dosyayı bir Android kaynağı olarak uygulamamıza yüklememiz gerekiyor.
NOT
Delphi kaynakları (resources)  Android kaynakları ile aynı değildir. Delphi kaynakları bir tür çoklu-ortam tarzında tanımlanmış olup, TResourceStream ile ulaşılmaktadır. Fakat burada farklı olarak bir Android kaynağı tanımlamamız gerekiyor. Android kaynağı oluşturmak için, dosyayı uygulamanızın varsayılan klasörünün altında bir res klasörüne yüklemeniz gerekiyor.
Bunun için, Delphi’de Menu->Project->Deployment gidin ve file_provider_paths.xml dosyasının "res\xml" klasörüne yüklenecek olduğuna emin olun.  platform combobox‘ında da "Android" seçili olmalı.

NOT
Delphi 10.3 Rio, Rad Studio Project Options->Application->Entitlement List kısmında "Secure File Sharing" seçeneğini içermektedir:
 
Bu checkbox’ı işaretlerseniz, Delphi Android manifest içinde hem bir provider üretecek hem de provider tarafından tanımlanmış yolları içeren provider_paths.xml adlı bir dosya oluşturacaktır. Bkz: http://docwiki.embarcadero.com/RADStudio/Rio/en/Entitlement_List#Entitlement_List_for_Android
Bu AndroidManifestTemplate.xml dosyasını elle değiştirmekten kurtardığı için ve 1’den 3’e kadar olan adımları yaptığı için neredeyse mükemmeldir. Fakat burada bir pürüz bulunmakta: Oluşturulan provider_paths.xml dosyası değiştiremediğiniz bir ifadeye sahip olmaktadır:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="." />
</paths>
Gördüğünüz gibi, harici depolama için izin istemeyi gerektiren harici bir yol tanımlamaktadır, ki en baştan beri bundan kaçınmaya çalışmaktayız. O halde uygulamanız zaten dosya paylaşma için harici depolamayı kullanmıyorsa, bu çok uygun seçeneği kullanamıyorsunuz. Eğer paylaşmak istediğiniz dosyalarınız muhtelif sebeplerle zaten harici depolamada ise, ancak o zaman bu checkbox’ı işaretlemeli ve manifest’i elle değiştirmeyi unutmalısınız.
4. adım - Kod yazma
Provider doğru şekilde yayınlandığında, son adım dosya paylaşma kodunun yazılmasıdır.
(TMS FlexCel komponentine sahip olanlar için yalnızca TFlexCelDocExport bileşenini forma bırakmak ve şu kodu eklemek yeterli: FlexCelDocExport.ExportFile(btnShare, PdfPath); )
NOT
Aşağıdaki gibi NullPointerExeption hata alıyorsanız:
Project Reports.apk raised exception class EJNIException with message 'java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference'.
Uygulamada provider doğru şekilde tanımlanmamış demektir.
Veya benzeri olarak şu hata çıkıyorsa:
Project Reports.apk raised exception class EJNIException with message 'java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.tms.Reports/files/delphiversions.pdf'.
problem file_provider_paths.xml içinde listelenmiş dosyalardadır.
 
Çevirenin notu:
* TMS Software FlexCel Android Guide https://doc.tmssoftware.com/flexcel/vcl/guides/android-guide.html sayfasından tercüme edilmiştir. Bu yazı Delphi 10.3 Rio sürümü için hazırlanmıştır.
** Buradaki dahili depolama dosyalarını Android sandbox koruması sebebi ile (root yapmadıkça) dosya yöneticisi ve PC bağlantısında göremezsiniz.
*** Özel harici depolama dosyalarını dosya yöneticisi ve diğer uygulamalar da görebilir.
**** Delphi’de derlemenin yapıldığı sırada fiziki olarak takılı cihaza ait android sürümü
 

 
Nitekim artık Mobil Uygulamadan Mp3 dosya paylaşı https://www.delphican.com/showthread.php?tid=821 konusunda anlatılan yol artık “android.os.FileUriExposedException: file:///ornek.txt exposed beyond app through ClipData.ltem.getUri0” hatası verip çalışmıyor. Sebebi yeni kuralların file provider yerine artık content provider API kullanılması istenmesi.
Fesih bey de bu konuda yol göstermiş: AndroidManifest Dosyasi Karakter Sorunu https://www.delphican.com/showthread.php?tid=2272
 [DCC Warning]: W1000 Symbol 'SharedActivity' is deprecated: 'Use TAndroidHelper.Activity' ikazı da çıkıyor.
 
 
Google’ın Android 7.0 Nougat API 25 Uygulamalar Arasında Dosya Paylaşma hakkındaki duyurusu:
For apps targeting Android 7.0, the Android framework enforces the StrictMode  API policy that prohibits exposing file:// URIs outside your app. If an intent containing a file URI leaves your app, the app fails with a FileUriExposedException exception.
To share files between applications, you should send a content:// URI and grant a temporary access permission on the URI. The easiest way to grant this permission is by using the FileProvider class. For more information on permissions and sharing files, see Sharing Files.
 
(URI, İngilizce “Uniform Resourse Identifier” kelimelerini belirtmektedir. Türkçe anlamı ise “tekdüzen kaynak tanımlayıcısı” dır. URI, URL’in işaret ettiği kaynak konumundan sonra gelen ilgili kaynağın ayırıcı adresini belirtir yani web üzerinde belli bir kaynağa (internet sitesi, belge, resim vb.) ulaşmak için kullanılan 1994 te Tim Berners-Lee’ın oluşturmuş olduğu belli bir formata sahip karakter dizisi,metindir. Bu format UNIX dizin yapısı formatındadır: URI = scheme:[//authority]path[?query][#fragment] URI’ın en bilinen şekli Uniform Resource Locator (URL)’dir.)
 
Android sürüm farkları: https://socialcompare.com/en/comparison/android-versions-comparison
 
 
Bu arada Deployment ile dosya yüklemede sıkıntı yok. Dahili klasörler koruma altında olduğu (ve root yapılmadığı) için Android dosya yöneticisi göstermiyor. FileExists ile yüklenen dosyalar bulunabiliyor
 
Dahili depolama klasörleri:
TPath.GetDocumentsPath: /data/user/0/com.embarcadero.Uygulamam/files
 
TPath.GetHomePath: /data/user/0/com.embarcadero.Uygulamam/files
TPath.GetTempPath: /storage/emulated/0/Android/data/com.embarcadero.Uygulamam/files/tmp
TPath.GetRingtonesPath: TPath./storage/emulated/0/Android/data/com.embarcadero.Uygulamam/files/Ringtones
TPath.GetDownloadsPath: /storage/emulated/0/Android/data/com.embarcadero.Uygulamam/files/Download
TPath.GetCachePath: /data/user/0/com.embarcadero.Uygulamam/cache
TPath.GetPicturesPath: /storage/emulated/0/Android/data/com.embarcadero.Uygulamam/files/Pictures
TPath.GetCameraPath: /storage/emulated/0/Android/data/com.embarcadero.Uygulamam/files/DCIM
TPath.GetMusicPath: /storage/emulated/0/Android/data/com.embarcadero.Uygulamam/files/Music
TPath.GetMoviesPath: /storage/emulated/0/Android/data/com.embarcadero.Uygulamam/files/Movies
TPath.GetAlarmsPath: /storage/emulated/0/Android/data/com.embarcadero.Uygulamam/files/Alarms
TPath.GetLibraryPath: /data/app/com.embarcadero.Uygulamam-gjDvLqqZBuqhRw43hNq8BA==/lib/arm
 
Harici özel depolama klasörü:
TPath.GetPublicPath: /storage/emulated/0/Android/data/com.embarcadero.Uygulamam/files
 
Harici depolama klasörleri:
 
TPath.GetSharedDocumentsPath: /storage/emulated/0/Documents
TPath.GetSharedDownloadsPath : /storage/emulated/0/Download
TPath.GetSharedPicturesPath : /storage/emulated/0/Pictures
TPath.GetSharedCameraPath: /storage/emulated/0/DCIM
TPath.GetSharedMusicPath: /storage/emulated/0/Music
TPath.GetSharedMoviesPath: /storage/emulated/0/Movies
TPath.GetSharedAlarmsPath: /storage/emulated/0/Alarms
TPath.GetSharedRingtonesPath: /storage/emulated/0/Ringtones
 
NOT: Delphi 10.3 veya üstünü kullanıyorsanız, izinler ve harici URI’lar için yerleşik destek kullanmanız gerekmektedir.
https://delphiworlds.com/2018/06/targeting-android-8-and-higher-continued/


Örnek proje:
AndroidDosyaDepolamaPaylasma.dproj


unit brAna;

interface

uses
   System.SysUtils, System.Types, System.UITypes, System.Classes,
   System.Variants,
   FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
   FMX.Memo.Types,
   FMX.ScrollBox, FMX.Memo, FMX.Controls.Presentation, FMX.StdCtrls,
   System.IOUtils, Posix.Unistd, System.Permissions
{$IFDEF ANDROID},
   Androidapi.Helpers, Androidapi.JNI.GraphicsContentViewText,
   Androidapi.JNI.Net, Androidapi.JNI.Os, Androidapi.JNI.JavaTypes,
   Androidapi.JNI.Webkit, Androidapi.JNI.App, Androidapi.JNI.Support,
   FMX.Helpers.Android, Androidapi.JNIBridge
{$ENDIF};

type
   TForm1 = class(TForm)
       DosyalarMevcutmu: TButton;
       DosyalariKaydet: TButton;
       DosyalariSil: TButton;
       DahilidenHariciyeKopyala: TButton;
       Mp3Paylas: TButton;
       GenelDosyaPaylas: TButton;
       EpostaGonder: TButton;
       PdfGoster: TButton;
       Memo1: TMemo;
       HariciDepolamaIcinIzinIste: TButton;
       procedure FormActivate(Sender: TObject);
       procedure DosyalarMevcutmuClick(Sender: TObject);
       procedure DosyalariKaydetClick(Sender: TObject);
       procedure DosyalariSilClick(Sender: TObject);
       procedure HariciDepolamaIcinIzinIsteClick(Sender: TObject);
       procedure DahilidenHariciyeKopyalaClick(Sender: TObject);
       procedure Mp3PaylasClick(Sender: TObject);
       procedure GenelDosyaPaylasClick(Sender: TObject);
       procedure EpostaGonderClick(Sender: TObject);
       procedure PdfGosterClick(Sender: TObject);
   private
       { Private declarations }
   public
       { Public declarations }
   end;

var
   Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.DahilidenHariciyeKopyalaClick(Sender: TObject);
begin
   TFile.Copy(TPath.Combine(TPath.GetDocumentsPath, 'delphican.pdf'),
     TPath.Combine(TPath.GetSharedDownloadsPath, 'delphican.pdf'));
end;

procedure TForm1.DosyalariKaydetClick(Sender: TObject);
begin
   // dahili depolama
   Memo1.Lines.SaveToFile(TPath.Combine(TPath.GetDocumentsPath,
     'memo1Dahili.txt'));

   // özel harici depolama
   Memo1.Lines.SaveToFile(TPath.Combine(TPath.GetPublicPath,
     'memo1ÖzelHarici.txt'));

   // harici depolama
   Memo1.Lines.SaveToFile(TPath.Combine(TPath.GetSharedDownloadsPath,
     'memo1Harici.txt'));
end;

procedure TForm1.DosyalariSilClick(Sender: TObject);
begin
   DeleteFile(TPath.Combine(TPath.GetDocumentsPath, 'memo1Dahili.txt'));
   DeleteFile(TPath.Combine(TPath.GetPublicPath, 'memo1ÖzelHarici.txt'));
   DeleteFile(TPath.Combine(TPath.GetSharedDownloadsPath, 'memo1Harici.txt'));
   DeleteFile(TPath.Combine(TPath.GetSharedDownloadsPath, 'delphican.pdf'));
   DeleteFile(TPath.Combine(TPath.GetPublicPath, 'delphican.pdf'));
   DeleteFile(TPath.Combine(TPath.GetPublicPath, 'm.mp3'));
end;

procedure TForm1.DosyalarMevcutmuClick(Sender: TObject);
var
   dosya: string;
begin
   Memo1.Lines.Clear;
   dosya := 'delphican.pdf';
   if (FileExists(TPath.Combine(TPath.GetDocumentsPath, dosya))) then
       Memo1.Lines.Add(dosya + ' dahili klasörde mevcut')
   else
       Memo1.Lines.Add(dosya + ' dahili klasörde yok');

   dosya := 'm.mp3';
   if (FileExists(TPath.Combine(TPath.GetDocumentsPath, dosya))) then
       Memo1.Lines.Add(dosya + ' dahili klasörde mevcut')
   else
       Memo1.Lines.Add(dosya + ' dahili klasörde yok');

   dosya := 'memo1Dahili.txt';
   if (FileExists(TPath.Combine(TPath.GetDocumentsPath, dosya))) then
       Memo1.Lines.Add(dosya + ' dahili klasörde mevcut')
   else
       Memo1.Lines.Add(dosya + ' dahili klasörde yok');

   dosya := 'memo1ÖzelHarici.txt';
   if (FileExists(TPath.Combine(TPath.GetPublicPath, dosya))) then
       Memo1.Lines.Add(dosya + ' özel harici klasörde mevcut')
   else
       Memo1.Lines.Add(dosya + ' özel harici klasörde yok');

   dosya := 'memo1Harici.txt';
   if (FileExists(TPath.Combine(TPath.GetSharedDownloadsPath, dosya))) then
       Memo1.Lines.Add(dosya + ' harici klasörde mevcut')
   else
       Memo1.Lines.Add(dosya + ' harici klasörde yok');

   dosya := 'delphican.pdf';
   if (FileExists(TPath.Combine(TPath.GetSharedDownloadsPath, dosya))) then
       Memo1.Lines.Add(dosya + ' harici klasörde mevcut')
   else
       Memo1.Lines.Add(dosya + ' harici klasörde yok');
end;

procedure TForm1.EpostaGonderClick(Sender: TObject);
   procedure EpostaGonder(const _Recipient, _Subject, _Content,
     _Attachment: string);
   var
       LIntent: JIntent;
       LAuthority: JString;
       LUri: Jnet_Uri;
       JRecipient: TJavaObjectArray<JString>;
   begin
       LAuthority := StringToJString
         (JStringToString(TAndroidHelper.Context.getApplicationContext.
         getPackageName) + '.fileprovider');
       LUri := TJFileProvider.JavaClass.getUriForFile(TAndroidHelper.Context,
         LAuthority, TJFile.JavaClass.init(StringToJString(_Attachment)));

       LIntent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_SEND);

       JRecipient := TJavaObjectArray<JString>.Create(1);
       JRecipient.Items[0] := StringToJString(_Recipient);
       LIntent.removeExtra(StringToJString(_Attachment));
       LIntent.removeExtra(TJIntent.JavaClass.EXTRA_EMAIL);
       LIntent.putExtra(TJIntent.JavaClass.EXTRA_EMAIL, JRecipient);
       LIntent.putExtra(TJIntent.JavaClass.EXTRA_SUBJECT,
         StringToJString(_Subject));
       LIntent.putExtra(TJIntent.JavaClass.EXTRA_TEXT,
         StringToJString(_Content));
       LIntent.putExtra(TJIntent.JavaClass.EXTRA_STREAM,
         TJParcelable.Wrap((LUri as ILocalObject).GetObjectID));
       LIntent.setDataAndType(LUri,
         StringToJString('vnd.android.cursor.dir/email'));
       TAndroidHelper.Activity.startActivity(LIntent);
   end;

begin
   EpostaGonder('x@gmail.com', ' konu', ' dosya paylaş',
     TPath.Combine(TPath.GetDocumentsPath, 'delphican.pdf'));

end;

procedure TForm1.FormActivate(Sender: TObject);
begin
   DosyalarMevcutmuClick(Self);
end;

(* Dosya Paylaşma İçin:
 Project Options->Application->Entitlement List kısmında "Secure File Sharing" seçeneği işaretli olmalı
 https://github.com/DelphiWorlds/Kastri -> Code-> Download ZIP kaydedip ileride değişmeyecek bir klasöre açın
 ve Project->Options->Delphi Compiler-> Search path ... Add ile .\KastriFree-master, API, Include klasörlerini ekleyip, Save tıklayın *)

procedure TForm1.Mp3PaylasClick(Sender: TObject);
   procedure SetArsMp3Gonder(Mp3DosyaAdı: String);
{$IFDEF ANDROID}
   var
       Intent: JIntent;
       fileuri: JParcelable;
       javafile: JFile;
{$ENDIF}
   begin
{$IFDEF ANDROID}
       Intent := TJIntent.Create;
       Intent.setAction(TJIntent.JavaClass.ACTION_SEND);
       javafile := TJFile.JavaClass.init(StringToJString(Mp3DosyaAdı));
       Intent.setDataAndType(TAndroidHelper.JFileToJURI(javafile),
         StringToJString('audio/mpeg'));
       fileuri := JParcelable(TJnet_Uri.JavaClass.fromFile(javafile));
       Intent.putExtra(TJIntent.JavaClass.EXTRA_STREAM, fileuri);
       Intent.addFlags(TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION);
       TAndroidHelper.Activity.startActivity
         (TJIntent.JavaClass.createChooser(Intent,
         StrToJCharSequence('Paylaş Bakalım: ')));
       // SharedActivity.startActivity (TJIntent.JavaClass.createChooser(Intent, StrToJCharSequence ('Share With')));
{$ENDIF}
   end;

var
   dosya: string;
begin
   dosya := 'm.mp3';
   if (not FileExists(TPath.Combine(TPath.GetPublicPath, dosya))) then
       TFile.Copy(TPath.Combine(TPath.GetDocumentsPath, dosya),
         TPath.Combine(TPath.GetPublicPath, dosya));
   dosya := TPath.Combine(TPath.GetPublicPath, dosya);
   SetArsMp3Gonder(dosya);
end;

procedure TForm1.GenelDosyaPaylasClick(Sender: TObject);
   procedure DosyaGonder(DosyaAdi: String);
{$IFDEF ANDROID}
   var
       Intent: JIntent;
       fileuri: JParcelable;
       javafile: JFile;
       mime: JMimeTypeMap;
       ExtToMime: JString;
       ExtFile: string;
{$ENDIF}
   begin
{$IFDEF ANDROID}
       ExtFile := AnsiLowerCase(StringReplace(TPath.GetExtension(DosyaAdi),
         '.', '', []));
       mime := TJMimeTypeMap.JavaClass.getSingleton();
       ExtToMime := mime.getMimeTypeFromExtension(StringToJString(ExtFile));
       Intent := TJIntent.Create;
       Intent.setAction(TJIntent.JavaClass.ACTION_SEND);
       javafile := TJFile.JavaClass.init(StringToJString(DosyaAdi));
       Intent.setDataAndType(TAndroidHelper.JFileToJURI(javafile), ExtToMime);
       fileuri := JParcelable(TJnet_Uri.JavaClass.fromFile(javafile));
       Intent.putExtra(TJIntent.JavaClass.EXTRA_STREAM, fileuri);
       Intent.addFlags(TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION);
       TAndroidHelper.Activity.startActivity
         (TJIntent.JavaClass.createChooser(Intent,
         StrToJCharSequence('Paylaş Bakalım: ')));
{$ENDIF}
   end;

var
   dosya: string;
begin
   dosya := 'delphican.pdf';
   if (not FileExists(TPath.Combine(TPath.GetPublicPath, dosya))) then
       TFile.Copy(TPath.Combine(TPath.GetDocumentsPath, dosya),
         TPath.Combine(TPath.GetPublicPath, dosya));
   dosya := TPath.Combine(TPath.GetPublicPath, 'delphican.pdf');
   DosyaGonder(dosya);
end;

procedure TForm1.HariciDepolamaIcinIzinIsteClick(Sender: TObject);
begin
   PermissionsService.RequestPermissions
     ([JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE),
      JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE)],
       procedure(const APermissions: TArray<string>;
         const AGrantResults: TArray<TPermissionStatus>)
       begin
           if (AGrantResults[0] = TPermissionStatus.Granted) then
               Memo1.Lines.Add('READ_EXTERNAL_STORAGE İZİNLİ')
           else
               Memo1.Lines.Add('READ_EXTERNAL_STORAGE İZİNSİZ');
           if (AGrantResults[1] = TPermissionStatus.Granted) then
               Memo1.Lines.Add('WRITE_EXTERNAL_STORAGE İZİNLİ')
           else
               Memo1.Lines.Add('WRITE_EXTERNAL_STORAGE İZİNSİZ');
       end);
end;


procedure TForm1.PdfGosterClick(Sender: TObject);
   procedure pdfAc(const AFileName: string);
   var
       LIntent: JIntent;
       LUri: Jnet_Uri;
   begin
       LUri := TAndroidHelper.JFileToJURI
         (TJFile.JavaClass.init(StringToJString(AFileName)));
       LIntent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_VIEW);
       LIntent.setDataAndType(LUri, StringToJString('application/pdf'));
       LIntent.setFlags(TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION);
       TAndroidHelper.Activity.startActivity(LIntent);
   end;

var
   dosya: string;
begin
   dosya := 'delphican.pdf';
   pdfAc(TPath.Combine(TPath.GetDocumentsPath, dosya));
end;

end.


Android'de özellikle Sqlite veritabanı gibi önemli dosyaları, harici klasöre ve eposta vs. ile yedekleklemek isteyenler için faydalı olacak şekilde düzenlenmiştir.


Ek Dosyalar
.zip   AndroidDosyaDepolamaPaylasma.zip (Dosya Boyutu: 442,19 KB / İndirme Sayısı: 120)
Cevapla
#2
Ellerinize ve emeklerinize sağlık. 
Çok kapsamlı ve derinlemesine bir çalışma olmuş. 
Makalenize oldukça fazla zaman ayırıp detaylı bir şekilde okudum. Belki de zaman zaman defalarca okuyacağım. 
Katkı ve desteğinizden dolayı teşekkür ederim @emozgun bey.
DelphiCan'dır!
Cevapla
#3
Teşekkürler makaleniz için.
Cevapla
#4
Çok güzel detaylı açıklayıcı bir makale olmuş.. Dökümantasyon açısından sitede olması çok hoş. Elinize Sağlık
// Bilgi paylaştıkça çoğalır.. 

Cevapla
#5
Çok teşekkür ederiz , Çok güzel bir anlatım ve çalışma olmuş oldukça detaylı . Elinize emeğinize sağlık.
Yeni makale ve paylaşımların gelmesi dileğiyle kolaylıklar diliyorum.
Cevapla
#6
Merhabalar
Buda Rad Studio 11de çalıştıramadım arkadaşlar. Uygulama açılıp hemen çöküyor. Rad studio 11de bunu deneyen varmı arkadaşlar.
Cevapla
#7
Yazının devamı için bakınız: Delphi ile Android 11 SDK 30 Kapsamlı Depolama Scoped Storage : SAF & MediaStore API
Cevapla


Konu ile Alakalı Benzer Konular
Konular Yazar Yorumlar Okunma Son Yorum
Lightbulb [FMX] Android - Indy ile HTTPS linklerine erişirken OpenSSL kütüphanesi kullanımı mrmarman 7 7.223 23-09-2021, Saat: 11:56
Son Yorum: Bay_Y
Lightbulb [GÜNCEL] Firebase GCM Android Bilgi Mesajı (Notification Push Message) mrmarman 20 25.626 11-12-2018, Saat: 14:50
Son Yorum: Bay_Y
  Tüm platformlar (Android, iOS vb.)  için telefon çağrı durumunu yakalamak Fesih ARSLAN 18 22.052 14-04-2017, Saat: 21:17
Son Yorum: quiet1day
  Delphi Firemonkey Android İzin Kontrolü esrehmaan 2 5.247 23-12-2016, Saat: 22:22
Son Yorum: esrehmaan



Konuyu Okuyanlar: 1 Ziyaretçi