简介

统一扫码服务(Scan Kit)提供便捷的条形码和二维码扫描、解析、生成能力,帮助您快速构建应用内的扫码功能。
得益于华为在计算机视觉领域能力的积累,Scan Kit可以实现远距离码或小型码的检测和自动放大,同时针对常见复杂扫码场景(如反光、暗光、污损、模糊、柱面)做了针对性识别优化,提升扫码成功率与用户体验。

您将建立什么

在本篇codelab中,你将创建一个使用Customized View Mode的扫码App。

您将会学到什么

硬件要求

若您需要正式发布集成Scan Kit的应用,请参见《HUAWEI HMS Core 集成准备》中详细说明来完成接入准备。

针对Android Studio开发环境,华为提供了Maven仓集成方式的HMS Core SDK包。在开始开发前,您需要将HMS Core SDK集成到您的Android Studio开发环境中。

添加当前应用的AppGallery Connect配置文件

如果在AppGallery Connect中开通了相关服务则需要将"agconnect-services.json"文件添加到您的App中。

  1. 登录AppGallery Connect网站,点击"我的项目"。
  2. 在项目列表中找到您的项目,在项目中点击需要集成HMS Core SDK的应用。
  3. 在"项目设置 > 常规"页面的"应用"区域,点击"agconnect-services.json"下载配置文件。
  4. 将"agconnect-services.json"文件拷贝到应用级根目录下。

配置HMS Core SDK的Maven仓地址

  1. 打开Android Studio项目级"build.gradle"文件。
  2. 添加HUAWEI agcp插件以及Maven代码库。
    • 在"buildscript > repositories"中配置HMS Core SDK的Maven仓地址。
    • 在"allprojects > repositories"中配置HMS Core SDK的Maven仓地址。
    • 如果App中添加了"agconnect-services.json"文件则需要在"buildscript > dependencies"中增加agcp插件配置。
      buildscript { repositories { google() jcenter() // 配置HMS Core SDK的Maven仓地址。 maven {url 'https://developer.huawei.com/repo/'} } dependencies { ... // 增加agcp插[最新版本](https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/agc-sdk-changenotes-0000001058732550)推荐您使用最新版本的agcp插件。 classpath 'com.huawei.agconnect:agcp:1.6.0.300' } } allprojects { repositories { google() jcenter() // 配置HMS Core SDK的Maven仓地址。 maven {url 'https://developer.huawei.com/repo/'} } }

添加编译依赖

  1. 打开应用级的"build.gradle"文件。
  2. 在"dependencies"中添加如下编译依赖,{version}需要替换为实际的SDK版本号,版本号索引请参见版本更新说明。如当前版本:implementation ‘com.huawei.hms:scan:1.3.2.300'。
    dependencies { implementation 'com.huawei.hms:scan:{version}' }
  3. 添加agcp插件配置。请根据实际情况选择:
    • 方式一:在文件头部声明下一行添加如下配置。
      apply plugin: 'com.huawei.agconnect'
    • 方式二:在plugins中添加如下配置。
      plugins { id 'com.android.application' // 添加如下配置 id 'com.huawei.agconnect' }
  4. 同步工程。在完成以上的配置后,点击工具栏中的gradle同步图标,完成"build.gradle"文件的同步,将相关依赖下载到本地。
  1. 在调用Scan Kit时,您需要先在AndroidManifest.xml文件中声明相应的权限。Android提供了两种扫码权限:CAMERA(相机权限)和READ_EXTERNAL_STORAGE(读文件权限)。如果已在Sample code中申请权限,不需要重复申请。
    <!--相机权限--> <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" />
  2. 声明权限后,还需要在代码中动态申请一下权限。在MainActivity.java中,增加:
    Java示例代码:
    public static final int DEFINED_CODE = 222; public static final int REQUEST_CODE_SCAN = 111; public void newViewBtnClick(View view) { // DEFINED_CODE为用户自定义用于接收权限校验结果。 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { this.requestPermissions( new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, DEFINED_CODE); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (permissions == null || grantResults == null || grantResults.length < 2 || grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) { return; } if (requestCode == DEFINED_CODE) { // 跳转到DefinedActivity自定义扫码页面。 this.startActivityForResult(new Intent(this, DefinedActivity.class), REQUEST_CODE_SCAN); } }

    Kotlin示例代码:

    val DEFINED_CODE = 222 val REQUEST_CODE_SCAN = 111 fun newViewBtnClick(view:View?) { // DEFINED_CODE为用户自定义用于接收权限校验结果。 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { this.requestPermissions( arrayOf(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE), DEFINED_CODE) } } override fun onRequestPermissionsResult(requestCode:Int, permissions:Array<out String>, grantResults:IntArray) { if (permissions == null || grantResults.size < 2 || grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) { return } if (requestCode == DEFINED_CODE) { // 跳转到DefinedActivity自定义扫码页面。 this.startActivityForResult(Intent(this, DefinedActivity::class.java), REQUEST_CODE_SCAN) } }

Scan Kit提供4种不同的调用模式,具体的差别请参见开发指南。本codelab选择了Customized View Mode进行开发,实现扫码功能。

自定义页面元素

开发者按需自定义页面元素,比如扫码框、扫码提示。详情请参见Customized View自定义页面元素

实现相机扫码操作

在自定义的Activity实现相机扫码操作,在Sample Code DefinedActivity.java文件中,增加:
Java示例代码:

// 请按Android Studio建议,导入所有依赖。 int SCAN_FRAME_SIZE=200; private RemoteView remoteView; public static final String SCAN_RESULT = "scanResult"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_defined); // 1.获取屏幕分辨率来计算扫描框的尺寸。 DisplayMetrics dm = getResources().getDisplayMetrics(); float density = dm.density; // 2.获取屏幕尺寸。 int mScreenWidth = getResources().getDisplayMetrics().widthPixels; int mScreenHeight = getResources().getDisplayMetrics().heightPixels; int scanFrameSize = (int) (SCAN_FRAME_SIZE * density); // 3.计算扫描框位置,当前扫描框在屏幕中间。 // 设置扫描框位置(可选配置,如果不设置默认在屏幕中间)。 Rect rect = new Rect(); rect.left = mScreenWidth / 2 - scanFrameSize / 2; rect.right = mScreenWidth / 2 + scanFrameSize / 2; rect.top = mScreenHeight / 2 - scanFrameSize / 2; rect.bottom = mScreenHeight / 2 + scanFrameSize / 2; // 初始化RemoteView并设置回调函数接收扫码结果。 remoteView = new RemoteView.Builder().setContext(this).setBoundingBox(rect).setFormat(HmsScan.ALL_SCAN_TYPE).build(); remoteView.setOnResultCallback(new OnResultCallback() { @Override public void onResult(HmsScan[] result) { if (result != null && result.length > 0 && result[0] != null && !TextUtils.isEmpty(result[0].getOriginalValue())) { Intent intent = new Intent(); intent.putExtra(SCAN_RESULT, result[0]); setResult(RESULT_OK, intent); DefinedActivity.this.finish(); } } }); // 将定义好的RemoteView添加到页面布局中。 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); FrameLayout frameLayout = findViewById(R.id.rim); frameLayout.addView(remoteView, params); }

Kotlin示例代码:

// 请按AndroidStudio建议,导入所有依赖。 private var remoteView:RemoteView?=null val SCAN_RESULT = "scanResult" override fun onCreate(savedInstanceState:Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_defined) // 1.获取屏幕分辨率来计算扫描框的尺寸。 val dm = resources.displayMetrics val density = dm.density // 2.获取屏幕尺寸。 var mScreenWidth = resources.displayMetrics.widthPixels var mScreenHeight = resources.displayMetrics.heightPixels var scanFrameSize = (SCAN_FRAME_SIZE * density) // 3.计算扫描框位置,当前扫描框在屏幕中间。 // 设置扫描框位置(可选配置,如果不设置默认在屏幕中间)。 val rect = Rect() 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() // 初始化RemoteView并设置回调函数接收扫码结果。 remoteView = RemoteView.Builder().setContext(this).setBoundingBox(rect).setFormat(HmsScan.ALL_SCAN_TYPE).build() remoteView?.setOnResultCallback{result-> if (result != null && result.size > 0 && result[0] != null && !TextUtils.isEmpty(result[0]!!.getOriginalValue())) { val intent = Intent() intent.putExtra(SCAN_RESULT, result[0]) setResult(RESULT_OK, intent) this@DefinedActivity.finish() } } // 将定义好的RemoteView添加到页面布局中。 val params = FrameLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT) val frameLayout = findViewById(R.id.rim1) frameLayout.addView(remoteView, params) }

添加RemoteView的生命周期管理,在Sample Code DefinedActivity.java文件中,增加如下代码:
Java示例代码:

@Override protected void onStart() { super.onStart(); remoteView.onStart(); } @Override protected void onResume() { super.onResume(); remoteView.onResume(); } @Override protected void onPause() { super.onPause(); remoteView.onPause(); } @Override protected void onDestroy() { super.onDestroy(); remoteView.onDestroy(); } @Override protected void onStop() { super.onStop(); remoteView.onStop(); }

Kotlin示例代码:

override protected fun onStart() { super.onStart() remoteView?.onStart() } override protected fun onResume() { super.onResume() remoteView?.onResume() } override protected fun onPause() { super.onPause() remoteView?.onPause() } override protected fun onDestroy() { super.onDestroy() remoteView?.onDestroy() } override protected fun onStop() { super.onStop() remoteView?.onStop() }

处理扫码结果

在MainActivity中处理扫码结果,在Sample Code MainActivity.java文件中,增加:
Java示例代码:

@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // 接收结果。 super.onActivityResult(requestCode, resultCode, data); if (resultCode != RESULT_OK || data == null) { return; } if (requestCode == REQUEST_CODE_SCAN) { HmsScan hmsScan = data.getParcelableExtra(DefinedActivity.SCAN_RESULT); if (hmsScan != null && !TextUtils.isEmpty(hmsScan.getOriginalValue())) { Toast.makeText(MainActivity.this, hmsScan.getOriginalValue(), Toast.LENGTH_SHORT).show(); } } }

Kotlin示例代码:

override protected fun onActivityResult(requestCode:Int, resultCode:Int, data:Intent?) { // 接收结果。 super.onActivityResult(requestCode, resultCode, data) if (resultCode != RESULT_OK || data == null) { return } if (requestCode == REQUEST_CODE_SCAN) { var hmsScan = data?.getParcelableExtra<HmsScan>(DefinedActivity.SCAN_RESULT) if (hmsScan != null && !TextUtils.isEmpty(hmsScan?.getOriginalValue())) { Toast.makeText(this@MainActivity, hmsScan?.getOriginalValue(), Toast.LENGTH_SHORT).show() } } }

完成开发后,点击开发界面上的运行图标,运行Android Studio工程打包生成APK,并安装在测试手机上。

干得好,你已经成功完成了codelab并学到了:

如需了解更多与华为Scan Kit相关的信息,请关注我们的官方网站。开发过程中如果遇见问题,请参考我们的常见问题解答

您可以阅读下面链接,了解更多相关的信息。

点击下载源码
Code copied