step1:
下载zxing源代码
step2:
在build.gradle中加入必须的核心库
dependencies {
/**zxing二维码生成与识别核心库**/
compile 'com.google.zxing:core:latest.integration'
/**zxing二维码扫描for android核心库**/
compile 'com.google.zxing:android-core:latest.integration'
}
step3:
增加使用摄像头所需要的权限
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.FLASHLIGHT"/>
step4:
精简源码
4.1 将zxing源码中->camera包下所有文件copy到需要移植的项目里面
4.2 新建一个decode包将解码相关的文件导入
4.3新建一个preference包将相关文件导入(虽然没多大用处,导入相关文件并不会影响程序,能减少引用error,减少麻烦就加进来了)
4.4 copy 自定义view
ViewfinderResultPointCallback.java
4.5 导入manager
提示音 BeepManager.java
解析管理 DecodeFormatManager.java DecodeHintManager.java
4.6 建议不要使用源码下的CaptureActivity.java 建议自己新建一个
package com.denong.happilitt.com3rd.zxing;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.TextView;
import com.denong.happilitt.R;
import com.denong.happilitt.com3rd.zxing.camera.CameraManager;
import com.denong.happilitt.com3rd.zxing.decoding.CaptureActivityHandler;
import com.denong.happilitt.com3rd.zxing.decoding.FinishListener;
import com.denong.happilitt.com3rd.zxing.decoding.InactivityTimer;
import com.denong.happilitt.com3rd.zxing.decoding.Intents;
import com.denong.happilitt.com3rd.zxing.view.ViewfinderView;
import com.denong.happilitt.frame.log.Logger;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.Result;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import butterknife.Bind;
import butterknife.ButterKnife;
/**
* Created by chendy on 15/12/3.
*/
public class CaptureActivity extends Activity implements SurfaceHolder.Callback {
@Bind(R.id.preview_view)
android.view.SurfaceView previewView;
@Bind(R.id.viewfinder_view)
ViewfinderView viewfinderView;
@Bind(R.id.txtResult)
TextView txtResult;
private CameraManager cameraManager;
private BeepManager beepManager;
private AmbientLightManager ambientLightManager;
private CaptureActivityHandler handler;
private Result savedResultToShow;
private Collection<BarcodeFormat> decodeFormats;
private Map<DecodeHintType,?> decodeHints;
private String characterSet;
private InactivityTimer inactivityTimer;
private boolean hasSurface;
public ViewfinderView getViewfinderView() {
return viewfinderView;
}
public Handler getHandler() {
return handler;
}
public CameraManager getCameraManager() {
return cameraManager;
}
public void drawViewfinder() {
viewfinderView.drawViewfinder();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.qrcode_capture_page);
ButterKnife.bind(this);
inactivityTimer = new InactivityTimer(this);
beepManager = new BeepManager(this);
ambientLightManager = new AmbientLightManager(this);
}
@Override
protected void onResume() {
super.onResume();
// CameraManager must be initialized here, not in onCreate(). This is necessary because we don't
// want to open the camera driver and measure the screen size if we're going to show the help on
// first launch. That led to bugs where the scanning rectangle was the wrong size and partially
// off screen.
cameraManager = new CameraManager(getApplication());
viewfinderView.setCameraManager(cameraManager);
beepManager.updatePrefs();
ambientLightManager.start(cameraManager);
inactivityTimer.onResume();
SurfaceHolder surfaceHolder = previewView.getHolder();
if (hasSurface) {
initCamera(surfaceHolder);
} else {
surfaceHolder.addCallback(this);
// surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
decodeFormats = null;
characterSet = null;
Intent intent = getIntent();
if(null != intent){
String action = intent.getAction();
if (Intents.Scan.ACTION.equals(action)) {
// Scan the formats the intent requested, and return the result to the calling activity.
decodeFormats = DecodeFormatManager.parseDecodeFormats(intent);
decodeHints = DecodeHintManager.parseDecodeHints(intent);
if (intent.hasExtra(Intents.Scan.WIDTH) && intent.hasExtra(Intents.Scan.HEIGHT)) {
int width = intent.getIntExtra(Intents.Scan.WIDTH, 0);
int height = intent.getIntExtra(Intents.Scan.HEIGHT, 0);
if (width > 0 && height > 0) {
cameraManager.setManualFramingRect(width, height);
}
}
if (intent.hasExtra(Intents.Scan.CAMERA_ID)) {
int cameraId = intent.getIntExtra(Intents.Scan.CAMERA_ID, -1);
if (cameraId >= 0) {
cameraManager.setManualCameraId(cameraId);
}
}
}
}
viewfinderView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(i == 0){
cameraManager.openLight();
i = 1;
}else{
cameraManager.offLight();
i = 0;
}
}
});
}
private int i = 0;
@Override
protected void onPause() {
if (handler != null) {
handler.quitSynchronously();
handler = null;
}
inactivityTimer.onPause();
ambientLightManager.stop();
beepManager.close();
cameraManager.closeDriver();
//historyManager = null; // Keep for onActivityResult
if (!hasSurface) {
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
surfaceHolder.removeCallback(this);
}
super.onPause();
}
@Override
protected void onDestroy() {
inactivityTimer.shutdown();
super.onDestroy();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (holder == null) {
Logger.output("*** WARNING *** surfaceCreated() gave us a null surface!");
}
if (!hasSurface) {
hasSurface = true;
initCamera(holder);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
hasSurface = false;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
private void initCamera(SurfaceHolder surfaceHolder) {
if (surfaceHolder == null) {
throw new IllegalStateException("No SurfaceHolder provided");
}
if (cameraManager.isOpen()) {
Logger.output("initCamera() while already open -- late SurfaceView callback?");
return;
}
try {
cameraManager.openDriver(surfaceHolder);
// Creating the handler starts the preview, which can also throw a RuntimeException.
if (handler == null) {
handler = new CaptureActivityHandler(this, decodeFormats, decodeHints, characterSet, cameraManager);
}
decodeOrStoreSavedBitmap(null, null);
} catch (IOException ioe) {
Logger.output("Exception:" + ioe.getMessage());
displayFrameworkBugMessageAndExit();
} catch (RuntimeException e) {
// Barcode Scanner has seen crashes in the wild of this variety:
// java.?lang.?RuntimeException: Fail to connect to camera service
Logger.output("Exception:" + e.getMessage());
displayFrameworkBugMessageAndExit();
}
}
private void displayFrameworkBugMessageAndExit() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.app_name));
builder.setMessage(getString(R.string.msg_camera_framework_bug));
builder.setPositiveButton(R.string.STR_COMMON_03, new FinishListener(this));
builder.setOnCancelListener(new FinishListener(this));
builder.show();
}
private void decodeOrStoreSavedBitmap(Bitmap bitmap, Result result) {
// Bitmap isn't used yet -- will be used soon
if (handler == null) {
savedResultToShow = result;
} else {
if (result != null) {
savedResultToShow = result;
}
if (savedResultToShow != null) {
Message message = Message.obtain(handler, R.id.decode_succeeded, savedResultToShow);
handler.sendMessage(message);
}
savedResultToShow = null;
}
}
/**
* A valid barcode has been found, so give an indication of success and show the results.
*
* @param rawResult The contents of the barcode.
* @param scaleFactor amount by which thumbnail was scaled
* @param barcode A greyscale bitmap of the camera data which was decoded.
*/
public void handleDecode(Result rawResult, Bitmap barcode, float scaleFactor) {
inactivityTimer.onActivity();
boolean fromLiveScan = barcode != null;
if (fromLiveScan) {
viewfinderView.drawResultBitmap(barcode);
txtResult.setText(rawResult.getBarcodeFormat().toString() + ":"
+ rawResult.getText());
// Then not from history, so beep/vibrate and we have an image to draw on
beepManager.playBeepSoundAndVibrate();
}
}
}
4.7 新建布局文件qrcode_capture_page.xml布局如下
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<SurfaceView
android:id="@+id/preview_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerInParent="true" />
<com.denong.happilitt.com3rd.zxing.view.ViewfinderView
android:id="@+id/viewfinder_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/transparent" />
<TextView
android:id="@+id/txtResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="二维码扫描" />
</FrameLayout>
4.8 根据错误提示导入相关资源文件
step5 切换竖屏
5.1 将CameraConfigurationManager.java 中 setDesiredCameraParameters()加入
//将摄像头旋转90度
setDisplayOrientation(camera, 90);
并添加方法
/**
*
* 改变相机成像方向
*
*/
protected void setDisplayOrientation(Camera camera, int angle) {
Method downPolymorphic;
try {
downPolymorphic = camera.getClass().getMethod("setDisplayOrientation", new Class[] { int.class });
if (downPolymorphic != null)
downPolymorphic.invoke(camera, new Object[] { angle });
} catch (Exception e1) {
e1.printStackTrace();
}
}
修改initFromCameraParameters()为如下:
void initFromCameraParameters(Camera camera) {
Camera.Parameters parameters = camera.getParameters();
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
Point theScreenResolution = new Point();
display.getSize(theScreenResolution);
screenResolution = theScreenResolution;
Log.i(TAG, "Screen resolution: " + screenResolution);
//解决竖屏后图像拉伸问题
Point screenResolutionForCamera = new Point();
screenResolutionForCamera.x = screenResolution.x;
screenResolutionForCamera.y = screenResolution.y;
// preview size is always something like 480*320, other 320*480
if (screenResolution.x < screenResolution.y) {
screenResolutionForCamera.x = screenResolution.y;
screenResolutionForCamera.y = screenResolution.x;
}
cameraResolution = CameraConfigurationUtils.findBestPreviewSizeValue(parameters, screenResolution);
Log.i(TAG, "Camera resolution: " + cameraResolution);
}
5.2 将CameraManager.java 中->getFramingRectInPreview()
//横屏模式
rect.left = rect.left * cameraResolution.x / screenResolution.x;
rect.right = rect.right * cameraResolution.x / screenResolution.x;
rect.top = rect.top * cameraResolution.y / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
替换为
//竖屏模式
rect.left = rect.left * cameraResolution.x / screenResolution.x;
rect.right = rect.right * cameraResolution.x / screenResolution.x;
rect.top = rect.top * cameraResolution.y / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
最后别忘了将该文件中buildLuminanceSource()height和width顺序调换
return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
rect.width(), rect.height(), false);
替换为
//切换竖屏注意要将width和height顺序调换,不然会抛IllegalArgumentException
return new PlanarYUVLuminanceSource(data, height, width, rect.left, rect.top,
rect.width(), rect.height(), false);