华为统一扫码服务(Scan Kit)提供便捷的条形码和二维码扫描、解析、生成能力,帮助您快速构建应用内的扫码功能。
得益于华为在计算机视觉领域能力的积累,Scan Kit可以实现远距离码或小型码的检测和自动放大,同时针对常见复杂扫码场景(如反光、暗光、污损、模糊、柱面)做了针对性识别优化,提升扫码成功率与用户体验。
在这个Codelab中,你将创建一个使用Customized View Mode的扫码App。
若您需要正式发布集成Scan Kit的应用,请参考《HUAWEI HMS Core 集成准备》中详细说明来完成接入准备。
若您使用本Codelab Demo验证时,直接使用Sample Code中的设置,可以跳过此步骤。
针对Android Studio开发环境,华为提供了Maven仓集成方式的HMS Core SDK包。在开始开发前,您需要将HMS Core SDK集成到您的Android Studio开发环境中。
如果在AppGallery Connect中开通了相关服务则需要将"agconnect-services.json"文件添加到您的App中
1. 打开Android Studio项目级"build.gradle"文件。
2. 添加HUAWEI agcp插件以及Maven代码库。
buildscript {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
...
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
}
}
allprojects {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
}
dependencies {
implementation 'com.huawei.hms:scan:{version}'
}
apply plugin: 'com.huawei.agconnect'
在调用Scan Kit时,开发者需要先在Manifest中声明相应的权限。Android提供了两种扫码权限:CAMERA
(相机权限)和READ_EXTERNAL_STORAGE
(读文件权限)。
在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" />
声明权限后,还需要在代码中动态申请一下权限。在MainActivity.java
中,增加:
Java示例代码:
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) {
//跳转转扫码界面
this.startActivityForResult(new Intent(this, DefinedActivity.class), REQUEST_CODE_SCAN);
}
}
Kotlin示例代码:
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),
DEFAULT_VIEW)
}
}
override public fun onRequestPermissionsResult(requestCode:Int, permissions:Array<out String>, grantResults:IntArray) {
if (permissions == null || grantResults == null || grantResults.length < 2 || grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) {
return
}
if (requestCode == DEFINED_CODE) {
//跳转转扫码界面
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示例代码:
//请按AndroidStudio建议,导入所有依赖
int SCAN_FRAME_SIZE=200;
private RemoteView remoteView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_defined);
//1.获取屏幕分辨率来计算扫描框的尺寸
DisplayMetrics dm = getResources().getDisplayMetrics();
float density = dm.density;
//2.获取屏幕尺寸
mScreenWidth = getResources().getDisplayMetrics().widthPixels;
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 remoteView:RemoteView?=null
override protected fun onCreate(savedInstanceState:Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_defined)
//1.获取屏幕分辨率来计算扫描框的尺寸
val dm = resources.displayMetrics
val density = dm.density
//2.获取屏幕尺寸
mScreenWidth = resources.displayMetrics.widthPixels
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.length > 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.rim)
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) {
//Receive result
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?) {
//Receive result
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != RESULT_OK || data == null) {
return
}
if (requestCode == REQUEST_CODE_SCAN) {
var hmsScan = data?.getParcelableExtra(DefinedActivity.SCAN_RESULT)
if (hmsScan != null && !TextUtils.isEmpty(hmsScan?.getOriginalValue())) {
Toast.makeText(this@MainActivity, hmsScan?.getOriginalValue(), Toast.LENGTH_SHORT).show()
}
}
}
完成开发后,点击开发界面上的运行图标,运行Android Studio工程打包生成APK,并安装在测试手机上。
首次进入应用时的界面:
点击 Customized View Mode:
扫码后返回结果:
干得好,你已经成功完成了Codelab并学到了:
如需了解更多与华为Scan Kit相关的信息,请关注我们的官方网站。开发过程中如果遇见问题,请参考我们的常见问题解答。
您可以阅读下面链接,了解更多相关的信息。
点击下方按钮下载源码。