
相關資料:
第三方資料太大沒法寫在博文上,請下載CSDN的程序包。
程序包下載:
http://download.csdn.net/detail/zhujianqiangqq/9657186
注意事項:
如果只加了Lib,然沒有改AndroidManifest.xml,App在呼叫BarCode時會ANR沒反應。
開始可能沒有官方的classes.dex,但如果發現編譯出錯后,請再檢查一下。
TMessageManager須加System.Messaging單元。
使用DelphiXE7加入JavaLibrary后,呼叫Zxing相機
1.新建一個DelphiXE工程,雙擊"Android-Android ADK 25.1.7.32bit"。
2.依照Zxing會用到的Android權限,在 project->options->uses permission 加上權限。
Access wifi state//訪問WIFI狀態
Camera//相機
Change wifi state//更改WIFI狀態
Flashlight//手電筒
Internet//互聯網
Read contacts//讀聯系人
Read history bookmarks//讀歷史書簽
Vibrate//顫動
Write extrnal storage//寫外置儲存
3.把解好的Jar檔案放到項目目錄下
如:"CreateActivity.jar"放到"C:\Users\zhujq-a\Desktop\Android實例之實現掃描二維碼並生成二維碼\"目錄下。
4.引入Jar包。
在"Project1"->"Android-Android SDK 25.1.7.32bit"->Libraries->右擊->"Add"->選中"C:\Users\zhujq-a\Desktop\Android實例之實現掃描二維碼並生成二維碼\CreateActivity.jar"->打開。
5.在"Project1"->"Compile"編譯一次,產生 AndroidManifest.template.xml ,但不要Run手機的App。
6.修改AndroidManifest.template.xml,加入CaptureActivity的區段。
位置在"<activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"下面。
代碼如下:
<activity android:name="com.google.zxing.client.android.CaptureActivity"
android:screenOrientation="portrait"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:configChanges="orientation|keyboardHidden"
android:theme="@style/CaptureTheme"
android:windowSoftInputMode="stateAlwaysHidden">
</activity>
7.這個時候編譯會出現下面錯誤訊息,表示找不到Android的資源。
[PAClient Error] Error: E2312 C:\Users\zhujq-a\Desktop\Android實例之實現掃描二維碼並生成二維碼\Android\Debug\Project1\AndroidManifest.xml:53: error: Error: No resource found that matches the given name (at 'theme' with value
8.接下來要合並 Android 和 Embarcadero 的數據文件
1>.把 Android 的資源復制到項目目錄
PS:這個地方說明一下:注意是編譯后的CaptureActivity\res文件夾(這里說的JAVA中的,但不是DLEPHI中的)
把"CaptureActivity\res"中的文件復制到"C:\Users\zhujq-a\Desktop\Android實例之實現掃描二維碼並生成二維碼\"中。
2>.打包這些資源文件
Project->Deployment->把drawable, layout, menu, raw, values 和 xml 目錄下的所有檔案加入->修改"Remote Path"為"Local Path"(如:"res\drawable\"的"Remote Path"為".\"改為"res\drawable\")。
9.接下來因為Zxing和 Embarcadero 都有相同的檔案 res\values\styles.xml,所以要取消其中一個,並手工把兩個檔案的內容合並。
1>.取消官方的Styles.xml
Project->Deployment->Styles.xml去掉對號。
2>.取消官方的classes.dex(20161018親測,去掉閃退,不去掉正好)
Project->Deployment->classes.dex去掉對號。
PS:這個地方說明一下:開始可能沒有官方的classes.dex,但如果發現編譯出錯后,請再檢查一下。
3>.把 (項目目錄)\Android\Debug\styles.xml 和 (項目目錄)\res\values\styles.xml 內容合並后如下
打開notepad,打開文件"C:\Users\zhujq-a\Desktop\Android實例之實現掃描二維碼並生成二維碼\Android\Debug\styles.xml",復制如下內容:
<style name="AppTheme" parent="@android:style/Theme.NoTitleBar">
<item name="android:windowBackground">@drawable/splash_image_def</item>
<item name="android:windowNoTitle">true</item>
</style>
打開notepad,打開文件"C:\Users\zhujq-a\Desktop\Android實例之實現掃描二維碼並生成二維碼\res\values\styles.xml",粘入復制的內容。位置是在 "<style>"的最后面。
合並結束后,將"C:\Users\zhujq-a\Desktop\Android實例之實現掃描二維碼並生成二維碼\res\values\styles.xml"整個文件復制到"C:\Users\zhujq-a\Desktop\Android實例之實現掃描二維碼並生成二維碼\Android\Debug\"中。
10.增加工程代碼(看博文)
生成二維碼功能
1.將"xZXIngQRCode.pas"文件放入"C:\Users\zhujq-a\Desktop\Android實例之實現掃描二維碼並生成二維碼\"工程代碼目錄下面。
2.在文件管理器中,選中"project1"->Add->選中xZXIngQRCode.pas->打開。
3.工程單元中引入"xZXIngQRCode"單元。
4.窗體中寫入生成二維碼的代碼(看博文)。
關於橫豎屏的問題
但是android提供的SDK(android.hardware.Camera)里大概不能正常的使用豎屏(portrait layout)加載照相機,當用豎屏模式加載照相機時會產生以下情況:1. 照相機成像左傾90度(傾斜);2. 照相機成像長寬比例不對(失比)。
基本上解決辦法如下:
1、在AndroidManifest.xml里面配置一下 ,使CaptureActivity屬性為portrait: android:screenOrientation="portrait"
2、如果只是單純的想改變照相機成像的方向,只需要在包com.google.zxing.client.android.camera下的 CameraConfigurationManager類中增加方法
protected void setDisplayOrientation(Camera camera, int angle) {
Method downPolymorphic;
try {
downPolymorphic = camera.getClass().getMethod(
"setDisplayOrientation", new Class[] { int.class });
if (downPolymorphic != null)
downPolymorphic.invoke(camera, new Object[] { angle });
} catch (Exception e1) {
}
}
然后在方法void setDesiredCameraParameters(Camera camera){}中調用,
setDisplayOrientation(camera, 90);
具體位置在camera.setParameters(parameters);語句前面。
2014-10-15
樓主上面增加過程的方法在我的(ZXing2.3)CameraConfigurationManager中出錯。
實際只需setDisplayOrientation(camera, 90);修改成camera.setDisplayOrientation(90);
3、改變完方向你會發現方向改變了可是分辨率會變得很低,接下來就是優化了
(1)首先在類CameraManager.java中
把 rect.left = rect.left * cameraResolution.x / screenResolution.x;
rect.right = rect.right * cameraResolution.x / screenResolution.x;
rect.top = rect.top * cameraResolution.y / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
替換成
rect.left = rect.left * cameraResolution.y / screenResolution.x;
rect.right = rect.right * cameraResolution.y / screenResolution.x;
rect.top = rect.top * cameraResolution.x / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
(2)然后是在DecodeHandler類中的方法private void decode(byte[] data,int width,int height){}
中添加byte[] rotatedData = new byte[data.length];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++)
rotatedData[x * height + height - y - 1] = data[x + y * width];
*具體內容可見附件
(3)再就是CameraConfigurationManager類中的方法void initFromCameraParameters(Camera camera){}中添加如下代碼:
Point screenResolutionForCamera = new Point();
screenResolutionForCamera.x = screenResolution.x;
screenResolutionForCamera.y = screenResolution.y;
// preview size is always something like 480*320, other 320*480
if (screenResolution.x < screenResolution.y) {
screenResolutionForCamera.x = screenResolution.y;
screenResolutionForCamera.y = screenResolution.x;
注: 到這就完成了。如果還有問題,只需下載附件直接替換相應文件即可; (直接替換很可能不行)
還有一個最后存在的問題,在 下編譯掃描窗口正常(豎屏),但打包后在DELPHI XE7下,掃描時提示是英文(標題是中文),不知為何?
以上修改之處,是本人環境下完成。
感謝[台北]Q面(2609815930)、[龜山]阿卍(1467948783) 、[北京]老貓(1765535979),還有許多不知名的作者。
實例代碼:
1 unit Unit1; 2 3 interface 4 5 uses 6 System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 7 FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, 8 FMX.Edit, FMX.Controls.Presentation, 9 System.Messaging,//需要引入 10 System.Rtti,//需要引入 11 System.Actions,//需要引入 12 Androidapi.JNI.Net,//需要引入 13 Androidapi.JNI.GraphicsContentViewText,//需要引入 14 Androidapi.JNI.JavaTypes,//需要引入 15 Androidapi.Helpers,//需要引入 16 Androidapi.JNI.App,//需要引入 17 FMX.Objects,//需要引入 18 FMX.ActnList,//需要引入 19 FMX.StdActns,//需要引入 20 FMX.Platform.Android,//需要引入 21 FMX.MediaLibrary.Actions,//需要引入 22 xZXIngQRCode;//需要引入 23 24 type 25 TForm1 = class(TForm) 26 Button1: TButton; 27 Button2: TButton; 28 Edit1: TEdit; 29 Edit2: TEdit; 30 Label1: TLabel; 31 Label2: TLabel; 32 Label3: TLabel; 33 Image1: TImage; 34 Panel1: TPanel; 35 Label4: TLabel; 36 Edit3: TEdit; 37 Label5: TLabel; 38 procedure Button1Click(Sender: TObject); 39 procedure FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; 40 Shift: TShiftState); 41 procedure Button2Click(Sender: TObject); 42 private 43 { Private declarations } 44 //掃描請求代碼 45 const ScanRequestCode = 0; 46 // 47 var FMessageSubscriptionID: Integer; 48 //活動結果事件 49 function OnActivityResult(RequestCode, ResultCode: Integer; Data: JIntent): Boolean; 50 //活動消息處理 51 procedure HandleActivityMessage(const Sender: TObject; const M: TMessage); 52 public 53 { Public declarations } 54 //掃描狀態 55 ScanState: Boolean;//TRUE代表掃描中,FALSE掃描結束 56 end; 57 58 var 59 Form1: TForm1; 60 61 implementation 62 63 {$R *.fmx} 64 {$R *.LgXhdpiPh.fmx ANDROID} 65 66 //啟用掃碼 67 procedure LaunchQRScanner(RequestCode: Integer); 68 var 69 Intent: JIntent; 70 begin 71 Intent := TJIntent.JavaClass.init; 72 Intent.setClassName(SharedActivityContext, StringToJString('com.google.zxing.client.android.CaptureActivity')); 73 //如果要預定掃描格式,UnComment 下面文字 74 //Intent.putExtra(StringToJString('SCAN_MODE'), StringToJString('QR_CODE_MODE')); 75 SharedActivity.startActivityForResult(Intent, RequestCode); 76 end; 77 78 //調用掃碼方法 79 procedure TForm1.Button1Click(Sender: TObject); 80 var 81 LIntent: JIntent; 82 begin 83 //LIntent := TJIntent.JavaClass.init; 84 //LIntent.setClassName(SharedActivityContext, StringToJString('com.google.zxing.client.android.CaptureActivity')); 85 //SharedActivity.startActivityForResult(LIntent, 0); 86 //加載掃碼 87 FMessageSubscriptionID := TMessageManager.DefaultManager.SubscribeToMessage(TMessageResultNotification, 88 HandleActivityMessage); 89 //開始掃碼 90 LaunchQRScanner(ScanRequestCode); 91 //狀態定為掃碼結束 92 ScanState := False; 93 end; 94 95 procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; 96 Shift: TShiftState); 97 begin 98 //如果按下物理返回鍵,但是掃碼未結束 99 if (Key = vkHardwareBack) and (ScanState = True) then 100 begin 101 ScanState := False; 102 Key := 0; 103 Exit; 104 end; 105 //如果按下物理返回鍵,並且掃碼結束 106 if (Key = vkHardwareBack) and (ScanState = False) then 107 begin 108 {$IFDEF ANDROID} 109 MessageDlg('確認退出嗎?', System.UITypes.TMsgDlgType.mtInformation, 110 [ 111 System.UITypes.TMsgDlgBtn.mbYes, 112 //System.UITypes.TMsgDlgBtn.mbNo, 113 System.UITypes.TMsgDlgBtn.mbCancel 114 ], 0, System.UITypes.TMsgDlgBtn.mbCancel, 115 procedure(const AResult: TModalResult) 116 begin 117 if AResult = mrYES then 118 MainActivity.finish; { 退出程序 } // use FMX.Platform.Android 119 end); 120 {$ENDIF ANDROID} 121 //close; 122 Key := 0; 123 Exit; 124 end; 125 end; 126 127 //活動消息處理 128 procedure TForm1.HandleActivityMessage(const Sender: TObject; 129 const M: TMessage); 130 begin 131 if M is TMessageResultNotification then 132 OnActivityResult(TMessageResultNotification(M).RequestCode, TMessageResultNotification(M).ResultCode, 133 TMessageResultNotification(M).Value); 134 end; 135 136 //活動結果事件 137 function TForm1.OnActivityResult(RequestCode, ResultCode: Integer; 138 Data: JIntent): Boolean; 139 var 140 ScanContent, ScanFormat: string; 141 begin 142 Result := False; 143 144 TMessageManager.DefaultManager.Unsubscribe(TMessageResultNotification, FMessageSubscriptionID); 145 FMessageSubscriptionID := 0; 146 //判斷請求代碼 147 if RequestCode = ScanRequestCode then 148 begin 149 //如果掃碼結束 150 if ResultCode = TJActivity.JavaClass.RESULT_OK then 151 begin 152 //有數據 153 if Assigned(Data) then 154 begin 155 //解析出數據 156 ScanContent := JStringToString(Data.getStringExtra(StringToJString('SCAN_RESULT'))); 157 ScanFormat := JStringToString(Data.getStringExtra(StringToJString('SCAN_RESULT_FORMAT'))); 158 Edit1.Text:= ScanContent; 159 Edit2.Text:= ScanFormat; 160 Label5.Text:= '掃描成功'; 161 end; 162 end 163 else if ResultCode = TJActivity.JavaClass.RESULT_CANCELED then 164 begin 165 Label5.Text:= '掃描取消'; 166 end; 167 Result := True; 168 end; 169 end; 170 171 //生成二維碼 172 procedure TForm1.Button2Click(Sender: TObject); 173 var 174 QRCode: TDelphiZXingQRCode; 175 begin 176 QRCode := TDelphiZXingQRCode.Create; 177 try 178 QRCode.Data := Edit3.Text; 179 QRCode.Encoding := TQRCodeEncoding(0); 180 QRCode.QuietZone := 4; 181 QRCode.DrawQrcode(Image1,QRCode); 182 finally 183 QRCode.Free; 184 end; 185 end; 186 187 end.
