Scan Kit提供4种调用方式,您可以根据需求选择相应的调用方式构建扫码功能。
-
对于希望快速构建强大扫码功能的开发者,建议选择Default View Mode或者Customized View Mode。在这两种模式下,Scan Kit直接控制相机实现最优的相机Zoom控制、自适应的曝光调节、自适应对焦调节等操作,保障最佳的扫码体验,减少开发者的工作量。Default View Mode和Customized View Mode的区别在于后者支持开发者自定义扫码界面UI。
-
Bitmap Mode为开发者提供了充分的灵活性,对于希望完全自定义扫码流程并自行控制相机的开发者,可以选择Bitmap Mode构建您的扫码功能。当用户在扫描较小或者较远的二维码时,Scan Kit会返回需要放大的倍数给您的应用,您只需按照返回值调整相机焦距就能快速获取满足条件的图片。请注意,Scan Kit返回的放大倍数是通过检测结果和用户场景计算得出,建议您不要更改此放大倍数,否则可能会降低实际使用效果。
调用方式 | 扫码流程 | 扫码界面 | 功能 |
Default View Mode | Scan Kit处理 | Scan Kit提供 | 相机扫码,导入图片扫码 |
Customized View Mode | Scan Kit处理 | 开发者自定义 | 相机扫码(可以叠加Bitmap mode增加导入图片扫码功能) |
Bitmap Mode | 开发者应用处理 | 开发者自定义 | 相机扫码、导入图片扫码 |
MultiProcessor Mode | 开发者应用处理 | 开发者自定义 | 相机扫码、导入图片扫码;支持同时检测多个码,或者与ML Kit匹配实现同时识别码和人脸等其他对象 |
一、本篇主要实现Customized View Mode扫码
Customized View支持开发者自定义扫码界面,扫码过程和相机控制将由Scan Kit完成。
1、 业务流程
使用Customized View Mode的主要业务流程如下:
1. 用户打开应用发起扫码请求。
2. 校验是否有相机权限和文件读取权限。
3. 初始化应用定制的view,构建扫码界面,开始扫码。
4. 如果扫码成功,HMS SDK回调应用的“onResult”接口传递扫码结果。
5. 应用封装扫码结果返回给用户。
扫码速度很快,实现的效果图如下:
Scan Kit支持十多种码制式
Scan Kit支持扫描13种全球主流的码制式
已支持的码制式:
-
一维码:EAN-8、EAN-13、UPC-A、UPC-E、Codabar、Code 39、Code 93、Code 128、ITF
-
二维码:QR Code、Data Matrix、PDF417、Aztec
码制式 | int值 |
Code 128 | HmsScan.CODE128_SCAN_TYPE |
Code 39 | HmsScan.CODE39_SCAN_TYPE |
Code 93 | HmsScan.CODE93_SCAN_TYPE |
Codabar | HmsScan.CODABAR_SCAN_TYPE |
EAN-13 | HmsScan.EAN13_SCAN_TYPE |
EAN-8 | HmsScan.EAN8_SCAN_TYPE |
ITF | HmsScan. ITF14_SCAN_TYPE |
UPC-A | HmsScan.UPCCODE_A_SCAN_TYPE |
UPC-E | HmsScan.UPCCODE_E_SCAN_TYPE |
QR code | HmsScan.QRCODE_SCAN_TYPE |
PDF417 | HmsScan. PDF417_SCAN_TYPE |
Aztec | HmsScan. AZTEC_SCAN_TYPE |
Data Matrix | HmsScan. DATAMATRIX_SCAN_TYPE |
2、Android Studio环境开发流程:
2.1 相关配置如下:
1、创建HuaweiScan应用;
2、 配置HMS SDK的maven仓地址。
a. 打开AndroidStudio项目级build.gradle文件。
b. 在allprojects ->repositories里面配置HMS SDK的maven仓地址。
maven {url 'http://developer.huawei.com/repo/'}
c. 在buildscript->repositories里面配置HMS SDK的maven仓地址。
maven {url 'http://developer.huawei.com/repo/'}
d. 在buildscript ->dependencies里面增加配置。
classpath 'com.huawei.agconnect:agcp:1.2.1.301'
b. 引用SDK,Scan Kit提供两种SDK,您可以根据需求选择合适的SDK。
3、 添加编译依赖。
a. 打开应用级的build.gradle文件。
b. 引用SDK,Scan Kit提供两种SDK,您可以根据需求选择合适的SDK。
SDK | Scan Kit SDK-Plus | Scan Kit SDK | |
API及功能特性 | 相同 | 相同 | |
识别能力 | 华为手机 | Excellent(使用HMS Core内的增强识别模型) | Excellent(使用HMS Core内的增强识别模型) |
非华为手机 | Excellent(SDK自带的增强识别模型) | Good(SDK自带的普通识别模型) | |
SDK大小 | ≈3.3M | ≈0.8M | |
适用开发者 | 对SDK大小不敏感且希望所有机型均具备最佳体验的开发者 | 对SDK大小敏感的开发者 | |
坐标名称 | com.huawei.hms:scanplus:{version} | com.huawei.hms:scan:{version} |
如使用Scan Kit SDK,则在“dependencies”中添加如下编译依赖,{version} 需要替换为实际的SDK版本号,如当前版本: implementation 'com.huawei.hms:scan:1.1.1.301'。
dependencies{
implementation 'com.huawei.hms:scan:{version}'
// implementation 'com.huawei.hms:scanplus:1.1.1.301'
}
c. 在文件头添加配置。
aply plugin: 'com.huawei.agconnect'
4、修改完build.gradle文件,点击“Sync Now”等待同步完成。
5、多语言设置。
− 如果您的应用不需要设置只支持某些特定语言,则请忽略本步骤。应用将默认支持所有HMS SDK支持的语言。
− 如果您的应用需要设置只支持某些特定语言,则可通过本步骤配置:
在“android”->“defaultConfig”中新增resConfigs配置,“en-rGB”(英式英语) 和 “zh-rCN”(简体中文) 为必须配置的语种,配置格式如下:
android {
defaultConfig{
...
resConfigs "en-rGB", "zh-rCN", "需要支持的其他语言"
}
}
HMS SDK支持的语言列表请参考 HMS SDK支持的语言。
6、配置混淆脚本
如果开发者开启混淆配置,请按照如下步骤配置,避免HMS SDK相关代码被混淆导致功能异常。
1. 打开Android工程的混淆配置文件。
2. 加入排除HMS SDK的混淆配置。
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.**{*;}
3. 如果开发者使用了AndResGuard,需要在混淆配置文件中加入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*"
2.2 添加所需权限
Scan Kit时,开发者需要先在Manifest文件中中指定相应的权限。构建相机扫码功能,需要申请“CAMERA”(相机权限);构建导入图片扫码功能,需要申请“READ_EXTERNAL_STORAGE”(读文件权限)。
<!--相机权限-->
<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.3 创建修改扫码页面的操作
在默认的 MainActivity.java文件中修改对应的布局文件(activity_main.xml):上面一个按钮,点击后跳转到扫码界面,识别成功返回在button按钮下面显示扫码的码内容。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_sacning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="华为Sacn kit扫码"
android:textSize="18sp" />
<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Hello World!"
android:textSize="18sp" />
</LinearLayout>
- 动态获取权限:
btn_sacning.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//DEFINED_CODE为用户自定义用于接收权限校验结果
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE},
DEFINED_CODE);
}
});
- 处理动态获取的权限结果:
/**
* 权限返回的结果处理
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull 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, ScaningActivity.class), REQUEST_CODE_SCAN);
}
}
onActivityResult(...)对扫码返回的结果进行处理:
@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(ScaningActivity.SCAN_RESULT);
//自定义扫码界面返回的结果
if (hmsScan != null && !TextUtils.isEmpty(hmsScan.getOriginalValue())) {
// Toast.makeText(MainActivity.this, hmsScan.getOriginalValue(), Toast.LENGTH_SHORT).show();
if (tv_result != null) {
tv_result.setText(hmsScan.getOriginalValue());
}
}
}
}
完整的MainActivity 代码如下:
public class MainActivity extends AppCompatActivity {
public static final int DEFINED_CODE = 222;//请求权限的code值
private static final int REQUEST_CODE_SCAN = 0X01;//请求带返回结果的跳转code值
Button btn_sacning;
TextView tv_result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_sacning = (Button) findViewById(R.id.btn_sacning);
tv_result = (TextView) findViewById(R.id.tv_result);
btn_sacning.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//DEFINED_CODE为用户自定义用于接收权限校验结果
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE},
DEFINED_CODE);
}
});
}
/**
* 权限返回的结果处理
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull 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, ScaningActivity.class), REQUEST_CODE_SCAN);
}
}
@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(ScaningActivity.SCAN_RESULT);
if (hmsScan != null && !TextUtils.isEmpty(hmsScan.getOriginalValue())) {
//Toast.makeText(MainActivity.this, hmsScan.getOriginalValue(), Toast.LENGTH_SHORT).show();
if (tv_result != null) {
//显示扫码回来的内容
tv_result.setText(hmsScan.getOriginalValue());
}
}
}
}
}
扫码页面ScaningActivity.java 的处理:ScaningActivity.java对应的布局文件activity_scaning.xml (扫码布局页面可自定义样式)
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:my_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- customize layout needed by scankit for camera preview -->
<FrameLayout
android:id="@+id/rim"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#C0C0C0"></FrameLayout>
<!-- 自定义返回按钮 -->
<ImageView
android:id="@+id/back_img"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentStart="true"
android:layout_marginStart="12dp"
android:layout_marginTop="4dp"
android:gravity="center"
android:padding="12dp"
android:src="@drawable/back" />
<!-- customize scanning mask -->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:alpha="0.1"
android:background="#FF000000" />
<!-- customize scanning viewfinder -->
<ImageView
android:id="@+id/scan_view_finder"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:background="@drawable/scanningframe" />
</RelativeLayout>
设置scan_view_finder的背景样式;
<?xml version="1.0" encoding="utf-8"?><!-- 设置扫码框样式 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 设置边框的宽度和颜色 -->
<stroke
android:width="3dp"
android:color="#e1ffff" />
<!-- 设置框内的填充色 -->
<solid android:color="#1f00BCD4" />
<!-- 设置圆角 -->
<corners android:radius="5dip" />
<!-- 设置内边距 -->
<padding
android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp" />
</shape>
自定义布局的整体操作可参照官方Demo ,只需修改扫码的UI界面,再修改对应的代码。
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.Window;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.huawei.hms.hmsscankit.OnResultCallback;
import com.huawei.hms.hmsscankit.RemoteView;
import com.huawei.hms.ml.scan.HmsScan;
public class ScaningActivity extends Activity {
//声明 RemoteView instance
private RemoteView remoteView;
//声明 key,用于从scankit得到返回的值
public static final String SCAN_RESULT = "scanResult";
int mSceenWidth;
int mSceenHeight;
//scan_view_finder width & height is 300dp
final int SCAN_FRAME_SIZE = 300;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_scaning);
//1.设置扫码识别区域,您可以按照需求调整参数
DisplayMetrics dm = getResources().getDisplayMetrics();
float density = dm.density;
//2.获取屏幕尺寸
mSceenWidth = getResources().getDisplayMetrics().widthPixels;
mSceenHeight = getResources().getDisplayMetrics().heightPixels;
int scanFrameSize = (int) (SCAN_FRAME_SIZE * density);
//3.声明 viewfinder'的 矩形,在布局中间
//设置扫描区域(可选,矩形可以为空,如果不配置,默认是中心的布局)
Rect rect = new Rect();
rect.left = mSceenWidth / 2 - scanFrameSize / 2;
rect.right = mSceenWidth / 2 + scanFrameSize / 2;
rect.top = mSceenHeight / 2 - scanFrameSize / 2;
rect.bottom = mSceenHeight / 2 + scanFrameSize / 2;
//初始化RemoteView,并通过如下方法设置参数:
// setContext()(必选)传入context、setBoundingBox()设置扫描区域、
// setFormat()设置识别码制式,设置完毕调用build()方法完成创建
remoteView = new RemoteView.Builder().setContext(this).setBoundingBox(rect).setFormat(HmsScan.ALL_SCAN_TYPE).build();
//将自定义view加载到activity
remoteView.onCreate(savedInstanceState);
remoteView.setOnResultCallback(new OnResultCallback() {
@Override
public void onResult(HmsScan[] result) {
//获取到扫码结果HmsScan,判断结果是否有效
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);
ScaningActivity.this.finish();
}
}
});
//添加 remoteView 到Framelayout布局中
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
//绑定相机预览布局
FrameLayout frameLayout = findViewById(R.id.rim);
frameLayout.addView(remoteView, params);
//设置返回监听
ImageView backBtn = findViewById(R.id.back_img);
backBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ScaningActivity.this.finish();
}
});
}
//管理 remoteView 生命周期
@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();
}
}
不想使用自定义页面 更简单,可参照下一篇:
华为Scan Kit扫码服务功能:二、Default View Mode
更详细的细节描述请参考: