서론
처음 플러터 개발을 시작했을 때 QR스캔이 필요해서 아무 패키지나 사용했다.
'플러터 패키지니까 사용량 높은 아무거나 써도 Android/iOS 다 지원하겠지?'
대충 이런 생각이었다. 아니 그냥 iOS에선 안될거란 생각 자체를 못했다.
그 때 사용한 패키지가 qrscan이라는 놈.... 코드 다짜고 iOS 지원이 안되어 싹 갈아엎었다...
그래서 오늘은 갈아엎으며 바꾸게 된 패키지인 qr_code_scanner를 소개해보고자 한다.
Android/iOS 모두 지원하며 qrscan보다 기본 디자인도 예쁘고 커스터마이즈도 가능해서 추천한다.
1. 설치
pubspce.yaml에 qr_code_scanner를 추가하고 Pub get
qr_code_scanner: ^1.0.1
qr_code_scanner | Flutter package
QR code scanner that can be embedded inside flutter. It uses zxing in Android and MTBBarcode scanner in iOS.
pub.dev
2. 카메라 접근 권한 추가
1) Android
· android > app > src > main > AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA"/>
2) iOS
· ios > Runner > info.plist
<dict></dict> 사이에 아래 코드를 넣어준다.
<string></string>사이에는 카메라를 사용하는 목적을 명확하게 적어줘야한다.
실제로 이 부분을 작성하지 않았다가 appstore에서 reject 당했다.
<!-- Permission options for the `camera` group -->
<key>NSCameraUsageDescription</key>
<string>라벨 QR코드 조회를 위해 카메라 사용 권한을 허용하시겠습니까?</string>
· ios > Runner > Podfile
## dart: PermissionGroup.camera 부분을 넣어준다.
※ Mac환경이 아닐 경우 Podfile이 없을 수 있음!!
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: PermissionGroup.camera
'PERMISSION_CAMERA=1',
]
end
end
end
3. 스캐너 위젯 추가
이제 실제로 QR코드 스캐너가 실행될 위젯을 작성해야한다.
나의 경우 lib> utils > scanner.dart를 생성하여 따로 빼두었다.
상세한 설명은 아래 코드블럭에 주석으로 포함되어있다.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
class QRScanner extends StatefulWidget {
const QRScanner({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _QRScannerState();
}
class _QRScannerState extends State<QRScanner> {
Barcode? result;
QRViewController? controller;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
// qr_code_scanner의 hot reload를 보장하려면 안드로이드의 경우에는 pauseCamera(),
// iOS의 경우에는 resumeCamera()를 처리해줘야한다.
@override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
controller!.pauseCamera();
}
controller!.resumeCamera();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
//_buildQrView를 실행하면서 스캐너를 뷰에 뿌려줌
Expanded(flex: 4, child: _buildQrView(context)),
],
),
);
}
Widget _buildQrView(BuildContext context) {
// 디바이스의 크기에 따라 scanArea를 지정 반응형(?)과 비슷한 개념
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, // QRView가 생성되면 _onQRViewCreated를 실행
// QR을 읽힐 네모난 칸의 디자인을 설정
overlay: QrScannerOverlayShape(
borderColor: Colors.blueAccent, // 모서리 테두리 색
borderRadius: 10, // 둥글게 둥글게
borderLength: 30, // 테두리 길이 길면 길수록 네모에 가까워진다.
borderWidth: 10, // 테두리 너비
cutOutSize: scanArea),
// 카메라 사용 권한을 체크한다.
onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
);
}
void _onQRViewCreated(QRViewController controller) {
setState(() {
this.controller = controller; // 컨트롤러를 통해 스캐너를 제어
});
// 인식시킬 QR코드가 여러개 붙어있을 경우 여러개를 한번에 인식해버리는
// 문제가 발생하여 먼저 인식된 QR코드 하나만 인식하기위한 코드
int counter = 0;
controller.scannedDataStream.listen((scanData) async{
counter++; // QR코드가 인식되면 counter를 1 올려준다.
await controller.pauseCamera(); // 인식되었으니 카메라를 멈춘다.
setState(() {
result = scanData; // 스캔된 데이터를 담는다.
print('barcode_result----------------');
print(result!.code);
// result를 다시 url로 담는다.
String url = result!.code.toString();
if(counter == 1){
// QR이 인식 되었을 경우 스캐너를 닫으며 결과를 넘긴다.
Navigator.pop(context, url);
}
});
});
}
// 권한 체크를 위한 함수
void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
//log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
if (!p) { // 카메라 사용 권한이 없을 경우
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('no Permission')),
);
}
}
// 요거는 자세히는 모르겠으나 사용이 끝나면 컨트롤러를 폐기시키는 듯.
@override
void dispose() {
controller?.dispose();
super.dispose();
}
}
4. 스캐너 위젯을 사용
void scanData() async {
// 3에서 만들었던 QRScanner로 화면을 이동
// QR을 스캔한 결과를 value로 받아서 사용
Navigator.of(context).push(MaterialPageRoute(builder: (context) => const QRScanner())).then((value){
_controller.evaluateJavascript(source: 'appToWeb_qrResult( "$value" )');
});
}
5. 테스트
6. 고생한 나에게 박수를 친다. 짝짝짝

'앱 개발 > Flutter' 카테고리의 다른 글
[Flutter] 플러터 InAppWebView JS로 값 주고받기 (0) | 2024.02.22 |
---|---|
[Flutter] 플러터 InAppWebView Post로 데이터 전송하기 (0) | 2024.02.22 |