Issue
I'm developing an Android app with Delphi 10.4.1 to deploy on a Zebra TC21. I'm trying to receive a barcode from DataWedge intent and the HandleIntentAction in my app doesn't fired. Zebra TC21 scanner configuration: Android 10, DataWedge version 8.2.60. I read some articles about receiving intents in Delphi, Embarcadero sample, DataWedge configuration demos and still I can't solve the problem. Can someone help me please?
"MyTest" application (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) -->
My DataWedge profile configuration:
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]
I hear a beep signal when scanning the code but nothing happens on the application. Where is the problem? In DataWedge config? In application?
Solution
As per my comment, if you're handling intents via RegisterIntentAction, you'll need to set Intent Delivery to Start Activity.
You can however receive Broadcast Intents by creating a receiver in code. In this case, your app would need to be already running, however here is a possible implementation:
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;
Create an instance of TDataWedgeBroadcastListener and hook up to the OnData event. Using this method, you do not need to set up an intent filter in the manifest
Answered By - Dave Nottage
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.