现在微信、淘宝在各自的终端平台上都推出了扫一扫的功能,一维码、二维码的图像识别技术技术得到了迅猛的推广,在我们日常生活中,这种技术也早已经渗透到方方面面,google的zxing 就是一个不错的条码图像识别库,delphi xe5推出后,你也想将这项技术应用到实际的工作中吗?希望这篇文章能够帮助到你;
1. 使用delphi 建立FireMonkey Mobile Application 选择空工程,命名为BarCodeScan ,保存后放着;
2. 下载并安装zxing到你的手机上
https://play.google.com/store/apps/details?id=com.google.zxing.client.android
3. 下载dex2jar
https://code.google.com/p/dex2jar/
将dex2jar解压,将delphi firemonkey原始的classes.dex文件拷贝到解压后的目录中(我的原始classes.dex 路径在D:ProgramFilesEmbarcaderoRADStudio12.0libandroiddebugclasses.dex,大家按照自己的路径找找把)
4. 检查下jdk配置,建议使用jdk1.6
5. 使用命令行工具进入dex2jar 解压后的目录,运行以下命令
l 将dex还原成jar包: d2j-dex2jar.bat classes.dex
l 释放到文件目录: jar xf classes-dex2jar.jarcom/embarcadero/firemonkey
l 重新打包: jar cf embarcadero.jar com
现在在当前目录下存在embarcadero.jar 这个jar包了,将此jar包拷贝到 DelphiBarCodeScan工程目录中;
6. 打开eclipse建立android application project项目,引用embarcadero.jar
新建java类NativeActivityExt,继承com.embarcadero.firemonkey.FMXNativeActivity,在这个类中将提供delphi能够使用的jni本地调用。
代码如下:
package com.cikk.barcode;
import android.content.Intent;
import com.embarcadero.firemonkey.FMXNativeActivity;
public class NativeActivityExt extendsFMXNativeActivity {
//供 xe5 for android 获取返回值使用
public native booleanonActivityResultNative(int requestCode, intresultCode, Intent data);
@Override
protected void onActivityResult(intrequestCode, int resultCode, Intent data) {
if (!onActivityResultNative(requestCode, resultCode,data))
super.onActivityResult(requestCode, resultCode,data);
}
}
保存下,将src目录下的所有文件拷贝到Delphi BarCodeScan工程目录中,见步骤5附图;
7. 编写Build.bat 批处理文件,内容如下
@echo off
setlocal
set ANDROID_PLATFORM="%ANDROID%platforms
android-10"
setDX_LIB="%ANDROID%build-tools19.0.0lib"
set PROJ_DIR="?%"
set EMBO_DEX="D:ProgramFilesEmbarcaderoRAD
Studio12.0libandroiddebugclasses.dex"
set VERBOSE=0
mkdir outputclasses 2> nul
mkdir outputjar 2> nul
mkdir outputdex 2> nul
echo.
echo 编译 NativeActivityExt.java 源文件
echo.
SET VERBOSE_FLAG=-verbose
javac %VERBOSE_FLAG% -Xlint:deprecation -cp
%ANDROID_PLATFORM%android.jar;embarcadero.jar -d
outputclasses srccomcikkbarcode
NativeActivityExt.java
echo.
echo 创建jar包
echo.
SET VERBOSE_FLAG=v
jar c%VERBOSE_FLAG%f outputjarnew_classes.jar
-C outputclasses com
echo.
echo 转换为dex格式
echo.
SET VERBOSE_FLAG=--verbose
call dx --dex %VERBOSE_FLAG% --output=%PROJ_DIR%
outputdexnew_classes.dex --positions=lines
%PROJ_DIR%outputjarnew_classes.jar
echo.
echo 合并dex 文件
echo.
java -cp %DX_LIB%dx.jar
com.android.dx.merge.DexMerger %PROJ_DIR%output
dexclasses.dex %PROJ_DIR%outputdex
new_classes.dex %EMBO_DEX%
echo 删除临时文件
echo.
del outputdexnew_classes.dex
del outputjarnew_classes.jar
rmdir outputjar
:Exit
Endlocal
确保build.bat 中各变量设置是否正确,如何设置可以参考我的另一篇文章《Delphi XE5 for Android启动无黑屏等待总结》
8. 运行Build.bat,成功后在outputdex 中可以获得我们需要的classes.dex文件(我尝试使用eclipse直接编译来获取classes.dex文件,但delphi调用失败)
9. 回到Delphi XE5,我们将SplashScreen 工程Build一次,然后点击Project->Deployment 进入发布管理模块
确保缺省的classes.dex未被选中,点击Add Files选择通过build生成的classes.dex,添加成功后选中新增项,点击Change RemotePath,更改发布后的路径
保存;
打开AndroidManifest.template.xml,做相应修改
调整activity配置
<activityandroid:name="com.embarcadero.firemonkey.FMXNativeActivity"
android:label="?tivityLabel%"
android:configChanges="orientation|keyboardHidden">
<meta-dataandroid:name="android.app.lib_name"
android:value="%libNameValue%"/>
<intent-filter>
<actionandroid:name="android.intent.action.MAIN"/>
<categoryandroid:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
为
<activityandroid:name="com.cikk.barcode.NativeActivityExt"
android:label="?tivityLabel%"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="portrait">
<!-- Tell NativeActivity the name of our .so-->
<meta-dataandroid:name="android.app.lib_name"
android:value="%libNameValue%"/>
<intent-filter>
<actionandroid:name="android.intent.action.MAIN"/>
<categoryandroid:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
保存;
新建FireMonkey mobile form ,设置下界面
F12编写调用zxing的代码
unit frmMain;
interface
uses
System.SysUtils,
System.Types,
System.UITypes,
System.Classes,
System.Variants,
FMX.Types,
FMX.Controls,
FMX.Forms,
FMX.Graphics,
FMX.Dialogs,
FMX.Edit,
FMX.StdCtrls,
Androidapi.JNI.GraphicsContentViewText;
type
TMainForm = class(TForm)
Label1: TLabel;
Button1: TButton;
edtScanFormat: TEdit;
edtScanCode: TEdit;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
const ScanRequestCode = 0;
procedure RegisterDelphiNativeMeth
function OnActivityResult(RequestCode, ResultCode: Integer;Data: JIntent): Boolean;
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
uses Posix.pthread,
Androidapi.JNI.JavaTypes,FMX.Helpers.Android,
Androidapi.JNI,
Androidapi.JNI.App,
Androidapi.JNIBridge,
Androidapi.NativeActivity;
var
ARNRequestCode, ARNResultCode: Integer;
ARNData: JIntent;
ARNResult: Boolean;
{$R *.fmx}
procedure OnActivityResultThreadSw
begin
ARNResult := MainForm.OnActivityResult(ARNRequestCode,ARNResultCode, ARNData);
end;
function OnActivityResultNative(PEnv: PJNIEnv; This:JNIObject;
RequestCode, ResultCode: Integer; dataIntent: JNIObject):Boolean; cdecl;
begin
ARNRequestCode := requestCode;
ARNResultCode := resultCode;
ARNData := nil;
if Assigned(DataIntent) then
ARNData := TJIntent.Wrap(DataIntent);
TThread.Synchronize(nil, OnActivityResultThreadSw
Result := ARNResult;
end;
procedure TMainForm.Button1Click(Sender: TObject);
var
Intent: JIntent;
ResolveInfo: JResolveInfo;
begin
Intent :=TJIntent.JavaClass.init(StringToJString('com.google.zxing.client.android.SCAN'));
Intent.setPackage(StringToJString('com.google.zxing.client.android'));
ResolveInfo :=SharedActivity.getPackageManager.resolveActivity(Intent, 0);
SharedActivity.startActivityForResult(Intent, 0);
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
RegisterDelphiNativeMeth
end;
function TMainForm.OnActivityResult(RequestCode, ResultCode:Integer;
Data: JIntent): Boolean;
var
ScanContent,
ScanFormat: string;
begin
Result := False;
if RequestCode = ScanRequestCode then
begin
if ResultCode = TJActivity.JavaClass.RESULT_OK then
begin
if Assigned(Data) then
begin
ScanContent :=JStringToString(Data.getStringExtra(StringToJString('SCAN_RESULT')));
ScanFormat :=JStringToString(Data.getStringExtra(StringToJString('SCAN_RESULT_FORMAT')));
Self.edtScanFormat.Text := ScanFormat;
Self.edtScanCode.Text := ScanContent;
Result := True;
end;
end;
end;
end;
procedure TMainForm.RegisterDelphiNativeMeth
var
PEnv: PJNIEnv;
ActivityClass: JNIClass;
NativeMethods: array[0..1] of JNINativeMethod;
begin
PEnv := TJNIResolver.GetJNIEnv;
NativeMethods[0].Name := 'onActivityResultNative';
NativeMethods[0].Signature :='(IILandroid/content/Intent;)Z';
NativeMethods[0].FnPtr := @OnActivityResultNative;
ActivityClass := PEnv^.GetObjectClass(
PEnv, PANativeActivity(System.DelphiActivity).clazz);
PEnv^.RegisterNatives(PEnv, ActivityClass, @NativeMethods[0],1);
PEnv^.DeleteLocalRef(PEnv, ActivityClass);
end;
end.
保存,调试运行把,是不是可以正常扫描及成功返回结果值了;
联系客服