Android的隐私变化10
Android 11-隐私与安全
行为变化:针对Android 11的应用程序11-隐私
使用所有文件访问(manage_external_storage)权限
共享存储的概述
在Android 10和11的隐私和安全性更改之后,通过仅范围内的应用程序访问存储的应用程序,并且现在纯粹访问了外部文件,纯粹是4个API:
所有文件访问API(Manage_external_storage -Action_Manage_App_App_App_App_App_Apcess_Access_permission允许和Action_Manage_storage Intent)仅适用于文件管理器和防病毒类型应用程序,所有其他类型的应用程序均由Google Play Play商店出版拒绝。数据库(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 | 意图,系统选择器(Action_)以第一个版本开始 |
| 4.4 | k | 19 | 31.10.13 | FILEPROVIDER(内容API),Document Contract,Document -Provider类 |
| 7 | n | 25 | 04.10.16 | 强制使用FileProvider(针对此版本时) |
| 8 | o | 26 | 21.03.17 | 2018年8月Google Play商店和。 8.0发布要求 |
| 10 | 问 | 29 | 03.09.19 | 范围存储。隐私和安全增加 |
| 11 | r | 30 | 09.09.20 | 2021年8月针对Android API 30(Google Play商店发布要求) |
文档提供商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
Delphi版本中的Android支持
RAD Studio Delphi 10+ versions accompany Android 10+ Java libraries (Androidapi.JNI.GraphicsContentViewText, Androidapi.IOUtils, Androidapi.JNI.Media, Androidapi.JNI.Provider, Androidapi.JNI.App, Androidapi.Helpers, androidapi.jni.javatypes,androidapi.jni.net,androidapi.jni.os,androidapi.jni.provider)支持范围的存储,SAF和一些MediaStore命令。
| 德尔菲 | 安卓 |
|---|---|
| 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拥有Android 30 API支持(Google Play商店2021要求)。
在Android中的文件存储和共享的差异:
•对于内部存储,Android 11没有差异。与Android 10及更早时一样,对文件的访问是无限的。同样,不需要许可。
•文件共享相同,再次使用“ Intent.setAction(tjintent.javaclass.action_send);”呼叫的内容API(FILEPROVIDER);''意图继续。要启用FileProvider功能,请在项目选项 - > Application-> witterment List中选择“安全文件共享”选项(在Delphi 10.3 Rio中可用,及以后),以继续使用此API。对于Delphi 10.3早期版本,应按照“存储和在Android中共享”>“使用FileProvider进行文件共享”中的“文件存储和共享”中的解释。
•针对目标的Android 10 SDK 29先前版本,即“ memo1.lines.savetofile(tpath.getSharedDownloadspath,'memo1external.txtsttern.txt'),外部存储复制命令在“文件存储和共享”示例项目中运行。当针对Android 11 SDK 30时,相同的应用程序提出“无法创建文件”(storage/emulation/download/download/memo1external.txt”。拒绝了“ deletefile”命令。“ deletefile”命令未在下载/getSharedDownloadspath文件夹下删除文件。相同的问题对所有共享的外部文件仪有效。
•Android 10之前和Android 11之前的当前状态,强制性范围存储文件存储更改:
•从范围存储中删除了“ RequestLegacyExternalStorge”,而现在希望访问它的应用程序已在GPStore中被拒绝。要发布您的应用程序,请在AndroidManifest.template.xml ::中进行以下更改。
android:requestLegacyExternalStorage="false">
• All Files Access API (ACTION_MANAGE_STORAGE) is rejected by Google Play Store, but if this permission is granted (and the app will not be published), it can read and save files as before Android 11. If you need this, you need to add under "AndroidManifest.template.xml" and request "ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION" at runtime and call the ACTION_MANAGE_STORAGE意图。
•共享数据库BlobStoreManager API仅在Android 11 SDK 30及更高版本上起作用,在Android 10及更早版本上不起作用。
•共享数据库BlobStoreManager API仅运行Android 11 SDK 30及更高版本,不会运行Android 10及更低版本。它不包括在内,因为当前大多数设备不支持它。
•使用SAF和MediaStore访问共享(外部)存储:
•获取URI:只有上面培训代码中的用例的前三个示例同时获得了file uri和访问权限的许可。通过使用OnActivityResult捕获其动作来访问外部文件URI。
•所有其他示例都描述了如何处理从这三种用例操作中获得的URI。如果您不知道文件URI,则不能使用它们。
•此外,旧的Action_get_content意图可以通过调用系统选择器来获得URI,类似于Action_Open_Document;但它不能提供永久访问。
•使用MediaStore.files,还可以检索媒体存储中文件的URI,但由于“ MediaStore.files.files的内容,媒体商店中的文件的内容也取决于您的应用程序是否使用针对Android 10或更高更高版本的应用程序中可用的广泛存储”,因此它不包含在本主题的内容中。”尽管MediaStore.Downloads和GetMediauri类也提供了对外部存储文件URI的访问权限,但它们仅支持SDK 29及以上。
• E If you want to operate on a file with any code without using a case, you can directly use a file Uri (eg: content://com.android.providers.downloads.documents/documents/16874) with the "java.lang.SecurityException: Permission" Denial: reading ... requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs” error message and you cannot access the file.
•简要地,范围存储中的外部存储文件记录应用在URI瓶颈中。此外,如果您想在SDK 29之前使用较旧版本覆盖市场上的所有Android设备,则必须使用SAF用例,除此之外,没有其他方法。在Android开发人员会议,视频,公告中,他们声称切换到范围存储的目的是删除不必要的权限,但实际上,开发人员和用户的情况恰恰相反。
•示例代码(全部在SAF教程中,大多数在MediaStore上)为SDK级别1-24,并由Delphi 10.x版本支持。
• Delphi 11 is required to use SDK levels 29 ve 30 MediaStore commands of “Downloads”, “getMediaUri” classes, Loading thumbnails > loadThumbnail, Add an item > VOLUME_EXTERNAL_PRIMARY, Toggle pending status for media files > IS_PENDING flag, Update other apps' media files > RecoverableSecurityException, Manage groups of media files > createWriteRequest createTrashRequest CreateFavoritErequest”。
•首先要从外部存储中共享文件共享文件,从而通过SAF File Picker获取文件,然后共享所需的意图。如果外部文件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);简要贬低了所有文件,内容,文件,档案操作和意图。
(PS:如果通过Action_open_document_tree访问文件所在的目录的权限,则可以通过这些命令访问文件,但不能尝试使用文件,因为此意图在Delphi 10中不起作用。)))))))))
•要使用存储访问框架SAF,无需从项目获得的权限 - >使用权限,所有这些都可以关闭。项目不需要任何许可即“ PermissionsService.Requestpermissions”。样本项目中的所有权限关闭。
•要使用SAF访问文件,只需调用用例(action_create_document,action_open_document,action_open_document_tree)。但是,与旧的tfile。
•Action_Create_Document用于保存具有类似“ AS”接口的新文件,并且Action_open_document用于打开,显示和修改现有文件。 Action_open_document_tree不仅用于访问目录,还用于访问其下的所有文件。
•使用SAF时,AndroidManifest.template.xml中的Intent-Filter部分已经准备好使用Delphi,因此无需添加其他意图。
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
•SAF用例仅通过与必要的Android库和示例代码调用,以针对SDK 30的Delphi项目中可用,因为它们与所有Delphi 10版本内置。
•在版本11中写入音频,图像,视频文件和下载,不受MediaStore的限制。即,未经许可,您可以保存图片。
•媒体收集只能在许可的情况下阅读。
•图像位置数据需要Access_Media_Location。
•PDF,文本等。访问“系统拾取器”可用的文件。
•在集合之外阅读和写作需要“系统选择器”。
•项目 - >使用权限 - > write_external_storage选项必须在sdk 29上关闭。读取需要read_external_storage。
•媒体店URI类在Delphi 11库中不可用,因为它们被删除以访问SDK 29上方的文件。因此,上述媒体店教程大多数只是从Java进口到Object Pascal,无法尝试。
•在运行时,根据设备的SDK级别,应要求(SDK <28)而不是(SDK> = 29),请要求写入权限。
•AndroidManifest.template.xml更改:
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="30" />
android:requestLegacyExternalStorage="false">
•MediaStore需要在外部存储时阅读权限,而不是写许可。有关在Android 10之前与版本的兼容性,在项目 - >使用权限下,请删除write_external_storage选项,并在清单中添加以下内容:
<%uses-permission%>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
•不再使用外部存储中的单个命令(tfile.copy)执行文件复制。首先,我们称呼用例(action_open_document或action_create_document)意图。然后,我们使用“ handlemessageactitivity”和“ 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 ;