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

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

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

支付宝 微信

摩拜 ofo

这里写图片描述

  • 导入开发资源的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_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)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Android应用中使用ZXing库来实现扫描二维码功能,您可以按照以下步骤操作: 1. 在您的项目中添加ZXing库的依赖。您可以在build.gradle文件中添加以下依赖: ```gradle implementation 'com.google.zxing:core:3.4.0' implementation 'com.journeyapps:zxing-android-embedded:3.6.0' ``` 2. 在您的布局文件中添加一个用于显示摄像头预览的SurfaceView: ```xml <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 3. 在您的代码中创建一个ZXing库的核心对象和一个用于处理扫描结果的回调函数: ```java private CaptureManager capture; private ZXingScannerView scannerView; private void initScanner() { scannerView = new ZXingScannerView(this); setContentView(scannerView); capture = new CaptureManager(this, scannerView); capture.initializeFromIntent(getIntent(), null); capture.decode(); scannerView.setResultHandler(new ResultHandler()); } private class ResultHandler implements ZXingScannerView.ResultHandler { @Override public void handleResult(Result rawResult) { // 处理扫描结果 String result = rawResult.getText(); // 在此处添加您的处理逻辑 // ... // 重新开始扫描 scannerView.resumeCameraPreview(this); } } ``` 4. 在您的Activity的onCreate方法中调用initScanner()方法来初始化扫描器: ```java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initScanner(); } ``` 5. 在您的Activity的onResume方法中调用capture.onResume()和scannerView.onResume()方法来恢复扫描器: ```java @Override protected void onResume() { super.onResume(); capture.onResume(); scannerView.onResume(); } ``` 6. 在您的Activity的onPause方法中调用capture.onPause()和scannerView.onPause()方法来暂停扫描器: ```java @Override protected void onPause() { super.onPause(); capture.onPause(); scannerView.onPause(); } ``` 7. (可选)您可以在您的Activity的onDestroy方法中调用capture.onDestroy()方法来释放扫描器: ```java @Override protected void onDestroy() { super.onDestroy(); capture.onDestroy(); } ``` 现在您的应用已经可以使用ZXing库来扫描二维码了。在您的应用中启动这个Activity,您将看到一个用于扫描二维码的摄像头预览界面。当您扫描到一个二维码时,它的内容将会传递给您在第3步中创建的ResultHandler对象的handleResult方法中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值