개요
많은 앱에 두 번째 기기가 필요합니다: 카메라와 뷰어, 휴대폰과 태블릿, 키오스크와 관리자 휴대폰 등. 사용자가 포기하는 지점은 이 두 번째 기기에 로그인하는 단계입니다. 사용자 이름을 기억하고, 비밀번호를 입력하고, 이메일 코드를 기다려야 하기 때문입니다.
KlugRegister는 이 단계를 카메라 한 번 촬영으로 바꿉니다. 첫 번째 기기가 QR 코드를 생성하고, 두 번째 기기가 네이티브 스캐너로 스캔하면 앱이 로그인합니다. QR 코드에는 앱에 필요한 내용, 보통 서버에서 발급한 일회용 코드가 담기며 비밀번호 자체는 절대 담기지 않습니다.
두 부분 모두 네이티브입니다. QR 코드는 시스템이 생성하며(어떤 크기에서도 선명하고, 바로 표시할 수 있는 AIR BitmapData로 제공), 스캐너도 네이티브입니다. iOS에서는 자체 안내 텍스트를 넣을 수 있는 전체 화면 카메라 뷰, Android에서는 카메라 권한이 전혀 필요 없는 Google의 코드 스캐너를 사용합니다.
KlugRegister는 개념 증명인 저희 앱의 현재 릴리스에서 실행됩니다. 등록 후 앱이 QR 코드를 표시하면 두 번째 기기가 스토어에서 앱을 설치한 직후에도 몇 초 만에 페어링됩니다.
기능
- 독립형: ANE 하나로 충분하며, 코어 라이브러리나 의존성 ANE를 추가할 필요가 없음
- 모든 텍스트나 URL에서 QR 코드를 생성하며, 적절한 여백(quiet zone)을 갖춘 BitmapData로 반환
- 모듈당 픽셀 크기를 선택할 수 있어 어떤 화면에서도 선명함
- 자체 안내 텍스트와 취소 버튼을 넣을 수 있는 네이티브 전체 화면 카메라 스캐너
- 카메라 권한을 요청하고 거부되면 보고
- Android: Play services의 Google 코드 스캐너, 카메라 권한 불필요
- 휴대폰과 태블릿에서 세로 및 가로 모드로 동작
- iOS와 macOS: 시스템 프레임워크만 사용. Android: ZXing과 Google 코드 스캐너, 앱 패키징 시 자동으로 해결됨
지원 플랫폼
기능을 사용할 수 없는 곳에서는 isSupported와 isScanSupported가 false를 반환하므로, 같은 코드를 모든 앱에 그대로 둘 수 있습니다.
시작하기
애플리케이션 디스크립터에 확장을 추가합니다:
<extensions>
<extensionID>com.klug.register.KlugRegister</extensionID>
</extensions>
iOS에서 스캔하려면 InfoAdditions에 카메라 사용 설명을 추가하세요:
<key>NSCameraUsageDescription</key> <string>Scan the QR code of your first device</string>
코드 예제
두 번째 기기를 페어링하는 네 가지 완전한 흐름입니다. 코드 생성은 즉시 이루어지며, 스캐너 결과는 KlugRegisterEvent로 전달됩니다. 전체 문서 →
import com.klug.register.KlugRegister; import com.klug.register.KlugRegisterEvent; import flash.display.Bitmap; import flash.display.BitmapData; var reg:KlugRegister = KlugRegister.getInstance(); if ( reg.isSupported ) // Android, iOS, macOS { // a short-lived one-time code from your server, never the password var bmp:BitmapData = reg.createQRCode( "https://your.server/pair?t=" + oneTimeCode, 10 ); if ( bmp != null ) // null: no code could be made from the text { var qr:Bitmap = new Bitmap( bmp ); // black on white, 4-module quiet zone included qr.x = ( stage.stageWidth - qr.width ) / 2; qr.y = 120; addChild( qr ); } }
reg.addEventListener( KlugRegisterEvent.SCANNED, onScanned ); reg.addEventListener( KlugRegisterEvent.CANCELED, onScanCanceled ); reg.addEventListener( KlugRegisterEvent.ERROR, onScanError ); function startScan():void { if ( !reg.isScanSupported ) { showCodeEntry(); // your app function: type the one-time code instead return; } // iOS: full-screen scanner with your hint and button; macOS 13+: a sheet on the app window; // Android: Google's own localized scanner, hint and cancel title are not used if ( !reg.scanQRCode( "Point the camera at the code on your first device", "Cancel" ) ) trace( "a scanner is already open" ); }
function onScanned( e:KlugRegisterEvent ):void { var prefix:String = "https://your.server/pair?t="; if ( e.text.indexOf( prefix ) != 0 ) { showMessage( "This is not a pairing code." ); // your app function return; } var vars:URLVariables = new URLVariables(); vars.t = e.text.substr( prefix.length ); var req:URLRequest = new URLRequest( "https://your.server/pair" ); req.method = URLRequestMethod.POST; req.data = vars; var loader:URLLoader = new URLLoader(); loader.addEventListener( Event.COMPLETE, function( ev:Event ):void { signInWith( String( loader.data ) ); // your app function: the server's answer }); loader.load( req ); }
function onScanCanceled( e:KlugRegisterEvent ):void { showPairingScreen(); // the user closed the scanner: back to the screen, no message } function onScanError( e:KlugRegisterEvent ):void { switch ( e.errorCode ) { case "denied": // iOS, macOS: camera permission refused showMessage( "Allow camera access in Settings to scan the code." ); break; case "nocamera": // iOS, macOS: no usable camera showCodeEntry(); break; default: // Android: "scanner" (e.g. scanner not ready yet) or "empty" showMessage( "The scanner could not start: " + e.errorMessage ); } }
API 개요
| KlugRegister.getInstance() | 단일 인스턴스를 반환합니다. |
| isSupported | QR 코드를 생성할 수 있는 곳(Android, iOS, macOS)에서 true입니다. |
| isScanSupported | 스캐너를 사용할 수 있는 곳에서 true입니다: Android, iOS, 카메라가 있는 macOS 13 이상. |
| createQRCode(text, modulePx) | QR 코드를 BitmapData로 반환합니다. 흰색 배경에 검은색이며 4모듈 여백(quiet zone)이 있고, modulePx는 모듈당 픽셀 수(기본값 8)입니다. 코드를 만들 수 없으면 Null을 반환합니다. |
| scanQRCode(hint, cancelTitle) | 스캐너를 엽니다: iOS에서는 전체 화면, Mac에서는 시트, Android에서는 Google 스캐너(hint와 title은 사용되지 않음)입니다. 결과는 이벤트로 도착합니다. 스캐너가 이미 열려 있으면 false를 반환합니다. |
| KlugRegisterEvent | text, errorCode, errorMessage. |
이벤트
| KlugRegisterEvent.SCANNED | 코드를 읽었습니다. e.text에 그 내용이 들어 있습니다. |
| KlugRegisterEvent.CANCELED | 사용자가 스캐너를 닫았습니다. |
| KlugRegisterEvent.ERROR | e.errorCode: iOS와 macOS에서는 denied(카메라 권한 없음) · nocamera, Android에서는 scanner · empty. 자세한 내용은 e.errorMessage에 있습니다. |
KlugRegister 구매
AIR 애플리케이션 1개에 대한 연간 라이선스이며 12개월간 모든 업데이트를 제공합니다. 결제 후 확장, ActionScript 라이브러리, 문서를 이메일로 보내 드리며, 보통 영업일 기준 1일 이내입니다. 라이선스 및 약관
요구 사항
| AIR SDK | 51.x (HARMAN) |
| Android | Android 6 이상, Google Play services(스캐너) |
| iOS | iOS 13 이상 |
| macOS | macOS 10.15 이상(QR 코드 생성), 스캔은 macOS 13 이상 |
| 권한 | iOS와 macOS: 스캔용 카메라(NSCameraUsageDescription), Android: 없음 |