Android – QR generator API

Issue

I’m trying to generate some QR from my app, but I’ve seen there’s a lot of types of QR like contact, Wi-Fi, etc.. And I’m wondering if there’s a free API or library to implement this, I’ve seen that there’s websites that are already generating it so I wanted to know if for Android is there any API or library to use.

What I’ve checked :

http://goqr.me/api

Zxing

But I’m not sure if there’s a function to say ok I want a QR for a contact so I can add all of the information of it.

Solution

QR code generation using ZXing

Add the following ZXing core dependency in your app level build.gradle file.

implementation 'com.google.zxing:core:3.4.0'

Sample code to generate a 512×512 px WiFi QR code. You can set the resultant Bitmap in an ImageView.

fun getQrCodeBitmap(ssid: String, password: String): Bitmap {
    val qrCodeContent  "WIFI:S:$ssid;T:WPA;P:$password;;"
    val hints  hashMapOf<EncodeHintType, Int>().also { it[EncodeHintType.MARGIN]  1 } // Make the QR code buffer border narrower
    val bits  QRCodeWriter().encode(qrCodeContent, BarcodeFormat.QR_CODE, size, size, hints)
    val size  512 //pixels
    return Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565).also {
        for (x in 0 until size) {
            for (y in 0 until size) {
                it.setPixel(x, y, if (bits[x, y]) Color.BLACK else Color.WHITE)
            }
        }
    }
}

To generate other types of QR code such as SMS, VCard etc. you can check out this helpful ZXing Wiki.

Scanning QR code using Google Mobile Vision API

Add the following GMS dependency to your app level build.gradle.

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

Step 1: Setup the Barcode processor callback.

private val processor  object : Detector.Processor<Barcode> {

    override fun receiveDetections(detections: Detector.Detections<Barcode>?) {
        detections?.apply {
            if (detectedItems.isNotEmpty()) {
                val qr  detectedItems.valueAt(0)
                // Parses the WiFi format for you and gives the field values directly
                // Similarly you can do qr.sms for SMS QR code etc.
                qr.wifi?.let { 
                    Log.d(TAG, "SSID: ${it.ssid}, Password: ${it.password}")
                }
            }
        }
    }

    override fun release() {}
} 

Step 2: Setup the BardcodeDetector with the barcode processor callback and add it to the CameraSource as follows. Don’t forget to check for Manifest.permission.CAMERA at runtime and add the same to your AndroidManifest.xml.

private fun setupCameraView() {
    if (ContextCompat.checkSelfPermission(requireContext(), android.Manifest.permission.CAMERA)  PackageManager.PERMISSION_GRANTED) {
        BarcodeDetector.Builder(requireContext()).setBarcodeFormats(QR_CODE).build().apply {
            setProcessor(processor)
            if (!isOperational) {
                Log.d(TAG, "Native QR detector dependencies not available!")
                return
            }
            cameraSource  CameraSource.Builder(requireContext(), this).setAutoFocusEnabled(true)
                .setFacing(CameraSource.CAMERA_FACING_BACK).build()
        }
    } else {
        // Request camers permission from user
        // Add <uses-permission android:name"android.permission.CAMERA" /> to AndroidManifest.xml
    }
}

Step 3: Add a SurfaceView to your layout to host your CameraSource.

<SurfaceView
    android:id"@+id/surfaceView"
    android:layout_width"match_parent"
    android:layout_height"match_parent" /> 

Step 4: Create a callback to start and stop the CameraSource when the surface is created / destroyed.

private val callback  object : SurfaceHolder.Callback {

    override fun surfaceCreated(holder: SurfaceHolder) {
        // Ideally, you should check the condition somewhere 
        // before inflating the layout which contains the SurfaceView
        if (isPlayServicesAvailable(requireActivity()))
            cameraSource?.start(holder)
    } 

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        cameraSource?.stop()
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { }
}


// Helper method to check if Google Play Services are up to-date on the phone
fun isPlayServicesAvailable(activity: Activity): Boolean {
    val code  GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(applicationContext)
    if (code ! ConnectionResult.SUCCESS) {
        GoogleApiAvailability.getInstance().getErrorDialog(activity, code, code).show()
        return false
    }
    return true
}

Step 5: Link everything together with the lifecycle methods.

// Create camera source and attach surface view callback to surface holder
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    return inflater.inflate(R.layout.fragment_camera_sheet, container, false).also {
        setupCamera()
        it.surfaceView.holder.addCallback(callback)
    }
}

// Free up camera source resources
override fun onDestroy() {
    super.onDestroy()
    cameraSource?.release()
}

Answered By – Siddharth Kamaria

Leave a Comment