← 所有扩展

原生扩展

KlugRegister

com.klug.register.KlugRegister

无需 APM。下载即用,再简单不过。

生成二维码,并通过原生全屏摄像头扫描器扫描,因此只需将第二台设备的摄像头对准第一台设备即可登录,无需输入用户名或密码。

AndroidiOSmacOSMac 上的 iPad 已投入生产 €19 / 年起 · 购买

概览

许多应用需要第二台设备:摄像头和观看端、手机和平板、自助终端和管理员手机。在第二台设备上登录正是用户放弃的环节:他们得记住用户名、输入密码,或等待邮件验证码。

KlugRegister 把这一步变成一次拍摄。第一台设备生成二维码;第二台设备用原生扫描器扫描,应用即完成登录。二维码携带您的应用所需的任何内容,通常是来自服务器的一次性代码,绝不是密码本身。

两部分都是原生的:二维码由系统生成(任意尺寸都清晰锐利,以可直接显示的 AIR BitmapData 形式提供),扫描器同样是原生的:iOS 上是带有您自己提示文字的全屏摄像头视图,Android 上是 Google 的代码扫描器,完全不需要摄像头权限。

KlugRegister 运行在我们的应用的当前版本中,这就是我们的概念验证:注册后应用显示一个二维码,第二台设备数秒内即可完成配对,即使是刚从商店安装应用之后。

特性

  • 自成一体:一个 ANE,无需添加核心库或依赖 ANE
  • 可从任意文本或 URL 生成二维码,以带有合规静区的 BitmapData 返回
  • 以每个模块的像素数选择尺寸,在任何屏幕上都清晰锐利
  • 原生全屏摄像头扫描器,可自定义提示文字和取消按钮
  • 请求摄像头权限,并在被拒绝时进行报告
  • Android:使用 Play 服务的 Google 代码扫描器,无需摄像头权限
  • 在手机和平板上均支持竖屏和横屏
  • iOS 和 macOS:仅使用系统框架;Android:ZXing 和 Google 代码扫描器,在打包应用时自动解析

支持的平台

Android 生成 + 扫描
iOS 生成 + 扫描 · arm64
macOS 生成 + 扫描 (macOS 13+) · arm64 · x86_64
Mac 上的 iPad 生成 + 扫描

在某项功能不可用的平台上,isSupported 和 isScanSupported 返回 false,因此同一份代码可以保留在每个应用中。

入门

将扩展添加到您的应用描述文件中:

app.xml
<extensions>
    <extensionID>com.klug.register.KlugRegister</extensionID>
</extensions>

要在 iOS 上扫描,请在 InfoAdditions 中添加摄像头使用说明:

app.xml · InfoAdditions
<key>NSCameraUsageDescription</key>
<string>Scan the QR code of your first device</string>

代码示例

配对第二台设备的四个完整流程。生成二维码是即时完成的;扫描结果以 KlugRegisterEvent 的形式到达。完整文档 →

1 · 在第一台设备上显示配对码
PairingCode.as
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 );
    }
}
2 · 在第二台设备上扫描
Scan.as
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" );
}
3 · 向您的服务器兑换该代码
Redeem.as
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 );
}
4 · 取消与错误
ScanErrors.as
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在可以生成二维码的平台上为 True(Android、iOS、macOS)。
isScanSupported在扫描器可用的平台上为 True:Android、iOS,以及配有摄像头的 macOS 13 或更高版本。
createQRCode(text, modulePx)以 BitmapData 返回二维码,白底黑码,带 4 个模块宽的静区;modulePx 为每个模块的像素数(默认 8)。若无法生成则返回 Null。
scanQRCode(hint, cancelTitle)打开扫描器:iOS 上为全屏,Mac 上为面板,Android 上为 Google 的扫描器(此处不使用提示和标题)。结果以事件形式到达。如果已有扫描器打开,则返回 false。
KlugRegisterEventtext, errorCode, errorMessage.

事件

KlugRegisterEvent.SCANNED已读取到一个代码;e.text 保存其内容。
KlugRegisterEvent.CANCELED用户关闭了扫描器。
KlugRegisterEvent.ERRORe.errorCode:denied(无摄像头权限)· nocamera 适用于 iOS 和 macOS;scanner · empty 适用于 Android。详情见 e.errorMessage。

购买 KlugRegister

一个 AIR 应用的年度许可,含 12 个月内的所有更新。付款后,您将通过电子邮件收到扩展、ActionScript 库和文档,通常在一个工作日内。许可与条款

基础版
€19 / 年
  • 一个 AIR 应用的许可
  • 12 个月内的所有更新
  • 不含支持
购买基础版
标准版
€149 / 年
  • 一个 AIR 应用的许可
  • 12 个月内的所有更新
  • 7 天内通过电子邮件答复
购买标准版
优先版
€299 / 年
  • 一个 AIR 应用的许可
  • 12 个月内的所有更新
  • 48 小时内通过电子邮件答复
购买优先版
税费在结账时由 Link (Stripe) 计算。您需要在结账时输入 AIR 应用的应用 ID。

要求

AIR SDK51.x (HARMAN)
AndroidAndroid 6 或更高版本,Google Play 服务(扫描器)
iOSiOS 13 或更高版本
macOSmacOS 10.15 或更高版本(生成二维码);扫描需 macOS 13 或更高版本
权限iOS 和 macOS:扫描需要摄像头 (NSCameraUsageDescription);Android:无