Android实例-实现扫描二维码并生成二维码(XE8+小米5)

Posted 疯狂delphi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android实例-实现扫描二维码并生成二维码(XE8+小米5)相关的知识,希望对你有一定的参考价值。

相关资料

第三方资料太大没法写在博文上,请下载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

\'@style/CaptureTheme\').

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.
View Code

 

以上是关于Android实例-实现扫描二维码并生成二维码(XE8+小米5)的主要内容,如果未能解决你的问题,请参考以下文章

Android基于Google Zxing实现二维码/条形码扫描生成二维码/条形码

jquery怎么实现url地址生成二维码实例

Android二维码扫描登陆网页

android 二维码

Android项目实战(二十八):Zxing二维码实现及优化

IOS原生方法实现二维码生成与扫描