Perubahan Privasi di Android 10
Android 11 - Privasi dan Keamanan
Perubahan Perilaku: Aplikasi Menargetkan Android 11 - Privasi
Penggunaan semua file akses (kelola_external_storage) izin
Tinjauan Penyimpanan Bersama
Setelah Android 10 dan 11 perubahan privasi dan keamanan, akses langsung ke penyimpanan dengan aplikasi yang dilengkapi dengan internal saja dan sekarang mengakses file eksternal yang mungkin murni dan hanya dengan 4 API:
Semua file akses API (kelola_external_storage - Action_Manage_AWS_ALL_FILES_ACCESS_PERMISSI IMSISI DAN ACTION_MANAGE_STORAGE INTEN) Tersedia hanya untuk manajer file dan aplikasi tipe antivirus, semua aplikasi jenis lainnya ditolak oleh Google Play Store Publishing. Database (BlobstoreManager) API hanya menjalankan Android 11 SDK 30 dan versi atas, bukan Android 10 dan yang sebelumnya. Oleh karena itu keduanya API dikecualikan di bawah ini.
Buka File Menggunakan Kerangka Akses Penyimpanan
Akses dokumen dan file lain dari penyimpanan bersama
Gunakan kasus untuk mengakses dokumen dan file lainnya
Kerangka kerja akses penyimpanan mendukung kasus penggunaan berikut untuk mengakses file dan dokumen lainnya.
Buat file baru
The ACTION_CREATE_DOCUMENT intent action allows users to save a file in a specific location.
Buka dokumen atau file
The ACTION_OPEN_DOCUMENT intent action allows users to select a specific document or file to open.
Memberikan akses ke konten direktori
The ACTION_OPEN_DOCUMENT_TREE intent action, available on Android 5.0 (API level 21) and higher, allows users to select a specific directory, granting your app access to all of the files and sub-directories within that directory.
Bagian berikut memberikan panduan tentang cara mengkonfigurasi setiap kasus penggunaan.
Buat file baru
// Request code for creating a PDF document.
const CREATE_FILE : integer = 11 ; // CREATE_FILE = 1
procedure createFile (pickerInitialUri : JNet_Uri); (* PdfDosyasiOlustur *)
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( ' invoice.pdf ' ));
// Optionally, specify a URI for the directory that should be opened in
// the system file picker when your app creates the document.
Intent.putExtra(TJDocumentsContract.JavaClass.EXTRA_INITIAL_URI,JParcelable(pickerInitialUri));
MainActivity.startActivityForResult(Intent, CREATE_FILE);
end ;Buka file
// Request code for selecting a PDF document.
// const PICK_PDF_FILE : integer = 22; //PICK_PDF_FILE = 2
procedure openFile (pickerInitialUri : JNet_Uri); (* PdfDosyasiSec *)
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 ' ));
// Optionally, specify a URI for the file that should appear in the
// system file picker when it loads.
Intent.putExtra(TJDocumentsContract.JavaClass.EXTRA_INITIAL_URI,JParcelable(pickerInitialUri));
TAndroidHelper.Activity.startActivityForResult(Intent, PICK_PDF_FILE);
end ;Memberikan akses ke konten direktori
procedure openDirectory (uriToLoad : JNet_Uri); (* DizinAc *)
// Choose a directory using the system's file picker.
var
Intent : JIntent;
begin
Intent := TJIntent.Create;
Intent.setAction(TJIntent.JavaClass.ACTION_OPEN_DOCUMENT_TREE);
// Optionally, specify a URI for the directory that should be opened in
// the system file picker when it loads.
Intent.putExtra(TJDocumentsContract.JavaClass.EXTRA_INITIAL_URI, JParcelable(uriToLoad));
Mainactivity.startActivityForResult(Intent, Open_Doc_Tree);
end ;Melakukan operasi di lokasi yang dipilih
procedure TForm1.HandleMessageAction ( const Sender: TObject; const M: TMessage); (* IletiFaaliyetiYakala *)
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
// The result data contains a URI for the document or directory that
// the user selected.
Uri := nil ;
if Assigned(Data) then
begin
Uri := Data.getData;
if RequestCode = your-request-code then
begin
// Perform operations on the document using its URI.
end ;
end ;
end ;Dengan mendapatkan referensi ke URI item yang dipilih, aplikasi Anda dapat melakukan beberapa operasi pada item tersebut. Misalnya, Anda dapat mengakses metadata item, mengedit item yang ada, dan menghapus item. Bagian berikut menunjukkan cara menyelesaikan tindakan pada file yang dipilih pengguna:
Izin bertahan
// TakeFlags: integer;
Intent := TJIntent.Create;
TakeFlags := Intent.getFlags
and (TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION
or TJIntent.JavaClass.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
TAndroidHelper.Activity.getContentResolver.takePersistableUriPermission
(Uri, TakeFlags);Periksa metadata dokumen
procedure dumpImageMetaData (uri : JNet_Uri); (* GoruntuMetaVerisiDokumu *)
// The query, because it only applies to a single document, returns only
// one row. There's no need to filter, sort, or select fields,
// because we want all fields for one document.
var
displayName, size : JString;
sizeIndex : integer;
cursor : JCursor;
begin
cursor := TAndroidHelper.Activity.getContentResolver.query(uri, nil , nil , nil , nil , nil );
try
// moveToFirst() returns false if the cursor has 0 rows. Very handy for
// "if there's anything to look at, look at it" conditionals.
if (cursor<> nil ) then
if (cursor.moveToFirst) then
begin
displayName := cursor.getString (cursor.getColumnIndex (TJOpenableColumns.JavaClass.DISPLAY_NAME));
Memo1.Lines.Add( { TAG.ToString + } ' Display Name: ' + JStringToString (displayName));
sizeIndex:=cursor.getColumnIndex(TJOpenableColumns.JavaClass.SIZE);
size := nil ;
if not (cursor.isNull(sizeIndex)) then
size := cursor.getString(sizeIndex)
else
size:=StringToJString ( ' Unknown ' );
Memo1.Lines.Add( { TAG.ToString + } ' Size: ' + JStringToString (size));
end ;
finally
cursor.close;
end ;
end ;Buka Dokumen - Bitmap
function getBitmapFromUri (uri : JNet_Uri): JBitmap; (* UridenBiteslemAl *)
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 ;Buka Dokumen - Stream Input
function TForm1.readTextFromUri (Uri : JNet_Uri): string; (* MetinDosyasiOkuyucu *)
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 ;Edit dokumen
procedure alterDocument (uri : JNet_Uri); (* MetinBelgesiDegistir *)
var
pfd : JParcelFileDescriptor;
fileOutputStream : JFileOutputStream;
begin
try
pfd := TAndroidHelper.Activity.getContentResolver
.openFileDescriptor(uri,StringToJString( ' w ' ));
fileOutputStream := TJFileOutputStream.JavaClass.init(pfd.getFileDescriptor);
fileOutputStream.write(StringToJString( ' Overwritten at ' + timetostr(Now)).getBytes);
fileOutputStream.close;
pfd.close;
except
on E: Exception do
ShowMessage(e.Message);
end ;
end ; Hapus dokumen
TJDocumentsContract.JavaClass.deleteDocument (TAndroidHelper.contentResolver, Uri);Buka file virtual
function isVirtualFile (Uri : JNet_Uri): boolean; (* SanalDosyami *)
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 ; file virtual sebagai gambar
function getInputStreamForVirtualFile (Uri : JNet_Uri; mimeTypeFilter : String): JInputStream; (* SanalDosyaIcinGirisAkisiAl *)
var
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
raise Exception.Create( ' File not found! ' );
result := nil ;
exit;
end ;
result := resolver.openTypedAssetFileDescriptor(uri,openableMimeTypes[ 0 ], nil )
.createInputStream;
end ;Fungsi jalur RTL standar di seluruh platform target yang didukung: penyimpanan internal, eksternal swasta internal S, penyimpanan eksternal bersama
Perubahan penyimpanan dalam versi Android
| # | Kode | SDK | Menerbitkan | Mengubah |
|---|---|---|---|---|
| 1 | - | 1 | 23.09.08 | Intent, System Picker (Action_) dimulai di versi pertama |
| 4.4 | K | 19 | 31.10.13 | FileProvider (API Konten), Kontrak Dokumen, Kelas DocumentProvider |
| 7 | N | 25 | 04.10.16 | Wajib Penggunaan FileProvider (saat menargetkan versi ini) |
| 8 | HAI | 26 | 21.03.17 | Agustus 2018 Google Play Store dan. 8.0 Persyaratan Penerbitan |
| 10 | Q | 29 | 03.09.19 | Penyimpanan SCOPED. Privasi dan keamanan meningkat |
| 11 | R | 30 | 09.09.20 | Agustus 2021 Menargetkan API Android 30 (Persyaratan Publikasi Google Play Store) |
Penyedia dokumen, Android 4.3 Action_pick, action_get_content; Android 4.4 (API 19) ACTION_OPEN_DOCUMENT; Android 5.0 (API 21) ACTION_OPEN_DOCUMENT_TREE
Dukungan Android di versi Delphi
Rad Studio Delphi 10+ versi menyertai Android 10+ Java Libraries (androidapi.jni.graphicscontentViewText, androidapi.ioutils, androidapi.jni.media, androidapi.jni.provider, androidapi.jni.app, androidapi.helprovider, androidapi.jni.app, androidapi.helprovider, androidapi.jni.appi.helprovider, androidapi.helprovider. Androidapi.jni.net, androidapi.jni.os, androidapi.jni.provider) Mendukung penyimpanan cakupan, SAF dan beberapa perintah Mediastore.
| 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 Delphi 11.0 Alexandria memiliki dukungan API Android 30 (persyaratan Google Play Store 2021).
Perbedaan penyimpanan file dan berbagi di Android:
• Tidak ada perbedaan dalam Android 11 untuk penyimpanan internal. Seperti di Android 10 dan sebelumnya, akses ke file tidak terbatas. Sekali lagi, tidak diperlukan izin.
• Berbagi file adalah sama, sekali lagi API konten (FileProvider) dan cara menelepon dengan “Intent.setAction (tjintent.javaclass.action_send);” niat berlanjut. Untuk mengaktifkan fitur FileProvider, memilih opsi "Sharing File Aman" di Opsi Proyek-> Aplikasi-> Daftar Hak (tersedia di Delphi 10.3 Rio dan kemudian) harus ditambahkan untuk terus menggunakan API ini. Untuk Delphi 10.3 versi sebelumnya, API FileProvider harus ditambahkan secara manual seperti yang dijelaskan dalam "Penyimpanan File dan Berbagi di Android"> “Menggunakan FileProvider untuk berbagi file”.
• Perintah Salin Penyimpanan Eksternal di Proyek "Penyimpanan File dan Berbagi dalam Android" dijalankan saat menargetkan Android 10 SDK 29 versi sebelumnya, yaitu "memo1.lines.savetofile (tpath.comBine (tpath.getshareddownloadspath, 'memo1external.txt'));". Ketika Android 11 SDK 30 ditargetkan, aplikasi yang sama menaikkan "tidak dapat membuat file" (penyimpanan/ditiru/0/download/memo1external.txt ". Izin ditolak" Pengecualian. Perintah "DeleteFile" tidak menghapus file di bawah unduhan/getshareddownloadspath. Masalah yang sama berlaku untuk semua folder eksternal yang dibagikan. Alasannya adalah dan getshareddownload folder.
• Status Saat Ini Sebelum Android 10 dan Setelah Android 11 Perubahan Penyimpanan File Penyimpanan Wajib:
• “RequestLegaCyExternalStorage” telah dihapus dari penyimpanan lingkup dan sekarang aplikasi yang ingin mengaksesnya ditolak di gpstore. Untuk mempublikasikan aplikasi Anda, buat perubahan berikut di androidmanifest.template.xml ::
android:requestLegacyExternalStorage="false">
• Semua file akses API (action_manage_storage) ditolak oleh Google Play Store, tetapi jika izin ini diberikan (dan aplikasi tidak akan diterbitkan), ia dapat membaca dan menyimpan file seperti sebelum Android 11. Jika Anda membutuhkan ini, Anda perlu menambahkan "AndroidManFest.template.xml" dan permintaan "Action_Manage_Anping_files. niat.
• Database bersama BlobstoreManager API hanya berfungsi di Android 11 SDK 30 ke atas, tidak berfungsi pada Android 10 dan versi sebelumnya.
• Database bersama BlobstoreMan API hanya menjalankan Android 11 SDK 30 dan versi yang lebih tinggi, tidak menjalankan Android 10 dan versi yang lebih rendah. Ini tidak termasuk pertimbangan karena tidak didukung oleh sebagian besar perangkat saat ini.
• Mengakses penyimpanan bersama (eksternal) dengan SAF dan Mediastore:
• Mendapatkan URI: Hanya tiga contoh pertama dari kasus penggunaan dari kode pelatihan di atas mendapatkan file URI dan izin untuk mengaksesnya. Mengakses file eksternal URI diperkenalkan dengan menangkap tindakan mereka dengan OnactivityResult.
• Semua contoh lain menjelaskan cara menangani URI yang diperoleh dari 3 tindakan kasus penggunaan ini. Jika Anda tidak tahu file URI, Anda tidak dapat menggunakannya.
• Juga, niat Action_Get_Content lama dapat digunakan untuk mendapatkan URI dengan memanggil pemilih sistem, mirip dengan action_open_document; tetapi tidak memberikan akses permanen.
• Dengan mediastore.files, URI dari file dalam penyimpanan media juga dapat diambil, tetapi tidak termasuk dalam konten topik ini karena pernyataan "konten Mediastore. Film di toko media juga tergantung pada apakah aplikasi Anda menggunakan penyimpanan ekstensif yang tersedia dalam aplikasi yang menargetkan Android 10 atau lebih tinggi". Meskipun kelas Mediastore.Downloads dan GetMediauri juga menyediakan akses ke file penyimpanan eksternal URI, mereka hanya mendukung SDK 29 ke atas.
• E Jika Anda ingin beroperasi pada file dengan kode apa pun tanpa menggunakan kasus, Anda dapat secara langsung menggunakan file URI (misalnya: konten: //com.android.providers.downloads.documents/documents/16874) dengan ACCESS Access.
• Secara singkat, aplikasi perekaman file penyimpanan eksternal dalam penyimpanan ruang lingkup berada di bottleneck URI. Selain itu, jika Anda ingin mencakup semua perangkat Android di pasaran menggunakan versi yang lebih lama sebelum SDK 29, Anda harus menggunakan kasus penggunaan SAF, tidak ada jalan keluar selain itu. Dalam konferensi pengembang Android, video, pengumuman, mereka mengklaim bahwa tujuan beralih ke ruang lingkup penyimpanan adalah untuk menghapus izin yang tidak perlu, tetapi dalam kenyataannya, yang sebaliknya telah terjadi pada pengembang dan pengguna.
• Kode sampel (semua pada tutorial SAF dan sebagian besar di Mediastore) adalah SDK Level 1-24 dan didukung oleh versi Delphi 10.x.
• Delphi 11 diperlukan untuk menggunakan level SDK 29 VE 30 Perintah Mediastore dari “Unduhan”, “GetMediauri” Kelas, Memuat Thumbnail> LoadThumbnail, Tambahkan Item> Volume_External_Primary, Take Status CEKREATECEURED MEDICECEURET> PENGANDURAN MEDICECECECECECED OF MEDICECECECECECEDSECECECECCED DRAINDECERECECECECCEDSECECECECCE, MEDICECECECECECECECCE, createFavouriteRequest ”.
• Untuk berbagi file dari penyimpanan eksternal terlebih dahulu mendapatkan URI dari file oleh saf file pemilih, lalu berbagi maksud yang diperlukan. Jika file eksternal URI tersedia, itu dapat digunakan untuk pembukaan file baru, membaca, menabung, menyalin tujuan.
• Item yang didepresiasi untuk penyimpanan eksternal:
// ExternalFile := TPath.Combine(TPath.GetSharedDownloadsPath,'delphican.txt');
Memo1.Lines.SaveToFile(ExternalFile);
TFile.Copy(InternalFile, ExternalFile);
DeleteFile(ExternalFile);
Uri := TJnet_Uri.JavaClass.fromFile(TJFile.JavaClass.init(StringToJString(ExternalFile)));
Uri := TJnet_Uri.JavaClass.parse(StringToJString( ' file:/// ' + ExternalFile));
JinputStream1 := TJFileInputStream.JavaClass.init(StringToJString(ExternalFile));
Uri := TJFileProvider.JavaClass.getUriForFile(TAndroidHelper.Context, LAuthority, TJFile.JavaClass.init(StringToJString(ExternalFile)));
Intent := TJFileProvider.JavaClass.getUriForFile(TJnet_Uri.JavaClass.fromFile(TJFile.JavaClass.init(StringToJString(ExternalFile))));
Uri := TAndroidHelper.JFileToJURI (TJFile.JavaClass.init(StringToJString(ExternalFile)));
Uri := TJFileProvider.JavaClass.getUriForFile(Context, LAuthority, AFile);Secara singkat semua file, konten, tindakan dan maksud fileprovider didepresiasi.
(PS: Jika izin untuk mengakses direktori di mana file berada diperoleh oleh action_open_document_tree, dimungkinkan untuk mengakses file dengan perintah ini, tetapi tidak dapat dicoba karena niat ini tidak berfungsi di Delphi 10.)))
• Untuk menggunakan Kerangka Akses Penyimpanan SAF, tidak ada izin yang diperlukan untuk mendapatkan dari proyek -> menggunakan izin, semua dapat ditutup. Proyek tidak memerlukan izin yaitu "IzinSservice.Ripspermissions". Semua izin dalam proyek sampel Off.
• Untuk mengakses file dengan SAF, cukup untuk hanya memanggil kasus penggunaan (action_create_document, action_open_document, action_open_document_tree) maksud. Namun, masing -masing dari mereka membuka antarmuka pemetik sistem, tidak seperti tfile lama.
• ACTION_CREATE_DOCUMENT digunakan untuk menyimpan file baru dengan antarmuka yang mirip dengan "save as", dan action_open_document digunakan untuk membuka, menunjukkan, dan memodifikasi file yang ada. Action_open_document_tree adalah untuk mengakses tidak hanya direktori tetapi juga semua file di bawahnya.
• Saat menggunakan SAF, bagian niat-filter di androidmanifest.template.xml siap dengan Delphi, tidak perlu menambahkan niat lain.
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
• Kasing penggunaan SAF segera tersedia di proyek-proyek Delphi yang menargetkan SDK 30 dengan hanya menyebutnya dengan perpustakaan Android yang diperlukan dan kode sampel, karena mereka dibangun dengan semua versi Delphi 10.
• Menulis ke audio, gambar, file video dan unduhan di atas versi 11 tidak dibatasi dengan Mediastore. Yaitu Anda dapat menyimpan gambar tanpa izin.
• Koleksi media hanya dapat dibaca dengan izin.
• Access_media_location diperlukan untuk data lokasi gambar.
• PDF, teks, dll. Mengakses file yang tersedia oleh "System Picker".
• “Pemilih Sistem” diperlukan untuk membaca dan menulis di luar koleksi.
• Proyek -> menggunakan izin -> write_external_storage harus dimatikan pada SDK 29. Read_external_Storage diperlukan untuk dibaca.
• Kelas Mediastore URI tidak tersedia di perpustakaan pra-Delphi 11 karena mereka dihapus untuk mengakses file di atas SDK 29. Jadi sebagian besar kode tutorial Mediastore di atas baru saja diimpor dari java ke objek Pascal, tidak dapat dicoba.
• Saat runtime, tergantung pada level SDK perangkat, tulis izin harus diminta (SDK <28) dan bukan untuk (SDK> = 29).
• Androidmanifest.template.xml Perubahan:
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="30" />
android:requestLegacyExternalStorage="false">
• Mediastore memerlukan izin baca pada penyimpanan eksternal, bukan izin menulis. Untuk kompatibilitas dengan versi sebelum Android 10, di bawah Project -> menggunakan izin, hapus opsi write_external_storage dan tambahkan yang berikut dalam manifes:
<%uses-permission%>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
• Menyalin file tidak dapat lagi dilakukan dengan satu perintah (tfile.copy) dari penyimpanan eksternal. Pertama, kita menyebut case penggunaan (action_open_document atau action_create_document) niat. Kemudian kami menangani kode permintaan dengan "HandlemessageActivity" dan "OnactivityResult". Akhirnya kami menulis ke file yang baru saja kami buka dengan URI dan stream (JinputStream, JFileOutputStream).
procedure TForm1.ButtonFileSharingClick (Sender: TObject);
var
Intent: JIntent;
mime: JMimeTypeMap;
ExtToMime: JString;
ExtFile: string;
File : string;
begin
File := File_name(UriCan);
ExtFile := AnsiLowerCase(StringReplace(TPath.GetExtension( File ),
' . ' , ' ' , []));
mime := TJMimeTypeMap.JavaClass.getSingleton();
ExtToMime := mime.getMimeTypeFromExtension(StringToJString(ExtFile));
Intent := TJIntent.Create;
Intent.setAction(TJIntent.JavaClass.ACTION_SEND);
Intent.setDataAndType(UriCan, ExtToMime);
Intent.putExtra(TJIntent.JavaClass.EXTRA_STREAM, JParcelable(UriCan));
Intent.addFlags(TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION);
TAndroidHelper.Activity.startActivity(TJIntent.JavaClass.createChooser(Intent,
StrToJCharSequence( ' Let '' s share: ' )));
end ; procedure TForm1.ButtonCopyFileFromInternalToExternalClick (Sender: TObject);
(* TFile.Copy(TPath.Combine(TPath.GetDocumentsPath, 'delphican.pdf'),
TPath.Combine(TPath.GetSharedDownloadsPath, 'delphican.pdf')); *)
procedure CreateFilePdf (pickerInitialUri: 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(TPath.GetFileName(FileToBeCopied)));
Intent.putExtra(TJDocumentsContract.JavaClass.EXTRA_INITIAL_URI,
JParcelable(pickerInitialUri));
MainActivity.startActivityForResult(Intent,
Copy_File_FromInternal_ToExternal);
end ;
begin
FileToBeCopied := TPath.Combine(TPath.GetDocumentsPath, ' delphican.pdf ' );
CreateFilePdf( nil );
end ;
procedure TForm1.CopyFile_FromInternalToExternal ( File : string);
const
bufferSize = 4096 * 2 ;
var
noOfBytes: Integer;
b: TJavaArray<Byte>;
File_Read: JInputStream;
File_Write: JFileOutputStream;
pfd: JParcelFileDescriptor;
begin
if not FileExists( File ) then
begin
ShowMessage( File + ' not found! ' );
exit;
end ;
try
DosyaOku := TAndroidHelper.Context.getContentResolver.openInputStream
(TJnet_Uri.JavaClass.fromFile(TJFile.JavaClass.init
(StringToJString( File ))));
pfd := TAndroidHelper.Activity.getContentResolver.openFileDescriptor(UriCan,
StringToJString( ' w ' ));
DosyaYaz := TJFileOutputStream.JavaClass.init(pfd.getFileDescriptor);
b := TJavaArray<Byte>.Create(bufferSize);
noOfBytes := File_Read.read(b);
while (noOfBytes > 0 ) do
begin
File_Write.write(b, 0 , noOfBytes);
noOfBytes := File_Read.read(b);
end ;
File_Write.close;
File_Read.close;
except
on E: Exception do
Application.ShowException(E);
end ;
Showmessage( ' File copied from Internal to External : ' + DosyaAdi(UriCan));
end ; procedure TForm1.ButtonFileCopyFromExternalToInternalClick (Sender: TObject);
(* TFile.Copy(TPath.Combine(TPath.GetSharedDownloadsPath, 'delphican.pdf'),
TPath.Combine(TPath.GetPublicPath, 'delphican.pdf')); *)
var
Intent: JIntent;
begin
Intent := TJIntent.Create;
Intent.setAction(TJIntent.JavaClass.ACTION_OPEN_DOCUMENT);
Intent.addCategory(TJIntent.JavaClass.CATEGORY_OPENABLE);
Intent.setType(StringToJString( ' */* ' ));
TAndroidHelper.Activity.startActivityForResult(Intent,
Copy_File_FromExternal_ToInternal);
end ;
procedure TForm1.FileCopy_FromExternalToInternal ;
const
bufferSize = 4096 * 2 ;
var
noOfBytes: Integer;
b: TJavaArray<Byte>;
File_Read: JInputStream;
File_Write: JFileOutputStream;
File : string;
// pfd : JParcelFileDescriptor;
begin
try
Dosya := TPath.Combine(TPath.GetPublicPath, DosyaAdi(UriCan));
if FileExists( File ) then
begin
ShowMessage( ' " ' + File + ' " zaten mevcut! ' );
exit;
end ;
File_Write := TJFileOutputStream.JavaClass.init(StringToJString( File ));
File_Read := TAndroidHelper.Context.getContentResolver.
openInputStream(UriCan);
b := TJavaArray<Byte>.Create(bufferSize);
noOfBytes := File_Read.read(b);
while (noOfBytes > 0 ) do
begin
File_Write.write(b, 0 , noOfBytes);
noOfBytes := File_Read.read(b);
end ;
File_Write.close;
File_Read.close;
except
on E: Exception do
Application.ShowException(E);
end ;
ShowMessage( ' File copied from External to Internal : ' + File_Name(UriCan));
end ;