Cambios de privacidad en Android 10
Android 11 - Privacidad y seguridad
Cambios de comportamiento: aplicaciones dirigidas a Android 11 - Privacidad
Uso de todos los archivos Acceso (manage_external_storage) Permiso
Descripción general del almacenamiento compartido
Después de los cambios de privacidad y seguridad de Android 10 y 11, el acceso directo al almacenamiento por aplicaciones alcanzó solo a interno y ahora accede a archivos externos posibles y simplemente por 4 API:
Todos los archivos Access API (manage_external_storage - Action_manage_app_all_files_access_permission Permiso y Action_Manage_Storage Intent) Disponible solo para aplicaciones de tipo de archivos y antivirus, todas las demás aplicaciones son rechazadas por Google Play Store Publishing. La API de bases de datos (blobstoremanager) ejecuta solo las versiones SDK 30 y superiores de Android 11 y las versiones superiores, no Android 10 y las anteriores. Por lo tanto, ambas API excluidas por debajo del sujeto.
Abra archivos utilizando el marco de acceso de almacenamiento
Acceder a documentos y otros archivos desde el almacenamiento compartido
Casos de uso para acceder a documentos y otros archivos
El marco de acceso de almacenamiento admite los siguientes casos de uso para acceder a archivos y otros documentos.
Crea un nuevo archivo
The ACTION_CREATE_DOCUMENT intent action allows users to save a file in a specific location.
Abra un documento o archivo
The ACTION_OPEN_DOCUMENT intent action allows users to select a specific document or file to open.
Otorgar acceso a los contenidos de un directorio
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.
Las siguientes secciones proporcionan orientación sobre cómo configurar cada caso de uso.
Crea un nuevo archivo
// 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 ;Abrir un archivo
// 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 ;Otorgar acceso a los contenidos de un directorio
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 ;Realizar operaciones en la ubicación elegida
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 ;Al obtener una referencia al URI del elemento seleccionado, su aplicación puede realizar varias operaciones en el elemento. Por ejemplo, puede acceder a los metadatos del artículo, editar el elemento en su lugar y eliminar el elemento. Las siguientes secciones muestran cómo completar acciones en los archivos que selecciona el usuario:
Permisos de persistir
// 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);Examinar los metadatos del documento
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 ;Abra un documento - 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 ;Abra un documento - flujo de entrada
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 ;Editar un documento
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 ; Eliminar un documento
TJDocumentsContract.JavaClass.deleteDocument (TAndroidHelper.contentResolver, Uri);Abra un archivo 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 ; archivo virtual como imagen
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 ;Funciones de ruta RTL estándar en las plataformas de destino compatibles: almacenamiento interno, sternal privado interno, almacenamiento externo compartido
Cambios de almacenamiento en las versiones de Android
| # | Código | Sdk | Publicar | Cambiar |
|---|---|---|---|---|
| 1 | - | 1 | 23.09.08 | Intención, System Picker (Action_) comenzó en la primera versión |
| 4.4 | K | 19 | 31.10.13 | FileProvider (API de contenido), DocumentsContract, DocumentProvider Classes |
| 7 | norte | 25 | 04.10.16 | Uso de FileProvider obligatorio (cuando se le dirija a esta versión) |
| 8 | O | 26 | 21.03.17 | Agosto de 2018 Google Play Store y. 8.0 Requisito de publicación |
| 10 | Q | 29 | 03.09.19 | Almacenamiento con alcance. La privacidad y la seguridad aumentaron |
| 11 | Riñonal | 30 | 09.09.20 | Agosto de 2021 apuntando a la API 30 de Android 30 (Google Play Store Publish Requisito) |
Proveedor de documentos, 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
Soporte de Android en versiones de Delphi
Rad Studio Delphi 10+ Versiones acompañan a las bibliotecas Java Android 10+ (androidapi.jni.graphicsContentViewText, androidapi.ioutils, androidapi.jni.media, androidapi.jni.provider, androidapi.jni.app, androidapi.helpers, androidapi.javates. Androidapi.jni.net, androidapi.jni.os, androidapi.jni.provider) que admite almacenamiento alcanzado, SAF y algunos comandos de medias.
| Delfi | Androide |
|---|---|
| Xe5 | 2.33 - 4.4 |
| 10 Seattle | 4.03 - 5 |
| 10.1 Berlín | 4.03 - 7 |
| 10.2 Tokio | 4.1 - 8 |
| 10.3 Río | 5.1 - 10 |
| 10.4 Sydney | 6 - 11 |
| 11 Alejandría | 8.1 - 11 |
Rad Studio Delphi 11.0 Alexandria tiene soporte de API Android 30 (Requisito de Google Play Store 2021).
Diferencias al almacenamiento de archivos y compartir en Android:
• No hay diferencia en Android 11 para el almacenamiento interno. Como en Android 10 y anterior, el acceso a los archivos es ilimitado. Nuevamente, no se requiere permiso.
• El intercambio de archivos es el mismo, nuevamente API de contenido (FileProvider) y la forma de llamar con "Intent.SetAction (tjintent.javaclass.action_send);" La intención continúa. Para habilitar la función FileProvider, la selección de la opción de "compartir archivos seguros" en las opciones de proyecto-> Aplicación-> Lista de derechos (disponible en Delphi 10.3 RIO y posterior) debe agregarse para continuar utilizando esta API. Para las versiones anteriores de Delphi 10.3, la API de FileProvider debe agregarse manualmente como se explica en "Almacenamiento de archivos y compartir en Android"> "Uso de FileProvider para compartir archivos".
• Proyecto de muestra de copia de almacenamiento externo en el proyecto de muestra "Almacenamiento de archivos y compartir en Android" se ejecuta cuando las versiones anteriores de Android 10 SDK 29 anteriores, es decir, "Memo1.lines.savetofile (tpath.combine (tpath.getshareddownloadspath, 'memo1external.txt'));". Cuando Android 11 SDK 30 se dirigió a la misma aplicación "no puede crear archivo" (almacenamiento/emulado/0/descarga/memo1External.txt ". Excepción de permiso denegado". El comando "DeleteFile" no elimina los archivos en la carpeta Download/GetShareddownloadSpath. El mismo problema válido para todas las carpetas externas compartidas. El motivo es Android 11 restricciones como se indica anteriormente.
• Estado actual antes de Android 10 y después de Android 11 Cambios de almacenamiento de archivo de almacenamiento alcanzado obligatorio:
• Se ha eliminado "SolicleLegacyExternalStorage" del almacenamiento de alcance y ahora las aplicaciones que desean acceder a él se rechazan en GPStore. Para publicar su aplicación, realice el siguiente cambio en AndroidManifest.template.xml ::
android:requestLegacyExternalStorage="false">
• Todos los archivos Access API (Action_Manage_Storage) son rechazados por Google Play Store, pero si se otorga este permiso (y la aplicación no se publicará), puede leer y guardar archivos como antes de Android 11. Si necesita esto, necesita agregar en "AndroidManifest.template.xml" y solicitar "Action_Manage_App_Files_Acess_Access_permissission" AtTime y Call TheAdgora.
• Las bases de datos compartidas Blobstoremanager API funciona solo en Android 11 SDK 30 y superior, no funciona en las versiones de Android 10 y anteriores.
• Las bases de datos compartidas Blobstoremanager API ejecuta solo versiones SDK 30 y superiores de Android 11 y no ejecuta versiones de Android 10 y más bajas. No se incluye consideración, ya que no es compatible con la mayoría de los dispositivos actualmente.
• Acceder al almacenamiento compartido (externo) con SAF y MediaStore:
• Obtener URI: solo los primeros tres ejemplos de casos de uso de los códigos de capacitación anteriores obtienen URI de archivo y permiso para acceder a ellos. Se introduce acceder a URI de archivo externo capturando sus acciones con OnActivityResult.
• Todos los otros ejemplos describen cómo lidiar con URI obtenidos de estas 3 acciones de casos de uso. Si no conoce el URI del archivo, no puede usarlos.
• Además, la antigua intención Action_Get_Content se puede usar para obtener un URI llamando al selector del sistema, similar a Action_open_Document; Pero no proporciona acceso permanente.
• Con MediaStore.files, el URI de los archivos en el almacenamiento de medios también se puede recuperar, pero no se incluyó en el contenido de este tema debido a la declaración "el contenido de MediaStore.files en la tienda de medios también depende de si su aplicación usa el amplio almacenamiento disponible en aplicaciones dirigidas a Android 10 o más". Aunque las clases MediaStore.downloads y GetMediauri también proporcionan acceso a URI de archivo de almacenamiento externo, solo admiten SDK 29 y superior.
• E Si desea operar en un archivo con cualquier código sin usar un caso, puede usar directamente un archivo URI (por ejemplo: content: //com.android.providers.downloads.documents/documents/16874) con el "java.lang.securityException: permiso" Denación: Lectura ... Requiere que obtenga el acceso utilizando Action_Pen_Document o Relation APIS "APIS".
• Brevemente, las aplicaciones de grabación de archivos de almacenamiento externos en el almacenamiento de alcance están en cuello de botella URI. Además, si desea cubrir todos los dispositivos Android en el mercado utilizando versiones anteriores antes de SDK 29, debe usar casos de uso SAF, no hay otra salida que eso. En la Conferencia de Desarrolladores de Android, Video, anuncios, afirman que el propósito de cambiar al almacenamiento de alcance es eliminar los permisos innecesarios, pero en realidad, lo contrario ha sucedido para los desarrolladores y usuarios.
• Los códigos de muestra (todos en los tutoriales de SAF y la mayoría en MediaStore) son SDK Nivel 1-24 y son compatibles con las versiones Delphi 10.x.
• Se requiere que Delphi 11 use los niveles de SDK 29 VE 30 MediaStorStore de "descargas", clases "getMediauri", cargando miniaturas> LoadThumbnail, agregue un elemento> volumen_external_primary, alterne el estado pendiente para los archivos de medios> flager de medios, actualice los archivos de medios de otros archivos de los medios de recuperación de otros medios. CreateFearIterequest ”.
• Para el intercambio de archivos desde el almacenamiento externo, primero obtenga URI de archivo por el selector de archivos SAF, luego se requieren intentos para compartir. Si el URI de archivo externo está disponible, se puede utilizar para nuevos propósitos de apertura de archivos, lectura, guardado, copia.
• Artículos depreciados para almacenamiento externo:
// 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);Brevemente, todos los archivos, el contenido, las acciones e intenciones de FileProvider se deprecian.
(PD: Si el permiso para acceder al directorio donde se encuentra el archivo se obtiene por Action_open_Document_Tree, puede ser posible acceder a los archivos por estos comandos, pero no podría probarse ya que esta intención no funciona en Delphi 10.))))
• Para usar el marco de acceso de almacenamiento SAF, no se requieren permisos para obtener del proyecto -> utiliza permisos, todos pueden cerrarse. Los proyectos no necesitan ningún permiso, es decir, "PermissionsService.RequestPermissions". Todos los permisos en el proyecto de muestra apagado.
• Para acceder a archivos con SAF, es suficiente simplemente llamar a los casos de uso (Action_Create_Document, Action_open_Document, Action_open_Document_Tree) intentos. Sin embargo, cada uno de ellos abre la interfaz del selector del sistema, a diferencia del antiguo tfile.copy.
• Action_Create_Document se usa para guardar un nuevo archivo con una interfaz similar a "Guardar como", y Action_open_Document se usa para abrir, mostrar y modificar los archivos existentes. Action_open_document_tree es para acceder no solo a los directorios sino también a todos los archivos en él.
• Cuando se usa SAF, la parte del filtro de intención en AndroidManifest.template.xml está lista con Delphi, no hay necesidad de agregar otra intención.
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
• Los casos de uso de SAF están disponibles de inmediato en proyectos de Delphi que se dirigen a SDK 30 simplemente llamándolo con las bibliotecas y códigos de muestra necesarios de Android, ya que están integrados con todas las versiones de Delphi 10.
• Escribir en audio, imagen, archivos de video y descargas anteriores a la versión 11 no está restringido con MediaStore. Es decir, puedes guardar la imagen sin permiso.
• Las colecciones de medios solo se pueden leer con permiso.
• Access_media_location es necesario para los datos de ubicación de la imagen.
• PDF, texto, etc. Acceso a los archivos disponibles por el "selector del sistema".
• Se requiere "seleccionador del sistema" para leer y escribir fuera de la colección.
• Proyecto -> Utiliza permisos -> Write_External_storage La opción debe desactivarse en SDK 29. Read_external_storage es necesario para leer.
• Las clases de URI de MediaStore no están disponibles en las bibliotecas previas a Delphi 11, ya que se eliminaron para acceder a archivos por encima de SDK 29. Por lo tanto, la mayoría de los códigos tutoriales de medias anteriores se importaron de Java a Object Pascal, no se pudo probar.
• En tiempo de ejecución, dependiendo del nivel SDK del dispositivo, se debe solicitar el permiso de escritura (SDK <28) y no para (SDK> = 29).
• AndroidManifest.template.xml cambia:
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="30" />
android:requestLegacyExternalStorage="false">
• MediaStore requiere permiso de lectura en almacenamiento externo, no permiso de escritura. Para la compatibilidad con versiones antes de Android 10, en Proyecto -> usa permisos, elimine la opción Write_External_Storage y agregue lo siguiente en Manifest:
<%uses-permission%>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
• La copia de archivos ya no se puede realizar con un solo comando (tfile.copy) desde el almacenamiento externo. Primero llamamos a la intención del caso de uso (Action_open_Document o Action_Create_Document). Luego manejamos el código de solicitud con "Handlemessageactivity" y "OnActivityResult". Finalmente escribimos en el archivo que acabamos de abrir con URI y Streams (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 ;