Changements de confidentialité dans Android 10
Android 11 - Confidentialité et sécurité
Modifications de comportement: applications ciblant Android 11 - Confidentialité
Utilisation de tous les fichiers Accès (manage_external_storage)
Aperçu du stockage partagé
Après les modifications de confidentialité et de sécurité Android 10 et 11, l'accès direct au stockage par les applications a étendu uniquement interne et accéder maintenant aux fichiers externes possibles uniquement et simplement par 4 API:
Tous les fichiers Access API (Manage_External_Storage - ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION Autorisation et intention ACTION_MANAGE_STORAGE) Disponible pour les applications de type de fichiers et de type antivirus, toutes les autres applications de type sont rejetées par Google Play Store Publishing. L'API Bases de données (BlobStoreManager) exécute uniquement les versions Android 11 SDK 30 et supérieures, et non Android 10 et les précédentes. Par conséquent, les deux API ont exclu ci-dessous le sujet.
Ouvrez les fichiers à l'aide du cadre d'accès au stockage
Accéder aux documents et autres fichiers à partir du stockage partagé
Des cas d'utilisation pour accéder aux documents et autres fichiers
Le cadre d'accès du stockage prend en charge les cas d'utilisation suivants pour accéder aux fichiers et autres documents.
Créer un nouveau fichier
The ACTION_CREATE_DOCUMENT intent action allows users to save a file in a specific location.
Ouvrez un document ou un fichier
The ACTION_OPEN_DOCUMENT intent action allows users to select a specific document or file to open.
Accorder l'accès au contenu d'un répertoire
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.
Les sections suivantes fournissent des conseils sur la façon de configurer chaque cas d'utilisation.
Créer un nouveau fichier
// 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 ;Ouvrir un fichier
// 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 ;Accorder l'accès au contenu d'un répertoire
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 ;Effectuer des opérations sur l'emplacement choisi
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 ;En obtenant une référence à l'URI de l'élément sélectionné, votre application peut effectuer plusieurs opérations sur l'élément. Par exemple, vous pouvez accéder aux métadonnées de l'élément, modifier l'élément en place et supprimer l'élément. Les sections suivantes montrent comment effectuer des actions sur les fichiers que l'utilisateur sélectionne:
Persister les autorisations
// 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);Examiner les métadonnées du document
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 ;Ouvrir un document - 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 ;Ouvrez un document - Stream d'entrée
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 ;Modifier un document
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 ; Supprimer un document
TJDocumentsContract.JavaClass.deleteDocument (TAndroidHelper.contentResolver, Uri);Ouvrez un fichier virtuel
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 ; Fichier virtuel comme image
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 ;Fonctions du chemin RTL standard sur les plates-formes cibles prises en charge: stockage interne, s interne privé externe, stockage externe partagé
Modifications de stockage dans les versions Android
| # | Code | SDK | Publier | Changement |
|---|---|---|---|---|
| 1 | - | 1 | 23.09.08 | Intention, Picker System (Action_) a commencé dans la première version |
| 4.4 | K | 19 | 31.10.13 | FileProvider (API de contenu), DocumentsContract, DocumentProvider Classes |
| 7 | N | 25 | 04.10.16 | Fileprovider Utilisation obligatoire (lorsqu'il est ciblé cette version) |
| 8 | O | 26 | 21.03.17 | Août 2018 Google Play Store et. 8.0 Exigence de publication |
| 10 | Q | 29 | 03.09.19 | Stockage à portée. La confidentialité et la sécurité ont augmenté |
| 11 | R | 30 | 09.09.20 | Août 2021 Cibler Android API 30 (Google Play Store Publish Exigence) |
Fournisseur de documents, 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
Prise en charge Android dans les versions de Delphi
RAD Studio Delphi 10+ versions accompagnent les bibliothèques Android 10+ Java (Androidapi.jni.graphicsContentViewText, Androidapi.ioutils, Androidapi.jni.media, Androidapi.Jni.Provider, Androidapi.jni.app, Androidapi.helpers, Androidapi.jni. Androidapi.jni.net, Androidapi.jni.os, Androidapi.jni.provider) prenant en charge le stockage dans le cadre, SAF et certaines commandes MediaStore.
| Delphes | Androïde |
|---|---|
| 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 Alexandrie | 8.1 - 11 |
RAD Studio Delphi 11.0 Alexandrie a une prise en charge de l'API Android 30 (Google Play Store 2021 Exigence).
Différences au stockage de fichiers et au partage dans Android:
• Il n'y a pas de différence dans Android 11 pour le stockage interne. Comme dans Android 10 et plus tôt, l'accès aux fichiers est illimité. Encore une fois, aucune autorisation n'est requise.
• Le partage de fichiers est le même, API de contenu (fileProvider) à nouveau et la façon d'appeler avec «Intent.setAction (tjintent.javaclass.action_send);» l'intention continue. Pour activer la fonctionnalité FileProvider, la sélection de l'option "Partage de fichiers sécurisé" dans les options de projet-> Application-> Liste des droits (disponible dans Delphi 10.3 Rio et ultérieurement) doit être ajoutée pour continuer à utiliser cette API. Pour les versions antérieures de Delphi 10.3, l'API FileProvider doit être ajoutée manuellement comme expliqué dans "Storage de fichiers et partage dans Android"> "Utilisation de FileProvider pour le partage de fichiers".
• Commandes de copie de stockage externe dans "STOCKAGE ET Partage dans Android" Exemple de projet lorsqu'il est ciblé Android 10 SDK 29 Versions antérieures, c'est-à-dire "memo1.lines.savetofile (tpath.combine (tpath.getshareddownloadspath," memo1external.txt ')); ". Lorsque le SDK 30 SDK 30 est ciblé, la même application soulève "Impossible de créer un fichier" (Storage / IMumulé / 0 / Download / Memo1External.txt ". Permission refusée" Exception. La commande "DeleteFile" ne supprime pas les fichiers de téléchargement / GetShareddownloadspath.
• Statut actuel avant Android 10 et après Android 11 Modifications de stockage de fichiers de stockage portée obligatoire:
• «RequestLegacyExternalStorage» a été supprimé du stockage de la portée et maintenant les applications qui souhaitent y accéder sont rejetées dans le gpstore. Pour publier votre application, effectuez le changement suivant dans AndroidManifest.Template.xml ::
android:requestLegacyExternalStorage="false">
• Tous les fichiers API Access (Action_Manage_Storage) sont rejetés par Google Play Store, mais si cette autorisation est accordée (et que l'application ne sera pas publiée), elle peut lire et enregistrer des fichiers comme avant Android 11. Si vous avez besoin de cela, vous devez ajouter sous "Androidmanifest.Temlate.xml" et demandez "Action_Manage_App_sal_Files_Access_permission" intention.
• Les bases de données partagées BlobStoreManager API fonctionnent uniquement sur Android 11 SDK 30 et plus, ne fonctionne pas sur les versions Android 10 et antérieures.
• Les bases de données partagées BlobStoreManager exécutent uniquement les versions Android 11 SDK 30 et plus, n'exécute pas les versions Android 10 et inférieures. Il n'est pas inclus en considération car il n'est pas pris en charge par la plupart des appareils actuellement.
• Accès à un stockage partagé (externe) avec SAF et MediaStore:
• Obtenir URI: seuls les trois premiers exemples de cas d'utilisation des codes de formation ci-dessus obtiennent à la fois un fichier URI et l'autorisation d'y accéder. L'accès à des fichiers externes URI est introduit en capturant leurs actions avec OnActivityResult.
• Tous les autres exemples décrivent comment gérer les URI obtenus à partir de ces 3 actions de cas d'utilisation. Si vous ne connaissez pas le fichier URI, vous ne pouvez pas les utiliser.
• De plus, l'ancienne intention d'action_get_content peut être utilisée pour obtenir un URI en appelant le sélecteur du système, similaire à Action_Open_Document; mais il ne fournit pas un accès permanent.
• Avec MediStore.Files, l'URI des fichiers dans le stockage des médias peut également être récupéré, mais il n'a pas été inclus dans le contenu de ce sujet en raison de la déclaration «Le contenu de MediStore.Files dans le magasin de médias dépend également de la question de savoir si votre application utilise le stockage étendu disponible dans les applications ciblant Android 10 ou plus». Bien que les classes MediStore.Downloads et Getmediauri donnent également accès au fichier de stockage externe URI, ils ne prennent en charge que le SDK 29 et plus.
• E Si vous souhaitez opérer sur un fichier avec n'importe quel code sans utiliser de cas, vous pouvez directement utiliser un fichier URI (par exemple: contenu: //com.android.providers.downloads.documents/Documents/16874) avec le "java.lang.securityException: permission" Denial: Reading ... nécessite l'accès à l'action_open_ducumentxect "
• En bref, les applications d'enregistrement de fichiers de stockage externes dans le stockage de portée sont dans le goulot d'étranglement URI. De plus, si vous souhaitez couvrir tous les appareils Android sur le marché en utilisant des versions plus anciennes avant le SDK 29, vous devez utiliser des cas d'utilisation SAF, il n'y a aucun moyen d'autre que cela. Dans Android Developer Conference, Video, Annonces, ils affirment que le but de passer à la portée du stockage est de supprimer les autorisations inutiles, mais en réalité, l'inverse s'est produit pour les développeurs et les utilisateurs.
• Les exemples de codes (tous sur les tutoriels SAF et la plupart sur le Medistore) sont le niveau SDK 1-24 et sont pris en charge par les versions Delphi 10.x.
• Delphi 11 est tenu d'utiliser les niveaux de SDK 29 Ve 30 commandes Medistore de «téléchargements», «getmediauri», charger des miniatures> ChargeThumbnail, ajouter un élément> volume_external_primary, basculer le statut en attente pour les fichiers médias> IS_PENDANT FLAGIN, MISE À JOUR AUTRES APPRIMARDS Fichiers médias> RecoreAptureSException, gérer les groupes de fichiers médias> CreatefavainErequest ».
• Pour le partage de fichiers à partir du stockage externe, l'obtention d'un URI de fichier par SAF File Picker, puis de partage des intentions requises. Si URI de fichier externe disponible, il peut être utilisé pour l'ouverture de fichiers, la lecture, l'enregistrement et la copie.
• Articles amortis pour le stockage externe:
// 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);Brièvement, tous les fichiers, le contenu, les actions et les intentions FileProvider sont dépréciés.
(PS: Si l'autorisation d'accéder au répertoire où le fichier est situé est obtenue par Action_Open_Document_Tree, il peut être possible d'accéder aux fichiers par ces commandes, mais n'a pas pu être essayé car cette intention ne fonctionne pas dans Delphi 10.))
• Pour utiliser le framework d'accès au stockage SAF, aucune autorisation requise pour obtenir du projet -> utilise les autorisations, tout peut être fermé. Les projets n'ont besoin d'aucune autorisation, c'est-à-dire «autorisation de permissions.requestpermisessions». Toutes les autorisations dans un échantillon de projet OFF.
• Pour accéder aux fichiers avec SAF, il suffit d'appeler simplement les cas d'utilisation (ACTION_CREATE_DOCUMENT, ACTION_OPEN_DOCUMENT, ACTION_OPEN_DOCUMENT_TREE). Cependant, chacun d'eux ouvre l'interface de sélecteur de système, contrairement à l'ancien tFile.copie.
• Action_create_Document est utilisé pour enregistrer un nouveau fichier avec une interface similaire à "Enregistrer sous", et Action_Open_Document est utilisé pour ouvrir, afficher et modifier les fichiers existants. ACTION_OPEN_DOCUMENT_TREE est pour accéder non seulement aux répertoires, mais aussi à tous les fichiers.
• Lors de l'utilisation de SAF, la pièce d'intention-filtre dans AndroidManifest.Template.xml est prête avec Delphi, il n'est pas nécessaire d'ajouter une autre intention.
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
• Les cas d'utilisation SAF sont immédiatement disponibles dans les projets Delphi ciblant le SDK 30 en l'appelant simplement avec les bibliothèques Android nécessaires et les exemples de codes, car ils sont intégrés avec toutes les versions Delphi 10.
• L'écriture sur l'audio, l'image, les fichiers vidéo et les téléchargements ci-dessus la version 11 n'est pas limitée avec MediaStore. C'est-à-dire que vous pouvez enregistrer l'image sans autorisation.
• Les collections de médias ne peuvent être lues qu'avec la permission.
• Access_media_location est requis pour les données de localisation de l'image.
• PDF, texte, etc. Accédant aux fichiers disponibles par le "Picker système".
• «Système Picker» est requis pour lire et écrire en dehors de la collection.
• Project -> Utilise les autorisations -> write_external_storage L'option doit être désactivée sur SDK 29. Read_external_storage est requis pour la lecture.
• Les classes URI Medistore ne sont pas disponibles dans les bibliothèques pré-Delphi 11 car elles ont été supprimées pour accéder aux fichiers au-dessus du SDK 29. Ainsi, la plupart des codes de didacticiel Medistore ci-dessus ont été importés de Java à Object Pascal, n'ont pas pu être essayés.
• Au moment de l'exécution, selon le niveau du SDK de l'appareil, l'autorisation d'écriture doit être demandée pour (SDK <28) et non pour (sdk> = 29).
• AndroidManifest.Template.xml Modifications:
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="30" />
android:requestLegacyExternalStorage="false">
• MediaStore nécessite une autorisation de lecture sur le stockage externe, pas une autorisation d'écriture. Pour la compatibilité avec les versions avant Android 10, sous Project -> utilise les autorisations, supprimez l'option écrite_external_storage et ajoutez ce qui suit dans Manifest:
<%uses-permission%>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
• La copie de fichiers ne peut plus être effectuée avec une seule commande (tfile.copy) à partir du stockage externe. Nous appelons d'abord le cas d'utilisation (ACTION_OPEN_DOCUMENT ou ACTION_CREATE_DOCUMENT). Ensuite, nous gérons le code de demande avec "HandleMessageActivity" et "OnActivityResult". Enfin, nous écrivons dans le fichier que nous venons d'ouvrir avec l'URI et les flux (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 ;