Delphi android - 将数据从本地前台服务发送到应用程序
Delphi android - Send data from local foreground service to application
我有一个启动前台本地服务的应用程序。我能够将命令从应用程序发送到服务。我还需要将数据(例如:位置)从前台本地服务发送到应用程序。 Embarcadero 提供了一个使用通知中心的示例,但它根本不起作用:http://docwiki.embarcadero.com/CodeExamples/Sydney/en/FMX.Android_Notification_Service_Sample。我编译了示例并将其安装在我的设备上,没有收到任何东西,当然我的应用程序也有同样的行为:我在设备中收到通知,而不是在应用程序中。
我看了很多关于服务和应用程序之间通信的帖子,其中大部分在java,但我不知道如何用delphi实现它。我想最简单的方法是使用意图,因为我没有太多数据要发送。是这样的吗? :
在服务中是这样的:
IntentMes := TJIntent.Create;
IntentMes.addCategory(TJIntent.JavaClass.CATEGORY_DEFAULT);
IntentMes.setAction(StringToJString(svcIntentAction)); // svcIntentAction = fr.MyApp.SVC
IntentMes.putExtra(StringToJString(svcIntentData),StringToJString('Hello'));
TAndroidHelper.Context.sendBroadcast(Intent); // Very not sure of that
在应用程序中是这样的:
function MyApp.HandleIntentAction(const Data: JIntent): Boolean;
var svcData : string;
begin
Result := False;
if Data <> nil then begin
if Data.hasExtra(StringToJString(svcIntentData)) then begin
svcData := JStringToString(Data.getStringExtra(StringToJString(svcIntentData)));
result := true;
// process data...
end;
end;
end;
在清单文件中:
<intent-filter>
<action android:name="fr.MyApp.SVC" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
在发送数据之前,我还需要确保应用程序 运行。
这是一种可能做你想做的事情的方法,基于我在这个演示中使用的一些代码:
https://github.com/DelphiWorlds/Kastri/tree/master/Demos/CrossPlatformLocation
接下来是这项工作的基础知识,但前提是相同的,即创建一个 class 的实例来实现 JFMXBroadcastReceiverListener,它会添加适当的操作,并为 OnMessageReceived 事件分配一个处理程序. “数据”通过 SendMessage 方法发送。
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
Androidapi.JNIBridge, Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.Embarcadero;
type
// Import that is missing from Delphi - it would pay to split this off into a separate unit
JLocalBroadcastManager = interface;
JLocalBroadcastManagerClass = interface(JObjectClass)
['{5CCF81B2-E170-47C4-873E-32E644085880}']
{class} function getInstance(context: JContext): JLocalBroadcastManager; cdecl;
end;
[JavaSignature('android/support/v4/content/LocalBroadcastManager')]
JLocalBroadcastManager = interface(JObject)
['{B5D9B2DA-E150-4CC5-BBDA-58FCD42C6C1E}']
procedure registerReceiver(receiver: JBroadcastReceiver; filter: JIntentFilter); cdecl;
function sendBroadcast(intent: JIntent): Boolean; cdecl;
procedure sendBroadcastSync(intent: JIntent); cdecl;
procedure unregisterReceiver(receiver: JBroadcastReceiver); cdecl;
end;
TJLocalBroadcastManager = class(TJavaGenericImport<JLocalBroadcastManagerClass, JLocalBroadcastManager>) end;
TMessageReceivedEvent = procedure(Sender: TObject; const Msg: string) of object;
// Local broadcast receiver class
TLocalReceiver = class(TJavaLocal, JFMXBroadcastReceiverListener)
private
FAction: JString;
FBroadcastReceiver: JFMXBroadcastReceiver;
FIntentFilter: JIntentFilter;
FOnMessageReceived: TMessageReceivedEvent;
procedure DoMessageReceived(const AMsg: string);
public
{ JFMXBroadcastReceiverListener }
procedure onReceive(context: JContext; intent: JIntent); cdecl;
public
constructor Create(const AAction: string);
destructor Destroy; override;
property OnMessageReceived: TMessageReceivedEvent read FOnMessageReceived write FOnMessageReceived;
end;
TForm1 = class(TForm)
private
FReceiver: TLocalReceiver;
procedure ReceiverMessageReceivedHandler(Sender: TObject; const AMsg: string);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
uses
Androidapi.Helpers;
const
cLocalBroadcastExtraMessage = 'MESSAGE';
// e.g. SendMessage('SERVICE_MESSAGE', 'Hello world');
procedure SendMessage(const AAction, AMessage: string);
var
LIntent: JIntent;
begin
LIntent := TJIntent.JavaClass.init(StringToJString(AAction));
LIntent.putExtra(StringToJString(cLocalBroadcastExtraMessage), StringToJString(AMessage));
TJLocalBroadcastManager.JavaClass.getInstance(TAndroidHelper.Context).sendBroadcast(LIntent);
end;
{ TLocalReceiver }
constructor TLocalReceiver.Create(const AAction: string);
begin
inherited Create;
FAction := StringToJString(AAction);
FBroadcastReceiver := TJFMXBroadcastReceiver.JavaClass.init(Self);
FIntentFilter := TJIntentFilter.JavaClass.init;
FIntentFilter.addAction(FAction);
TJLocalBroadcastManager.JavaClass.getInstance(TAndroidHelper.Context).registerReceiver(FBroadcastReceiver, FIntentFilter);
end;
destructor TLocalReceiver.Destroy;
begin
TJLocalBroadcastManager.JavaClass.getInstance(TAndroidHelper.Context).unregisterReceiver(FBroadcastReceiver);
FBroadcastReceiver := nil;
end;
procedure TLocalReceiver.onReceive(context: JContext; intent: JIntent);
begin
if intent.getAction.equals(FAction) then
DoMessageReceived(JStringToString(intent.getStringExtra(StringToJString(cLocalBroadcastExtraMessage))));
end;
procedure TLocalReceiver.DoMessageReceived(const AMsg: string);
begin
if Assigned(FOnMessageReceived) then
FOnMessageReceived(Self, AMsg);
end;
{ TForm1 }
constructor TForm1.Create(AOwner: TComponent);
begin
inherited;
// For the service, do a similar setup with an instance of TLocalReceiver, but use an action of something like 'APP_MESSAGE'
FReceiver := TLocalReceiver.Create('SERVICE_MESSAGE'); // i.e. receiving messages from the service
FReceiver.OnMessageReceived := ReceiverMessageReceivedHandler;
end;
destructor TForm1.Destroy;
begin
FReceiver.Free;
inherited;
end;
procedure TForm1.ReceiverMessageReceivedHandler(Sender: TObject; const AMsg: string);
begin
// Handle AMsg here
end;
end.
我有一个启动前台本地服务的应用程序。我能够将命令从应用程序发送到服务。我还需要将数据(例如:位置)从前台本地服务发送到应用程序。 Embarcadero 提供了一个使用通知中心的示例,但它根本不起作用:http://docwiki.embarcadero.com/CodeExamples/Sydney/en/FMX.Android_Notification_Service_Sample。我编译了示例并将其安装在我的设备上,没有收到任何东西,当然我的应用程序也有同样的行为:我在设备中收到通知,而不是在应用程序中。
我看了很多关于服务和应用程序之间通信的帖子,其中大部分在java,但我不知道如何用delphi实现它。我想最简单的方法是使用意图,因为我没有太多数据要发送。是这样的吗? :
在服务中是这样的:
IntentMes := TJIntent.Create;
IntentMes.addCategory(TJIntent.JavaClass.CATEGORY_DEFAULT);
IntentMes.setAction(StringToJString(svcIntentAction)); // svcIntentAction = fr.MyApp.SVC
IntentMes.putExtra(StringToJString(svcIntentData),StringToJString('Hello'));
TAndroidHelper.Context.sendBroadcast(Intent); // Very not sure of that
在应用程序中是这样的:
function MyApp.HandleIntentAction(const Data: JIntent): Boolean;
var svcData : string;
begin
Result := False;
if Data <> nil then begin
if Data.hasExtra(StringToJString(svcIntentData)) then begin
svcData := JStringToString(Data.getStringExtra(StringToJString(svcIntentData)));
result := true;
// process data...
end;
end;
end;
在清单文件中:
<intent-filter>
<action android:name="fr.MyApp.SVC" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
在发送数据之前,我还需要确保应用程序 运行。
这是一种可能做你想做的事情的方法,基于我在这个演示中使用的一些代码:
https://github.com/DelphiWorlds/Kastri/tree/master/Demos/CrossPlatformLocation
接下来是这项工作的基础知识,但前提是相同的,即创建一个 class 的实例来实现 JFMXBroadcastReceiverListener,它会添加适当的操作,并为 OnMessageReceived 事件分配一个处理程序. “数据”通过 SendMessage 方法发送。
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
Androidapi.JNIBridge, Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.Embarcadero;
type
// Import that is missing from Delphi - it would pay to split this off into a separate unit
JLocalBroadcastManager = interface;
JLocalBroadcastManagerClass = interface(JObjectClass)
['{5CCF81B2-E170-47C4-873E-32E644085880}']
{class} function getInstance(context: JContext): JLocalBroadcastManager; cdecl;
end;
[JavaSignature('android/support/v4/content/LocalBroadcastManager')]
JLocalBroadcastManager = interface(JObject)
['{B5D9B2DA-E150-4CC5-BBDA-58FCD42C6C1E}']
procedure registerReceiver(receiver: JBroadcastReceiver; filter: JIntentFilter); cdecl;
function sendBroadcast(intent: JIntent): Boolean; cdecl;
procedure sendBroadcastSync(intent: JIntent); cdecl;
procedure unregisterReceiver(receiver: JBroadcastReceiver); cdecl;
end;
TJLocalBroadcastManager = class(TJavaGenericImport<JLocalBroadcastManagerClass, JLocalBroadcastManager>) end;
TMessageReceivedEvent = procedure(Sender: TObject; const Msg: string) of object;
// Local broadcast receiver class
TLocalReceiver = class(TJavaLocal, JFMXBroadcastReceiverListener)
private
FAction: JString;
FBroadcastReceiver: JFMXBroadcastReceiver;
FIntentFilter: JIntentFilter;
FOnMessageReceived: TMessageReceivedEvent;
procedure DoMessageReceived(const AMsg: string);
public
{ JFMXBroadcastReceiverListener }
procedure onReceive(context: JContext; intent: JIntent); cdecl;
public
constructor Create(const AAction: string);
destructor Destroy; override;
property OnMessageReceived: TMessageReceivedEvent read FOnMessageReceived write FOnMessageReceived;
end;
TForm1 = class(TForm)
private
FReceiver: TLocalReceiver;
procedure ReceiverMessageReceivedHandler(Sender: TObject; const AMsg: string);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
uses
Androidapi.Helpers;
const
cLocalBroadcastExtraMessage = 'MESSAGE';
// e.g. SendMessage('SERVICE_MESSAGE', 'Hello world');
procedure SendMessage(const AAction, AMessage: string);
var
LIntent: JIntent;
begin
LIntent := TJIntent.JavaClass.init(StringToJString(AAction));
LIntent.putExtra(StringToJString(cLocalBroadcastExtraMessage), StringToJString(AMessage));
TJLocalBroadcastManager.JavaClass.getInstance(TAndroidHelper.Context).sendBroadcast(LIntent);
end;
{ TLocalReceiver }
constructor TLocalReceiver.Create(const AAction: string);
begin
inherited Create;
FAction := StringToJString(AAction);
FBroadcastReceiver := TJFMXBroadcastReceiver.JavaClass.init(Self);
FIntentFilter := TJIntentFilter.JavaClass.init;
FIntentFilter.addAction(FAction);
TJLocalBroadcastManager.JavaClass.getInstance(TAndroidHelper.Context).registerReceiver(FBroadcastReceiver, FIntentFilter);
end;
destructor TLocalReceiver.Destroy;
begin
TJLocalBroadcastManager.JavaClass.getInstance(TAndroidHelper.Context).unregisterReceiver(FBroadcastReceiver);
FBroadcastReceiver := nil;
end;
procedure TLocalReceiver.onReceive(context: JContext; intent: JIntent);
begin
if intent.getAction.equals(FAction) then
DoMessageReceived(JStringToString(intent.getStringExtra(StringToJString(cLocalBroadcastExtraMessage))));
end;
procedure TLocalReceiver.DoMessageReceived(const AMsg: string);
begin
if Assigned(FOnMessageReceived) then
FOnMessageReceived(Self, AMsg);
end;
{ TForm1 }
constructor TForm1.Create(AOwner: TComponent);
begin
inherited;
// For the service, do a similar setup with an instance of TLocalReceiver, but use an action of something like 'APP_MESSAGE'
FReceiver := TLocalReceiver.Create('SERVICE_MESSAGE'); // i.e. receiving messages from the service
FReceiver.OnMessageReceived := ReceiverMessageReceivedHandler;
end;
destructor TForm1.Destroy;
begin
FReceiver.Free;
inherited;
end;
procedure TForm1.ReceiverMessageReceivedHandler(Sender: TObject; const AMsg: string);
begin
// Handle AMsg here
end;
end.