Я пытаюсь использовать java API в приложении Delphi для Android для доступа и управления сервисом сканирования устройств Android PDT.Некоторое время назад у меня уже была похожая проблема для другого устройства, но тогда это было намного проще и понятнее.Все функции и свойства представлены в части интерфейса.На этот раз все по-другому, и мои знания об использовании Java и интерфейсов слишком бедны, чтобы понять это.На этот раз все процедуры представлены в определении класса и ни одной в интерфейсной части, я не могу понять, как получить к ним доступ и использовать их.Я провел несколько дней в поисках подсказок и решений для подобных проблем и других устройств или API.Есть некоторые, но у всех были процедуры, уже представленные в интерфейсной части, или они должны были написать собственный класс Java, чтобы показать функциональность этого API на основе демонстрационного приложения Android Studio.
с другим устройством, для доступа к которому мне нужен был только этот кодсканер
var
ScanDevice: JScanDevice;
begin
ScanDevice := TJScanDevice.Create;
ScanDevice.setScanCodeEnterKey;
ScanDevice.setOutScanMode(0);
ScanDevice.openScan;
.......
с файлом моста, содержащим интерфейс:
type
JScanDevice = interface; { android/device/ScanDevice }
JScanDeviceClass = interface(JObjectClass)
['{58979737-4A26-4134-A604-C6FAB0D224CA}']
{ Methods }
function init: JScanDevice; cdecl;
function toHexString(s: JString): JString; cdecl;
end;
[JavaSignature('android/device/ScanDevice')]
JScanDevice = interface(JObject)
['{A11B33C8-394C-4180-9003-9C66326B4A2B}']
{ Methods }
function closeScan: Boolean; cdecl;
.......
function stopScan: Boolean; cdecl;
function openScan: Boolean; cdecl;
end;
TJScanDevice = class(TJavaGenericImport<JScanDeviceClass, JScanDevice>)
Но AUTOID6L отличается от файла моста следующим образом:
Jscanner_ScannerClass = interface(JObjectClass)
['{84F85EBE-57DD-48C5-B2AE-38D3A5E31355}']
{ class } procedure close; cdecl;
........
{ class } procedure stopScan; cdecl;
end;
[JavaSignature('com/seuic/scanner/Scanner')]
Jscanner_Scanner = interface(JObject)
['{692FF5AE-6C4B-4222-B858-DA029630F7A5}']
end;
TJscanner_Scanner = class(TJavaGenericImport<Jscanner_ScannerClass, Jscanner_Scanner>)
end;
Я незнать, как правильно использовать этот интерфейс и класс, не могу получить доступ к функциям класса.
Устройство PDT - это Seuic AUTOID6L, оно поставляется с универсальным SDK, используемым для нескольких их устройств.Для приложения для сканирования Android есть библиотека ScannerAPI.jar с файлами классов com \ seuic \ scannerScanner.class, com \ seuic \ ScannerFactory.class.
java2op.exe для сгенерированного файла моста:
unit SeuicScanner;
interface
uses
Androidapi.JNIBridge,
Androidapi.JNI.GraphicsContentViewText,
Androidapi.JNI.JavaTypes,
Androidapi.JNI.Os;
type
// ===== Forward declarations =====
JAccount = interface; // android.accounts.Account
Jscanner_BuildConfig = interface; // com.seuic.scanner.BuildConfig
JDecodeInfo = interface; // com.seuic.scanner.DecodeInfo
JDecodeInfoCallBack = interface; // com.seuic.scanner.DecodeInfoCallBack
Jscanner_Scanner = interface; // com.seuic.scanner.Scanner
JScannerFactory = interface; // com.seuic.scanner.ScannerFactory
JScannerKey = interface; // com.seuic.scanner.ScannerKey
JStatusCallBack = interface; // com.seuic.scanner.StatusCallBack
JVideoCallBack = interface; // com.seuic.scanner.VideoCallBack
// JStringBuffer = interface;//java.lang.StringBuffer
// JStringBuilder = interface;//java.lang.StringBuilder
// ===== Interface declarations =====
JAccountClass = interface(JObjectClass)
['{94EE6861-F326-489F-8919-E20B39E3D9C1}']
{ class } function _GetCREATOR: JParcelable_Creator; cdecl;
{ class } function _Getname: JString; cdecl;
{ class } function _Gettype: JString; cdecl;
{ class } function init(name: JString; type_: JString): JAccount; cdecl; overload; // Deprecated
{ class } function init(in_: JParcel): JAccount; cdecl; overload; // Deprecated
{ class } function describeContents: Integer; cdecl; // Deprecated
{ class } function equals(o: JObject): Boolean; cdecl; // Deprecated
{ class } property CREATOR: JParcelable_Creator read _GetCREATOR;
{ class } property name: JString read _Getname;
{ class } property &type: JString read _Gettype;
end;
[JavaSignature('android/accounts/Account')]
JAccount = interface(JObject)
['{71476381-8B6E-471F-9189-9857ECD7508C}']
function hashCode: Integer; cdecl; // Deprecated
function toString: JString; cdecl; // Deprecated
procedure writeToParcel(dest: JParcel; flags: Integer); cdecl; // Deprecated
end;
TJAccount = class(TJavaGenericImport<JAccountClass, JAccount>)
end;
Jscanner_BuildConfigClass = interface(JObjectClass)
['{6AD54B95-FC70-418E-AA52-5846F17E981F}']
{ class } function _GetAPPLICATION_ID: JString; cdecl;
{ class } function _GetBUILD_TYPE: JString; cdecl;
{ class } function _GetDEBUG: Boolean; cdecl;
{ class } function _GetFLAVOR: JString; cdecl;
{ class } function _GetVERSION_CODE: Integer; cdecl;
{ class } function _GetVERSION_NAME: JString; cdecl;
{ class } function init: Jscanner_BuildConfig; cdecl;
{ class } property APPLICATION_ID: JString read _GetAPPLICATION_ID;
{ class } property BUILD_TYPE: JString read _GetBUILD_TYPE;
{ class } property DEBUG: Boolean read _GetDEBUG;
{ class } property FLAVOR: JString read _GetFLAVOR;
{ class } property VERSION_CODE: Integer read _GetVERSION_CODE;
{ class } property VERSION_NAME: JString read _GetVERSION_NAME;
end;
[JavaSignature('com/seuic/scanner/BuildConfig')]
Jscanner_BuildConfig = interface(JObject)
['{1584DFE9-2B25-481A-8AF3-0E512A80A042}']
end;
TJscanner_BuildConfig = class(TJavaGenericImport<Jscanner_BuildConfigClass, Jscanner_BuildConfig>)
end;
JDecodeInfoClass = interface(JObjectClass)
['{D37439A1-F763-4798-8291-30E01196985A}']
{ class } function _Getbarcode: JString; cdecl;
{ class } function init: JDecodeInfo; cdecl;
{ class } property barcode: JString read _Getbarcode;
end;
[JavaSignature('com/seuic/scanner/DecodeInfo')]
JDecodeInfo = interface(JObject)
['{0169284C-55E4-45BF-B648-87471A0AB873}']
function _Getcodetype: JString; cdecl;
function _Getlength: Integer; cdecl;
property codetype: JString read _Getcodetype;
property length: Integer read _Getlength;
end;
TJDecodeInfo = class(TJavaGenericImport<JDecodeInfoClass, JDecodeInfo>)
end;
JDecodeInfoCallBackClass = interface(IJavaClass)
['{81EA2AA6-F12D-41D0-ADA4-61EEB0F3FB9D}']
{ class } procedure onDecodeComplete(P1: JDecodeInfo); cdecl;
end;
[JavaSignature('com/seuic/scanner/DecodeInfoCallBack')]
JDecodeInfoCallBack = interface(IJavaInstance)
['{CE9270B9-CD79-4FE7-8C29-7BFA9C2D8804}']
end;
TJDecodeInfoCallBack = class(TJavaGenericImport<JDecodeInfoCallBackClass, JDecodeInfoCallBack>)
end;
Jscanner_ScannerClass = interface(JObjectClass)
['{84F85EBE-57DD-48C5-B2AE-38D3A5E31355}']
{ class } procedure close; cdecl;
{ class } procedure disable; cdecl;
{ class } procedure enable; cdecl;
{ class } function getLastImage: TJavaArray<Byte>; cdecl;
{ class } function getParams(P1: Integer): Integer; cdecl;
{ class } function open: Boolean; cdecl;
{ class } procedure setDecodeInfoCallBack(P1: JDecodeInfoCallBack); cdecl;
{ class } function setParams(P1: Integer; P2: Integer): Boolean; cdecl;
{ class } procedure setStatusCallBack(P1: JStatusCallBack); cdecl;
{ class } procedure setVideoCallBack(P1: JVideoCallBack); cdecl;
{ class } procedure startScan; cdecl;
{ class } function startVideo(P1: Integer): Integer; cdecl;
{ class } procedure stopScan; cdecl;
{ class } procedure stopVideo; cdecl;
end;
[JavaSignature('com/seuic/scanner/Scanner')]
Jscanner_Scanner = interface(JObject)
['{692FF5AE-6C4B-4222-B858-DA029630F7A5}']
end;
TJscanner_Scanner = class(TJavaGenericImport<Jscanner_ScannerClass, Jscanner_Scanner>)
end;
JScannerFactoryClass = interface(JObjectClass)
['{00796D3B-F41D-4FC1-9F68-475CE7DB738E}'] { class }
function init: JScannerFactory; cdecl;
function getScanner(P1: JContext): Jscanner_Scanner; cdecl;
end;
[JavaSignature('com/seuic/scanner/ScannerFactory')]
JScannerFactory = interface(JObject)
['{77AE2625-EEFB-4EF2-838E-D8178AF6A9BD}']
end;
TJScannerFactory = class(TJavaGenericImport<JScannerFactoryClass, JScannerFactory>)
end;
JScannerKeyClass = interface(JObjectClass)
['{00D92230-CBC1-42EF-A1BA-7A84E4E70AB9}']
{ class } function _GetKEY_DOWN: Integer; cdecl;
{ class } function _GetKEY_UP: Integer; cdecl;
{ class } procedure close; cdecl;
{ class } function getKeyEvent: Integer; cdecl;
{ class } function init: JScannerKey; cdecl;
{ class } function open: Integer; cdecl;
{ class } property KEY_DOWN: Integer read _GetKEY_DOWN;
{ class } property KEY_UP: Integer read _GetKEY_UP;
end;
[JavaSignature('com/seuic/scanner/ScannerKey')]
JScannerKey = interface(JObject)
['{CE5ADF91-7ED1-46B5-B51D-694277A743AD}']
end;
TJScannerKey = class(TJavaGenericImport<JScannerKeyClass, JScannerKey>)
end;
JStatusCallBackClass = interface(IJavaClass)
['{58DA1A43-E11A-4F47-82FF-15DB0D65750E}']
{ class } procedure onStatusCallBack(P1: Integer; P2: Integer); cdecl;
end;
[JavaSignature('com/seuic/scanner/StatusCallBack')]
JStatusCallBack = interface(IJavaInstance)
['{75C0B88C-71DC-4645-A11D-76CFE299F28C}']
end;
TJStatusCallBack = class(TJavaGenericImport<JStatusCallBackClass, JStatusCallBack>)
end;
JVideoCallBackClass = interface(IJavaClass)
['{2C57576F-B3EC-4784-B190-C36924D62BAC}']
{ class } function onVideoCallBack(P1: Integer; P2: Integer; P3: TJavaArray<Byte>): Boolean; cdecl;
end;
[JavaSignature('com/seuic/scanner/VideoCallBack')]
JVideoCallBack = interface(IJavaInstance)
['{A8CB0355-4451-4FCD-B6D6-9E718CA500D0}']
end;
TJVideoCallBack = class(TJavaGenericImport<JVideoCallBackClass, JVideoCallBack>)
end;
// java.lang.StringBuffer
// java.lang.StringBuilder
implementation
procedure RegisterTypes;
begin
TRegTypes.RegisterType('Android.JNI.SeuicScanner.JAccount', TypeInfo(SeuicScanner.JAccount));
TRegTypes.RegisterType('Android.JNI.SeuicScanner.Jscanner_BuildConfig', TypeInfo(SeuicScanner.Jscanner_BuildConfig));
TRegTypes.RegisterType('Android.JNI.SeuicScanner.JDecodeInfo', TypeInfo(SeuicScanner.JDecodeInfo));
TRegTypes.RegisterType('Android.JNI.SeuicScanner.JDecodeInfoCallBack', TypeInfo(SeuicScanner.JDecodeInfoCallBack));
TRegTypes.RegisterType('Android.JNI.SeuicScanner.Jscanner_Scanner', TypeInfo(SeuicScanner.Jscanner_Scanner));
TRegTypes.RegisterType('Android.JNI.SeuicScanner.JScannerFactory', TypeInfo(SeuicScanner.JScannerFactory));
TRegTypes.RegisterType('Android.JNI.SeuicScanner.JScannerKey', TypeInfo(SeuicScanner.JScannerKey));
TRegTypes.RegisterType('Android.JNI.SeuicScanner.JStatusCallBack', TypeInfo(SeuicScanner.JStatusCallBack));
TRegTypes.RegisterType('Android.JNI.SeuicScanner.JVideoCallBack', TypeInfo(SeuicScanner.JVideoCallBack));
// TRegTypes.RegisterType('Android.JNI.SeuicScanner.JStringBuffer', TypeInfo(Android.JNI.SeuicScanner.JStringBuffer));
// TRegTypes.RegisterType('Android.JNI.SeuicScanner.JStringBuilder', TypeInfo(Android.JNI.SeuicScanner.JStringBuilder));
end;
initialization
RegisterTypes;
end.
Я успешно попытался запустить демонстрационное приложение, предоставленное в SDK для Android Studio.
Сценарий обслуживания:
package com.seuic.scannerapitest.service;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import com.seuic.scanner.DecodeInfo;
import com.seuic.scanner.DecodeInfoCallBack;
import com.seuic.scanner.Scanner;
import com.seuic.scanner.ScannerFactory;
import com.seuic.scanner.ScannerKey;
import com.seuic.scanner.VideoCallBack;
import com.seuic.scannerapitest.activity.MainActivity;
@SuppressWarnings("unused")
public class ScannerService extends Service implements DecodeInfoCallBack,VideoCallBack {
static final String TAG = "ScannerApiTest";
Scanner scanner;
private static MainActivity mcontext = null;
private boolean mScanRunning = false;
private void log(String string){
Log.i(TAG, string);
}
public static void MyService(Context context){
mcontext = (MainActivity)context;
}
@Override
public void onCreate() {
super.onCreate();
scanner = ScannerFactory.getScanner(this);
scanner.open();
scanner.setDecodeInfoCallBack(this);
scanner.setVideoCallBack(this);
scanner.enable();
mScanRunning = true;
new Thread(runnable).start();
};
Runnable runnable = new Runnable() {
@Override
public void run() {
int ret1 = ScannerKey.open();
if (ret1 > -1) {
while (mScanRunning) {
int ret = ScannerKey.getKeyEvent();
if (ret > -1) {
switch (ret) {
case ScannerKey.KEY_DOWN:
if (scanner != null && mScanRunning) {
scanner.startScan();
}
break;
case ScannerKey.KEY_UP:
if (scanner != null && mScanRunning) {
scanner.stopScan();
}
break;
}
}
}
}
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return Service.START_STICKY;
};
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
mScanRunning = false;
ScannerKey.close();
scanner.setDecodeInfoCallBack(null);
scanner.setVideoCallBack(null);
scanner.close();
scanner = null;
super.onDestroy();
}
public static final String BAR_CODE = "barcode";
public static final String CODE_TYPE = "codetype";
public static final String LENGTH = "length";
// this is a custom broadcast receiver action
public static final String ACTION = "seuic.android.scanner.scannertestreciever";
@Override
public void onDecodeComplete(DecodeInfo info) {
Intent intent = new Intent(ACTION);
Bundle bundle = new Bundle();
bundle.putString(BAR_CODE, info.barcode);
bundle.putString(CODE_TYPE, info.codetype);
bundle.putInt(LENGTH, info.length);
intent.putExtras(bundle);
sendBroadcast(intent);
}
@Override
public boolean onVideoCallBack(int width, int height, byte[] img) {
if (img == null||width == 0||height == 0||img.length == 0){
return false;
}
log("onVideCallBack E");
Message video_msg = mcontext.mHandler.obtainMessage(img.length, width, height, img);
mcontext.mHandler.sendMessage(video_msg);
try {
Thread.sleep(80);
} catch (InterruptedException e) {
e.printStackTrace();
}
log("onVideCallBack X");
return false;
}
}
mainactivity:
package scannertest.test2;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import com.seuic.scanner.Scanner;
import com.seuic.scanner.ScannerFactory;
public class MainActivity extends AppCompatActivity {
public static final String TAG;
static final int SCANNER_KEYCODE;
static {
TAG = "ScannerApiTest";
SCANNER_KEYCODE = 142;
}
Scanner scanner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Intent intent = new Intent(this, ScannerService. class);
// startService(intent);
scanner = ScannerFactory.getScanner(this);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
void init() {
scanner = ScannerFactory.getScanner(this);
if (scanner == null){
log("scanner(NULL)");
}
}
private void log(String string){
Log.i(TAG, string);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Редактировать:
scanner = TJScannerFactory.JavaClass.getScanner(TAndroidHelper.Context)
вызывает исключение, стек вызовов:
System._DbgExcNotify(-506670960,0xe0015d30,0xe20e463d,0xe0015d30,0xe20e463d)
System.NotifyReRaise(0xe0015d30,0xe20e463d)
System._RaiseAtExcept(0xe0015d30,0xe20e463d)
System._RaiseExcept(0xe0015d30)
System.Internal.Excutils.DoRaiseJNIExceptionCallBack('class java.lang.RuntimeException','java.lang.RuntimeException: Stub!')
Androidapi.Jni.HandleJNIException(0xef826b20)
Androidapi.Jnimarshal.ExecJNI(0xe1ccd540,0xe13fa138)
:E27BFA70 DispatchToImport
:E27CBE5C dispatch_first_stage_intercept
Unit1.TForm1.Button1Click(0xef89d800,0xef8b4a00)
Fmx.Controls.TControl.Click(0xef8b4a00)
Fmx.Stdctrls.TCustomButton.Click(0xef8b4a00)
Fmx.Controls.TControl.MouseClick(0xef8b4a00,System.Uitypes.mbLeft,0x430a0088,66.3783722,5.73217773)
:E25182D2 __stub_in864v88__ZN3Fmx8Controls8TControl10MouseClickEN6System7Uitypes12TMouseButtonENS2_3SetINS2_7Classes17System_Classes__1ELS7_0ELS7_10EEEff
Fmx.Forms.TCommonCustomForm.MouseUp(0xef89d800,System.Uitypes.mbLeft,0xe1cc0088,138.378372,359.732178,true)
Fmx.Platform.Android.TWindowManager.MouseUp(0xe1698a20,System.Uitypes.mbLeft,0x88,138.378372,384.732178,true)
Fmx.Platform.Android.TPlatformAndroid.ProcessAndroidMouseEvents(0xefa59740)
Fmx.Platform.Android.TPlatformAndroid.HandleAndroidMotionEvent(0xefa59740,0xf4a48d00)
Fmx.Platform.Android.TPlatformAndroid.HandleAndroidInputEvent(0xefa59740,0xf4a48d00)
Fmx.Platform.Android.HandleAndroidInputEvent(@0xf4acbec0: {userData = nil, onAppCmd = 0xe264cf69 <Fmx.Platform.Android.HandleAndroidCmd(Androidapi.Appglue.TAndroid_app&, int)>, onInputEvent = 0xe264cf31 <Fmx.Platform.Android.HandleAndroidInputEvent(Androidapi.Appglue.TAndroid_app&, AInputEvent*)>, activity = 0xf4acb4c0, config = 0xef82f550, savedState = nil, savedStateSize = 0, looper = 0xef82e2e0, inputQueue = 0xf4ae6200, window = 0xf49a8e08, contentRect = {left = 0, top = -496709783, right = -496709839, bottom = -190008128}, activityState = 11, destroyRequested = 0, mutex = {value = 0}, cond = {value = 0}, msgread = 29, msgwrite = 30, thread = 0, cmdPollSource = {id = 0, app = 0xe264cf69, process = 0xe264cf31 <Fmx.Platform.Android.HandleAndroidInputEvent(Androidapi.Appglue.TAndroid_app&, AInputEvent*)>}, inputPollSource = {id = 0, app = 0xe264cf69, process = 0xe264cf31 <Fmx.Platform.Android.HandleAndroidInputEvent(Androidapi.Appglue.TAndroid_app&, AInputEvent*)>}, running = 1, stateSaved = 0, destroyed = 0, redrawNeeded = 0, pendingInputQueue = 0xf4ae6200, pendingWindow = 0xf49a8e08, pendingContentRect = {left = 0, top = -496709783, right = -496709839, bottom = -190008128}},0xf4a48d00)
Androidapi.Appglue.process_input(0xf4acbec0,0xf4acbf20)
Fmx.Platform.Android.TPlatformAndroid.InternalProcessMessages(0xefa59740)
Fmx.Platform.Android.TPlatformAndroid.Run(0xefa59740)
:E2637FF2 __stub_in272s__ZN3Fmx8Platform7Android16TPlatformAndroid3RunEv
Fmx.Forms.TApplication.Run(0xefac7940)
_NativeMain
Androidapi.Appglue.android_app_entry(void*).SystemEntry(void*)(@0x0: {})
Androidapi.Appglue.android_app_entry(0xf4acbec0)
:F71950C4 __pthread_start(void*)
:F71930B0 __start_thread
:00000000 ??