繁体   English   中英

zxing活动扫描嵌入的二维码

[英]zxing activity to scan QR code embedded

在这里,我期待zxing-core有一些活动可以从其他应用程序启动,这就是他们如何集成而无需启动一些第三方应用程序来扫描二维码

我尝试添加

compile 'com.google.zxing:core:3.1.0'
compile 'com.google.zxing:android-integration:3.1.0'

build.gradle文件我可以看到这些jar是导入的,但我没有看到这个类存在于jar中

com.google.zxing.client.android.CaptureActivity

在旁边的罐子里

$ unzip -l ./modules-2/files-2.1/com.google.zxing/core/3.1.0/908e18674f895e3e1fa8f4a954b8c637a23d2801/core-3.1.0.jar | grep -i 'activity'

我没有看到核心模块的类部分在这里

我究竟做错了什么 ?

Suppressed: java.lang.ClassNotFoundException: com.google.zxing.client.android.CaptureActivity
        at java.lang.Class.classForName(Native Method)
        at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
        at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:504)

我正在使用这种方法:

Intent intent = new Intent("com.google.zxing.client.android.SCAN");
                intent.putExtra("com.google.zxing.client.android.SCAN.SCAN_MODE", "QR_CODE_MODE");
                startActivityForResult(intent, 0);

只是为了确保:我的期望是,当用户想要使用嵌入式扫描程序而不是将扫描委派给其他应用程序时,活动是用户库的一部分

这是一个非常长的答案所以仔细阅读,以确保你不会错过任何东西。

你可以在我的Github Repo上看到一个示例项目

好的,首先你必须将核心zxing库jar添加到项目目录中的libs文件夹中。 您还必须为zxing类创建一个包。 见下文

foo.bar.yourpackagename.zxing
foo.bar.yourpackagename.zxing.view

在第一个包foo.bar.yourpackagename.zxing添加以下类


CameraManager.java

import android.app.Activity;
import android.graphics.Rect;
import android.hardware.Camera;
import android.util.Log;
import android.view.Surface;
import com.google.zxing.PlanarYUVLuminanceSource;

/**
 * Camera manager
 */
public class CameraManager {
    /**
     * Fraction of bounds size in view
     */
    private static final double BOUNDS_FRACTION = 0.6;
    /**
     * Fraction of height of bounds in view
     */
    private static final double VERTICAL_HEIGHT_FRACTION = 0.3;

    /**
     * Camera instance
     */
    private Camera camera;
    /**
     * Id of camera instance
     */
    private int cameraId;
    /**
     * Current orientation of camera
     * Possible values : 0, 90, 180, 270
     */
    private int orientation;

    public CameraManager() {
        this.camera = getCameraInstance();
    }

    /**
     * Getter for camera
     *
     * @return camera instance, if it has been initialized
     */
    public Camera getCamera() {
        return camera;
    }

    /**
     * Starts preview of camera, if it has been initialized
     */
    public synchronized void startPreview() {
        if (camera != null) {
            camera.startPreview();
        }
    }

    /**
     * Stops preview of camera, if it has been initialized
     */
    public synchronized void stopPreview() {
        if (camera != null) {
            camera.stopPreview();
        }
    }

    /**
     * Release camera, if it has been initialized
     */
    public synchronized void release() {
        if (camera != null) {
            camera.release();
            camera = null;
        }
    }

    /**
     * @return if camera has been initialized<br/>( <code>camera != null</code> )
     */
    public synchronized boolean hasCamera() {
        return camera != null;
    }

    /**
     * @return bounding rect for ui
     */
    public final synchronized Rect getBoundingRectUi(int uiWidth, int uiHeight) {
        double heightFraction = BOUNDS_FRACTION;
        double widthFraction = BOUNDS_FRACTION;
        if (orientation == 90 || orientation == 270) {
            heightFraction = VERTICAL_HEIGHT_FRACTION;
        }

        Log.d("CameraManager", "dimsUI[" + uiWidth + ", " + uiHeight + "]");

        int height = (int) (uiHeight * heightFraction);
        int width = (int) (uiWidth * widthFraction);
        int left = (int) (uiWidth * ((1 - widthFraction) / 2));
        int top = (int) (uiHeight * ((1 - heightFraction) / 2));
        int right = left + width;
        int bottom = top + height;

        return new Rect(left, top, right, bottom);
    }

    /**
     * @return bounding rect for camera
     */
    public final synchronized Rect getBoundingRect() {
        if (camera != null) {
            Camera.Size previewSize = camera.getParameters().getPreviewSize();
            int previewHeight = previewSize.height;
            int previewWidth = previewSize.width;

            double heightFraction = BOUNDS_FRACTION;
            double widthFraction = BOUNDS_FRACTION;
            if (orientation == 90 || orientation == 270) {
                widthFraction = VERTICAL_HEIGHT_FRACTION;
            }
            Log.d("CameraManager", "dimsPrev[" + previewWidth + ", " + previewHeight + "]");

            int height = (int) (previewHeight * heightFraction);
            int width = (int) (previewWidth * widthFraction);
            int left = (int) (previewWidth * ((1 - widthFraction) / 2));
            int top = (int) (previewHeight * ((1 - heightFraction) / 2));
            int right = left + width;
            int bottom = top + height;

            return new Rect(left, top, right, bottom);
        }
        return null;
    }

    /**
     * executes <br/> <code>camera.setOneShotPreviewCallback(callback)</code> if <br/>
     * <code>camera != null</code>
     * @param callback callback to provide
     */
    public synchronized void requestNextFrame(Camera.PreviewCallback callback) {
        if (camera != null) {
            camera.setOneShotPreviewCallback(callback);
        }
    }

    /**
     * A factory method to build the appropriate LuminanceSource object based on the format
     * of the preview buffers, as described by Camera.Parameters.
     *
     * @param data   A preview frame.
     * @param width  The width of the image.
     * @param height The height of the image.
     * @return A PlanarYUVLuminanceSource instance.
     */
    public synchronized PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height, Rect boundingRect) {
        switch (orientation) {
            case 0:
                //data = flip(data);
                break;
            case 90:
                rotate90(data, width, height);
                return new PlanarYUVLuminanceSource(data, height, width, boundingRect.top, boundingRect.left,
                        boundingRect.height(), boundingRect.width(), false);

            case 180:
                break;
            case 270:
                rotate90(data, width, height);
                break;
        }

        return new PlanarYUVLuminanceSource(data, width, height, boundingRect.left, boundingRect.top,
                boundingRect.width(), boundingRect.height(), false);
    }

    /**
     * Rotates image data
     * @param data raw image data
     * @param width width of image
     * @param height height of image
     */
    public void rotate90(byte[] data, int width, int height) {
        int length = height * width;
        int lengthDec = length - 1;
        int i = 0;
        do {
            int k = (i * height) % lengthDec;
            while (k > i) k = (height * k) % lengthDec;
            if (k != i) swap(data, k, i);
        } while (++i <= (length - 2));
    }

    /**
     * Sets camera display orientation depending on current activity orientation
     * @param activity activity, which holds camera preview
     */
    public void setCameraDisplayOrientation(Activity activity) {
        android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
        android.hardware.Camera.getCameraInfo(cameraId, info);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }

        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360; // compensate the mirror
        } else { // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        orientation = result;
        camera.setDisplayOrientation(result);
    }


    /**
     * A safe way to get an instance of the Camera object.
     */
    private Camera getCameraInstance() {
        Camera c = null;
        try {
            cameraId = 0;
            c = Camera.open(); // attempt to get a Camera instance
            Camera.Parameters p = c.getParameters();
            p.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
            c.setParameters(p);
        } catch (Exception e) {
            Log.e(CameraManager.class.getSimpleName(), "Camera error", e);
            // Camera is not available (in use or does not exist)
        }
        return c; // returns null if camera is unavailable
    }

    /**
     * Swaps two elements in array
     * @param data array
     * @param k first element to swap
     * @param i second element to swap
     */
    private static void swap(byte[] data, int k, int i) {
        byte temp = data[k];
        data[k] = data[i];
        data[i] = temp;
    }
}

CaptureHandler.java

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;

/**
 */
public class CaptureHandler extends Handler {
    public static final String DECODED_DATA = "decoded_data";
    private CameraManager cameraManager;
    private Context context;
    private OnDecodedCallback callback;

    public CaptureHandler(CameraManager cameraManager, Context context, OnDecodedCallback callback) {
        this.cameraManager = cameraManager;
        this.context = context;
        this.callback = callback;
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case R.id.decoded:
                String data = msg.getData().getString(DECODED_DATA);
                Toast.makeText(context, data, Toast.LENGTH_LONG).show();
                if (callback != null){
                    callback.onDecoded(data);
                }
                break;
            case R.id.decode_failed:
                //getting new frame
                cameraManager.requestNextFrame(new PreviewCallback(this, cameraManager));
                break;
        }
    }

    public static interface OnDecodedCallback {
        void onDecoded(String decodedData);
    }
}

PreviewCallback.java

import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.google.zxing.*;
import com.google.zxing.common.HybridBinarizer;
import foo.bar.yourpackagename.R;

/**
 * Camera preview callback
 */
public class PreviewCallback implements Camera.PreviewCallback {
    private static final String TAG = PreviewCallback.class.getSimpleName();
    /**
     * Xzing multi format reader
     */
    private final MultiFormatReader multiFormatReader = new MultiFormatReader();
    /**
     * Handler to send messages
     *
     * @see CaptureHandler
     */
    private Handler handler;
    /**
     * Camera manager
     */
    private CameraManager cameraManager;

    public PreviewCallback(Handler handler, CameraManager cameraManager) {
        this.handler = handler;
        this.cameraManager = cameraManager;
    }

    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) {
        try {
            Camera.Size previewSize = camera.getParameters().getPreviewSize();
            new DecodeAsyncTask(previewSize.width, previewSize.height).execute(bytes);
        } catch (Exception e) {
            //Random errors from zxing
        }
    }

    /**
     * Asynchronous task for decoding and finding barcode
     */
    private class DecodeAsyncTask extends AsyncTask<byte[], Void, Result> {
        /**
         * Width of image
         */
        private int width;
        /**
         * Height of image
         */
        private int height;

        /**
         * @param width  Width of image
         * @param height Height of image
         */
        private DecodeAsyncTask(int width, int height) {
            this.width = width;
            this.height = height;
        }

        @Override
        protected void onPostExecute(Result result) {
            if (result != null) {
                Log.i(TAG, "Decode success.");
                if (handler != null) {
                    Message message = Message.obtain(handler, R.id.decoded);
                    Bundle bundle = new Bundle();
                    bundle.putString(CaptureHandler.DECODED_DATA, result.toString());
                    message.setData(bundle);
                    message.sendToTarget();
                }
            } else {
                Log.i(TAG, "Decode fail.");
                if (handler != null) {
                    Message message = Message.obtain(handler, R.id.decode_failed);
                    message.sendToTarget();
                }
            }
        }

        @Override
        protected Result doInBackground(byte[]... datas) {
            if (!cameraManager.hasCamera()) {
                return null;
            }
            Result rawResult = null;
            final PlanarYUVLuminanceSource source =
                    cameraManager.buildLuminanceSource(datas[0], width,
                            height, cameraManager.getBoundingRect());
            if (source != null) {
                BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
                try {
                    rawResult = multiFormatReader.decodeWithState(bitmap);
                } catch (Exception re) {
                    Log.e(TAG, "ERROR", re);
                } finally {
                    multiFormatReader.reset();
                }
            }

            return rawResult;
        }
    }
}

然后在将这三个类添加到foo.bar.yourpackagename.zxing包之后,必须将以下类添加到foo.bar.yourpackagename.zxing.view包中


BoundingView.java

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import foo.bar.yourpackagename.zxing.CameraManager;

/**
 * View for displaying bounds for active camera region
 */
public class BoundingView extends View {
    /**
     * Camera manager
     */
    private CameraManager cameraManager;

    public BoundingView(Context context) {
        super(context);
    }

    public BoundingView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * Sets camera manger
     * @param cameraManager
     */
    public void setCameraManager(CameraManager cameraManager) {
        this.cameraManager = cameraManager;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (cameraManager != null) {
             Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
             paint.setColor(Color.parseColor("#00000000"));

//             Rect boundingRect = cameraManager.getBoundingRectUi(canvas.getWidth(), canvas.getHeight());
             Rect boundingRect = cameraManager.getBoundingRect();
             canvas.drawRect(boundingRect, paint);

             paint = new Paint(Paint.ANTI_ALIAS_FLAG);
             paint.setColor(Color.parseColor("#44FF0000"));
             paint.setStrokeWidth(5);
             int incY = (canvas.getHeight() - boundingRect.height())/2;
             int incX = (canvas.getWidth() - boundingRect.width())/2;

             int y = (boundingRect.height()/2) + incY;
             int x = boundingRect.width() + incX;
             canvas.drawLine(incX, y, x, y, paint);
             canvas.drawRect(new Rect(incX, boundingRect.top, x, boundingRect.bottom), paint);
        }
    }
}

CameraPreviewView.java

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import foo.bar.yourpackagename.zxing.CameraManager;

import java.io.IOException;

/**
 * Camera preview view. Shows camera preview data
 */
public class CameraPreviewView extends SurfaceView implements SurfaceHolder.Callback {
    private static final String TAG = CameraPreviewView.class.getSimpleName();

    /**
     * Surface holder for camera preview data
     */
    private SurfaceHolder surfaceHolder;
    /**
     * Camera manager
     */
    private CameraManager cameraManager;

    public CameraPreviewView(Context context) {
        super(context);

        surfaceHolder = getHolder();
        surfaceHolder.addCallback(this);

        // deprecated setting, but required on Android versions prior to 3.0
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public CameraPreviewView(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);

        surfaceHolder = getHolder();
        surfaceHolder.addCallback(this);

        // deprecated setting, but required on Android versions prior to 3.0
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    /**
     * Setter for camera manager
     * @param cameraManager camera manager to set
     */
    public void setCameraManager(CameraManager cameraManager) {
        this.cameraManager = cameraManager;
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            cameraManager.setCameraDisplayOrientation((Activity) getContext());
            cameraManager.getCamera().setPreviewDisplay(holder);
            cameraManager.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // empty. Taking care of releasing the Camera preview in activity.
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (surfaceHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            cameraManager.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            cameraManager.setCameraDisplayOrientation((Activity) getContext());
            cameraManager.getCamera().setPreviewDisplay(surfaceHolder);
            cameraManager.startPreview();

        } catch (Exception e) {
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

完成后,您可以从实现Activity开始。 请注意,有些类要求您为某些状态创建id,例如

R.id.decode_failed

您需要在应用程序的资源文件夹中创建这些ID。 接下来我们可以进入实现Activity


CaptureActivity.java

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.RelativeLayout;

import foo.bar.yourpackagename.R;
import foo.bar.yourpackagename.zxing.CameraManager;
import foo.bar.yourpackagename.zxing.CaptureHandler;
import foo.bar.yourpackagename.zxing.PreviewCallback;
import foo.bar.yourpackagename.zxing.view.BoundingView;
import foo.bar.yourpackagename.zxing.view.CameraPreviewView;

/**
 * Capture activity (camera barcode activity)
 */
public class CaptureActivity extends Activity {
    public static String PUBLIC_STATIC_STRING_IDENTIFIER;

    /**
     * Camera preview view
     */
    private CameraPreviewView cameraPreview;
    /**
     * Camera manager
     */
    private CameraManager cameraManager;

    /**
     * Capture handler
     */
    private Handler captureHandler;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(getContentView());

        initializeCamera();
        initializeCameraPreview();
        initializeBoundingView();
    }

    private View getContentView() {
        RelativeLayout contentView = new RelativeLayout(this);
        contentView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        contentView.addView(getBoundingView());
        contentView.addView(getCameraPreviewView());

        return contentView;
    }

    private CameraPreviewView getCameraPreviewView() {
        //This is the camera SurfaceView
        CameraPreviewView camPreview = new CameraPreviewView(this);
        camPreview.setId(R.id.camera_preview);
        camPreview.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

        return camPreview;
    }

    private BoundingView getBoundingView() {
        //Displays the bounding content
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        params.addRule(RelativeLayout.CENTER_IN_PARENT);

        BoundingView boundingView = new BoundingView(this);
        boundingView.setId(R.id.bounding_view);
        boundingView.setLayoutParams(params);

        return boundingView;
    }

    private void initializeCamera() {
        // Create an instance of Camera
        cameraManager = new CameraManager();
        captureHandler = new CaptureHandler(cameraManager, this, new OnDecoded());

        //requesting next frame for decoding
        cameraManager.requestNextFrame(new PreviewCallback(captureHandler, cameraManager));
    }

    private void initializeCameraPreview() {
        // Create our Preview view and set it as the content of our activity.
        cameraPreview = (CameraPreviewView) findViewById(R.id.camera_preview);
        cameraPreview.setCameraManager(cameraManager);
    }

    private void initializeBoundingView() {
        //Set the cameraManager to the bounding view
        ((BoundingView) findViewById(R.id.bounding_view)).setCameraManager(cameraManager);
    }

    @Override
    protected void onPause() {
        super.onPause();

        //We don't want the cameraManager to take up unneeded 
        //resources so we release it from memory onPause
        cameraManager.release();
    }

    /**
     * This handles the decoded content from the Zxing framework. As
     * soon as the framework has completed the decoding process the CaptureHandler
     * will pass it back via this listener for you to handle it further.
     *
     */
    private class OnDecoded implements CaptureHandler.OnDecodedCallback {
        @Override
        public void onDecoded(String decodedData) {
            Intent resultIntent = new Intent();
            resultIntent.putExtra(PUBLIC_STATIC_STRING_IDENTIFIER, decodedData);
            setResult(Activity.RESULT_OK, resultIntent);
            finish();
        }
    }
}

要开始活动,您只需致电

startActivity(new Intent(this, CaptureActivity.class));

还要记住添加以下权限

<uses-permission android:name="android.permission.CAMERA" />

<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />

和你的Activity

<activity
    android:name=".CaptureActivity"
    android:configChanges="orientation|keyboardHidden"
    android:screenOrientation="landscape"
    android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
    android:windowSoftInputMode="stateAlwaysHidden" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    <intent-filter>
        <action android:name="com.google.zxing.client.android.SCAN" />

        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

Manifest

如果正确实现所有这些类,则应该能够开始扫描条形码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM