Trang chủHướng dẫnHướng dẫn quét mã QR trên Android bằng camera chi tiết
Android

Hướng dẫn quét mã QR trên Android bằng camera chi tiết

CyStack blog 8 phút để đọc
CyStack blog17/08/2025
Locker Avatar

Chris Pham

Technical Writer

Locker logo social
Reading Time: 8 minutes

Tính năng quét mã QR trên Android được tích hợp trong nhiều ứng dụng nhằm đọc và xử lý các dữ liệu hữu ích. Trong hướng dẫn này, chúng ta sẽ tìm hiểu và triển khai API Barcode thuộc Google Mobile Vision API.

quét mã QR trên Android

Quét mã QR trên Android

Với sự ra đời của Google Vision API, việc tích hợp mã vạch vào ứng dụng đã trở nên dễ dàng hơn nhiều đối với lập trình viên. Dưới đây là các định dạng chính mà Vision API hỗ trợ.

  • Mã vạch 1D: EAN-13, EAN-8, UPC-A, UPC-E, Code-39, Code-93, Code-128, ITF, Codabar
  • Mã vạch 2D: QR Code, Data Matrix, PDF-417, AZTEC

Mã vạch có thể chứa nhiều loại dữ liệu khác nhau như URL, thông tin liên hệ, vị trí địa lý, WIFI, giấy phép lái xe… QR Code là định dạng phổ biến hơn và thường thấy trong nhiều ứng dụng. Dưới đây, chúng ta sẽ phát triển một ứng dụng có khả năng quét mã QR từ ảnh bitmap cũng như nhận diện mã QR qua camera và thực hiện các thao tác tương ứng.

Cấu trúc dự án quét mã QR trên Android

android barcode detector project structure

Cấu hình Android Studio cho thư viện Barcode

Thêm dòng sau vào tệp build.gradle.

implementation 'com.google.android.gms:play-services-vision:11.8.0'

Thêm phần sau vào thẻ <application> trong tệp AndroidManifest.xml để kích hoạt tính năng quét mã vạch trong ứng dụng:

<meta-data
    android:name="com.google.android.gms.vision.DEPENDENCIES"
    android:value="barcode" />

Quét mã QR từ ảnh

Dưới đây là mã cho tệp giao diện activity_main.xml.

<RelativeLayout xmlns:android="<https://schemas.android.com/apk/res/android>"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <Button
        android:id="@+id/btnTakePicture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/take_barcode_picture" />

    <Button
        android:id="@+id/btnScanBarcode"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btnTakePicture"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="@dimen/activity_horizontal_margin"
        android:text="@string/scan_barcode" />
</RelativeLayout>

Mã cho tệp MainActivity.java được trình bày dưới đây.

package com.journaldev.barcodevisionapi;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    Button btnTakePicture, btnScanBarcode;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private void initViews() {
        btnTakePicture = findViewById(R.id.btnTakePicture);
        btnScanBarcode = findViewById(R.id.btnScanBarcode);
        btnTakePicture.setOnClickListener(this);
        btnScanBarcode.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnTakePicture:
                startActivity(new Intent(MainActivity.this, PictureBarcodeActivity.class));
                break;
            case R.id.btnScanBarcode:
                startActivity(new Intent(MainActivity.this, ScannedBarcodeActivity.class));
                break;
        }
    }
}

Lớp MainActivity.java chứa hai nút.

  • Nút đầu tiên mở một Activity dùng để quét mã QR từ ảnh bitmap chụp từ camera và trả về dữ liệu chứa trong mã QR (nếu có).
  • Nút thứ hai thực hiện việc quét mã QR theo thời gian thực.

Trước khi triển khai phần xử lý chính của ứng dụng, cần thêm các quyền sau vào tệp AndroidManifest.xml:

<uses-feature
    android:name="android.hardware.camera"
    android:required="true" />

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />

Để chia sẻ và truy cập tệp do ứng dụng khác tạo ra, cần thêm đoạn mã sau vào trong thẻ <application> của AndroidManifest.xml:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths" />
</provider>

Thành phần này cần thiết để truy xuất ảnh được chụp từ camera trong ứng dụng quét mã QR. Chúng ta sẽ bắt đầu với phần đầu tiên, cụ thể là lớp PictureBarcodeActivity.java. Dưới đây là mã giao diện của activity_barcode_picture.xml.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="<https://schemas.android.com/apk/res/android>"
    xmlns:tools="<https://schemas.android.com/tools>"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_centerHorizontal="true"
        android:src="@mipmap/journaldev_logo" />

    <TextView
        android:id="@+id/txtResultsHeader"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/imageView"
        android:layout_centerHorizontal="true"
        android:text="Results"
        android:textSize="18sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/txtResultsBody"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/txtResultsHeader"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="@dimen/activity_horizontal_margin"
        android:gravity="center" />

    <Button
        android:id="@+id/btnOpenCamera"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="@dimen/activity_horizontal_margin"
        android:layout_marginTop="@dimen/activity_horizontal_margin"
        android:text="@string/open_camera" />
</RelativeLayout

Mã nguồn cho lớp PictureCodeActivity.java được trình bày dưới đây.

package com.journaldev.barcodevisionapi;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.vision.Frame;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.barcode.BarcodeDetector;

import java.io.File;
import java.io.FileNotFoundException;

public class PictureBarcodeActivity extends AppCompatActivity implements View.OnClickListener {

    Button btnOpenCamera;
    TextView txtResultBody;

    private BarcodeDetector detector;
    private Uri imageUri;
    private static final int REQUEST_CAMERA_PERMISSION = 200;
    private static final int CAMERA_REQUEST = 101;
    private static final String TAG = "API123";
    private static final String SAVED_INSTANCE_URI = "uri";
    private static final String SAVED_INSTANCE_RESULT = "result";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_barcode_picture);

        initViews();

        if (savedInstanceState != null) {
            if (imageUri != null) {
                imageUri = Uri.parse(savedInstanceState.getString(SAVED_INSTANCE_URI));
                txtResultBody.setText(savedInstanceState.getString(SAVED_INSTANCE_RESULT));
            }
        }

        detector = new BarcodeDetector.Builder(getApplicationContext())
                .setBarcodeFormats(Barcode.DATA_MATRIX | Barcode.QR_CODE)
                .build();

        if (!detector.isOperational()) {
            txtResultBody.setText("Detector initialisation failed");
            return;
        }
    }

    private void initViews() {
        txtResultBody = findViewById(R.id.txtResultsBody);
        btnOpenCamera = findViewById(R.id.btnTakePicture);
        txtResultBody = findViewById(R.id.txtResultsBody);
        btnOpenCamera.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btnTakePicture:
                ActivityCompat.requestPermissions(PictureBarcodeActivity.this, new
                        String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
                break;
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_CAMERA_PERMISSION:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                    takeBarcodePicture();
                } else {
                    Toast.makeText(getApplicationContext(), "Permission Denied!", Toast.LENGTH_SHORT).show();
                }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) {
            launchMediaScanIntent();
            try {

                Bitmap bitmap = decodeBitmapUri(this, imageUri);
                if (detector.isOperational() && bitmap != null) {
                    Frame frame = new Frame.Builder().setBitmap(bitmap).build();
                    SparseArray<Barcode> barcodes = detector.detect(frame);
                    for (int index = 0; index < barcodes.size(); index++) {
                        Barcode code = barcodes.valueAt(index);
                        txtResultBody.setText(txtResultBody.getText() + "\\n" + code.displayValue + "\\n");

                        int type = barcodes.valueAt(index).valueFormat;
                        switch (type) {
                            case Barcode.CONTACT_INFO:
                                Log.i(TAG, code.contactInfo.title);
                                break;
                            case Barcode.EMAIL:
                                Log.i(TAG, code.displayValue);
                                break;
                            case Barcode.ISBN:
                                Log.i(TAG, code.rawValue);
                                break;
                            case Barcode.PHONE:
                                Log.i(TAG, code.phone.number);
                                break;
                            case Barcode.PRODUCT:
                                Log.i(TAG, code.rawValue);
                                break;
                            case Barcode.SMS:
                                Log.i(TAG, code.sms.message);
                                break;
                            case Barcode.TEXT:
                                Log.i(TAG, code.displayValue);
                                break;
                            case Barcode.URL:
                                Log.i(TAG, "url: " + code.displayValue);
                                break;
                            case Barcode.WIFI:
                                Log.i(TAG, code.wifi.ssid);
                                break;
                            case Barcode.GEO:
                                Log.i(TAG, code.geoPoint.lat + ":" + code.geoPoint.lng);
                                break;
                            case Barcode.CALENDAR_EVENT:
                                Log.i(TAG, code.calendarEvent.description);
                                break;
                            case Barcode.DRIVER_LICENSE:
                                Log.i(TAG, code.driverLicense.licenseNumber);
                                break;
                            default:
                                Log.i(TAG, code.rawValue);
                                break;
                        }
                    }
                    if (barcodes.size() == 0) {
                        txtResultBody.setText("No barcode could be detected. Please try again.");
                    }
                } else {
                    txtResultBody.setText("Detector initialisation failed");
                }
            } catch (Exception e) {
                Toast.makeText(getApplicationContext(), "Failed to load Image", Toast.LENGTH_SHORT)
                        .show();
                Log.e(TAG, e.toString());
            }
        }
    }

    private void takeBarcodePicture() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        File photo = new File(Environment.getExternalStorageDirectory(), "pic.jpg");
        imageUri = FileProvider.getUriForFile(PictureBarcodeActivity.this,
                BuildConfig.APPLICATION_ID + ".provider", photo);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        startActivityForResult(intent, CAMERA_REQUEST);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        if (imageUri != null) {
            outState.putString(SAVED_INSTANCE_URI, imageUri.toString());
            outState.putString(SAVED_INSTANCE_RESULT, txtResultBody.getText().toString());
        }
        super.onSaveInstanceState(outState);
    }

    private void launchMediaScanIntent() {
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        mediaScanIntent.setData(imageUri);
        this.sendBroadcast(mediaScanIntent);
    }

    private Bitmap decodeBitmapUri(Context ctx, Uri uri) throws FileNotFoundException {
        int targetW = 600;
        int targetH = 600;
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(ctx.getContentResolver().openInputStream(uri), null, bmOptions);
        int photoW = bmOptions.outWidth;
        int photoH = bmOptions.outHeight;

        int scaleFactor = Math.min(photoW / targetW, photoH / targetH);
        bmOptions.inJustDecodeBounds = false;
        bmOptions.inSampleSize = scaleFactor;

        return BitmapFactory.decodeStream(ctx.getContentResolver()
                .openInputStream(uri), null, bmOptions);
    }
}

Một số suy luận rút ra từ đoạn mã trên được trình bày như sau.

Đoạn mã sau đây tạo một đối tượng Barcode Detector:

detector = new BarcodeDetector.Builder(getApplicationContext())
           .setBarcodeFormats(Barcode.DATA_MATRIX | Barcode.QR_CODE)
           .build();

Các định dạng mã cần quét được thiết lập trong phương thức setBarcodeFormats().

Hàm takeBarcodePicture() là nơi khởi chạy camera. Để truy xuất hình ảnh, chúng ta sử dụng launchMediaScanIntent(), đây là phương thức gửi một Intent dạng broadcast nhằm tìm kiếm hình ảnh thông qua URI của ảnh.

Một đối tượng Frame.Builder được dùng để tạo một khung hình từ ảnh Bitmap. Trên khung hình này, Barcode Detector sẽ quét để tìm các mã QR có thể có. Dòng mã sau đây tạo một Frame từ đối tượng Bitmap:

Frame frame = new Frame.Builder().setBitmap(bitmap).build();

Chúng ta tạo một đối tượng SparseArray để chứa tất cả các mã QR có thể có trong ảnh bằng cách gọi phương thức detect() trên đối tượng Barcode Detector:

SparseArray<Barcode> barcodes = detector.detect(frame);

Để lấy định dạng của mã QR, trường valueFormat sẽ được truy xuất từ đối tượng Barcode, như sau:

barcodes.valueAt(index).valueFormat

Để lấy giá trị hiển thị và giá trị thô, có thể sử dụng các lệnh sau:

barcodes.valueAt(index).displayValue
barcodes.valueAt(index).rawValue

Giá trị tương ứng được trả về sẽ hiển thị trong một TextView. Với trường hợp có nhiều mã Barcode trong một ảnh Bitmap, các giá trị sẽ được nối thêm vào nội dung hiện có của TextView.

Lớp ScannedBarcodeActivity.java sẽ quét mã Barcode thông qua camera. Chúng tôi đã tạo hai mã QR tùy chỉnh riêng của mình từ đây. Mã nguồn của tệp giao diện activity_scan_barcode.xml được trình bày dưới đây.

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

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/btnAction"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true" />

    <TextView
        android:id="@+id/txtBarcodeValue"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="@dimen/activity_horizontal_margin"
        android:layout_marginStart="@dimen/activity_horizontal_margin"
        android:text="No Barcode Detected"
        android:textColor="@android:color/white"
        android:textSize="20sp" />

    <Button
        android:id="@+id/btnAction"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="ADD CONTENT IN THE MAIL" />

</RelativeLayout>

Trình quét mã vạch cho Android sử dụng Camera

Mã nguồn cho lớp ScannedBarcodeActivity.java được trình bày dưới đây.

package com.journaldev.barcodevisionapi;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.SparseArray;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.vision.CameraSource;
import com.google.android.gms.vision.Detector;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.barcode.BarcodeDetector;

import java.io.IOException;

public class ScannedBarcodeActivity extends AppCompatActivity {

    SurfaceView surfaceView;
    TextView txtBarcodeValue;
    private BarcodeDetector barcodeDetector;
    private CameraSource cameraSource;
    private static final int REQUEST_CAMERA_PERMISSION = 201;
    Button btnAction;
    String intentData = "";
    boolean isEmail = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scan_barcode);

        initViews();
    }

    private void initViews() {
        txtBarcodeValue = findViewById(R.id.txtBarcodeValue);
        surfaceView = findViewById(R.id.surfaceView);
        btnAction = findViewById(R.id.btnAction);

        btnAction.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (intentData.length() > 0) {
                    if (isEmail)
                        startActivity(new Intent(ScannedBarcodeActivity.this, EmailActivity.class).putExtra("email_address", intentData));
                    else {
                        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(intentData)));
                    }
                }

            }
        });
    }

    private void initialiseDetectorsAndSources() {

        Toast.makeText(getApplicationContext(), "Barcode scanner started", Toast.LENGTH_SHORT).show();

        barcodeDetector = new BarcodeDetector.Builder(this)
                .setBarcodeFormats(Barcode.ALL_FORMATS)
                .build();

        cameraSource = new CameraSource.Builder(this, barcodeDetector)
                .setRequestedPreviewSize(1920, 1080)
                .setAutoFocusEnabled(true) //you should add this feature
                .build();

        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                try {
                    if (ActivityCompat.checkSelfPermission(ScannedBarcodeActivity.this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                        cameraSource.start(surfaceView.getHolder());
                    } else {
                        ActivityCompat.requestPermissions(ScannedBarcodeActivity.this, new
                                String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }

            }

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

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                cameraSource.stop();
            }
        });

        barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
            @Override
            public void release() {
                Toast.makeText(getApplicationContext(), "To prevent memory leaks barcode scanner has been stopped", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void receiveDetections(Detector.Detections<Barcode> detections) {
                final SparseArray<Barcode> barcodes = detections.getDetectedItems();
                if (barcodes.size() != 0) {

                    txtBarcodeValue.post(new Runnable() {

                        @Override
                        public void run() {

                            if (barcodes.valueAt(0).email != null) {
                                txtBarcodeValue.removeCallbacks(null);
                                intentData = barcodes.valueAt(0).email.address;
                                txtBarcodeValue.setText(intentData);
                                isEmail = true;
                                btnAction.setText("ADD CONTENT TO THE MAIL");
                            } else {
                                isEmail = false;
                                btnAction.setText("LAUNCH URL");
                                intentData = barcodes.valueAt(0).displayValue;
                                txtBarcodeValue.setText(intentData);

                            }
                        }
                    });

                }
            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();
        cameraSource.release();
    }

    @Override
    protected void onResume() {
        super.onResume();
        initialiseDetectorsAndSources();
    }
}

Một số suy luận rút ra từ đoạn mã trên được trình bày như sau.

SurfaceView là thành phần thích hợp để hiển thị ảnh xem trước từ camera nhờ khả năng kết xuất giao diện nhanh. Giao diện SurfaceHolder.Callback được sử dụng để tiếp nhận thông tin về các thay đổi xảy ra trên surface (trong trường hợp này là ảnh xem trước từ camera). SurfaceHolder.Callback triển khai ba phương thức:

  • surfaceChanged: Phương thức này được gọi khi kích thước hoặc định dạng của surface thay đổi.
  • surfaceCreated: Phương thức này được gọi khi surface được tạo lần đầu tiên.
  • surfaceDestroyed: Phương thức này được gọi khi surface bị hủy.

CameraSource quản lý camera phối hợp với một detector bên dưới. Trong trường hợp này, SurfaceView đóng vai trò là surface mà detector sử dụng. Phương thức CameraSource.start() sẽ mở camera và bắt đầu gửi các khung hình xem trước đến SurfaceView. CameraSource được khởi tạo theo cách sau:

cameraSource = new CameraSource.Builder(this, barcodeDetector)
                .setRequestedPreviewSize(1920, 1080)
                .setAutoFocusEnabled(true) // nên bật tính năng này
                .build();

Chúng ta đã gán một processor cho BarcodeDetector thông qua phương thức setProcessor(). Giao diện này cung cấp callback đến phương thức receiveDetections(), nơi nhận các mã QR từ ảnh xem trước của camera và lưu trữ chúng trong SparseArray.

Giá trị của mã QR được hiển thị trong TextView thông qua một đối tượng Runnable do quá trình phát hiện mã QR được thực hiện trên một luồng nền.

Trong ví dụ này, chúng tôi đã tạo hai mã QR bằng trình tạo mã. Một mã chứa địa chỉ URL, mã còn lại chứa địa chỉ email. Khi người dùng nhấn nút, tùy thuộc vào giá trị của mã QR được nhận diện, ứng dụng sẽ hoặc mở URL, hoặc mở giao diện gửi email với địa chỉ tương ứng lấy từ mã QR.

Kết quả đầu ra của lớp PictureBarcodeActivity.java được hiển thị bên dưới.

android barcode detector project structure

Kết quả đầu ra của hoạt động ScannedBarcodeActivity.java khi vận hành được trình bày bên dưới.

android barcode detector project structure

Đó là toàn bộ nội dung của dự án quét mã QR trên Android sử dụng Mobile Vision API. Chúng ta đã thêm các mã QR mẫu vào mã nguồn. Bạn có thể tải xuống toàn bộ dự án Android QR Code Scanner/Barcode Scanner từ liên kết bên dưới và thử nghiệm với nhiều mã QR khác nhau.

Tải xuống dự án mẫu QR Code, Barcode Scanner

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất