#はじめに
タイトルの通りなのですが、手探りだった為にあやふやな点が多く、記事の公開後に訂正が入る可能性があります。ご了承ください。
発端としては、自作アプリケーションで生成したデータをGoogleドライブに出力するにはどうしたらいいんだろう?というものです。FMXもAndroid開発もわからん・・という人が書いています。
Delphi 10.3 CommunityEditionにて動作確認しています。
※画像ファイルを送る場合はTShowShareSheetActionを使いましょう!
##とりあえず実例
画像のようにコントロールを配置します。
保存ボタンを押すと、Edit1.Text
をファイル名としたファイルを作成し、ローカルに保存します。
送るボタンを押すと、インテント発生させ、ファイルを外部に出力します。
###「保存」ボタンのイベント
procedure TForm1.Button1Click(Sender: TObject);
var
filepath:String;
begin
if Edit1.Text.IsEmpty then Exit;
filepath := TPath.Combine(TPath.GetTempPath,Edit1.Text);
if TFile.Exists(filepath) then
TFile.Delete(filepath);
memo1.Lines.SaveToFile(filepath);
end;
保存先にTPath.GetTempPath
を指定します(GetPublicPath+'/Tmp'に等しいパスです。参考:(AndroidアプリケーションでSystem.IOUtils.TPathのメソッドが返すディレクトリについての簡単なまとめ )。
###「送る」ボタンのイベント
先に以下のソースコードをリンクしておく必要があります。
uses
Androidapi.JNIBridge, //ILocalObject
Androidapi.JNI.Os, //JParcelable
Androidapi.JNI.Net, //Jnet_Url
Androidapi.JNI.JavaTypes, //JFile
Androidapi.JNI.GraphicsContentViewText, // JIntent
Androidapi.Helpers, //StringToJString, TAndroidHelper.JFileToJURI
FMX.Platform.Android; //MainActivity
ボタンイベントは以下になります。
procedure TForm1.Button2Click(Sender: TObject);
var
filepath:String;
SendFile: JFile;
Uri:JParcelable;
intent: JIntent;
begin
if Edit1.Text.IsEmpty then Exit;
filepath := TPath.Combine(TPath.GetTempPath,Edit1.Text);
if not TFile.Exists(filepath) then Exit;
try
SendFile := TJFile.JavaClass.init( StringToJString( filepath ));
Uri := JParcelable(TAndroidHelper.JFileToJURI(SendFile));
intent := TJIntent.Create;
intent.setAction(TJIntent.JavaClass.ACTION_SEND);
intent.putExtra(TJIntent.JavaClass.EXTRA_STREAM, Uri);
intent.setType(StringToJString('application/octet-stream'));
MainActivity.startActivity(intent);
except on e:Exception do
ShowMessage(e.Message);
end;
end;
setType
に渡すMIMEタイプについては、送信するメディアに応じて設定してください。(メールの場合message/rfc822
にする、など。 参考:MIME の基礎 )
##解説めいたもの
インテントはAndroid独自の仕組みなので、Firemonkeyフレームワークではなく、Androidの機能を薄くラップしたライブラリを使用します。そのため、インテント作成~送信部分は、Javaで書いたAndroidアプリのソースコードそっくりです。
Javaのサンプルを眺めると、インテントでファイルを渡す場合intent.putExtra(Intent.EXTRA_STREAM, <対象のUri>)
という方法で行うので、Delphiの場合もそれに倣ってJNet_Uri型変数を作成し、JParcelable型でラップして渡しています(なぜParcelable型にラップする必要があるのかはわかりませんでした)。
そのJNet_Uri
を取得するために、まずファイルパスからJFile
型オブジェクトを作成します。
SendFile := TJFile.JavaClass.init( StringToJString( filepath ));
Uri := JParcelable( TAndroidHelper.JFileToJURI(SendFile) );
(このあたりの事情については以下を参考にしました。Android 画像ファイルを扱う際のFileとUriまとめ)
なお、JFileToJURI(JFile)
の内部では、(動作環境がAndroidOS7以上の場合)FileProviderを使用し、FileをUriに変換しています。
FileProviderを動作させるためには、IDEのプロジェクト→オプション→資格リストにて、「セキュアファイル共有」にチェックを入れる(Trueにする)必要があります。
(実行時にこういうエラーが出ます)
チェックを入れた後にコンパイルすると、出力フォルダ(Android\Debug\)内のAndroidManifest.xml
に、FileProviderに関するタグが自動で追加されてるのが確認できます。また、FileProviderの設定となるprovider_paths.xml
も追加されています。
配置マネージャでもprovider_paths.xml
も追加されてることが確認できます。カスタマイズしたprovider_paths.xml
を使う場合は、配置マネージャで自動追加された方のファイルと切り替えておけばいいのかなと思います。
以上です!