Datenschutzänderungen in Android 10
Android 11 - Privatsphäre und Sicherheit
Verhaltensänderungen: Apps zu Android 11 - Privatsphäre
Verwendung aller Dateienzugriff
Überblick über den gemeinsam genutzten Speicher
Nach Android 10 und 11 Änderungen der Datenschutz- und Sicherheitsänderungen, direkter Zugriff auf Speicher durch Anwendungen, die nur auf interne gesammelt wurden und jetzt nur durch 4 APIs auf externe Dateien zugreifen:
Alle Dateien zugreifen auf API (verwalten_external_storage - action_manage_app_all_files_access_permission und action_manage_storage intent) für nur Apps für Dateimanager und Antiviren -Typen verfügbar. Alle anderen Typ -Apps werden von Google Play Store Publishing abgelehnt. Datenbanken (Blobstoremanager) API werden nur Android 11 SDK 30 und obere Versionen ausgeführt, nicht Android 10 und vorherige. Daher wurden beide APIs unter dem Thema ausgeschlossen.
Öffnen Sie Dateien mit dem Speicherzugriffs -Framework
Greifen Sie auf Dokumente und andere Dateien aus dem gemeinsam genutzten Speicher zu
Anwendungsfälle zum Zugriff auf Dokumente und andere Dateien
Das Speicherzugriffs -Framework unterstützt die folgenden Anwendungsfälle für den Zugriff auf Dateien und andere Dokumente.
Erstellen Sie eine neue Datei
The ACTION_CREATE_DOCUMENT intent action allows users to save a file in a specific location.
Öffnen Sie ein Dokument oder eine Datei
The ACTION_OPEN_DOCUMENT intent action allows users to select a specific document or file to open.
Gewähren Sie Zugang zu dem Inhalt eines Verzeichnisses
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.
In den folgenden Abschnitten werden Leitlinien zur Konfiguration jedes Anwendungsfalls enthält.
Erstellen Sie eine neue Datei
// 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 ;Öffnen Sie eine Datei
// 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 ;Gewähren Sie Zugang zu dem Inhalt eines Verzeichnisses
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 ;Führen Sie Operationen am ausgewählten Standort aus
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 ;Durch einen Verweis auf das URI des ausgewählten Elements kann Ihre App mehrere Vorgänge für den Artikel ausführen. Sie können beispielsweise auf die Metadaten des Artikels zugreifen, das Element an Ort und Stelle bearbeiten und das Element löschen. In den folgenden Abschnitten werden angezeigt, wie die Aktionen in den Dateien, die der Benutzer auswählt, auszuführen:
Beständige Berechtigungen
// 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);Untersuchen Sie die Dokumentmetadaten
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 ;Öffnen Sie ein Dokument - 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 ;Öffnen Sie ein Dokument - Eingabestream
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 ;Bearbeiten Sie ein Dokument
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 ; Löschen Sie ein Dokument
TJDocumentsContract.JavaClass.deleteDocument (TAndroidHelper.contentResolver, Uri);Öffnen Sie eine virtuelle Datei
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 ; Virtuelle Datei als Bild
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 ;Standard -RTL -Pfadfunktionen auf den unterstützten Zielplattformen: interner Speicher, externe private interne S, gemeinsamer externer Speicherplatz
Speicheränderungen in Android -Versionen
| # | Code | SDK | Veröffentlichen | Ändern |
|---|---|---|---|---|
| 1 | - - | 1 | 23.09.08 | Intent, System Picker (Action_) in der ersten Version gestartet |
| 4.4 | K | 19 | 31.10.13 | FileProvider (Content API), DocumentsContract, DocumentProvider -Klassen |
| 7 | N | 25 | 04.10.16 | FileProvider -Nutzung obligatorisch (wenn diese Version abzielt) |
| 8 | O | 26 | 21.03.17 | August 2018 Google Play Store und. 8.0 Veröffentlichungsanforderung |
| 10 | Q | 29 | 03.09.19 | Scoped Storage. Privatsphäre und Sicherheit nahmen zu |
| 11 | R | 30 | 09.09.20 | August 2021 Targeting Android API 30 (Google Play Store veröffentlichen Anforderungen) |
Dokumentanbieter, 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
Android -Unterstützung in Delphi -Versionen
RAD Studio Delphi 10+ -versionen begleiten Android 10+ Java -Bibliotheken (Androidapi.jni.graphicsContentViewtext, Androidapi.Ioutils, Androidapi.jni.Media, Androidapi.jni.Provider, Androidapi.jni.jni.App, Androidapi.helpers, Androidapi.jni.App, Androidapi.helpers, Androidapi.jni.App, Androidapi. Androidapi.jni.javatypes, Androidapi.jni.net, Androidapi.jni.OS, Androidapi.jni.provider), der Scoped Storage, SAF und einige mediale Befehle unterstützt.
| Delphi | Android |
|---|---|
| Xe5 | 2.33 - 4.4 |
| 10 Seattle | 4.03 - 5 |
| 10.1 Berlin | 4.03 - 7 |
| 10.2 Tokio | 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 hat Android 30 API -Unterstützung (Google Play Store 2021 Anforderung).
Unterschiede zum Speichern und der Freigabe in Android:
• Es gibt keinen Unterschied in Android 11 für den internen Speicher. Wie in Android 10 und früher ist der Zugriff auf Dateien unbegrenzt. Auch hier ist keine Erlaubnis erforderlich.
• Die Dateifreigabe ist dieselbe, wieder in der Content -API (FileProvider) und der Anrufe mit "Intent.setAction (tjintent.javaclass.Action_send);"; Absicht geht weiter. Um die Funktion "FileProvider" aktivieren zu können, sollte die Option "Sicherheitsfreigabe" in Projektoptionen-> Anwendungen-> Berechtigungsliste (in Delphi 10.3 RIO und später verfügbar) auswählen, um diese API weiterhin zu verwenden. Für die früheren Versionen von Delphi 10.3 sollte die FileProvider -API manuell hinzugefügt werden, wie in "Dateispeicher und Freigabe in Android"> "Verwenden von FileProvider zur Dateifreigabe".
• Befehle für externe Speicherkopien in "Dateispeicher und Freigabe in Android" -Samprojekt, das bei gezielten Android 10 SDK 29 frühere Versionen ausgeführt wird, dh „memo1.lines.savetofile (tpath.combine (tpath.getShareddownloadspath), 'memo1external.txt'); Wenn Android 11 SDK 30 zielgerichtet ist, erhöht die gleiche App nicht "Datei" (Speicher/emuliert/0/download/memo1external.txt ". Berechtigung verweigert" Ausnahme.
• Der aktuelle Status vor Android 10 und nach Android 11 Obligatorische Speicherdateispeicheränderungen:
• „RequestLegacyExternalStorage“ wurde aus dem Bereich "Geltungsbereich" entfernt, und jetzt werden Anwendungen, die darauf zugreifen möchten, im GPStore abgelehnt. Um Ihre App zu veröffentlichen, ändern Sie die folgende Änderung in AndroidManifest.template.xml ::
android:requestLegacyExternalStorage="false">
• Alle Dateien zugreifen auf API (Action_Manage_Storage) werden vom Google Play Store abgelehnt. Wenn diese Berechtigung jedoch erteilt wird (und die App nicht veröffentlicht wird), kann sie wie vor Android 11 gelesen und speichern. Absicht.
• Shared Databasen Blobstoremanager API funktioniert nur auf Android 11 SDK 30 und höher und funktioniert nicht auf Android 10 und früheren Versionen.
• Shared Databases Blobstoremanager API ausgeführt nur Android 11 SDK 30 und höhere Versionen, werden Android 10 und niedrigere Versionen nicht ausgeführt. Es wird nicht berücksichtigt, da es von den meisten derzeit nicht von den meisten Geräten unterstützt wird.
• Zugriff auf gemeinsamen (externen) Speicher mit SAF und Mediastore:
• URI erhalten: Nur die ersten drei Beispiele von Anwendungsfällen aus den obigen Trainingscodes erhalten Sie sowohl die URI als auch die Erlaubnis, darauf zuzugreifen. Der Zugriff auf externe Datei -URIs wird eingeführt, indem ihre Handlungen mit Onaktivitätsresult erfasst werden.
• Alle anderen Beispiele beschreiben, wie sie mit URIs umgehen können, die aus diesen 3 Anwendungsfällen erhalten werden. Wenn Sie die Datei -URI nicht kennen, können Sie sie nicht verwenden.
• Außerdem kann die alte Action_Get_Content -Absicht verwendet werden, um einen URI zu erhalten, indem der Systemauswahl aufgerufen wird, ähnlich wie action_open_document. Es bietet jedoch keinen dauerhaften Zugang.
• Mit Mediastore.files kann auch der URI der Dateien im Medienspeicher abgerufen werden, aber es wurde nicht in den Inhalt dieses Themas enthalten, da die Anweisung „Inhalt von Mediastore.files im Medienspeicher auch abhängt, ob Ihre Anwendung den umfangreichen Speicher verwendet, der in Anwendungen zur Verfügung steht, die auf Android 10 oder höher abzielen.“ Obwohl die Klassen mediDeTore.downloads und GetMediauri auch Zugriff auf externe Speicherdatei -URI bieten, unterstützen sie nur SDK 29 und höher.
• E Wenn Sie ohne Verwendung eines Falles auf einer Datei mit einem Codes arbeiten möchten, können Sie direkt eine Datei -URI (z.
• Kurz gesagt, Apps für externe Speicherdateien im Bereich "Speicherspeicher" befinden sich im URI -Engpass. Wenn Sie alle Android -Geräte auf dem Markt mit älteren Versionen vor SDK 29 abdecken möchten, müssen Sie SAF -Anwendungsfälle verwenden. In der Android Developer Conference, Video, Ankündigungen behaupten sie, dass der Zweck des Umschaltens in den Bereich "Umgang" darin besteht, unnötige Berechtigungen zu entfernen, aber in Wirklichkeit ist das Gegenteil für Entwickler und Benutzer stattgefunden.
• Die Beispielcodes (alle in den SAF-Tutorials und die meisten auf dem Mediastore) sind SDK Level 1-24 und werden von Delphi 10.x-Versionen unterstützt.
• Delphi 11 ist erforderlich, um SDK -Ebenen zu verwenden. CreateFavoriterequest “.
• Für die Dateifreigabe vom externen Speicher wird zunächst die URI von Datei per SAF -Datei -Picker abgerufen und die Absichten der Freigabe erforderlich. Wenn externe Datei -URI verfügbar ist, kann sie für die neue Datei Öffnung, Lesen, Speichern und Kopierzwecke verwendet werden.
• Abgeschriebene Elemente für die externe Speicherung:
// 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);Kurz alle Dateien, Inhalte, FileProvider -Aktionen und Absichten werden abgeschrieben.
(PS: Wenn die Erlaubnis, auf das Verzeichnis zuzugreifen, in dem die Datei lokalisiert wird, von Action_open_document_Tree erhalten wird, kann es möglich sein, auf Dateien auf Dateien zugreifen zu können, aber nicht ausprobiert werden konnten, da diese Absicht in Delphi 10 nicht funktioniert.))
• Um den Speicherzugriffs -Framework SAF zu verwenden, sind keine Berechtigungen erforderlich, um aus dem Projekt zu erhalten -> Verwendet Berechtigungen, alle können geschlossen werden. Projekte benötigen keine Erlaubnis, dh "Berechtigungenservice.requestPermissions". Alle Berechtigungen im Beispielprojekt aus.
• Um mit SAF auf Dateien zuzugreifen, reicht es aus, einfach Anwendungsfälle (Action_Create_Document, Action_open_Document, Action_open_Document_Tree) aufzurufen. Jede von ihnen öffnet jedoch im Gegensatz zur alten tfile.copy die System -Picker -Schnittstelle.
• Action_Create_Document wird verwendet, um eine neue Datei mit einer Schnittstelle zu speichern, die "Speichern als" ähnelt, und action_open_document wird verwendet, um vorhandene Dateien zu öffnen, anzuzeigen und zu ändern. Action_open_document_tree dient zum Zugriff auf nicht nur Verzeichnisse, sondern auch alle darunter liegenden Dateien.
• Bei der Verwendung von SAF ist der Intent-Filter-Teil in AndroidManifest.template.xml mit Delphi fertig. Sie müssen keine weitere Absicht hinzufügen.
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
• SAF-Anwendungsfälle sind sofort in Delphi-Projekten verfügbar, die auf SDK 30 abzielen, indem sie einfach mit den erforderlichen Android-Bibliotheken und Beispielcodes aufgerufen werden, da sie mit allen Delphi 10-Versionen integriert sind.
• Das Schreiben in Audio, Bild, Videodateien und Downloads über Version 11 ist nicht mit Mediastore eingeschränkt. Dh Sie können das Bild ohne Erlaubnis speichern.
• Mediensammlungen können nur mit Genehmigung gelesen werden.
• Access_Media_Location ist für Bildortdaten erforderlich.
• PDF, Text usw. Zugriff auf die vom "System Picker" verfügbaren Dateien.
• Für das Lesen und Schreiben außerhalb der Sammlung ist „System Picker“ erforderlich.
• Projekt -> Verwendet Berechtigungen -> Write_external_Storage -Option muss auf SDK 29 ausgeschaltet werden. Read_external_Storage ist für das Lesen erforderlich.
• Mediastore-URI-Klassen sind in Bibliotheken vor dem Delphi 11 nicht verfügbar, da sie zum Zugriff auf Dateien über SDK 29 entfernt wurden. Die meisten der oben genannten Mediastore-Tutorial-Codes wurden also nur von Java in Objekt Pascal importiert und nicht ausprobiert werden.
• Zur Laufzeit sollte abhängig von der SDK -Ebene des Geräts die Schreibberechtigung für (SDK <28) und nicht für (SDK> = 29) angefordert werden.
• AndroidManifest.template.xml Änderungen:
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="30" />
android:requestLegacyExternalStorage="false">
• Mediastore erfordert eine Leseberechtigung zum externen Speicher, nicht für die Schreibberechtigung. Für die Kompatibilität mit Versionen vor Android 10 unter Projekt -> verwendet die Berechtigungen die Option write_external_storage und fügen Sie Folgendes in Manifest hinzu:
<%uses-permission%>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
• Das Kopieren von Dateien kann nicht mehr mit einem einzelnen Befehl (tfile.copy) aus dem externen Speicher durchgeführt werden. Zuerst nennen wir den Anwendungsfall (action_open_document oder action_create_document) intent. Anschließend verarbeiten wir den Anforderungscode mit "Handlemessageaktivität" und "OnactivityResult". Schließlich schreiben wir in die Datei, die wir gerade mit URI und Streams geöffnet haben (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 ;