Android 项目开发进程中,扫码场景运用最多的开源库是 ZXing ,Github 上针对 ZXing 的优化和二次封装不胜枚举,但是 Zxing 的缺陷在于只是结束了扫码的一些根底操作,关于更为凌乱的扫码环境比如强光,弯曲,形变等情况,并不能很好地支撑。现在干流的做法是依据Zxing 的源码做部分优化,但是效果仍然不算志向,一同还会花费许多人力。

今日,我们就介绍下 ZXing 的完美替代品 —— 华为统一扫码服务( Scan Kit )。关于 ZXing 和 Scan Kit 的对比,论坛内有一篇文章写得很全面:

developer.huawei.com/consumer/cn…
感兴趣的读者可以阅读一下。

简介

华为统一扫码服务(Scan Kit)供应快捷的条形码和二维码扫描、解析、生成才干,帮忙开发者快速构建运用内的扫码功用。

得益于华为在核算机视觉范畴才干的堆集,Scan Kit 可以结束远距离码或小型码的检测和自动扩展,一同针对常见凌乱扫码场景(如反光、暗光、污损、迷糊、柱面)做了针对性辨认优化,进步扫码成功率与用户领会。

Scan Kit 支撑 Android 和 iOS 系统集成。其间,Android 系统集成 Scan Kit 后支撑横屏扫码才干。

支撑的设备

渠道 设备类型 OS版别
Android 华为手机、华为平板 EMUI 3.1以上
Android 非华为手机 Android 4.4及以上
iOS 手机 iOS 9.0以上

场景介绍

扫码

Scan Kit 支撑扫描13种全球干流的码制式。假如开发者的运用只处理部分特定的码制式,开发者也可以在接口中指定制式以便加快扫码速度。已支撑的码制式:

  • 一维码:EAN-8、EAN-13、UPC-A、UPC-E、Codabar、Code 39、Code 93、Code 128、ITF-14
  • 二维码:QR Code、Data Matrix、PDF417、Aztec

Scan Kit 供应多种调用方式,开发者可依据需求选择一个适合的方式构建扫码功用。

调用方法 支撑渠道 扫码流程 扫码界面 功用
Default View Mode Android/iOS Scan Kit处理 Scan Kit供应 相机扫码(可以调用Bitmap mode添加导入图片扫码功用)。
Customized View Mode Android/iOS Scan Kit处理 开发者自定义 相机扫码(可以叠加Bitmap mode添加导入图片扫码功用)。
Bitmap Mode Android/iOS 开发者运用处理 开发者自定义 相机扫码、导入图片扫码。
MultiProcessor Mode Android 开发者运用处理 开发者自定义 相机扫码、导入图片扫码,支撑一同检测多个码。
  • 关于期望快速构建强大扫码功用的开发者,建议选择 Default View Mode 或许 Customized View Mode。在这两种方式下,Scan Kit 直接控制相机结束最优的相机 Zoom 控制、自适应的曝光调度、自适应对焦调度等操作,保证最佳的扫码领会,减少开发者的工作量。Default View Mode 和 Customized View Mode 的差异在于后者支撑开发者自定义扫码界面 UI。
  • 关于期望彻底自定义扫码流程并自行控制相机的开发者,可以选择 Bitmap Mode 构建您的扫码功用。Bitmap Mode 需求开发者自行控制相机,且供应相机扫码和导入图片扫码两种方式,在调用扫码接口时设置。当用户在扫描较小或许较远的二维码时,Scan Kit 会回来需求扩展的倍数给您的运用,您只需按照回来值调整相机焦距就能快速获取满意条件的图片。请注意,Scan Kit 回来的扩展倍数是通过检测效果和用户场景核算得出,建议您不要更改此扩展倍数,否则或许会降低实践运用效果。
  • MultiProcessor Mode 适用于需求一同扫描多个码的场景。由于MultiProcessor处理效率低于其他三种调用方法,假如您没有上述需求,建议您运用其他三种调用方法。MultiProcessor Mode供应同步和异步两种方式,可以依据实践需求选择一个适合的方式。

码值解析

Scan Kit可以将码的原始内容回来给开发者,还会针对运用特定内容格局编码的二维码/条形码进行剖析并提取结构化数据,帮忙开发者快速构建相关服务。已支撑如下场景:联系人信息Wi-Fi 衔接信息网页日历日程ID 卡短信电话邮件地理位置产品条码ISBN

码生成

Scan Kit 支撑将字符串转换为一维码或二维码,现在已支撑的码制式为EAN-8、EAN-13、UPC-A、UPC-E、Codabar、Code 39、Code 93、Code 128、ITF-14、QR Code、Data Matrix、PDF417、Aztec。开发者只需求供应字符串、码制式和尺度要求即可取得相应的码图。

集成进程

官方教程中【配备AppGallery Connect】进程,假如运用无上架需求,可以疏忽。

集成HMS Core SDK

配备HMS Core SDK的Maven仓地址

翻开Android Studio项目级“build.gradle”文件

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.5.0"
repositories {
google()
jcenter()
// 配备HMS Core SDK的Maven仓地址。
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
classpath "com.android.tools.build:gradle:4.2.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
jcenter()
// 配备HMS Core SDK的Maven仓地址。
maven {url 'https://developer.huawei.com/repo/'}
}
}

添加编译依托

翻开运用级的“build.gradle”文件,添加对应的编译依托。华为官方给我们供应了两种类型的依托包:

还在用 ZXing ? 试试华为统一扫码服务吧!

差异比较显着,包的巨细和辨认才干两个方面的影响,这儿为了展示 Scan Kit 的才干,我们选用才干更全面的 scanplus 系列。

implementation 'com.huawei.hms:scanplus:1.3.2.300'

运用开发

动态权限央求处理,不单独介绍,穿插于代码中,要点介绍下 Scan Kit 的四种方式:

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

Default View Mode

Default View Mode供应相机扫码和导入图片扫码两个功用,供应完好的Activity,不需求开发者开发扫码界面的UI。一键打开扫码,处理扫码效果即可,十分适合定制化要求不高的一般扫码场景。首要进程:

  • 创建扫码选项参数;
  • 启动扫码;
  • 结束回调接口接收扫码效果。
fun startDefaultMode(view: View) {
// 扫码选项参数
val options =
HmsScanAnalyzerOptions.Creator().setHmsScanTypes(HmsScan.ALL_SCAN_TYPE).create()
ScanUtil.startScan(
this, REQUEST_CODE_SCAN_DEFAULT_MODE,
options
)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != RESULT_OK || data == null) {
return
}
when (requestCode) {
REQUEST_CODE_SCAN_DEFAULT_MODE -> {
val hmsScan: HmsScan? = data.getParcelableExtra(ScanUtil.RESULT) // 获取扫码效果 ScanUtil.RESULT
if (!TextUtils.isEmpty(hmsScan?.getOriginalValue())) {
mBinding.tvResult.text = hmsScan?.getOriginalValue()
}
}
……
}
}

Customized View Mode

Customized View支撑开发者自定义扫码界面,扫码进程和相机控制将由Scan Kit结束。这种方式更适合对扫码界面有定制化要求的场景,凭借 Scan Kit 的扫码才干结束 UI 定制化需求。首要进程:

  • 自定义扫码页面元素;
  • 通过Customized View结束相机扫码功用【详细进程请看注释】。
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 从何而来。前面两种方式,我们只需求关系 UI 界面和扫码选项,而 Bitmap 方式愈加活络,你可以通过相机取帧的方法生成 Bitmap 进行检测,也可以通过图片文件转换成 Bitmap 进行检测等等,能 Bitmap 就能 检测,适用于图片识码等场景。首要进程:

  • 将数据转成 Bitmap (相机数据、文件等);
  • 初始化HmsScanAnalyzerOptions,设置支撑辨认的码制式和设置 Bitmap 方式为图片扫码方式;
  • 调用 ScanUtil的静态方法decodeWithBitmap建议扫码央求并获取扫码效果方针HmsScan
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

相机扫码、导入图片扫码,支撑一同检测多个码,支撑同步异步两种方法。这种方式是 Bitmap Mode 的连续,该方式下运用的 MLFrame需求运用 Bitmap 生成,当然我们也有其他方法生成MLFrame,但是 Bitmap 居多。首要进程:

  • 将数据转成 Bitmap (相机数据、文件等);

  • 初始化HmsScanAnalyzerOptions并设置支撑辨认的码制式;

  • 初始化HmsScanAnalyzer方针;

  • 将图像信息转换为MLFrameMLFrame为ML Kit封装的图像信息类;

  • 调用HmsScanAnalyzer方针的analyseFrame扫码方法建议扫码央求并获取扫码效果。

 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()
}
})
}

效果

Scan Kit 效果图

源码

github.com/onlyloveyd/…