Mudanças de privacidade no Android 10
Android 11 - Privacidade e segurança
Alterações de comportamento: aplicativos direcionados para Android 11 - Privacidade
Uso de todos os arquivos Acesso (gerencia_external_storage) permissão
Visão geral do armazenamento compartilhado
Após as mudanças de privacidade e segurança do Android 10 e 11, o acesso direto ao armazenamento por aplicativos escopo apenas interno e agora acessando arquivos externos é possível e simplesmente por 4 APIs:
Todos os arquivos API Access (Manage_External_Storage - Action_Manage_App_all_Files_Access_Permission Permission e Action_Manage_Storage Intent) Disponível para aplicativos do tipo Gerenciador e Antivírus, todos os outros aplicativos de tipo são rejeitados pelo Google Play Store Publishing. Os bancos de dados (API BlobStoremanager) executam apenas o Android 11 SDK 30 e as versões superiores, não o Android 10 e as anteriores. Portanto, ambas as APIs excluídas abaixo do assunto.
Abra arquivos usando a estrutura de acesso de armazenamento
Acesse documentos e outros arquivos do armazenamento compartilhado
Use casos para acessar documentos e outros arquivos
A estrutura de acesso ao armazenamento suporta os seguintes casos de uso para acessar arquivos e outros documentos.
Crie um novo arquivo
The ACTION_CREATE_DOCUMENT intent action allows users to save a file in a specific location.
Abra um documento ou arquivo
The ACTION_OPEN_DOCUMENT intent action allows users to select a specific document or file to open.
Conceder acesso ao conteúdo de um diretório
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.
As seções a seguir fornecem orientações sobre como configurar cada caso de uso.
Crie um novo arquivo
// 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 ;Abra um arquivo
// 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 ;Conceder acesso ao conteúdo de um diretório
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 ;Executar operações no local escolhido
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 ;Ao obter uma referência ao URI do item selecionado, seu aplicativo pode executar várias operações no item. Por exemplo, você pode acessar os metadados do item, editar o item no lugar e excluir o item. As seções a seguir mostram como concluir as ações nos arquivos que o usuário seleciona:
Permissões persistentes
// 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);Examine os metadados do 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 um 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 um documento - fluxo 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 ;Edite um 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 ; Exclua um documento
TJDocumentsContract.JavaClass.deleteDocument (TAndroidHelper.contentResolver, Uri);Abra um arquivo 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 ; arquivo virtual como imagem
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 ;Funções de caminho RTL padrão em todas as plataformas de destino suportadas: armazenamento interno, s interno privado externo, armazenamento externo compartilhado
Mudanças de armazenamento nas versões do Android
| # | Código | Sdk | Publicar | Mudar |
|---|---|---|---|---|
| 1 | - | 1 | 23.09.08 | Intenção, seletor de sistema (ação_) iniciado na primeira versão |
| 4.4 | K | 19 | 31.10.13 | FileProvider (API de conteúdo), DocumentSContract, DocumentProvider Classes |
| 7 | N | 25 | 04.10.16 | Uso do FileProvidor obrigatório (quando direcionado a esta versão) |
| 8 | O | 26 | 21.03.17 | Agosto de 2018 Google Play Store e. 8.0 Requisito de publicação |
| 10 | Q | 29 | 03.09.19 | Armazenamento com escopo. Privacidade e segurança aumentaram |
| 11 | R | 30 | 09.09.20 | Agosto de 2021, direcionando Android API 30 (Requisito de publicação do Google Play Store) |
Provedor 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
Suporte Android nas versões Delphi
As versões Rad Studio Delphi 10+ acompanham as bibliotecas Java Android 10+ (Androidapi.jni.GraphicsContentViewText, Androidapi.ioutils, Androidapi.jni.media, androidapi.jni.provider, Androidapi.jni.appi, erapides, erapapi. Androidapi.jni.javatypes, Androidapi.jni.net, Androidapi.jni.os, Androidapi.jni.provider) Apoia o armazenamento escopo, SAF e alguns comandos da mediaStore.
| Delphi | Android |
|---|---|
| XE5 | 2.33 - 4.4 |
| 10 Seattle | 4.03 - 5 |
| 10.1 Berlim | 4.03 - 7 |
| 10.2 Tóquio | 4.1 - 8 |
| 10.3 Rio | 5.1 - 10 |
| 10.4 Sydney | 6 - 11 |
| 11 Alexandria | 8.1 - 11 |
O Rad Studio Delphi 11.0 Alexandria possui suporte Android 30 API (requisito do Google Play Store 2021).
Diferenças para armazenamento e compartilhamento de arquivos no Android:
• Não há diferença no Android 11 para armazenamento interno. Como no Android 10 e anterior, o acesso aos arquivos é ilimitado. Novamente, nenhuma permissão é necessária.
• O compartilhamento de arquivos é o mesmo, novamente a API de conteúdo (FileProvider) e a maneira de ligar com "Intent.SetAction (tjintent.javaclass.action_send);" A intenção continua. Para ativar o recurso FileProvider, a seleção da opção "Compartilhamento de Arquivos Seguro" nas opções do projeto-> Application-> Lista de direito (disponível no Delphi 10.3 Rio e posterior) deve ser adicionado para continuar a usar essa API. Para versões anteriores Delphi 10.3, a API do FileProvider deve ser adicionada manualmente, conforme explicado em "Armazenamento e compartilhamento de arquivos no Android"> "Usando o FileProvider para compartilhamento de arquivos".
• Comandos de cópia de armazenamento externo em "Armazenamento e compartilhamento de arquivos no Android" Projeto de amostra executado quando o Android 10 SDK 29 versões anteriores, ou seja, “memo1.lines.savetofile (tpath.combine (tpath.getshareddownloadspath, 'memo1external.txt');”. Quando o Android 11 SDK 30 segmentou, o mesmo aplicativo aumenta “não pode criar arquivo“ (armazenamento/emulado/0/download/memo1external.txt ”. Permissão negada” Exceção.
• Status atual antes do Android 10 e após o Android 11 Scoped Arquivo de armazenamento obrigatório Alterações de armazenamento:
• “RequestLegacyExternalStorage” foi removido do armazenamento de escopo e agora os aplicativos que desejam acessá -lo são rejeitados no GPStore. Para publicar seu aplicativo, faça a seguinte alteração no androidmanifest.template.xml ::
android:requestLegacyExternalStorage="false">
• Todos os arquivos API Access API (Action_Manage_Storage) é rejeitado pelo Google Play Store, mas se essa permissão for concedida (e o aplicativo não será publicado), ele poderá ler e salvar arquivos como antes do Android 11. Se você precisar disso, você precisa adicionar e adicionar "AndroidManifest.template.xml" e "Action_Manage_Alp_All_All_Files. intenção.
• Os bancos de dados compartilhados BlobStoremanager API funciona apenas no Android 11 SDK 30 e acima, não funciona no Android 10 e versões anteriores.
• Os bancos de dados compartilhados BlobStoremanager API executa apenas o Android 11 SDK 30 e as versões superiores, não executa o Android 10 e as versões inferiores. Não é incluído consideração, pois não é suportado pela maioria dos dispositivos atualmente.
• Acessando o armazenamento compartilhado (externo) com SAF e MediaStore:
• Obter URI: apenas os três primeiros exemplos de casos de uso dos códigos de treinamento acima recebem URI de arquivo e permissão para acessá -los. O acesso a URIs de arquivo externo é introduzido capturando suas ações com o OnactivityResult.
• Todos os outros exemplos descrevem como lidar com URIs obtidos nessas 3 ações de casos de uso. Se você não conhece o URI do arquivo, não pode usá -los.
• Além disso, a intenção antiga Action_Get_Content pode ser usada para obter um URI chamando o seletor do sistema, semelhante ao Action_open_document; mas não fornece acesso permanente.
• Com o MediaStore.Files, o URI dos arquivos no armazenamento de mídia também pode ser recuperado, mas não foi incluído no conteúdo deste tópico devido à declaração “o conteúdo do mediastore.Files no mídia também depende se o seu aplicativo usa o armazenamento extenso disponível em aplicativos direcionados ao Android 10 ou superior”. Embora as classes MediaStore.Downloads e GetMediauri também forneçam acesso ao URI de arquivo de armazenamento externo, eles suportam apenas o SDK 29 e acima.
• e se você deseja operar em um arquivo com qualquer código sem usar um caso, pode usar diretamente um URI de arquivo (por exemplo: Content: //com.android.providers.downloads.documents/documents/16874) com o "Java.Lang.SecurityException: Permission" Denial: Reading ... requer que você obtenha que você obtenha o acesso a acção.
• Resumidamente, os aplicativos de gravação de arquivos de armazenamento externo no armazenamento de escopo estão no gargalo URI. Além disso, se você deseja cobrir todos os dispositivos Android no mercado usando versões mais antigas antes do SDK 29, você deve usar os casos de uso do SAF, não há saída além disso. Na Android Developer Conference, Video, anúncios, eles afirmam que o objetivo de mudar para o armazenamento de escopo é remover permissões desnecessárias, mas, na realidade, o oposto aconteceu para desenvolvedores e usuários.
• Os códigos de amostra (todos nos tutoriais do SAF e a maioria na mediaStore) são o nível 1-24 do SDK e são suportados pelas versões Delphi 10.x.
• Delphi 11 é necessário para usar os níveis SDK 29 VE 30 Comandos de mediaStore de "Downloads", "GetMediauri", carregando miniaturas> LoadThumbnail, adicione um item> volume_external_primary, alternar o status pendente para arquivos de mídia> IS_PENDING SPAND, Atualizar outros Apps 'Arquivos> Recuperação CreateFavoriteRequest ”.
• Para compartilhamento de arquivos do armazenamento externo, primeiro obtendo URI do arquivo por seletor de arquivos SAF, compartilhando as intenções necessárias. Se o URI de arquivo externo estiver disponível, ele poderá ser usado para fins de abertura, leitura, salvamento e cópia.
• Itens depreciados para armazenamento 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);Resumidamente, todo o arquivo, conteúdo, ações e intenções do FileProvider são depreciados.
(PS: Se permissão para acessar o diretório em que o arquivo está localizado for obtido por action_open_document_tree, pode ser possível acessar arquivos por esses comandos, mas não pode ser tentado, pois essa intenção não funciona em Delphi 10.))
• Para usar a estrutura de acesso ao armazenamento SAF, sem permissões necessárias para obter do projeto -> usa permissões, tudo pode ser fechado. Os projetos não precisam de nenhuma permissão, ou seja, “permissões service.RequestPermissions”. Todas as permissões no projeto de amostra OFF.
• Para acessar arquivos com SAF, é suficiente simplesmente chamar casos de uso (action_create_document, action_open_document, action_open_document_tree). No entanto, cada um deles abre a interface do seletor do sistema, diferentemente do antigo tfile.Copy.
• Action_Create_Document é usado para salvar um novo arquivo com uma interface semelhante a "Salvar como", e action_open_document é usado para abrir, mostrar e modificar arquivos existentes. Action_open_document_tree é para acessar não apenas diretórios, mas também todos os arquivos sob ele.
• Ao usar o SAF, a parte do filtro de intenção no AndroidManifest.Template.xml está pronta com o Delphi, não há necessidade de adicionar outra intenção.
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
• Os casos de uso da SAF estão disponíveis imediatamente em projetos Delphi direcionados ao SDK 30, simplesmente chamando-o com as bibliotecas Android necessárias e os códigos de amostra, pois estão embutidos com todas as versões Delphi 10.
• Escrever para áudio, imagem, arquivos de vídeo e downloads acima da versão 11 não se restringe com o MediaStore. Ou seja, você pode salvar a imagem sem permissão.
• As coleções de mídia só podem ser lidas com permissão.
• Access_media_location é necessário para dados de localização da imagem.
• PDF, texto, etc. Acessando os arquivos disponíveis pelo "seletor do sistema".
• “Picker do sistema” é necessário para ler e escrever fora da coleção.
• Projeto -> Usa permissões -> Write_external_storage A opção deve ser desligada no SDK 29. Read_external_storage é necessário para a leitura.
• As classes MediaStore URI não estão disponíveis nas bibliotecas pré-Delphi 11, pois foram removidas para acessar os arquivos acima do SDK 29. Portanto, a maioria dos códigos de tutoriais da MediaStore acima foi importada do Java para o objeto Pascal, não pôde ser experimentado.
• Em tempo de execução, dependendo do nível SDK do dispositivo, a permissão de gravação deve ser solicitada para (SDK <28) e não para (SDK> = 29).
• Androidmanifest.template.xml Alterações:
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="30" />
android:requestLegacyExternalStorage="false">
• MediaStore requer permissão de leitura sobre armazenamento externo, não permissão de gravação. Para compatibilidade com as versões antes do Android 10, no projeto -> usa permissões, remova a opção write_external_storage e adicione o seguinte no manifesto:
<%uses-permission%>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
• A cópia do arquivo não pode mais ser executada com um único comando (tfile.copy) do armazenamento externo. Primeiro, chamamos o caso de uso (Action_open_document ou Action_create_document). Em seguida, lidamos com o código de solicitação com "HandleMessageActivity" e "OnactivityResult". Finalmente, escrevemos no arquivo que acabamos de abrir com o URI e os fluxos (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 ;