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 ;