笛里谁知壮士心,沙头空照征人骨。这篇文章主要讲述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">
【Android实例-实现扫描二维码并生成二维码(XE8+小米5)】< 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 = https://www.songbingjia.com/android/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 6System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 7FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, 8FMX.Edit, FMX.Controls.Presentation, 9System.Messaging,//需要引入 10System.Rtti,//需要引入 11System.Actions,//需要引入 12Androidapi.JNI.Net,//需要引入 13Androidapi.JNI.GraphicsContentViewText,//需要引入 14Androidapi.JNI.JavaTypes,//需要引入 15Androidapi.Helpers,//需要引入 16Androidapi.JNI.App,//需要引入 17FMX.Objects,//需要引入 18FMX.ActnList,//需要引入 19FMX.StdActns,//需要引入 20FMX.Platform.Android,//需要引入 21FMX.MediaLibrary.Actions,//需要引入 22xZXIngQRCode; //需要引入 23 24 type 25TForm1 = class(TForm) 26Button1: TButton; 27Button2: TButton; 28Edit1: TEdit; 29Edit2: TEdit; 30Label1: TLabel; 31Label2: TLabel; 32Label3: TLabel; 33Image1: TImage; 34Panel1: TPanel; 35Label4: TLabel; 36Edit3: TEdit; 37Label5: TLabel; 38procedure Button1Click(Sender: TObject); 39procedure FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; 40Shift: TShiftState); 41procedure Button2Click(Sender: TObject); 42private 43{ Private declarations } 44//扫描请求代码 45const ScanRequestCode = 0; 46// 47var FMessageSubscriptionID: Integer; 48//活动结果事件 49function OnActivityResult(RequestCode, ResultCode: Integer; Data: JIntent): Boolean; 50//活动消息处理 51procedure HandleActivityMessage(const Sender: TObject; const M: TMessage); 52public 53{ Public declarations } 54//扫描状态 55ScanState: Boolean; //TRUE代表扫描中,FALSE扫描结束 56end; 57 58 var 59Form1: TForm1; 60 61 implementation 62 63 {$R *.fmx} 64 {$R *.LgXhdpiPh.fmx ANDROID} 65 66 //启用扫码 67 procedure LaunchQRScanner(RequestCode: Integer); 68 var 69Intent: JIntent; 70 begin 71Intent := TJIntent.JavaClass.init; 72Intent.setClassName(SharedActivityContext, StringToJString(\'com.google.zxing.client.android.CaptureActivity\')); 73//如果要预定扫描格式,UnComment 下面文字 74//Intent.putExtra(StringToJString(\'SCAN_MODE\'), StringToJString(\'QR_CODE_MODE\')); 75SharedActivity.startActivityForResult(Intent, RequestCode); 76 end; 77 78 //调用扫码方法 79 procedure TForm1.Button1Click(Sender: TObject); 80 var 81LIntent: 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//加载扫码 87FMessageSubscriptionID := TMessageManager.DefaultManager.SubscribeToMessage(TMessageResultNotification, 88HandleActivityMessage); 89//开始扫码 90LaunchQRScanner(ScanRequestCode); 91//状态定为扫码结束 92ScanState := False; 93 end; 94 95 procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; 96Shift: TShiftState); 97 begin 98//如果按下物理返回键,但是扫码未结束 99if (Key = vkHardwareBack) and (ScanState = True) then 100begin 101ScanState := False; 102Key := 0; 103Exit; 104end; 105//如果按下物理返回键,并且扫码结束 106if (Key = vkHardwareBack) and (ScanState = False) then 107begin 108{$IFDEF ANDROID} 109MessageDlg(\'确认退出吗?\', System.UITypes.TMsgDlgType.mtInformation, 110[ 111System.UITypes.TMsgDlgBtn.mbYes, 112//System.UITypes.TMsgDlgBtn.mbNo, 113System.UITypes.TMsgDlgBtn.mbCancel 114], 0, System.UITypes.TMsgDlgBtn.mbCancel, 115procedure(const AResult: TModalResult) 116begin 117if AResult = mrYES then 118MainActivity.finish; { 退出程序 }// use FMX.Platform.Android 119end); 120{$ENDIF ANDROID} 121//close; 122Key := 0; 123Exit; 124end; 125 end; 126 127 //活动消息处理 128 procedure TForm1.HandleActivityMessage(const Sender: TObject; 129const M: TMessage); 130 begin 131if M is TMessageResultNotification then 132OnActivityResult(TMessageResultNotification(M).RequestCode, TMessageResultNotification(M).ResultCode, 133TMessageResultNotification(M).Value); 134 end; 135 136 //活动结果事件 137 function TForm1.OnActivityResult(RequestCode, ResultCode: Integer; 138Data: JIntent): Boolean; 139 var 140ScanContent, ScanFormat: string; 141 begin 142Result := False; 143 144TMessageManager.DefaultManager.Unsubscribe(TMessageResultNotification, FMessageSubscriptionID); 145FMessageSubscriptionID := 0; 146//判断请求代码 147if RequestCode = ScanRequestCode then 148begin 149//如果扫码结束 150if ResultCode = TJActivity.JavaClass.RESULT_OK then 151begin 152//有数据 153if Assigned(Data) then 154begin 155//解析出数据 156ScanContent := JStringToString(Data.getStringExtra(StringToJString(\'SCAN_RESULT\'))); 157ScanFormat := JStringToString(Data.getStringExtra(StringToJString(\'SCAN_RESULT_FORMAT\'))); 158Edit1.Text:= ScanContent; 159Edit2.Text:= ScanFormat; 160Label5.Text:= \'扫描成功\'; 161end; 162end 163else if ResultCode = TJActivity.JavaClass.RESULT_CANCELED then 164begin 165Label5.Text:= \'扫描取消\'; 166end; 167Result := True; 168end; 169 end; 170 171 //生成二维码 172 procedure TForm1.Button2Click(Sender: TObject); 173 var 174QRCode: TDelphiZXingQRCode; 175 begin 176QRCode := TDelphiZXingQRCode.Create; 177try 178QRCode.Data := Edit3.Text; 179QRCode.Encoding := TQRCodeEncoding(0); 180QRCode.QuietZone := 4; 181QRCode.DrawQrcode(Image1,QRCode); 182finally 183QRCode.Free; 184end; 185 end; 186 187 end.
View Code
推荐阅读
- Android Gradle 引用本地 AAR 的几种方式
- Android Service的绑定过程
- Android网络编程之使用HttpClient和MultipartEntityBuilder 批量同时上传文件和文字
- AndroidStudio利用android-support-multidex解决65536问题64k问题
- java.lang.UnsupportedClassVersionError: com/android/build/gradle/AppPlugin : Unsupported major.minor
- AndroidManifest.xml中的注册组件
- React Native DEMO for Android
- Android之聊天室设计与开发
- Android java.lang.IllegalStateException: Already logged in to server.