Android Zxing實現掃描二維碼條形碼功能仿微信整合閃光燈生成二維碼
阿新 • • 發佈:2018-12-14
最近在做android專案需要用到二維碼條形碼掃描功能,我用的是Eclipse網上原始碼大多是GitHup上的Android studio版本的所以我改了一版整合到專案中去。
效果圖:
左邊版本的掃碼框是自定義的。右邊版本的掃碼框和掃描線是圖片因為太醜所以最終換成左邊樣式。
自定義版本我是仿著微信的樣式大小來做的。
整合步驟:
以左邊圖片樣式為例
1.首先將原始碼中com.google.zxing五個包引入到自己的專案中。
2.拷貝資源目錄raw至本專案中,beep.ogg是掃描成功時的提示音。
3.拷貝或合併檔案內容values裡面的xml檔案。
4.許可權配置在AndroidManifest.xml中新增許可權申請程式碼:
<uses-permission android:name="android.permission.INTERNET" /> <!-- 網路許可權 --> <uses-permission android:name="android.permission.VIBRATE" /> <!-- 震動許可權 --> <uses-permission android:name="android.permission.CAMERA" /> <!-- 攝像頭許可權 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <!-- 自動聚焦許可權 -->
還要配置CaptureActivity.java
功能實現:
完成上述整合之後,通過呼叫CaptureActivity就可以實現掃碼功能。 MainActivity原始碼部分:
package com.example.scandemo2; import android.Manifest; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import com.dommy.qrcode.util.Constant; import com.google.zxing.activity.CaptureActivity; public class MainActivity extends Activity implements View.OnClickListener { Button btnQrCode; // 掃碼 TextView tvResult; // 結果 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { btnQrCode = (Button) findViewById(R.id.btn_qrcode); btnQrCode.setOnClickListener(this); tvResult = (TextView) findViewById(R.id.txt_result); } // 開始掃碼 private void startQrCode() { // 二維碼掃碼 Intent intent = new Intent(MainActivity.this, CaptureActivity.class); startActivityForResult(intent, Constant.REQ_QR_CODE); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.btn_qrcode: startQrCode(); break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); //掃描結果回撥 if (requestCode == Constant.REQ_QR_CODE && resultCode == RESULT_OK) { Bundle bundle = data.getExtras(); String scanResult = bundle.getString(Constant.INTENT_EXTRA_KEY_QR_SCAN); //將掃描出的資訊顯示出來 tvResult.setText(scanResult); } } }
activity_scanner.xml
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/scanner_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />
<ImageButton
android:onClick="btn_back"
android:layout_width="40dip"
android:layout_height="40dip"
android:padding="10dip"
android:scaleType="centerCrop"
android:background="#00000000"
android:src="@drawable/btn_back" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="17sp"
android:layout_x="0dp"
android:layout_y="0dp"
android:text="二維碼/條碼"
android:gravity="center"
android:textColor="#FFFFFF"
/>
<com.google.zxing.view.ViewfinderView
android:id="@+id/viewfinder_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:corner_color="@color/corner_color"
app:frame_color="@color/viewfinder_frame"
app:label_text="將二維碼/條形碼放入框內,即可自動掃描"
app:label_text_color="@color/colorAccent"
app:laser_color="@color/laser_color"
app:mask_color="@color/viewfinder_mask"
app:result_color="@color/result_view"
app:result_point_color="@color/result_point_color" />
<ImageButton
android:id="@+id/btn_flash"
android:layout_width="40dip"
android:layout_height="40dip"
android:padding="6dip"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="80dip"
android:scaleType="centerInside"
android:src="@drawable/flash_off"
android:background="#00000000" />
<TextView
android:text="輕觸照亮"
android:layout_width="80dip"
android:layout_height="20dip"
android:layout_marginBottom="80dp"
android:layout_marginLeft="168dp"
android:layout_marginTop="550dp"
android:textColor="#FFFFFF" />
</FrameLayout>
</LinearLayout>
CaptureActivity.java
package com.google.zxing.activity;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.dommy.qrcode.util.Constant;
import com.dommy.qrcode.util.UriUtil;
import com.example.scandemo2.R;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.DecodeHintType;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.camera.CameraManager;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.decoding.CaptureActivityHandler;
import com.google.zxing.decoding.InactivityTimer;
import com.google.zxing.decoding.RGBLuminanceSource;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.view.ViewfinderView;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;
public class CaptureActivity extends Activity implements Callback {
private static final int REQUEST_CODE_SCAN_GALLERY = 100;
private CaptureActivityHandler handler;
private ViewfinderView viewfinderView;
private ImageButton back;
private ImageButton btnFlash;
private Button btnAlbum; // 相簿
private boolean isFlashOn = false;
private boolean hasSurface;
private Vector<BarcodeFormat> decodeFormats;
private String characterSet;
private InactivityTimer inactivityTimer;
private MediaPlayer mediaPlayer;
private boolean playBeep;
private static final float BEEP_VOLUME = 0.10f;
private boolean vibrate;
private ProgressDialog mProgress;
private String photo_path;
private Bitmap scanBitmap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scanner);
CameraManager.init(getApplication());
viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_content);
btnFlash = (ImageButton) findViewById(R.id.btn_flash);
btnFlash.setOnClickListener(flashListener);
hasSurface = false;
inactivityTimer = new InactivityTimer(this);
}
//返回
public void btn_back(View view){
this.finish();
}
@Override
protected void onActivityResult(final int requestCode, int resultCode, Intent data) {
if (resultCode==RESULT_OK) {
switch (requestCode) {
case REQUEST_CODE_SCAN_GALLERY:
handleAlbumPic(data);
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
/**
* 處理選擇的圖片
* @param data
*/
private void handleAlbumPic(Intent data) {
//獲取選中圖片的路徑
photo_path = UriUtil.getRealPathFromUri(CaptureActivity.this, data.getData());
mProgress = new ProgressDialog(CaptureActivity.this);
mProgress.setMessage("正在掃描...");
mProgress.setCancelable(false);
mProgress.show();
runOnUiThread(new Runnable() {
@Override
public void run() {
mProgress.dismiss();
Result result = scanningImage(photo_path);
if (result != null) {
Intent resultIntent = new Intent();
Bundle bundle = new Bundle();
bundle.putString(Constant.INTENT_EXTRA_KEY_QR_SCAN ,result.getText());
resultIntent.putExtras(bundle);
CaptureActivity.this.setResult(RESULT_OK, resultIntent);
finish();
} else {
Toast.makeText(CaptureActivity.this, "識別失敗", Toast.LENGTH_SHORT).show();
}
}
});
}
/**
* 掃描二維碼圖片的方法
* @param path
* @return
*/
public Result scanningImage(String path) {
if(TextUtils.isEmpty(path)){
return null;
}
Hashtable<DecodeHintType, String> hints = new Hashtable<>();
hints.put(DecodeHintType.CHARACTER_SET, "UTF8"); //設定二維碼內容的編碼
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 先獲取原大小
scanBitmap = BitmapFactory.decodeFile(path, options);
options.inJustDecodeBounds = false; // 獲取新的大小
int sampleSize = (int) (options.outHeight / (float) 200);
if (sampleSize <= 0)
sampleSize = 1;
options.inSampleSize = sampleSize;
scanBitmap = BitmapFactory.decodeFile(path, options);
RGBLuminanceSource source = new RGBLuminanceSource(scanBitmap);
BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
try {
return reader.decode(bitmap1, hints);
} catch (NotFoundException e) {
e.printStackTrace();
} catch (ChecksumException e) {
e.printStackTrace();
} catch (FormatException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onResume() {
super.onResume();
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.scanner_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
if (hasSurface) {
initCamera(surfaceHolder);
} else {
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
decodeFormats = null;
characterSet = null;
playBeep = true;
AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
playBeep = false;
}
initBeepSound();
vibrate = true;
}
@Override
protected void onPause() {
super.onPause();
if (handler != null) {
handler.quitSynchronously();
handler = null;
}
CameraManager.get().closeDriver();
}
@Override
protected void onDestroy() {
inactivityTimer.shutdown();
super.onDestroy();
}
/**
* Handler scan result
*
* @param result
* @param barcode
*/
public void handleDecode(Result result, Bitmap barcode) {
inactivityTimer.onActivity();
playBeepSoundAndVibrate();
String resultString = result.getText();
//FIXME
if (TextUtils.isEmpty(resultString)) {
Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();
} else {
Intent resultIntent = new Intent();
Bundle bundle = new Bundle();
bundle.putString(Constant.INTENT_EXTRA_KEY_QR_SCAN, resultString);
resultIntent.putExtras(bundle);
this.setResult(RESULT_OK, resultIntent);
}
CaptureActivity.this.finish();
}
private void initCamera(SurfaceHolder surfaceHolder) {
try {
CameraManager.get().openDriver(surfaceHolder);
} catch (IOException ioe) {
return;
} catch (RuntimeException e) {
return;
}
if (handler == null) {
handler = new CaptureActivityHandler(this, decodeFormats,
characterSet);
}
}
@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 viewfinderView;
}
public Handler getHandler() {
return handler;
}
public void drawViewfinder() {
viewfinderView.drawViewfinder();
}
private void initBeepSound() {
if (playBeep && mediaPlayer == null) {
setVolumeControlStream(AudioManager.STREAM_MUSIC);
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnCompletionListener(beepListener);
AssetFileDescriptor file = getResources().openRawResourceFd(
R.raw.beep);
try {
mediaPlayer.setDataSource(file.getFileDescriptor(),
file.getStartOffset(), file.getLength());
file.close();
mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
mediaPlayer.prepare();
} catch (IOException e) {
mediaPlayer = null;
}
}
}
private static final long VIBRATE_DURATION = 200L;
private void playBeepSoundAndVibrate() {
if (playBeep && mediaPlayer != null) {
mediaPlayer.start();
}
if (vibrate) {
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
vibrator.vibrate(VIBRATE_DURATION);
}
}
private final OnCompletionListener beepListener = new OnCompletionListener() {
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.seekTo(0);
}
};
/**
* 閃光燈開關按鈕
*/
private View.OnClickListener flashListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
boolean isSuccess = CameraManager.get().setFlashLight(!isFlashOn);
if(!isSuccess){
Toast.makeText(CaptureActivity.this, "暫時無法開啟閃光燈", Toast.LENGTH_SHORT).show();
return;
}
if (isFlashOn) {
// 關閉閃光燈
btnFlash.setImageResource(R.drawable.flash_off);
isFlashOn = false;
} else {
// 開啟閃光燈
btnFlash.setImageResource(R.drawable.flash_on);
isFlashOn = true;
}
}catch (Exception e){
e.printStackTrace();
}
}
};
}
原始碼下載:
首先掃描框掃描線是圖片的樣式Eclipse版本。
原始碼下載-->
然後這是自定義掃碼框掃描線邊框樣式Eclipse版本。
原始碼下載-->
最後是自定義掃碼框掃描線邊框樣式Android studio版本。
原始碼下載-->
需要哪一版自己去下載。