Delphi 10 SeattleのAndroidアプリケーションでIntentを受信する方法です。
以前に書いた「Delphi XE8のFiremoneky AndroidアプリケーションでIntentを受信するには」には、Activity.OnNewIntentを処理していないという問題がありましたので、修正しました。
文字列を他のアプリケーションに送信する
新しいマルチデバイスアプリケーションを作成し、フォームにTButtonとTMemoを配置します。
ボタンを押すと、入力した文字列を他のアプリケーションに送信します。
Button1を押したときのイベントを記述します。
JIntentを作成して、送信するデータの設定を行います。
Intent := TJIntent.Create;
Intent.setType(StringToJString('text/plain'));
Intent.setAction(TJIntent.JavaClass.ACTION_SEND);
Intent.putExtra(TJIntent.JavaClass.EXTRA_TEXT, StringToJString(AText));
Android APIのPackageManagerクラスのqueryIntentActivitiesメソッドを使用して、インテントを処理できるアプリケーションの有無を確認しています。
処理できるアプリケーションがあれば、インテントを送信します。
if MainActivity.getPackageManager.queryIntentActivities(Intent,
TJPackageManager.JavaClass.MATCH_DEFAULT_ONLY).size > 0 then
MainActivity.startActivity(Intent)
else
ShowMessage('Receiver not found');
ソースコードは次のようになります。
uses
Androidapi.JNI.GraphicsContentViewText, // JIntent
Androidapi.Helpers, // StringToJString
FMX.Platform.Android; // MainActivity
procedure TForm1.Button1Click(Sender: TObject);
var
AText: string;
Intent: JIntent;
begin
AText := Memo1.Text;
Intent := TJIntent.Create;
Intent.setType(StringToJString('text/plain'));
Intent.setAction(TJIntent.JavaClass.ACTION_SEND);
Intent.putExtra(TJIntent.JavaClass.EXTRA_TEXT, StringToJString(AText));
if MainActivity.getPackageManager.queryIntentActivities(Intent,
TJPackageManager.JavaClass.MATCH_DEFAULT_ONLY).size > 0 then
MainActivity.startActivity(Intent)
else
ShowMessage('Receiver not found');
end;
送信された文字列を受信する
新しいマルチデバイスアプリケーションを作成し、フォームにTMemoを配置します。
AndroidManifest.template.xmlを編集する
アプリケーションをビルドすると「AndroidManifest.template.xml」が生成されます。
「AndroidManifest.template.xml」をテキストエディタで開き、次の行を追加します。
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
//↓追加
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
これでインテントを受信できるようになります。
文字列を受信する
インテントから文字列を受け取ります。
フォームのOnCreateイベントを記述します。
アプリケーションのイベントハンドラ(HandleAppEvent)を設定し、アプリケーションがアクティブになったときのイベントを取得するようにします。
procedure TForm2.FormCreate(Sender: TObject);
var
AppEventService: IFMXApplicationEventService;
begin
if TPlatformServices.Current.SupportsPlatformService
(IFMXApplicationEventService, AppEventService) then
AppEventService.SetApplicationEventHandler(HandleAppEvent);
end;
フォームにHandleAppEventメソッドを追加します。
type
TForm2 = class(TForm)
private
function HandleAppEvent(AAppEvent: TApplicationEvent;
AContext: TObject): Boolean;
アプリケーションがアクティブになったとき、インテントがあればHandleIntentActionメソッドを呼び出します。
function TForm2.HandleAppEvent(AAppEvent: TApplicationEvent;
AContext: TObject): Boolean;
var
StartupIntent: JIntent;
begin
Result := False;
if AAppEvent = TApplicationEvent.BecameActive then
begin
StartupIntent := MainActivity.getIntent;
if StartupIntent <> nil then
HandleIntentAction(StartupIntent);
end;
end;
フォームにHandleIntentActionメソッドを追加します。
type
TForm2 = class(TForm)
private
function HandleIntentAction(const Data: JIntent): Boolean;
インテントから送信された文字列を取り出します。
function TForm2.HandleIntentAction(const Data: JIntent): Boolean;
var
Extras: JBundle;
begin
Result := False;
if Data <> nil then
begin
Memo1.ClearContent;
Extras := Data.getExtras;
if Extras <> nil then
Memo1.Text := JStringToString
(Extras.getString(TJIntent.JavaClass.EXTRA_TEXT));
Invalidate;
end;
end;
アプリケーションが終了状態の時は問題なく動作しますが、アプリケーションが待機中の時はインテントを受信できません。
待機中のアプリケーションがインテントを受信すると、ActivityのOnNewIntentが呼び出されます。
OnNewIntentが呼ばれたときにインテントを処理できるようにします。
FormのOnCreateイベントに次のコードを追加します。
MainActivityのregisterIntentActionメソッドで、TJIntent.JavaClass.ACTION_SENDを受け取るようにします。
これによって、ActivityのOnNewIntentが呼ばれたときに、TJIntent.JavaClass.ACTION_SENDのインテントがあると通知が来るようになります。
通知はHandleActivityMessageメソッドで受け取ります。
procedure TForm2.FormCreate(Sender: TObject);
var
AppEventService: IFMXApplicationEventService;
begin
if TPlatformServices.Current.SupportsPlatformService
(IFMXApplicationEventService, AppEventService) then
AppEventService.SetApplicationEventHandler(HandleAppEvent);
//次のコードを追加
MainActivity.registerIntentAction(TJIntent.JavaClass.ACTION_SEND);
TMessageManager.DefaultManager.SubscribeToMessage
(TMessageReceivedNotification, HandleActivityMessage);
end;
フォームにHandleActivityMessageメソッドを追加します。
type
TForm2 = class(TForm)
private
procedure HandleActivityMessage(const Sender: TObject; const M: TMessage);
ここでHandleIntentActionメソッドを呼び出すと、アプリケーションがアクティブになったときにHandleAppEventメソッドで上書きされてしまいます。
そこで、インテントを受け取ったら、MainActivityのインテントを更新するようにします。
※ここの処理は検証が不十分です。問題があるかもしれません。
procedure TForm2.HandleActivityMessage(const Sender: TObject;
const M: TMessage);
var
Intent: JIntent;
begin
if M is TMessageReceivedNotification then
begin
Intent := TMessageReceivedNotification(M).Value;
if Intent <> nil then
MainActivity.setIntent(Intent);
end;
end;
以上で、インテントを受信できるようになりました。
Hey Is it Possible in Delphi XE7 . Then Please help me.
Thank you.
ちょっとそれは、Delphi XE7で可能です。そして、私を助けてください。
ありがとう。
registerIntentAction is a new feature of Delphi 10 Seattle.
It can not be used in Delphi XE7.
MainActivityが未定義の識別子になります。
どこかで指定するのでしょうか?
Usesが不足していたようです。
山本さん、こんにちは。長町です。
データの送受信はできるようになったのですが、
他のアプリから受信できるようにするにはどのようにすれば良いのでしょうか。
などしてみましたが、Androidが受け付けていないようです。
この場合、INTENT受信ではない?
古い記事に失礼します。
アプリの未起動時のインテント処理としてBecameActiveで制御されていますが
この場合、アプリのフォアグラウンド移行の度に、起動時のインテントを引き継いだまま
何度も処理が走ってしまいます。
インテント受信時のみ処理される、といった形が望ましいかと思いますので
FinishedLaunchingを使用した方が良いかと。
(未起動時に1回だけ実行。起動中はregisterIntentActionからのHandleActivityMessageで処理)
Berlinでは上記で問題ないこと確認しました。
SeattleでもTApplicationEventの内容は変わっていないので、問題ないかと存じます。