如何在 Delphi 10.4.1 应用程序中从 Zebra TC21 扫描仪接收 Android Intent
How to receive Android Intent from Zebra TC21 Scanner in Delphi 10.4.1 application
我正在使用 Delphi 10.4.1 开发 Android 应用程序以部署在 Zebra TC21 上。我正在尝试从 DataWedge Intent 接收条形码,但我的应用程序中的 HandleIntentAction 未触发。 Zebra TC21 扫描器配置:Android10,DataWedge 版本 8.2.60。我在 Delphi、Embarcadero 示例、DataWedge 配置演示中阅读了一些关于接收意图的文章,但我仍然无法解决问题。有人可以帮我吗?
“MyTest”应用程序(pl.dplodz.MyTest):
procedure TMainForm.FormCreate(Sender: TObject);
var AppEventService: IFMXApplicationEventService;
begin
if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, AppEventService) then
AppEventService.SetApplicationEventHandler(HandleAppEvent);
// Register the type of intent action that we want to be able to receive.
// Note: A corresponding <action> tag must also exist in the <intent-filter> section of AndroidManifest.template.xml.
MainActivity.RegisterIntentAction(StringToJString('pl.dplodz.ACTION'));
TMessageManager.DefaultManager.SubscribeToMessage(TMessageReceivedNotification, HandleActivityMessage);
Memo1.Lines.Clear;
Memo1.Lines.Add(TimeToStr(Now) + ': AppStarted');
end;
procedure TMainForm.HandleActivityMessage(const Sender: TObject; const M: TMessage);
begin
Memo1.Lines.Add(TimeToStr(Now) + ': HandleActivityMessage Fired');
if M is TMessageReceivedNotification then
HandleIntentAction(TMessageReceivedNotification(M).Value);
end;
function TMainForm.HandleAppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean;
var StartupIntent: JIntent;
begin
Memo1.Lines.Add(TimeToStr(Now) + ': HandleAppEvent Fired');
Result := False;
if AAppEvent = TApplicationEvent.BecameActive then
begin
StartupIntent := MainActivity.getIntent;
if StartupIntent <> nil then
HandleIntentAction(StartupIntent);
end;
end;
function TMainForm.HandleIntentAction(const Data: JIntent): Boolean;
var Extras : JBundle;
JStr : JString;
begin
Memo1.Lines.Add(TimeToStr(Now) + ': HandleIntentAction Fired');
Result := False;
if Data <> nil then
begin
Extras := Data.getExtras;
if Extras <> nil then
Memo1.Lines.Add(JStringToString(Extras.getString(TJIntent.JavaClass.EXTRA_TEXT)))
else
Memo1.Lines.Add(TimeToStr(Now) + ': Extras = nil');
end
else
Memo1.Lines.Add(TimeToStr(Now) + ': Data = nil');
Invalidate;
end;
procedure TMainForm.CloseBtnClick(Sender: TObject);
begin
Close;
end;
procedure TMainForm.ClearMemoBtnClick(Sender: TObject);
begin
Memo1.Lines.Clear;
end;
AndroidManifest.Template.XML:
<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="%package%"
android:versionCode="%versionCode%"
android:versionName="%versionName%"
android:installLocation="%installLocation%">
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="%targetSdkVersion%" />
<%uses-permission%>
<uses-feature android:glEsVersion="0x00020000" android:required="True"/>
<application android:persistent="%persistent%"
android:restoreAnyVersion="%restoreAnyVersion%"
android:label="%label%"
android:debuggable="%debuggable%"
android:largeHeap="%largeHeap%"
android:icon="%icon%"
android:theme="%theme%"
android:hardwareAccelerated="%hardwareAccelerated%"
android:resizeableActivity="false"
android:requestLegacyExternalStorage="true">
<%provider%>
<%application-meta-data%>
<%uses-libraries%>
<%services%>
<!-- Our activity is a subclass of the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
android:label="%activityLabel%"
android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
android:launchMode="singleTask">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="%libNameValue%" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="pl.dplodz.ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<%activity%>
<%receivers%>
</application>
</manifest>
<!-- END_INCLUDE(manifest) -->
我的 DataWedge 配置文件配置:
New profile: "MyTest", key configuration:
Profile Enabled
Associated Apps: "com.embarcadero.firemonkey.FMXNativeActivity | pl.dplodz.MyTest"
Barcode Input: Enabled
Keystroke Output: Disabled
Intent Output section:
Intent action: pl.dplodz.ACTION
Intent category: android.intent.category.DEFAULT (btw. I tested with empty value - no changes)
Intent delivery: Broadcast intent
Component Information: [empty]
我在扫描代码时听到哔声,但应用程序没有任何反应。问题出在哪里?在 DataWedge 配置中?在申请中?
根据我的评论,如果您通过 RegisterIntentAction 处理意图,则需要将 Intent Delivery 设置为 Start Activity。
但是,您可以通过在代码中创建接收器来接收广播意图。在这种情况下,您的应用程序需要已经 运行,但这里有一个可能的实现:
uses
Androidapi.JNIBridge, Androidapi.JNI.Embarcadero, Androidapi.JNI.GraphicsContentViewText;
type
TDataWedgeDataEvent = procedure(Sender: TObject; const Data: string) of object;
TDataWedgeBroadcastListener = class(TJavaLocal, JFMXBroadcastReceiverListener)
private
FReceiver: JBroadcastReceiver;
FOnData: TDataWedgeDataEvent;
public
{ JFMXBroadcastReceiverListener }
procedure onReceive(context: JContext; intent: JIntent); cdecl;
public
constructor Create;
destructor Destroy; override;
property OnData: TDataWedgeDataEvent read FOnData write FOnData;
end;
implementation
uses
Androidapi.Helpers;
{ TDataWedgeBroadcastListener }
constructor TDataWedgeBroadcastListener.Create;
var
LIntentFilter: JIntentFilter;
begin
inherited;
FReceiver := TJFMXBroadcastReceiver.JavaClass.init(Self);
LIntentFilter := TJIntentFilter.JavaClass.init;
LIntentFilter.addAction(StringToJString('pl.dplodz.ACTION')); // or whatever value the profile is configured for
LIntentFilter.addCategory(StringToJString('android.intent.category.DEFAULT'));
TAndroidHelper.Context.registerReceiver(FReceiver, LIntentFilter);
end;
destructor TDataWedgeBroadcastListener.Destroy;
begin
TAndroidHelper.Context.unregisterReceiver(FReceiver);
inherited;
end;
procedure TDataWedgeBroadcastListener.onReceive(context: JContext; intent: JIntent);
begin
if (intent <> nil) and Assigned(FOnData) then
FOnData(Self, JStringToString(intent.getStringExtra(StringToJString('com.symbol.datawedge.data_string'))));
end;
创建 TDataWedgeBroadcastListener 实例并连接到 OnData 事件。使用此方法,您无需在清单中设置 Intent 过滤器
我正在使用 Delphi 10.4.1 开发 Android 应用程序以部署在 Zebra TC21 上。我正在尝试从 DataWedge Intent 接收条形码,但我的应用程序中的 HandleIntentAction 未触发。 Zebra TC21 扫描器配置:Android10,DataWedge 版本 8.2.60。我在 Delphi、Embarcadero 示例、DataWedge 配置演示中阅读了一些关于接收意图的文章,但我仍然无法解决问题。有人可以帮我吗?
“MyTest”应用程序(pl.dplodz.MyTest):
procedure TMainForm.FormCreate(Sender: TObject);
var AppEventService: IFMXApplicationEventService;
begin
if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, AppEventService) then
AppEventService.SetApplicationEventHandler(HandleAppEvent);
// Register the type of intent action that we want to be able to receive.
// Note: A corresponding <action> tag must also exist in the <intent-filter> section of AndroidManifest.template.xml.
MainActivity.RegisterIntentAction(StringToJString('pl.dplodz.ACTION'));
TMessageManager.DefaultManager.SubscribeToMessage(TMessageReceivedNotification, HandleActivityMessage);
Memo1.Lines.Clear;
Memo1.Lines.Add(TimeToStr(Now) + ': AppStarted');
end;
procedure TMainForm.HandleActivityMessage(const Sender: TObject; const M: TMessage);
begin
Memo1.Lines.Add(TimeToStr(Now) + ': HandleActivityMessage Fired');
if M is TMessageReceivedNotification then
HandleIntentAction(TMessageReceivedNotification(M).Value);
end;
function TMainForm.HandleAppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean;
var StartupIntent: JIntent;
begin
Memo1.Lines.Add(TimeToStr(Now) + ': HandleAppEvent Fired');
Result := False;
if AAppEvent = TApplicationEvent.BecameActive then
begin
StartupIntent := MainActivity.getIntent;
if StartupIntent <> nil then
HandleIntentAction(StartupIntent);
end;
end;
function TMainForm.HandleIntentAction(const Data: JIntent): Boolean;
var Extras : JBundle;
JStr : JString;
begin
Memo1.Lines.Add(TimeToStr(Now) + ': HandleIntentAction Fired');
Result := False;
if Data <> nil then
begin
Extras := Data.getExtras;
if Extras <> nil then
Memo1.Lines.Add(JStringToString(Extras.getString(TJIntent.JavaClass.EXTRA_TEXT)))
else
Memo1.Lines.Add(TimeToStr(Now) + ': Extras = nil');
end
else
Memo1.Lines.Add(TimeToStr(Now) + ': Data = nil');
Invalidate;
end;
procedure TMainForm.CloseBtnClick(Sender: TObject);
begin
Close;
end;
procedure TMainForm.ClearMemoBtnClick(Sender: TObject);
begin
Memo1.Lines.Clear;
end;
AndroidManifest.Template.XML:
<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="%package%"
android:versionCode="%versionCode%"
android:versionName="%versionName%"
android:installLocation="%installLocation%">
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="%targetSdkVersion%" />
<%uses-permission%>
<uses-feature android:glEsVersion="0x00020000" android:required="True"/>
<application android:persistent="%persistent%"
android:restoreAnyVersion="%restoreAnyVersion%"
android:label="%label%"
android:debuggable="%debuggable%"
android:largeHeap="%largeHeap%"
android:icon="%icon%"
android:theme="%theme%"
android:hardwareAccelerated="%hardwareAccelerated%"
android:resizeableActivity="false"
android:requestLegacyExternalStorage="true">
<%provider%>
<%application-meta-data%>
<%uses-libraries%>
<%services%>
<!-- Our activity is a subclass of the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
android:label="%activityLabel%"
android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
android:launchMode="singleTask">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="%libNameValue%" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="pl.dplodz.ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<%activity%>
<%receivers%>
</application>
</manifest>
<!-- END_INCLUDE(manifest) -->
我的 DataWedge 配置文件配置:
New profile: "MyTest", key configuration:
Profile Enabled
Associated Apps: "com.embarcadero.firemonkey.FMXNativeActivity | pl.dplodz.MyTest"
Barcode Input: Enabled
Keystroke Output: Disabled
Intent Output section:
Intent action: pl.dplodz.ACTION
Intent category: android.intent.category.DEFAULT (btw. I tested with empty value - no changes)
Intent delivery: Broadcast intent
Component Information: [empty]
我在扫描代码时听到哔声,但应用程序没有任何反应。问题出在哪里?在 DataWedge 配置中?在申请中?
根据我的评论,如果您通过 RegisterIntentAction 处理意图,则需要将 Intent Delivery 设置为 Start Activity。
但是,您可以通过在代码中创建接收器来接收广播意图。在这种情况下,您的应用程序需要已经 运行,但这里有一个可能的实现:
uses
Androidapi.JNIBridge, Androidapi.JNI.Embarcadero, Androidapi.JNI.GraphicsContentViewText;
type
TDataWedgeDataEvent = procedure(Sender: TObject; const Data: string) of object;
TDataWedgeBroadcastListener = class(TJavaLocal, JFMXBroadcastReceiverListener)
private
FReceiver: JBroadcastReceiver;
FOnData: TDataWedgeDataEvent;
public
{ JFMXBroadcastReceiverListener }
procedure onReceive(context: JContext; intent: JIntent); cdecl;
public
constructor Create;
destructor Destroy; override;
property OnData: TDataWedgeDataEvent read FOnData write FOnData;
end;
implementation
uses
Androidapi.Helpers;
{ TDataWedgeBroadcastListener }
constructor TDataWedgeBroadcastListener.Create;
var
LIntentFilter: JIntentFilter;
begin
inherited;
FReceiver := TJFMXBroadcastReceiver.JavaClass.init(Self);
LIntentFilter := TJIntentFilter.JavaClass.init;
LIntentFilter.addAction(StringToJString('pl.dplodz.ACTION')); // or whatever value the profile is configured for
LIntentFilter.addCategory(StringToJString('android.intent.category.DEFAULT'));
TAndroidHelper.Context.registerReceiver(FReceiver, LIntentFilter);
end;
destructor TDataWedgeBroadcastListener.Destroy;
begin
TAndroidHelper.Context.unregisterReceiver(FReceiver);
inherited;
end;
procedure TDataWedgeBroadcastListener.onReceive(context: JContext; intent: JIntent);
begin
if (intent <> nil) and Assigned(FOnData) then
FOnData(Self, JStringToString(intent.getStringExtra(StringToJString('com.symbol.datawedge.data_string'))));
end;
创建 TDataWedgeBroadcastListener 实例并连接到 OnData 事件。使用此方法,您无需在清单中设置 Intent 过滤器