最近,我在学习实现安卓手机扫码功能,在网上搜了相关的资料,很多都是讲如何使用Zxing库来实现扫码功能的,但我照着做后,总是出现各类错误,本人能力有限,无法解决,烦恼不已。之后无意中在一篇文章的评论里,发现有网友推荐了华为统一扫码服务,出于对华为的好感,我决定试试,于是特意搜华为统一扫码服务相关的资料,在CSDN找到了两篇博文,并照着进行了设置和代码编辑,但出现了一些错误,导致无法调试。后来我又到华为开发者联盟网站里找到统一扫码服务的相关页面,研究了一番后,发现了问题所在,对配置进行了修改,总算能够实现扫码功能了。特写下这篇日志,记录一下过程。
一、参考资料
首先是发五个链接,是本次实现扫码功能参考的资料。
我先是按照下面第一个链接的文章对build.gradle文件进行了配置,但是在点“Sync Now”后,总是出现错误提示。之后又找到了第二篇文章,这篇文章给出了集成HMS Core SDK的官方文档地址(就是第三个链接),我是看了这个链接后才搞清楚,我错在哪里,并照着修改了配置,总算消除了错误。实现扫描的java代码也是参照的第二个链接里MainActivity.java中的内容。
第四个链接是华为的官方文档,介绍了华为统一扫码服务的开发环境和开发流程,学习官方文档能更好的了解华为统一扫码服务。
第五个链接是华为统一扫码服务默认扫码模式的官方文档,供参考。
Android 扫描二维码(使用华为统一扫码服务 + 附源码)
https://blog.csdn.net/qq_38436214/article/details/106282643?spm=1001.2014.3001.5506
Android扫码功能--华为统一扫码服务
https://blog.csdn.net/w15112532465/article/details/124818693?spm=1001.2014.3001.5506
华为统一扫码服务 - Android - 开发准备 - 集成HMS Core SDK
https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-integrating-sdk-0000001050042006
华为统一扫码服务 - Android - 使用入门
https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-dev-process-0000001050043953
华为统一扫码服务 - Default View Mode
https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/tutorials_ScanKit-DefaultView
二、集成HMS Core SDK
根据第三个链接里的说明,配置HMS Core SDK的Maven仓地址在Gradle插件7.0以下版本、7.0版本和7.1及以上版本有所不同。第一个链接发表于2020年,文章中的配置方法是针对Gradle插件为7.0以下版本的。而我的Gradle插件版本在Android Studio中查询是7.2的(见下图)。因此按第一个链接配置出错了。我按照官方文档中7.1及以上版本中的方法重新进行了配置,这次正常了。
1. 项目级“build.gradle”文件,增加Android Gradle插件配置。
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:7.2.0'
classpath 'com.huawei.agconnect:agcp:1.2.1.301'
}
}
2. 项目级“settings.gradle”文件,配置HMS Core SDK的Maven仓地址。
分别在pluginManagement和dependencyResolutionManagement中添加
maven { url 'https://developer.huawei.com/repo/' }
3. 应用级的“build.gradle”文件,添加依赖(SDK)和AGC插件。
3.1 根据官方文档说明,我添加的SDK是scanplus增强型的。
dependencies{
implementation 'com.huawei.hms:scan:1.1.3.301'
}
注意:SDK的版本说明可以在 华为统一扫码服务-Android-版本更新说明 内查到,示例是参考的第一个链接的内容编写的,我用1.1.3.301测试成功后,又尝试调整到更新的版本,也没问题。
3.2 AGC插件按方式二添加在plugins中
plugins {
id 'com.android.application'
// 添加如下配置
id 'com.huawei.agconnect'
}
完成以上设置后,点击界面上的“Sync Now”进行文件同步,过一会提示完成,没有出现错误。
三、配置混淆脚本
根据官方文档的要求,在“proguard-rules.pro”,加入排除统一扫码服务SDK的混淆配置脚本。
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.huawei.hianalytics.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
五、实现扫描功能代码
完成了前面的设置,就可以开始写代码了。
1. XML布局
代码如下:
2. java代码
Java代码部分,主要参考了第二个链接中的内容结合自己的开发目的,做了一点小小的调整。如将扫码类型修改为了“HmsScan.ALL_SCAN_TYPE”(参考了第五个链接的官方文档),以便能够扫码条形码。还增加了显示条形码类型。
代码如下:
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.Toast;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.huawei.hms.hmsscankit.ScanUtil;
import com.huawei.hms.ml.scan.HmsScan;
import com.huawei.hms.ml.scan.HmsScanAnalyzerOptions;
public class ScanQRCodeActivity extends AppCompatActivity implements View.OnClickListener {
private final static String TAG = "ScanQRCodeActivity";
private TextView qrCodeText;
private static final int REQUEST_CODE_SCAN_ONE = 99;
private static final int REQUEST_CODE_PERMISSION = 98;
// 扫码必须的权限
private final String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scan_qrcode);
findViewById(R.id.btn_scan).setOnClickListener(this); // 扫描二维码
qrCodeText = findViewById(R.id.tv_qrCodeText); // 显示扫码结果
}
@Override
public void onClick(View v) {
if(v.getId() == R.id.btn_scan ) { // 扫一扫
// 判断操作系统的版本,Android 6.0及以上需要动态申请权限
Log.d(TAG, "开始扫描");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
this.requestPermissions(permissions, REQUEST_CODE_PERMISSION);
} else {
startDefaultScanMode();
}
}
} // onClick-end
//开启默认扫码模式
private void startDefaultScanMode() {
// 要设置扫码类型,修改setHmsScanTypes()方法的参数 HmsScan.QRCODE_SCAN_TYPE, HmsScan.DATAMATRIX_SCAN_TYPE
HmsScanAnalyzerOptions options = new HmsScanAnalyzerOptions
.Creator()
.setHmsScanTypes(HmsScan.ALL_SCAN_TYPE)
.create();
ScanUtil.startScan(this, REQUEST_CODE_SCAN_ONE, options);
}
// 申请权限后的返回结果处理
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_PERMISSION) {
for (int grantResult : grantResults) {
if (grantResult == PackageManager.PERMISSION_DENIED) {
Toast.makeText(this, "需要开启该相机和存储权限才能正常使用扫码功能!", Toast.LENGTH_SHORT).show();
return;
}
}
startDefaultScanMode(); // 使用默认扫码模式
}
}
// 处理扫码结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_SCAN_ONE) {
//解析出扫码结果对象,并toast一下
HmsScan obj = data.getParcelableExtra(ScanUtil.RESULT);
if (obj != null) {
int scanType = obj.getScanType(); // 获取条码类型
//Toast.makeText(this, obj.originalValue, Toast.LENGTH_LONG).show();
String str = "结果:\n" + obj.originalValue + "\n条码类型:" + scanType;
qrCodeText.setText(str);
}
}
}
}
六、效果展示
最后展示一下运行效果。
1. 扫码二维码
在草料二维码网站生成一个二维码进行测试,正确识别到了输入的文字内容。
2. 扫码条形码
随手拿起身边的一包小零食测试扫码条形码,扫码结果与商品上的一致。