Изменения конфиденциальности в Android 10
Android 11 - Конфиденциальность и безопасность
Изменения поведения: приложения, нацеленные на Android 11 - Конфиденциальность
Использование всех файлов Access (Manage_external_storage) разрешение
Обзор общего хранения
После изменений в конфиденциальности и 11 и безопасности Android 10 и 11, прямой доступ к хранилищу приложениями, оцениваемыми только для внутренних и теперь доступ к внешним файлам, возможно, и просто 4 API:
Все файлы доступа к API (Manage_External_Storage - Action_Manage_App_all_files_access_permission разрешение и Action_manage_storage Intant) доступны только для приложений файлового менеджера и антивирусного типа, все другие приложения типа отклоняются публикацией Google Play Store. Базы данных (BlobstoreManager) API запускает только Android 11 SDK 30 и верхние версии, а не Android 10, а также предыдущие. Поэтому оба API исключены ниже субъекта.
Откройте файлы, используя структуру доступа к хранилищам
Доступ к документам и другим файлам из общего хранилища
Варианты использования для доступа к документам и другим файлам
Структура доступа к хранилищу поддерживает следующие варианты использования для доступа к файлам и другим документам.
Создать новый файл
The ACTION_CREATE_DOCUMENT intent action allows users to save a file in a specific location.
Откройте документ или файл
The ACTION_OPEN_DOCUMENT intent action allows users to select a specific document or file to open.
Предоставить доступ к содержимому каталога
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.
В следующих разделах предусмотрено руководство о том, как настроить каждый случай использования.
Создать новый файл
// 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 ;Откройте файл
// 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 ;Предоставить доступ к содержимому каталога
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 ;Выполнить операции в выбранном месте
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 ;Получив ссылку на URI выбранного элемента, ваше приложение может выполнить несколько операций на элементе. Например, вы можете получить доступ к метаданным элемента, отредактировать элемент на месте и удалить элемент. В следующих разделах показано, как выполнить действия в файлах, которые пользователь выбирает:
Постоянные разрешения
// 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);Изучите метаданные документа
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 ;Откройте документ - растровый карта
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 ;Откройте документ - поток ввода
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 ;Редактировать документ
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 ; Удалить документ
TJDocumentsContract.JavaClass.deleteDocument (TAndroidHelper.contentResolver, Uri);Откройте виртуальный файл
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 ; Виртуальный файл в виде изображения
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 ;Стандартные функции пути RTL на поддерживаемых целевых платформах: внутреннее хранилище, внешнее частное внутреннее S, общее внешнее хранилище
Изменения хранения в версиях Android
| # | Код | SDK | Публиковать | Изменять |
|---|---|---|---|---|
| 1 | - | 1 | 23.09.08 | Намерение, System Picker (action_) начался в первой версии |
| 4.4 | K | 19 | 31.10.13 | FileProvider (Content API), DocumentsContract, классы DocumentProvider |
| 7 | Не | 25 | 04.10.16 | FileProvider Использование обязательно (при нацеливании на эту версию) |
| 8 | О | 26 | 21.03.17 | Август 2018 Google Play Store и. 8.0 Требование о публикации |
| 10 | Q. | 29 | 03.09.19 | Сфера хранения. Конфиденциальность и безопасность увеличились |
| 11 | Ведущий | 30 | 09.09.20 | Август 2021 г. нацеливание на Android API 30 (Google Play Store Publish Temporment) |
Поставщик документов, 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 в версиях Delphi
Rad Studio Delphi 10+ версии Accompany Android 10+ Java Libraries (Androidapi.jni.graphicscontentviewtext, Androidapi.ioutils, Androidapi.jni.media, Androidapi.jni.provider, Androidapi.jni.appi.helpers, androidapi AndroidApi.jni.net, Androidapi.jni.os, Androidapi.jni.provider) Поддерживающий хранение SACE, SAF и некоторые команды MediaStore.
| Дельфи | Android |
|---|---|
| XE5 | 2.33 - 4.4 |
| 10 Сиэтл | 4.03 - 5 |
| 10.1 Берлин | 4.03 - 7 |
| 10.2 Токио | 4.1 - 8 |
| 10.3 Рио | 5.1 - 10 |
| 10.4 Сидней | 6 - 11 |
| 11 Александрия | 8.1 - 11 |
Rad Studio Delphi 11.0 Alexandria имеет поддержку API 30 API (Google Play Store 2021. Требование).
Различия в хранилище и обмене файлами в Android:
• Не существует разницы в Android 11 для внутренней хранилища. Как и в Android 10 и раньше, доступ к файлам не ограничен. Опять же, разрешение не требуется.
• Обмен файлами одинаково, опять же, API контента (fileProvider) и способ вызовы с «intent.SetAction (tJintent.javaclass.action_send)»; »; намерение продолжается. Чтобы включить функцию FileProvider, выбор опции «Secure File File» в параметрах проекта-> Приложение-> Список прав (доступен в Delphi 10.3 RIO и позже), чтобы продолжить использование этого API. Для более ранних версий Delphi 10.3 API FileProvider следует добавлять вручную, как объяснено в «Хранилище файлов и обмен в Android»> «Использование FileProvider для обмена файлами».
• Команды копирования внешнего хранилища в «Способность и обмен файлами в Android». Пример проекта запускается при целевом Android 10 SDK 29 более ранних версий, то есть «memo1.lines.savetofile (tpath.combine (tpath.getshareddownloadspath, 'memo1external.txt'));». Когда нацелен на Android 11 SDK 30, то же приложение поднимает «не может создать файл» ((хранилище/эмулирование/0/загрузка/memo1external.txt ». Исключение отказано в разрешении».
• Текущее состояние перед Android 10 и после Android 11 Обязательные изменения хранилища хранения:
• «requestlegacyExternalStorage» был удален из хранилища областей, а теперь приложения, которые хотят получить к нему доступ, отклоняются в GPStore. Чтобы опубликовать ваше приложение, внесите следующее изменение в AndroidManifest.template.xml ::
android:requestLegacyExternalStorage="false">
• Все файлы доступа к API (action_manage_storage) отклоняется Google Play Store, но если это разрешение предоставляется (и приложение не будет опубликовано), оно может читать и сохранять файлы, как и до Android 11. Если вам нужно это, вам нужно добавить под "Androidmanifest.template.xml" и запросить "action_manage_apl_fles_files_files_files_files_files_files_files_fils_files_files_files_files_fils_files_files_files_files_fils_files_fils_files_files_ples намерение.
• Общие базы данных BlobstoreManager API работает только на Android 11 SDK 30 и выше, не работает на Android 10 и более ранних версиях.
• Общие базы данных BlobstoreManager API запускают только Android 11 SDK 30 и более высокие версии, не запускают Android 10 и нижние версии. Это не включено, так как он не поддерживается большинством устройств в настоящее время.
• Доступ к общему (внешнему) хранению с помощью SAF и MediaStore:
• Получение URI: только первые три примера использования из приведенных выше кодов обучения получают как файл URI, так и разрешение на их доступ. Доступ к внешнему файлу URI вводится путем захвата их действий с помощью OnActivityResult.
• Все другие примеры описывают, как справиться с URI, полученным из этих 3 действий использования. Если вы не знаете URI файла, вы не можете их использовать.
• Кроме того, старый намерение action_get_content может использоваться для получения URI, вызывая селектор системы, аналогичный Action_open_document; Но это не обеспечивает постоянный доступ.
• С помощью mediaStore.files также может быть извлечен URI файлов в хранилище медиа, но он не был включен в содержимое этой темы из -за утверждения «Содержание MediaStore.files в медиа -магазине также зависит от того, использует ли ваше приложение обширное хранилище, доступное в приложениях, нацеленных на Android 10 или выше». Хотя классы MediaStore.downloads и GetMediauri также предоставляют доступ к URI File File Feelse, они поддерживают только SDK 29 и выше.
• E, если вы хотите работать в файле с каким -либо кодом без использования случая, вы можете напрямую использовать файл URI (например: Content: //com.android.providers.downloads.documents/documents/16874) с «java.lang.securityException: разрешение» отрицание: чтение ... требует, чтобы вы получали доступ к Action_open_PEN
• Вкратце, приложения записи файлов внешнего хранилища в хранилище применения находятся в узком месте URI. Более того, если вы хотите охватить все устройства Android на рынке, используя более старые версии до SDK 29, вам нужно использовать варианты использования SAF, выхода нет, кроме этого. На конференции Android Developer, видео, объявления, они утверждают, что целью перехода на хранилище сфера является удаление ненужных разрешений, но на самом деле обратное произошло для разработчиков и пользователей.
• Примерные коды (все на учебных пособиях SAF и большинство в MediaStore) являются уровнем SDK 1-24 и поддерживаются версиями Delphi 10.x.
• Delphi 11 необходим для использования уровней SDK 29 VE 30 Команды MediaStore «Загрузки», классы «getMediauri», загрузка миниатюр> загрузки, добавьте элемент> vume_external_primary, переключатель, ожидающий статус Media files> is_pend CreateForavoritERequest ».
• Для обмена файлами от внешнего хранилища сначала получение URI файла с помощью SAF File Sicker, а затем обмениваться намерениями. Если доступен внешний файл URI, его можно использовать для открытия новых файлов, чтения, сохранения, копирования.
• амортизированные элементы для внешней памяти:
// 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);Вкратце, все файлы, содержание, действия FileProvider и намерения амортизируются.
(PS: Если разрешение доступа к каталогу, в котором находится расположенный файл, получено Action_open_document_tree, можно получить доступ к файлам с помощью этих команд, но не может быть опробовано, поскольку это намерение не работает в Delphi 10.)))
• Чтобы использовать SAF SAF SAF -файлы для хранения, не требуется разрешений, чтобы получить от проекта -> Использование разрешений, все можно закрыть. Проектам не требуется никакого разрешения, т.е. Все разрешения в образце проекта отключены.
• Чтобы получить доступ к файлам с помощью SAF, достаточно просто вызовать варианты использования (action_create_document, action_open_document, action_open_document_tree). Тем не менее, каждый из них открывает интерфейс System Picker, в отличие от Old Tfile.copy.
• action_create_document используется для сохранения нового файла с интерфейсом, аналогичным «Сохранить как», а action_open_document используется для открытия, показа и изменения существующих файлов. Action_open_document_tree предназначен для доступа не только к каталогам, но и всем файлам под ним.
• При использовании SAF часть фильтра «Намерения» в AndroidManifest.template.xml готова с Delphi, нет необходимости добавлять еще одно намерение.
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
• Примеры использования SAF сразу доступны в Delphi Projects, нацеленных на SDK 30, просто призывая его с необходимыми библиотеками Android и примерами кодов, поскольку они встроены со всеми версиями Delphi 10.
• Написание на аудио, изображение, видеофайлы и загрузки выше версии 11 не ограничены MediaStore. Т.е. вы можете сохранить изображение без разрешения.
• СОБЫТИЯ СМИ могут быть прочитаны только с разрешения.
• Access_media_location требуется для данных местоположения изображения.
• PDF, текст и т. Д. Доступ к файлам, доступным «System Picker».
• «Сборщик системы» необходим для чтения и написания вне коллекции.
• Project -> Использование разрешений -> write_external_Storage Опция должна быть отключена на SDK 29. Read_external_Storage требуется для чтения.
• Классы URI MediaStore не доступны в библиотеках Pre-Delphi 11, так как они были удалены для доступа к файлам выше SDK 29. Таким образом, большинство вышеуказанных кодов учебных пособий MediaStore были просто импортированы из Java в объект Pascal, не могли быть опробованы.
• Во время выполнения, в зависимости от уровня SDK устройства, следует запросить разрешение на запись (SDK <28), а не для (SDK> = 29).
• AndroidManifest.template.xml Изменения:
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="30" />
android:requestLegacyExternalStorage="false">
• MediaStore требует разрешения на чтение на внешнем хранилище, а не разрешение на запись. Для совместимости с версиями перед Android 10, в рамках Project -> используется разрешения, удалите параметр write_external_storage и добавьте следующее в Manifest:
<%uses-permission%>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
• Копирование файла больше не может быть выполнено с помощью одной команды (tfile.copy) из внешней хранилища. Сначала мы называем намерение использования (Action_open_document или Action_create_document). Затем мы обрабатываем код запроса с «HandlemessageActivity» и «OnActivityResult». Наконец, мы пишем в файл, который мы только что открыли с помощью URI и потоков (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 ;