Android 解析二维码/条形码,推荐使用 BGAQRCode-Android
二维码已经有很多人写过了,这里写一篇一维码/条形码的博客,
导入方法如下:
implementation 'cn.bingoogolapple:bga-qrcode-zbar:1.3.7'
或者
implementation 'cn.bingoogolapple:bga-qrcode-zxing:1.3.7'
本来没有什么好说的,可是竟然花费了我一天的时间,这里就顺手写一下zbar跟zxing的区别吧
就使用摄像头读取而言:
目录
Android 解析二维码/条形码,推荐使用 BGAQRCode-Android
一开始用的是原始的zxing,
//implementation 'com.google.zxing:core:3.4.1'//Older SDK versions 这里不用
implementation 'com.journeyapps:zxing-android-embedded:4.1.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
先设置 xml:
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
由于调用了加速硬件,所以还要加上一句
<application android:hardwareAccelerated="true" ... >
调用也比较简单:
new IntentIntegrator(this).initiateScan(); // `this` is the current Activity
// Get the results:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if(result != null) {
if(result.getContents() == null) {
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
如果是fragment,则可以使用
IntentIntegrator.forFragment(this).initiateScan(); // `this` is the current Fragment
// If you're using the support library, use IntentIntegrator.forSupportFragment(this) instead.
//自定义
IntentIntegrator integrator = new IntentIntegrator(this);
integrator.setDesiredBarcodeFormats(IntentIntegrator.ONE_D_CODE_TYPES);
integrator.setPrompt("Scan a barcode");
integrator.setCameraId(0); // Use a specific camera of the device
integrator.setBeepEnabled(false);
integrator.setBarcodeImageEnabled(true);
integrator.initiateScan();
本来使用读取就可以,但是这个zxing非常原始,需要跳转到Activity再跳转回来,且不能在布局里自定义
由于无法识别红底黑线的一维码,zxing对颜色感应比较差,特别是贴了透明膜带反光效果的物体基本识别不出来,就摄像头读取而言,不得不改使用zbar
测试可以网站生成红底/绿底的条形码进行测试:在线条形码生成传送门 https://barcode.tec-it.com/zh/?data=12345678901256
最后使用了 BGAQRCode-Android 的zbar
implementation 'cn.bingoogolapple:bga-qrcode-zbar:1.3.7'
如果只是读取条形码,需要添加
app:qrcv_isBarcode="true"
布局文件如下:
<cn.bingoogolapple.qrcode.zbar.ZBarView
android:id="@+id/zxingview"
app:qrcv_animTime="500"
app:qrcv_isBarcode="true"
app:qrcv_isScanLineReverse="true"
app:qrcv_borderColor="@android:color/white"
app:qrcv_borderSize="1dp"
app:qrcv_cornerColor="@android:color/transparent"
app:qrcv_cornerLength="20dp"
app:qrcv_cornerSize="3dp"
app:qrcv_maskColor="#33FFFFFF"
app:qrcv_rectWidth="300dp"
app:qrcv_scanLineColor="@color/design_default_color_secondary"
app:qrcv_scanLineSize="1dp"
app:qrcv_topOffset="90dp"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
调用也很简单
QRCodeView mQRCodeView = (ZBarView) findViewById(R.id.zbarview);
mQRCodeView.setDelegate(this);
@Override
public void onScanQRCodeSuccess(String result) {
Toast.makeText(this,result,Toast.LENGTH_SHORT).show();
mQRCodeView.startSpot();
}
@Override
public void onScanQRCodeOpenCameraError() {
Toast.makeText(this,"错误",Toast.LENGTH_SHORT).show();
}
烦人的生命周期
@Override
protected void onStart() {
super.onStart();
mQRCodeView.startCamera();//打开相机
mQRCodeView.showScanRect();//显示扫描框
mQRCodeView.startSpot();//开始识别二维码
//mQRCodeView.openFlashlight();//开灯
//mQRCodeView.closeFlashlight();//关灯
}
@Override
protected void onStop() {
mQRCodeView.stopCamera();
super.onStop();
}
@Override
protected void onDestroy() {
mQRCodeView.onDestroy();
super.onDestroy();
}
好了,如果使用zxing去调用摄像头,则会一直弹出log
com.google.zxing.NotFoundException
原因是:摄像头一直在搜索二维码,但是搜索不到
而且,对颜色依然是感应比较差,速度比zbar慢了3-5倍
最后总结了一下:Zbar适合摄像头读取,zxing适合生成二维码/条形码
其他的都可以去搜索,就到这了,因为是一维码/条形码,就不涉及读取二维码精度的问题了
附录:flutter 调用二维码
dependencies: qr_code_scanner: ^0.3.5
附上代码
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
void main() => runApp(MaterialApp(home: QRViewExample()));
class QRViewExample extends StatefulWidget {
const QRViewExample({
Key key,
}) : super(key: key);
@override
State<StatefulWidget> createState() => _QRViewExampleState();
}
class _QRViewExampleState extends State<QRViewExample> {
Barcode result;
QRViewController controller;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
// In order to get hot reload to work we need to pause the camera if the platform
// is android, or resume the camera if the platform is iOS.
@override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
controller.pauseCamera();
}
controller.resumeCamera();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(flex: 4, child: _buildQrView(context)),
Expanded(
flex: 1,
child: FittedBox(
fit: BoxFit.contain,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
if (result != null)
Text(
'Barcode Type: ${describeEnum(result.format)} Data: ${result.code}')
else
Text('Scan a code'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.toggleFlash();
setState(() {});
},
child: FutureBuilder(
future: controller?.getFlashStatus(),
builder: (context, snapshot) {
return Text('Flash: ${snapshot.data}');
},
)),
),
Container(
margin: EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.flipCamera();
setState(() {});
},
child: FutureBuilder(
future: controller?.getCameraInfo(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return Text(
'Camera facing ${describeEnum(snapshot.data)}');
} else {
return Text('loading');
}
},
)),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.pauseCamera();
},
child: Text('pause', style: TextStyle(fontSize: 20)),
),
),
Container(
margin: EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.resumeCamera();
},
child: Text('resume', style: TextStyle(fontSize: 20)),
),
)
],
),
],
),
),
)
],
),
);
}
Widget _buildQrView(BuildContext context) {
// For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
var scanArea = (MediaQuery.of(context).size.width < 400 ||
MediaQuery.of(context).size.height < 400)
? 150.0
: 300.0;
// To ensure the Scanner view is properly sizes after rotation
// we need to listen for Flutter SizeChanged notification and update controller
return QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderColor: Colors.red,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea),
);
}
void _onQRViewCreated(QRViewController controller) {
setState(() {
this.controller = controller;
});
controller.scannedDataStream.listen((scanData) {
setState(() {
result = scanData;
});
});
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
}