Android 10のプライバシーの変更
Android 11-プライバシーとセキュリティ
動作の変化:Android 11-プライバシーをターゲットとするアプリ
すべてのファイルの使用アクセス(manage_external_storage)許可
共有ストレージの概要
Android 10および11のプライバシーとセキュリティの変更の後、内部のみにスコープされたアプリケーションによるストレージに直接アクセスし、現在は4つのAPIで可能な外部ファイルにアクセスするようになりました。
すべてのファイルにアクセスAPI(manage_external_storage -action_manage_app_all_files_access_permission_manage_storage Intent)は、ファイルマネージャーとアンチウイルスタイプのアプリのみで利用できます。データベース(blobstoremanager)APIは、Android 10および以前のバージョンではなく、Android 11 SDK 30および上部バージョンのみを実行します。したがって、両方の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 ;ドキュメントを開く-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 ;ドキュメントを開く - 入力ストリーム
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 | Intent、System Picker(Action_)は最初のバージョンで開始されました |
| 4.4 | k | 19 | 31.10.13 | FileProvider(Content API)、DocumentsContract、DocumentProviderクラス |
| 7 | n | 25 | 04.10.16 | FileProviderの使用法が必須(このバージョンをターゲットにした場合) |
| 8 | o | 26 | 21.03.17 | 2018年8月Google Playストアと。 8.0公開要件 |
| 10 | Q | 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+バージョンは、Android 10+ Javaライブラリ(androidapi.jni.graphicscontentviewtext、androidapi.ioutils、androidapi.jni.mediaに付属しています。 androidapi.jni.javatypes、androidapi.jni.net、androidapi.jni.os、androidapi.jni.provider)Scoped Storage、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 Store 2021要件)があります。
Androidでのファイルストレージと共有の違い:
•内部ストレージについては、Android 11に違いはありません。 Android 10以前のように、ファイルへのアクセスは無制限です。繰り返しますが、許可は必要ありません。
•ファイル共有は同じですが、繰り返しますが、コンテンツAPI(fileProvider)と「intent.setaction(tjintent.javaclass.action_send);」で呼び出し方法があります。意図は続きます。 FileProvider機能を有効にするには、プロジェクトオプションで「ファイル共有」オプションを「セキュアファイル共有」を選択します - >アプリケーション - >資格リスト(Delphi 10.3 Rio以降で利用可能)を追加して、このAPIを使用し続ける必要があります。 Delphi 10.3の以前のバージョンの場合、FileProvider APIは、「Androidでのファイルストレージと共有」で説明されているように手動で追加する必要があります。
•「Androidでのファイルストレージと共有」の外部ストレージコピーコマンドは、ターゲットを絞ったときに「ファイルストレージと共有」サンプルプロジェクトを実行します。 Android 11 SDK 30のターゲットを絞った場合、同じアプリが「Storage/Emulated/0/download/memo1external.txt」を作成できません。許可は拒否されました。
•Android 10前およびAndroid 11後の現在のステータス11必須スコープストレージファイルストレージの変更:
•「RequestLegacyExternalStorage」はScope Storageから削除されており、現在ではGPSTOREで拒否されます。アプリを公開するには、次の変更をandroidmanifest.template.xml ::で変更します
android:requestLegacyExternalStorage="false">
•すべてのファイルアクセスAPI(Action_manage_storage)はGoogle Playストアによって拒否されますが、この許可が付与されている場合(およびアプリが公開されない)、Android 11の前と同様にファイルを読み取り、保存できます。 Action_manage_storage Intent。
•共有データベースBlobstoreManager APIは、Android 11 SDK 30以上でのみ動作し、Android 10以前のバージョンでは機能しません。
•共有データベースBLOBSTOREMANAGER APIは、Android 11 SDK 30以下のバージョンのみを実行し、Android 10以下のバージョンを実行しません。現在のほとんどのデバイスではサポートされていないため、考慮は含まれていません。
•SAFおよびMediastoreを使用した共有(外部)ストレージへのアクセス:
•URIの取得:上記のトレーニングコードからのユースケースの最初の3つの例のみが、ファイルURIとアクセス許可の両方を取得します。外部ファイルへのアクセスURISは、OnActivityResultでアクションをキャプチャすることにより導入されます。
•他のすべての例では、これら3つのユースケースアクションから得られたURIに対処する方法について説明します。ファイルURIがわからない場合は、それらを使用できません。
•また、古いAction_Get_Contentの意図を使用して、Action_open_documentと同様に、システムセレクターを呼び出すことでURIを取得できます。しかし、それは恒久的なアクセスを提供しません。
•Mediastore.Filesを使用すると、メディアストレージ内のファイルのURIも取得できますが、「Mediastore.FilesのコンテンツがAndroid 10以上を標的とするアプリケーションで利用可能な広範なストレージを使用するかどうか」のために、このトピックの内容には含まれていません。 Mediastore.DownloadsおよびGetMediauriクラスは、外部ストレージファイルURIへのアクセスも提供しますが、SDK 29以上のみをサポートしています。
•eケースを使用せずにコードを含むファイルで操作する場合は、ファイルURI(content://com.android.providers.downloads.documents/documents/16874)を「java.lang.securityexception:purmission "denial:recove access and your can open_document_document_ddocument_document_document_document_document_document_documentを使用できます。
•簡単に言えば、Scopeストレージの外部ストレージファイル録音アプリはURI Bottleneckにあります。さらに、SDK 29より前に古いバージョンを使用して市場にあるすべてのAndroidデバイスをカバーしたい場合は、SAFユースケースを使用する必要があります。 Android Developer Conference、Video、Announcementsでは、スコープストレージに切り替える目的は不必要な許可を削除することであると主張していますが、実際には、開発者とユーザーにとっては逆のことが起こりました。
•サンプルコード(すべてSAFチュートリアルのすべておよびMediastoreのほとんど)はSDKレベル1-24であり、Delphi 10.xバージョンでサポートされています。
•Delphi 11は、SDKレベルを使用する必要があります29 VE 30「ダウンロード」、「GetMediauri」クラスのMediaStoreコマンド、サムネイルのロード> loadthumbnail、volume_external_primary、トグル保留ステータス>メディアファイル> is_pendingフラグの更新createfavoriterequest」。
•外部ストレージからのファイル共有の場合、最初にSAFファイルピッカーによるファイルのURIを取得し、次に必要な意図を共有します。外部ファイル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では機能しないため、試すことができませんでした。
•Storage Access Framework SAFを使用するには、プロジェクトから取得するために必要なアクセス許可はありません。プロジェクトには許可を必要としません。つまり、「permissionsservice.requestpermissions」。サンプルプロジェクトのすべての許可。
•SAFを使用してファイルにアクセスするには、ユースケース(action_create_document、action_open_document、action_open_document_tree)の意図を単純に呼び出すだけで十分です。ただし、それらのそれぞれは、古いtfile.copyとは異なり、システムピッカーインターフェイスを開きます。
•action_create_documentは、「save 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ユースケースは、SDK 30をターゲットにしたDelphiプロジェクトですぐに利用できます。これは、すべてのDelphi 10バージョンに組み込まれているため、必要なAndroidライブラリとサンプルコードを使用して電話をかけるだけです。
•オーディオ、画像、ビデオファイル、およびバージョン11を超えるダウンロードへの書き込みは、Mediastoreに制限されていません。つまり、許可なく写真を保存できます。
•メディアコレクションは許可を得てのみ読むことができます。
•Access_Media_Locationは、画像の位置データに必要です。
•PDF、テキストなど。「システムピッカー」が利用できるファイルにアクセスします。
•「システムピッカー」は、コレクションの外側の読み書きに必要です。
•Project->使用権限 - > write_external_storageオプションは、sdk 29でオフにする必要があります。読み取りにはread_external_storageが必要です。
•Mediastore URIクラスは、SDK 29を超えるファイルにアクセスするために削除されたため、Delphi Pre-Delphi 11ライブラリでは利用できません。したがって、上記のMediastoreチュートリアルコードのほとんどは、Javaからオブジェクトパスカルにインポートされただけで、試してみませんでした。
•ランタイムでは、デバイスのSDKレベルに応じて、(SDK <28)(SDK> = 29)に対して(SDK <28)に対して許可を要求する必要があります。
•AndroidManifest.template.xmlの変更:
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="30" />
android:requestLegacyExternalStorage="false">
•Mediastoreは、書き込み許可ではなく、外部ストレージの読み取り許可を必要とします。 Android 10の前のバージョンとの互換性については、Project-> UseS Permissionsを使用して、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)の意図を呼び出します。次に、「handlemessageactivity」と「onactivityResult」でリクエストコードを処理します。最後に、URIと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 ;