使用HMS Scan Kit实现安卓扫码功能

@TOC

简介

    Zxing 是常用的第三方开源 SDK。但是,Zxing存在以下缺陷:仅实现扫描二维码的基本操作,不支持强光、弯曲、变形等更复杂的扫描环境。目前主流做法是基于Zxing对源码进行优化。但是,优化效果仍然不理想,很多人会在优化上花费大量时间。
    华为Scan Kit服务提供便捷的条码和二维码扫描、解析、生成能力,帮助开发者快速构建应用中的二维码扫描功能。得益于华为在计算机视觉领域的长期积累,华为统一条码扫描服务(Scan Kit)可检测并自动放大远距离或小尺寸条码,优化识别常见复杂条码扫描场景(如反射等)。 、暗光、污迹、模糊和圆柱体)。提高二维码扫描成功率和用户体验。

设备支持

平台设备版本
Android手机和平板EMUI 3.1以上、其他Android 4.4及以上
iOS手机iOS 9.0以上

集成

如果APP需要在应用商店上架,请先在 AppGallery Connect 中配置应用信息。查看开发指南
如果应用无上架需求,可以忽略。

配置HMS Core SDK的Maven仓地址

在项目的build.gradle中配置HMS Core SDK的Maven仓地址。

buildscript {
    repositories {
        ...
        // 配置HMS Core SDK的Maven仓地址。
        maven {url 'https://developer.huawei.com/repo/'}
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.0.1"
         配置HMS Core
        classpath 'com.huawei.agconnect:agcp:1.2.1.301'
    }
}

allprojects {
    repositories {
        ...
        // 配置HMS Core SDK的Maven仓地址。
        maven {url 'https://developer.huawei.com/repo/'}

    }
}

在应用级的“build.gradle中添加依赖包,HMS Core提供了两种类型的依赖包。

implementation 'com.huawei.hms:scanplus:1.3.2.300'
或者
implementation 'com.huawei.hms:scan:1.3.2.300'

并在文件头部添加插件:

apply plugin: 'com.huawei.agconnect'
  • 如果您的应用不需要支持其他语言,请跳过此步骤。默认情况下,该应用程序将支持 HMS SDK 支持的所有语言。
  • 如果您的应用仅支持某些语言,您可以在此步骤中配置语言。
android { 
    defaultConfig{ 
        ... 
        resConfigs "en-rGB", "zh-rCN" 
    } 
 }

添加权限

在调用模块的AndroidManifest.xml文件中声明二维码扫描页面。

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

配置混淆脚本

-ignorewarnings 
-keepattributes *Annotation*  
-keepattributes Exceptions  
-keepattributes InnerClasses  
-keepattributes Signature  
-keepattributes SourceFile,LineNumberTable  
-keep class com.hianalytics.android.**{*;}  
-keep class com.huawei.**{*;}

如果使用过 AndResGuard,请将其添加到混淆脚本文件中的许可名单中。

"R.string.hms*" ,           
"R.string.connect_server_fail_prompt_toast" ,           
"R.string.getting_message_fail_prompt_toast" ,            
"R.string.no_available_network_prompt_toast" ,
"R.string.third_app_*" ,           
"R.string.upsdk_*" ,           
"R.layout.hms*" ,           
"R.layout.upsdk_*" ,           
"R.drawable.upsdk*" ,          
"R.color.upsdk*" ,       
"R.dimen.upsdk*" ,      
"R.style.upsdk*" ,R.string.agc*

使用

Scan Kit 有四种模式:

  • Default View Mode
  • Customized View Mode
  • Bitmap Mode
  • MultiProcessor Mode

Default View Mode

提供相机扫码和导入图片扫码两个功能,提供完整的Activity,不需要开发者开发扫码界面的UI。

    private fun gotoScan() {
        val options =
            HmsScanAnalyzerOptions.Creator().setHmsScanTypes(HmsScan.ALL_SCAN_TYPE).create()
        ScanUtil.startScan(
            this, REQUEST_CODE,
            options
        )

    }
        override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            REQUEST_CODE -> {
                val hmsScan: HmsScan? =
                    data?.getParcelableExtra(ScanUtil.RESULT) // 获取扫码结果 ScanUtil.RESULT
                if (!TextUtils.isEmpty(hmsScan?.getOriginalValue())) {
                    tv_card_id.text = hmsScan?.getOriginalValue()
                }
            }
        }

    }

Customized View Mode

支持开发者自定义扫码界面,扫码过程和相机控制将由Scan Kit完成。这种模式更适合对扫码界面有定制化要求的场景。

class CustomizedModeActivity : AppCompatActivity() {
    companion object {
        const val SCAN_RESULT = "scanResult"
        private const val SCAN_FRAME_SIZE = 300
    }

    private var remoteView: RemoteView? = null
    var mScreenWidth = 0
    var mScreenHeight = 0

    private val mBinding by lazy {
        ActivityCustomizedModeBinding.inflate(layoutInflater)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(mBinding.root)

        //1. 获取屏幕密度计算 viewfinder 的矩形
        val dm = resources.displayMetrics
        //2. 获取屏幕尺寸
        val density = dm.density
        mScreenWidth = dm.widthPixels
        mScreenHeight = dm.heightPixels
        val scanFrameSize = (SCAN_FRAME_SIZE * density)
        //3. 计算 viewinder 的矩形,放在布局中央
        val rect = Rect()
        apply {
            rect.left = (mScreenWidth / 2 - scanFrameSize / 2).toInt()
            rect.right = (mScreenWidth / 2 + scanFrameSize / 2).toInt()
            rect.top = (mScreenHeight / 2 - scanFrameSize / 2).toInt()
            rect.bottom = (mScreenHeight / 2 + scanFrameSize / 2).toInt()
        }
        // 4. 初始化RemoteView, 并且设置回调监听,这里可能设置扫码选项
        remoteView = RemoteView.Builder().setContext(this).setBoundingBox(rect)
            .setFormat(HmsScan.ALL_SCAN_TYPE).build()
        remoteView?.onCreate(savedInstanceState)
        remoteView?.setOnResultCallback { result ->
            if (result != null && result.isNotEmpty() && result[0] != null && !TextUtils.isEmpty(
                    result[0].getOriginalValue()
                )
            ) {
                val intent = Intent()
                intent.apply {
                    putExtra(SCAN_RESULT, result[0])
                }
                setResult(Activity.RESULT_OK, intent)
                this.finish()
            }
        }
        // 5. 添加 RemoteView 至布局.
        val params = FrameLayout.LayoutParams(
            LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.MATCH_PARENT
        )
        mBinding.rim1.addView(remoteView, params)
    }

    // 6. 管理RemoteView 的生命周期
    override fun onStart() {
        super.onStart()
        remoteView?.onStart()
    }

    override fun onResume() {
        super.onResume()
        remoteView?.onResume()
    }

    override fun onPause() {
        super.onPause()
        remoteView?.onPause()
    }

    override fun onDestroy() {
        super.onDestroy()
        remoteView?.onDestroy()
    }

    override fun onStop() {
        super.onStop()
        remoteView?.onStop()
    }
}

Bitmap Mode

可以通过相机取帧的方式生成 Bitmap 进行检测,也可以通过图片文件转换成 Bitmap 进行检测等等,能 Bitmap 就能 检测,适用于图片识码等场景。

fun startBitmapMode(view: View) {
    EasyPhotos.createAlbum(
        this, false, false,
        GlideEngine.getInstance()
    )
        .setFileProviderAuthority(BuildConfig.APPLICATION_ID)
        .setCount(1)
        .start(object : SelectCallback() {
            override fun onResult(photos: ArrayList<Photo>?, isOriginal: Boolean) {
                photos?.let {
                    val path = photos.first().path
                    if (TextUtils.isEmpty(path)) {
                        return
                    }
                    // 1. 转换为 Bitmap
                    val bitmap = ScanUtil.compressBitmap(this@MainActivity, path)
                    // 2. 调用 decodeWithBitmap 方法识别 Bitmap.
                    val result = ScanUtil.decodeWithBitmap(
                        this@MainActivity,
                        bitmap,
                        HmsScanAnalyzerOptions.Creator().setHmsScanTypes(0).setPhotoMode(false)
                            .create()
                    )
                    // 3. 显示识别结果
                    if (result != null && result.isNotEmpty()) {
                        if (!TextUtils.isEmpty(result[0].getOriginalValue())) {
                            mBinding.tvResult.text = result[0].getOriginalValue()
                        }
                    }
                }
            }

            override fun onCancel() {
                Toast.makeText(
                    this@MainActivity,
                    "图片选取失败",
                    Toast.LENGTH_SHORT
                )
                    .show()
            }

        })
}

MultiProcessor Mode

相机扫码、导入图片扫码,支持同时检测多个码,支持同步和异步两种方式。

fun startMultiProcessorMode(view: View) {
        EasyPhotos.createAlbum(
            this, false, false,
            GlideEngine.getInstance()
        )
            .setFileProviderAuthority(BuildConfig.APPLICATION_ID)
            .setCount(1)
            .start(object : SelectCallback() {
                override fun onResult(photos: ArrayList<Photo>?, isOriginal: Boolean) {
                    photos?.let {
                        val path = photos.first().path
                        if (TextUtils.isEmpty(path)) {
                            return
                        }
                        // 1. 转换为 Bitmap
                        val bitmap = ScanUtil.compressBitmap(this@MainActivity, path)
						// 2. 配置可选项
                        val options =
                            HmsScanAnalyzerOptions.Creator().setHmsScanTypes(HmsScan.ALL_SCAN_TYPE)
                                .create()
                        // 3. 初始化 HmsScanAnalyzer 对象
                        val scanAnalyzer = HmsScanAnalyzer(options)
                        // 4. 构建 MLFrame
                        val image = MLFrame.fromBitmap(bitmap)
                        // 5. 扫码识别
                        /*  同步模式                      
                            val result: SparseArray<HmsScan> = scanAnalyzer.analyseFrame(image)
                            Log.d(TAG, result.toString())
                        */
                        // 异步模式
                        scanAnalyzer.analyzInAsyn(image).addOnSuccessListener {
                            if (it != null && it.size > 0) {
                                var resultStr = ""
                                it.forEach { value ->
                                    resultStr = resultStr.plus(value.originalValue).plus("\n")
                                }
                                mBinding.tvResult.text = resultStr
                            }
                        }.addOnFailureListener {
                            it?.printStackTrace()
                            Log.d(TAG, it.message ?: "")
                        }
                    }
                }

                override fun onCancel() {
                    Toast.makeText(
                        this@MainActivity,
                        "图片选取失败",
                        Toast.LENGTH_SHORT
                    )
                        .show()
                }

            })
    }
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值