現(xiàn)在微信、淘寶在各自的終端平臺(tái)上都推出了掃一掃的功能,一維碼、二維碼的圖像識(shí)別技術(shù)技術(shù)得到了迅猛的推廣,在我們?nèi)粘I钪?,這種技術(shù)也早已經(jīng)滲透到方方面面,google 的zxing 就是一個(gè)不錯(cuò)的條碼圖像識(shí)別庫(kù),delphi xe5 推出后,你也想將這項(xiàng)技術(shù)應(yīng)用到實(shí)際的工作中嗎?希望這篇文章能夠幫助到你; 1. 使用delphi 建立FireMonkey Mobile Application 選擇空工程,命名為 BarCodeScan ,保存后放著; 2. 下載并安裝zxing到你的手機(jī)上 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 5. 使用命令行工具進(jìn)入dex2jar 解壓后的目錄,運(yùn)行以下命令 l 將dex還原成jar包: d2j-dex2jar.bat classes.dex l 釋放到文件目錄: jar xf classes-dex2jar.jar com/embarcadero/firemonkey l 重新打包: jar cf embarcadero.jar com 現(xiàn)在在當(dāng)前目錄下存在embarcadero.jar 這個(gè)jar包了,將此jar包拷貝到 Delphi BarCodeScan工程目錄中; 6. 打開(kāi)eclipse建立android application project 項(xiàng)目,引用embarcadero.jar 新建java類NativeActivityExt,繼承com.embarcadero.firemonkey.FMXNativeActivity,在這個(gè)類中將提供delphi能夠使用的jni 本地調(diào)用。 代碼如下: 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工程目錄中,見(jiàn)步驟5附圖; 7. 編寫(xiě)B(tài)uild.bat 批處理文件,內(nèi)容如下 @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 創(chuàng)建jar包 echo. SET VERBOSE_FLAG=v jar c%VERBOSE_FLAG%f outputjarnew_classes.jar -C outputclasses com echo. echo 轉(zhuǎn)換為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 刪除臨時(shí)文件 echo. del outputdexnew_classes.dex del outputjarnew_classes.jar rmdir outputjar :Exit Endlocal 確保build.bat 中各變量設(shè)置是否正確,如何設(shè)置可以參考我的另一篇文章《Delphi XE5 for Android 啟動(dòng)無(wú)黑屏等待總結(jié)》 8. 運(yùn)行Build.bat,成功后在outputdex 中可以獲得我們需要的 classes.dex文件(我嘗試使用eclipse直接編譯來(lái)獲取classes.dex文件,但delphi調(diào)用失?。?/p> 9. 回到Delphi XE5,我們將SplashScreen 工程Build一次,然后點(diǎn)擊Project ->Deployment 進(jìn)入發(fā)布管理模塊 確保缺省的classes.dex未被選中,點(diǎn)擊Add Files 選擇通過(guò)build生成的classes.dex,添加成功后選中新增項(xiàng),點(diǎn)擊Change Remote Path,更改發(fā)布后的路徑 保存; 打開(kāi)AndroidManifest.template.xml,做相應(yīng)修改 調(diào)整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 ,設(shè)置下界面 F12編寫(xiě)調(diào)用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. 保存,調(diào)試運(yùn)行把,是不是可以正常掃描及成功返回結(jié)果值了; |
|