QR / 바코드 스캔
QR 코드와 바코드를 스캔합니다.
개요
카메라를 열어 QR 코드 또는 바코드를 스캔하고 결과를 반환합니다. Android와 iOS 모두 동일한 JS API와 동일한 응답 형식을 사용합니다.
| 기능 | Android | iOS |
|---|---|---|
| QR 코드 스캔 | ✓ (Android 7.0+) | ✓ |
| 바코드 스캔 | ✓ (Android 7.0+) | ✓ |
지원 플랜: Basic 이상 (라이선스 기능 qr 필요)
사전 준비
QR 스캔은 카메라 권한을 사용합니다. 사용하는 플랫폼에 맞게 권한을 설정하세요.
Android
AndroidManifest.xml에는 카메라 권한이 주석 처리된 상태로 배포됩니다. QR 스캔을 사용하려면 주석을 해제하세요.
<uses-permission android:name="android.permission.CAMERA" />iOS
Info.plist에 카메라 권한 설명을 추가해야 합니다.
<key>NSCameraUsageDescription</key>
<string>QR 코드 및 바코드 스캔을 위해 카메라에 접근합니다.</string>사용법
unveilyBridge.qr.scan(cb)를 호출하면 스캐너가 열립니다. cb는 결과를 받을 콜백 함수 이름 문자열입니다. 생략하면 기본값 'onQRResult'가 사용됩니다.
// 콜백 이름을 직접 지정
window.unveilyBridge.qr.scan("onQRResult");
// 또는 기본 콜백(onQRResult) 사용
window.unveilyBridge.qr.scan();
function onQRResult(result) {
if (result.cancelled) {
return; // 사용자가 스캐너를 닫음
}
if (result.error) {
console.error("스캔 실패:", result.error); // 오류 또는 플랜 미지원
return;
}
console.log("스캔 내용:", result.text); // 스캔된 문자열
console.log("포맷:", result.format); // 예: "QR_CODE", "EAN_13"
console.log("타입:", result.type); // 콘텐츠 타입 (예: "URL", "TEXT")
}결과는 이미 파싱된 JS 객체로 전달됩니다. JSON.parse()를 호출할 필요가 없습니다.
응답 구조
콜백은 다음 세 가지 형태 중 하나의 객체를 받습니다.
{ "text": "https://example.com", "format": "QR_CODE", "type": "URL" }{ "cancelled": true }{ "error": "..." }| 필드 | 설명 |
|---|---|
text | 스캔된 문자열 (성공 시) |
format | 바코드 심볼로지 — QR_CODE, EAN_13, EAN_8, CODE_128, CODE_39, ITF, DATA_MATRIX, PDF_417, AZTEC 등 |
type | 콘텐츠 타입 분류 (예: URL, TEXT) |
cancelled | 사용자가 스캐너를 닫으면 true |
error | 오류 또는 플랜/기능 미지원 시 오류 메시지 |
오류 처리는 별도의 onError 콜백이 아니라 결과 객체의 cancelled / error 필드로 이루어집니다. 콜백은 하나뿐입니다.
실전 예시
QR 코드가 URL이면 이동하고, 그 외는 서버로 전송하는 패턴입니다.
document.getElementById('scan-btn').addEventListener('click', () => {
window.unveilyBridge.qr.scan("onScanComplete");
});
function onScanComplete(result) {
if (result.cancelled) return;
if (result.error) {
alert('스캔에 실패했습니다. 다시 시도해 주세요.');
return;
}
const text = result.text;
if (text.startsWith('http')) {
window.location.href = text;
} else {
sendToServer(text);
}
}
async function sendToServer(text) {
await fetch('/api/qr-result', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text })
});
}서버측 처리
app.post('/api/qr-result', (req, res) => {
const { text } = req.body;
// 바코드 값으로 상품 조회 등 처리
const product = productService.findByBarcode(text);
res.json({ product });
});[HttpPost("qr-result")]
public async Task<IActionResult> ProcessQR([FromBody] QRRequest request)
{
var product = await _productService.FindByBarcodeAsync(request.Text);
return Ok(new { product });
}@PostMapping("/api/qr-result")
public ResponseEntity<?> processQR(@RequestBody QRRequest request) {
Product product = productService.findByBarcode(request.getText());
return ResponseEntity.ok(Map.of("product", product));
}<?php
$data = json_decode(file_get_contents('php://input'), true);
$text = $data['text'];
$stmt = $pdo->prepare('SELECT * FROM products WHERE barcode = ?');
$stmt->execute([$text]);
$product = $stmt->fetch(PDO::FETCH_ASSOC);
header('Content-Type: application/json');
echo json_encode(['product' => $product]);<%
Dim text
text = Request.Form("text")
Dim conn, rs, sql
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open Application("ConnectionString")
sql = "SELECT * FROM products WHERE barcode = '" & text & "'"
Set rs = conn.Execute(sql)
Response.ContentType = "application/json"
If Not rs.EOF Then
Response.Write "{""found"": true, ""name"": """ & rs("name") & """}"
Else
Response.Write "{""found"": false}"
End If
%>