您的位置:首页 > 移动开发 > Android开发

[置顶] Android移动开发-在Android项目里集成开源框架ZXing实现扫描二维码的功能

2017-11-23 15:49 976 查看
二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型。

二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集;每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识别功能、及处理图形旋转变化点。

那么在Android项目里集成Google开源框架ZXing实现扫描二维码的功能呢?

在集成二维码之前,我们先看一下国内比较主流用到的二维码的手机应用的二维码界面(以下截图分别是支付宝、微信、摩拜单车、ofo单车)









首先下载或直接引入zxing开源项目,项目的github地址:https://github.com/zxing/zxing/tree/zxing-3.2.1



导入开发资源的jar包并引入



在AndroidManifest.xml文件里配置Manifest里的权限声明

<!-- 拍照 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<!-- 震动 -->
<uses-permission android:name="android.permission.VIBRATE" />


在AndroidManifest.xml文件里面添加声明:

<activity android:name=".FindScanActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ScanResultActivity"/>
</application>


把ZXing相应的项目文件导入



在res目录下新建raw目录,并把扫描识别时的震动声音文件beep.ogg导入



-开始扫描时的界面, layout/layout/activity_find_scan.xml界面布局代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<SurfaceView
android:id="@+id/sv_scan"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />

<com.fukaimei.scanqrcodetest.zxing.view.ViewfinderView
android:id="@+id/vv_finder"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="@drawable/bg_alpha"
android:gravity="center"
android:text="扫描二维码/条形码"
android:textColor="#ffffffff"
android:textSize="20sp" />

</RelativeLayout>


开始扫描时FindScanActivity.java逻辑代码如下:

package com.fukaimei.scanqrcodetest;

import java.io.IOException;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.widget.Toast;

import com.fukaimei.scanqrcodetest.zxing.camera.CameraManager;
import com.fukaimei.scanqrcodetest.zxing.decoding.CaptureActivityHandler;
import com.fukaimei.scanqrcodetest.zxing.decoding.InactivityTimer;
import com.fukaimei.scanqrcodetest.zxing.view.ViewfinderView;
import com.google.zxing.Result;

public class FindScanActivity extends Activity implements SurfaceHolder.Callback {
private final static String TAG = "FindScanActivity";
private CaptureActivityHandler mHandler;
private ViewfinderView vv_finder;
private boolean hasSurface = false;
private InactivityTimer mTimer;
private MediaPlayer mPlayer;
private boolean bBeep;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_find_scan);
// 获取相机的动态权限
cameraPermissions();
CameraManager.init(getApplication(), CameraManager.QR_CODE);
vv_finder = (ViewfinderView) findViewById(R.id.vv_finder);
mTimer = new InactivityTimer(this);
}

// 定义获取相机的动态权限
private void cameraPermissions() {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{
android.Manifest.permission.CAMERA}, 1);
}
}

/**
* 重写onRequestPermissionsResult方法
* 获取动态权限请求的结果,再开启相机扫码
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
CameraManager.init(getApplication(), CameraManager.QR_CODE);
} else {
Toast.makeText(this, "用户拒绝了权限", Toast.LENGTH_SHORT).show();
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

@Override
protected void onResume() {
super.onResume();
SurfaceView sv_scan = (SurfaceView) findViewById(R.id.sv_scan);
SurfaceHolder surfaceHolder = sv_scan.getHolder();
if (hasSurface) {
initCamera(surfaceHolder);
} else {
surfaceHolder.addCallback(this);
}
bBeep = true;
AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
bBeep = false;
}
initBeepSound();
}

@Override
protected void onPause() {
super.onPause();
if (mHandler != null) {
mHandler.quitSynchronously();
mHandler = null;
}
CameraManager.get().closeDriver();
}

@Override
protected void onDestroy() {
mTimer.shutdown();
super.onDestroy();
}

public void handleDecode(Result result, Bitmap barcode) {
mTimer.onActivity();
beepAndVibrate();
String resultString = result.getText();
if (resultString == null || resultString.length() <= 0) {
Toast.makeText(this, "Scan failed or result is null", Toast.LENGTH_SHORT).show();
} else {
String desc = String.format("barcode width=%d,height=%d",
barcode.getWidth(), barcode.getHeight());
//            Toast.makeText(this, desc, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(this, ScanResultActivity.class);
intent.putExtra("result", resultString);
startActivity(intent);
}
}

private void initCamera(SurfaceHolder surfaceHolder) {
try {
CameraManager.get().openDriver(surfaceHolder);
if (mHandler == null) {
mHandler = new CaptureActivityHandler(this, null, null);
}
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!hasSurface) {
hasSurface = true;
initCamera(holder);
}
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
hasSurface = false;
}

public ViewfinderView getViewfinderView() {
return vv_
afb3
finder;
}

public Handler getHandler() {
return mHandler;
}

public void drawViewfinder() {
vv_finder.drawViewfinder();
}

private void initBeepSound() {
if (bBeep && mPlayer == null) {
setVolumeControlStream(AudioManager.STREAM_MUSIC);
mPlayer = new MediaPlayer();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setOnCompletionListener(beepListener);
AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
try {
mPlayer.setDataSource(file.getFileDescriptor(),
file.getStartOffset(), file.getLength());
file.close();
mPlayer.setVolume(0.1f, 0.1f);
mPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
mPlayer = null;
}
}
}

private static final long VIBRATE_DURATION = 200L;

private void beepAndVibrate() {
if (bBeep && mPlayer != null) {
mPlayer.start();
}
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
vibrator.vibrate(VIBRATE_DURATION);
}

private final OnCompletionListener beepListener = new OnCompletionListener() {
public void onCompletion(MediaPlayer mPlayer) {
mPlayer.seekTo(0);
}
};

}


扫描识别结果返回的界面, layout/layout/activity_scan_result.xml界面布局代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">

<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="17sp" />

</LinearLayout>


扫描识别结果返回的ScanResultActivity.java逻辑代码如下:

package com.fukaimei.scanqrcodetest;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class ScanResultActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scan_result);
TextView tv_result = (TextView) findViewById(R.id.tv_result);
String result = getIntent().getStringExtra("result");
tv_result.setText("扫码结果为:" + result);
}

}


Demo程序运行效果界面截图如下:





Demo程序源码下载地址一(GitHub)

Demo程序源码下载地址二(Gitee)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐