一、背景

之前一直用开源的Zxing来扫描二维码,但是随着使用场景的复杂,Zxing的识别就捉襟见肘了。很多场景下Zxing都很难识别,比如:绿底白纹的二维码;光线较暗的场景;二维码比较小的场景……

用户在识别的时候,会去与微信支付宝的二维码识别做比较,如果微信支付宝能识别,而我们自己的APP无法识别,用户评价就会极其糟糕。

我们这里就找到了更好的二维码识别方案,就是基于华为的HMS Core的二维码识别功能。

二、开发准备

​HMS Core官网​

1、首先登录​AppGallery Connect​网站,添加项目,项目中再添加应用。

2、在“项目设置 > 常规”页面的“应用”区域,点击“agconnect-services.json”下载配置文件。

Android扫描二维码(基于华为HMS Core)_HMS Core

3、将“agconnect-services.json”文件拷贝到应用级根目录下。

Android扫描二维码(基于华为HMS Core)_HMS Core_02

4、配置项目级的build.gradle

buildscript {
repositories {
google()
jcenter()
// 配置HMS Core SDK的Maven仓地址。
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
...
// 增加AGC插件配置,请您参见AGC插件依赖关系选择合适的AGC插件版本。
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}

allprojects {
repositories {
google()
jcenter()
// 配置HMS Core SDK的Maven仓地址。
maven {url 'https://developer.huawei.com/repo/'}
}
}

5、在app级的build.gradle中引用依赖

dependencies {
...
implementation 'com.huawei.hms:scan:2.6.0.300'
}

在文件头部声明

apply plugin: 'com.huawei.agconnect'

三、构建代码

1、调用默认界面
HmsScanAnalyzerOptions options = new HmsScanAnalyzerOptions.Creator()
.setHmsScanTypes(HmsScan.QRCODE_SCAN_TYPE, HmsScan.DATAMATRIX_SCAN_TYPE)//此处配置识别二维码格式
.create();
ScanUtil.startScan(this, REQUEST_CODE_SCAN_ONE, options);

使用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_ONE) {
// 导入图片扫描返回结果
HmsScan obj = data.getParcelableExtra(ScanUtil.RESULT);
if (obj != null) {
// 展示解码结果
showResult(obj);
}
}
}
2、自定义扫码界面

自定义Activity:DefinedActivity

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Bundle;
import android.provider.MediaStore;
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.OnLightVisibleCallBack;
import com.huawei.hms.hmsscankit.OnResultCallback;
import com.huawei.hms.hmsscankit.RemoteView;
import com.huawei.hms.hmsscankit.ScanUtil;
import com.huawei.hms.ml.scan.HmsScan;
import com.huawei.hms.ml.scan.HmsScanAnalyzerOptions;

import java.io.IOException;

public class DefinedActivity extends Activity {
private FrameLayout frameLayout;
private RemoteView remoteView;
private ImageView backBtn;
private ImageView imgBtn;
private ImageView flushBtn;
int mScreenWidth;
int mScreenHeight;
//The width and height of scan_view_finder is both 240 dp.
final int SCAN_FRAME_SIZE = 240;

private int[] img = {R.drawable.flashlight_on, R.drawable.flashlight_off};
private static final String TAG = "DefinedActivity";

//Declare the key. It is used to obtain the value returned from Scan Kit.
public static final String SCAN_RESULT = "scanResult";
public static final int REQUEST_CODE_PHOTO = 0X1113;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_defined);
// Bind the camera preview screen.
frameLayout = findViewById(R.id.rim);

//1. Obtain the screen density to calculate the viewfinder's rectangle.
DisplayMetrics dm = getResources().getDisplayMetrics();
float density = dm.density;
//2. Obtain the screen size.
mScreenWidth = getResources().getDisplayMetrics().widthPixels;
mScreenHeight = getResources().getDisplayMetrics().heightPixels;

int scanFrameSize = (int) (SCAN_FRAME_SIZE * density);

//3. Calculate the viewfinder's rectangle, which in the middle of the layout.
//Set the scanning area. (Optional. Rect can be null. If no settings are specified, it will be located in the middle of the layout.)
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;


//Initialize the RemoteView instance, and set callback for the scanning result.
remoteView = new RemoteView.Builder().setContext(this).setBoundingBox(rect).
// setFormat(HmsScan.ALL_SCAN_TYPE). //此处设置二维码格式
build();
// When the light is dim, this API is called back to display the flashlight switch.
flushBtn = findViewById(R.id.flush_btn);
remoteView.setOnLightVisibleCallback(new OnLightVisibleCallBack() {
@Override
public void onVisibleChanged(boolean visible) {
if(visible){
flushBtn.setVisibility(View.VISIBLE);
}
}
});
// Subscribe to the scanning result callback event.
remoteView.setOnResultCallback(new OnResultCallback() {
@Override
public void onResult(HmsScan[] result) {
//Check the 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();
}
}
});
// Load the customized view to the activity.
remoteView.onCreate(savedInstanceState);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
frameLayout.addView(remoteView, params);
// Set the back, photo scanning, and flashlight operations.
setBackOperation();
setPictureScanOperation();
setFlashOperation();
}

/**
* Call the lifecycle management method of the remoteView activity.
*/
private void setPictureScanOperation() {
imgBtn = findViewById(R.id.img_btn);
imgBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent pickIntent = new Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
DefinedActivity.this.startActivityForResult(pickIntent, REQUEST_CODE_PHOTO);

}
});
}

private void setFlashOperation() {
flushBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (remoteView.getLightStatus()) {
remoteView.switchLight();
flushBtn.setImageResource(img[1]);
} else {
remoteView.switchLight();
flushBtn.setImageResource(img[0]);
}
}
});
}

private void setBackOperation() {
backBtn = findViewById(R.id.back_img);
backBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DefinedActivity.this.finish();
}
});
}

/**
* Call the lifecycle management method of the remoteView activity.
*/
@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();
}

/**
* Handle the return results from the album.
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_PHOTO) {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), data.getData());
HmsScan[] hmsScans = ScanUtil.decodeWithBitmap(DefinedActivity.this, bitmap, new HmsScanAnalyzerOptions.Creator().setPhotoMode(true).create());
if (hmsScans != null && hmsScans.length > 0 && hmsScans[0] != null && !TextUtils.isEmpty(hmsScans[0].getOriginalValue())) {
Intent intent = new Intent();
intent.putExtra(SCAN_RESULT, hmsScans[0]);
setResult(RESULT_OK, intent);
DefinedActivity.this.finish();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

调用DefinedActivity

Intent intent = new Intent(mUniSDKInstance.getContext(), DefinedActivity.class);
((Activity)mUniSDKInstance.getContext()).startActivityForResult(intent, REQUEST_CODE);

接收结果

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == REQUEST_CODE && data.hasExtra("respond")) {
Log.e("Test", "原生页面返回----"+data.getStringExtra("respond"));

} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
3、图片解析模式

还有种解析图片的模式,这里就不做介绍了,自行查找​​官网​​中的说明。