http://blog.sina.com.cn/s/blog_5f8861b60101hx1b.html

[转载]delphi for android 条码扫描初步解决方案

  (2014-02-22 20:55:41)
标签: 

转载

分类: 软件设计

现在微信、淘宝在各自的终端平台上都推出了扫一扫的功能,一维码、二维码的图像识别技术技术得到了迅猛的推广,在我们日常生活中,这种技术也早已经渗透到方方面面,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:Program FilesEmbarcaderoRAD Studio12.0libandroiddebugclasses.dex,大家按照自己的路径找找把)

4. 检查下jdk配置,建议使用jdk1.6

clip_image002

clip_image004

5. 使用命令行工具进入dex2jar 解压后的目录,运行以下命令

l 将dex还原成jar包: d2j-dex2jar.bat classes.dex

l 释放到文件目录: jar xf classes-dex2jar.jar com/embarcadero/firemonkey

l 重新打包: jar cf embarcadero.jar com

clip_image006

现在在当前目录下存在embarcadero.jar 这个jar包了,将此jar包拷贝到 Delphi BarCodeScan工程目录中;

clip_image008

6. 打开eclipse建立android application project 项目,引用embarcadero.jar

clip_image010

新建java类NativeActivityExt,继承com.embarcadero.firemonkey.FMXNativeActivity,在这个类中将提供delphi能够使用的jni 本地调用。

代码如下:

package com.cikk.barcode;

import android.content.Intent;

import com.embarcadero.firemonkey.FMXNativeActivity;

public class NativeActivityExt extends FMXNativeActivity {

//供 xe5 for android 获取返回值使用

public native boolean onActivityResultNative(int requestCode, int resultCode, Intent data);

@Override

protected void onActivityResult(int requestCode, 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"

set DX_LIB="%ANDROID%build-tools19.0.0lib"

set PROJ_DIR="�%"

set EMBO_DEX="D:Program FilesEmbarcaderoRAD

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 进入发布管理模块

clip_image012

确保缺省的classes.dex未被选中,点击Add Files 选择通过build生成的classes.dex,添加成功后选中新增项,点击Change Remote Path,更改发布后的路径

clip_image014

保存;

打开AndroidManifest.template.xml,做相应修改

调整activity配置

<activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"

android:label="�tivityLabel%"

android:configChanges="orientation|keyboardHidden">

<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>

</activity>

<activity android:name="com.cikk.barcode.NativeActivityExt"

android:label="�tivityLabel%"

android:configChanges="orientation|keyboardHidden"

android:screenOrientation="portrait">

<!-- 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>

</activity>

保存;

新建FireMonkey mobile form ,设置下界面

clip_image016

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 RegisterDelphiNativeMethods;

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 OnActivityResultThreadSwitcher;

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, OnActivityResultThreadSwitcher);

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

RegisterDelphiNativeMethods;

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.RegisterDelphiNativeMethods;

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.

保存,调试运行把,是不是可以正常扫描及成功返回结果值了;