如何在 Delphi 多设备应用程序中读取从 android 应用广播的意图
How to read intent in Delphi multi-device app broadcasted from android app
我最近得到了一个 Android 条形码扫描仪设备。我想在 Delphi 10 Seattle 编写一个小型库存多设备应用程序。扫描仪有两种模式设置 return 扫描条码,第一种模式只是将条码传递给聚焦的编辑控件,第二种模式是广播模式。因为 Delphi 仍然有一些编辑控件无法正常工作的怪癖,特别是在 android 环境中与虚拟键盘串联时,我必须使用广播模式。在网上,我发现手册几乎没有 none 有用的信息,API 用于控制设备,android 用 eclipse 编写的演示应用程序。
我能够为 Delphi 获取 API 包装器并成功控制设备、更改参数、打开扫描仪等
然而,由于对 android 意图和广播的工作原理了解不多,我无法成功实施它。
我研究了 Delphi http://docwiki.embarcadero.com/CodeExamples/Seattle/en/FMX.Android_Intents_Sample 的意图样本。 运行 Android Intent 示例应用程序确实有效。
Eclipse android 演示项目也工作正常,编译和 运行 没有问题。现在的困境是如何在 Delphi 中接收广播的意图。我有 manifest.xml 和 mainactivity 代码来自这里的 eclipse 演示...
清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testscan"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.testscan.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
主要活动:
package com.example.testscan;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.device.ScanDevice;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
public class MainActivity extends Activity {
ScanDevice sm;
private final static String SCAN_ACTION = "scan.rcv.message";
private String barcodeStr;
private EditText showScanResult;
private BroadcastReceiver mScanReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
byte[] barocode = intent.getByteArrayExtra("barocode");
int barocodelen = intent.getIntExtra("length", 0);
byte temp = intent.getByteExtra("barcodeType", (byte) 0);
android.util.Log.i("debug", "----codetype--" + temp);
barcodeStr = new String(barocode, 0, barocodelen);
showScanResult.append("tere");
showScanResult.append(barcodeStr);
showScanResult.append("\n");
// showScanResult.setText(barcodeStr);
sm.stopScan();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sm = new ScanDevice();
CheckBox ch = (CheckBox) findViewById(R.id.checkBox1);
if(sm.getOutScanMode()==1){
ch.setChecked(true);
}else{
ch.setChecked(false);
}
ch.setOnCheckedChangeListener(new OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
// TODO Auto-generated method stub
if(arg1){
sm.setOutScanMode(1);
}else{
sm.setOutScanMode(0);
}
}});
showScanResult=(EditText) findViewById(R.id.editText1);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.openScanner:
System.out.println("openScanner = "+sm.getOutScanMode());
sm.openScan();
break;
case R.id.closeScanner:
sm.closeScan();
break;
case R.id.startDecode:
sm.startScan();
break;
case R.id.stopDecode:
sm.stopScan();
break;
case R.id.start_continue:
sm.setScanLaserMode(4);
break;
case R.id.stop_continue:
sm.setScanLaserMode(8);
break;
case R.id.close:
finish();
break;
default:
break;
}
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
if(sm != null) {
sm.stopScan();
}
unregisterReceiver(mScanReceiver);
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction(SCAN_ACTION);
registerReceiver(mScanReceiver, filter);
}
}
编辑:2017-04-24
我发现一位日本博主写了一篇关于使用 Delphi 10 Seattle 和更新版本 http://www.gesource.jp/weblog/?p=7269 创建简单广播接收器的文章。我后来发现,在 @alit运行 提到的来源评论之一中提到了这一点。
因此,要在广播模式下使用扫描仪,您需要 U8000S_ScanSDK.pas jar wrapper 来访问和控制设备。需要在广播模式下设置扫描仪应用程序。然后你需要创建 BroadcastReceiverListener class ...
上面提到的 android 应用程序的简单端口在这里:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes,
System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics,
FMX.Dialogs,
FMX.Controls.Presentation, FMX.Edit,
Androidapi.JNIBridge, Androidapi.JNI.Embarcadero,
Androidapi.JNI.GraphicsContentViewText,
U8000S_ScanSDK; { U8000S_ScanSDK.jar wrapper }
type
TMyReceiver = class(TJavaLocal, JFMXBroadcastReceiverListener)
public
constructor Create;
procedure onReceive(context: JContext; intent: JIntent); cdecl;
end;
TForm1 = class(TForm)
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
FMyListener: TMyReceiver;
FBroadcastReceiver: JFMXBroadcastReceiver;
ScanDevice: JScanDevice; { U8000S_ScanSDK.jar api device interface }
procedure managebarcodescan(barcode: string);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
Androidapi.Helpers,
Androidapi.JNI.JavaTypes;
{$R *.fmx}
function HexToString(H: String): String;
var
I: Integer;
begin
Result := '';
for I := 1 to length(H) div 2 do
Result := Result + Char(StrToInt('$' + Copy(H, (I - 1) * 2 + 1, 2)));
end;
constructor TMyReceiver.Create;
begin
inherited;
end;
procedure TMyReceiver.onReceive(context: JContext; intent: JIntent);
var
barocode: tjavaarray<System.byte>;
len: Integer;
buffer: string;
I: Integer;
begin
if JStringToString(intent.getAction) = 'scan.rcv.message' then
begin
len := intent.getIntExtra(StringToJString('length'), 0);
barocode := intent.getByteArrayExtra(StringToJString('barocode'));
for I := 0 to len - 1 do
begin
buffer := buffer + inttohex(barocode[I], 2);
end;
buffer := HexToString(buffer);
barocode.Free;
// do something with result
Form1.managebarcodescan(buffer);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Filter: JIntentFilter;
begin
FMyListener := TMyReceiver.Create;
FBroadcastReceiver := TJFMXBroadcastReceiver.JavaClass.init(FMyListener);
Filter := TJIntentFilter.JavaClass.init;
Filter.addAction(StringToJString('scan.rcv.message'));
TAndroidHelper.context.getApplicationContext.registerReceiver(FBroadcastReceiver, Filter);
ScanDevice := TJScanDevice.Create; {creating scanner interface}
ScanDevice.setScanCodeEnterKey;
ScanDevice.setOutScanMode(0); {setting scanner to broadcast mode }
ScanDevice.openScan;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
TAndroidHelper.context.getApplicationContext.unregisterReceiver(FBroadcastReceiver);
ScanDevice.stopScan;
ScanDevice._Release;
end;
procedure TForm1.managebarcodescan(barcode: string);
begin
Edit1.Text := barcode;
end;
end.
我最近得到了一个 Android 条形码扫描仪设备。我想在 Delphi 10 Seattle 编写一个小型库存多设备应用程序。扫描仪有两种模式设置 return 扫描条码,第一种模式只是将条码传递给聚焦的编辑控件,第二种模式是广播模式。因为 Delphi 仍然有一些编辑控件无法正常工作的怪癖,特别是在 android 环境中与虚拟键盘串联时,我必须使用广播模式。在网上,我发现手册几乎没有 none 有用的信息,API 用于控制设备,android 用 eclipse 编写的演示应用程序。
我能够为 Delphi 获取 API 包装器并成功控制设备、更改参数、打开扫描仪等
然而,由于对 android 意图和广播的工作原理了解不多,我无法成功实施它。
我研究了 Delphi http://docwiki.embarcadero.com/CodeExamples/Seattle/en/FMX.Android_Intents_Sample 的意图样本。 运行 Android Intent 示例应用程序确实有效。
Eclipse android 演示项目也工作正常,编译和 运行 没有问题。现在的困境是如何在 Delphi 中接收广播的意图。我有 manifest.xml 和 mainactivity 代码来自这里的 eclipse 演示...
清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testscan"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.testscan.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
主要活动:
package com.example.testscan;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.device.ScanDevice;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
public class MainActivity extends Activity {
ScanDevice sm;
private final static String SCAN_ACTION = "scan.rcv.message";
private String barcodeStr;
private EditText showScanResult;
private BroadcastReceiver mScanReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
byte[] barocode = intent.getByteArrayExtra("barocode");
int barocodelen = intent.getIntExtra("length", 0);
byte temp = intent.getByteExtra("barcodeType", (byte) 0);
android.util.Log.i("debug", "----codetype--" + temp);
barcodeStr = new String(barocode, 0, barocodelen);
showScanResult.append("tere");
showScanResult.append(barcodeStr);
showScanResult.append("\n");
// showScanResult.setText(barcodeStr);
sm.stopScan();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sm = new ScanDevice();
CheckBox ch = (CheckBox) findViewById(R.id.checkBox1);
if(sm.getOutScanMode()==1){
ch.setChecked(true);
}else{
ch.setChecked(false);
}
ch.setOnCheckedChangeListener(new OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
// TODO Auto-generated method stub
if(arg1){
sm.setOutScanMode(1);
}else{
sm.setOutScanMode(0);
}
}});
showScanResult=(EditText) findViewById(R.id.editText1);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.openScanner:
System.out.println("openScanner = "+sm.getOutScanMode());
sm.openScan();
break;
case R.id.closeScanner:
sm.closeScan();
break;
case R.id.startDecode:
sm.startScan();
break;
case R.id.stopDecode:
sm.stopScan();
break;
case R.id.start_continue:
sm.setScanLaserMode(4);
break;
case R.id.stop_continue:
sm.setScanLaserMode(8);
break;
case R.id.close:
finish();
break;
default:
break;
}
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
if(sm != null) {
sm.stopScan();
}
unregisterReceiver(mScanReceiver);
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction(SCAN_ACTION);
registerReceiver(mScanReceiver, filter);
}
}
编辑:2017-04-24
我发现一位日本博主写了一篇关于使用 Delphi 10 Seattle 和更新版本 http://www.gesource.jp/weblog/?p=7269 创建简单广播接收器的文章。我后来发现,在 @alit运行 提到的来源评论之一中提到了这一点。 因此,要在广播模式下使用扫描仪,您需要 U8000S_ScanSDK.pas jar wrapper 来访问和控制设备。需要在广播模式下设置扫描仪应用程序。然后你需要创建 BroadcastReceiverListener class ...
上面提到的 android 应用程序的简单端口在这里:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes,
System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics,
FMX.Dialogs,
FMX.Controls.Presentation, FMX.Edit,
Androidapi.JNIBridge, Androidapi.JNI.Embarcadero,
Androidapi.JNI.GraphicsContentViewText,
U8000S_ScanSDK; { U8000S_ScanSDK.jar wrapper }
type
TMyReceiver = class(TJavaLocal, JFMXBroadcastReceiverListener)
public
constructor Create;
procedure onReceive(context: JContext; intent: JIntent); cdecl;
end;
TForm1 = class(TForm)
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
FMyListener: TMyReceiver;
FBroadcastReceiver: JFMXBroadcastReceiver;
ScanDevice: JScanDevice; { U8000S_ScanSDK.jar api device interface }
procedure managebarcodescan(barcode: string);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
Androidapi.Helpers,
Androidapi.JNI.JavaTypes;
{$R *.fmx}
function HexToString(H: String): String;
var
I: Integer;
begin
Result := '';
for I := 1 to length(H) div 2 do
Result := Result + Char(StrToInt('$' + Copy(H, (I - 1) * 2 + 1, 2)));
end;
constructor TMyReceiver.Create;
begin
inherited;
end;
procedure TMyReceiver.onReceive(context: JContext; intent: JIntent);
var
barocode: tjavaarray<System.byte>;
len: Integer;
buffer: string;
I: Integer;
begin
if JStringToString(intent.getAction) = 'scan.rcv.message' then
begin
len := intent.getIntExtra(StringToJString('length'), 0);
barocode := intent.getByteArrayExtra(StringToJString('barocode'));
for I := 0 to len - 1 do
begin
buffer := buffer + inttohex(barocode[I], 2);
end;
buffer := HexToString(buffer);
barocode.Free;
// do something with result
Form1.managebarcodescan(buffer);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Filter: JIntentFilter;
begin
FMyListener := TMyReceiver.Create;
FBroadcastReceiver := TJFMXBroadcastReceiver.JavaClass.init(FMyListener);
Filter := TJIntentFilter.JavaClass.init;
Filter.addAction(StringToJString('scan.rcv.message'));
TAndroidHelper.context.getApplicationContext.registerReceiver(FBroadcastReceiver, Filter);
ScanDevice := TJScanDevice.Create; {creating scanner interface}
ScanDevice.setScanCodeEnterKey;
ScanDevice.setOutScanMode(0); {setting scanner to broadcast mode }
ScanDevice.openScan;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
TAndroidHelper.context.getApplicationContext.unregisterReceiver(FBroadcastReceiver);
ScanDevice.stopScan;
ScanDevice._Release;
end;
procedure TForm1.managebarcodescan(barcode: string);
begin
Edit1.Text := barcode;
end;
end.