Adding Barcode Support to a Salesforce Mobile Application

John Vester - Mar 21 '22 - - Dev Community

Article Image

Mobile devices have become a core aspect of our lives. Of course, this can be a good and bad thing. However, for the purposes of this article, I’ll focus on the positive ways mobile devices enrich our lives.

In fact, when my college-senior son, Eric visits, our conversations often provoke Eric to use his phone to locate and validate information related to our discussions. The crazy thing is: No matter what we talk about, his favorite search engine and voice-to-text skills provide an almost-immediate answer.

My use of technology even extends to thrifty shopping approaches where I can scan the barcode for a product of interest to see if the same product is available for a better price. This made me wonder how easily I could implement barcode technology into a custom application or component.

Barcode Support in Salesforce Mobile Applications

The engineering team at Salesforce knows that barcodes are a quick and easy way for mobile device users to pinpoint information. Both UPC barcodes and QR codes have been in place for decades now, and their usage isn’t fading.

Using the Salesforce mobile client and the camera on the mobile device, barcodes can be easily integrated into an application via the BarcodeScanner API. Here are a few common use cases for creating a Lightning Web Component (LWC) which includes the BarcodeScanner API:

  • Perform a lookup in Salesforce, using the barcode as a primary key.
  • Auto-populate form data by reading contact data inside a QR code.
  • Make an external system call with barcode data, such as tracking a shipment via a third-party API.

In this article, I’ll explore the first option, where the scanned barcode performs a lookup for data stored inside of Salesforce.

Salesforce DX and VS Code

Salesforce DX makes development on the Salesforce Platform easy, open, integrated, and collaborative. With Salesforce DX, developers can build together and deliver continuously. When coupled with Visual Studio (VS) Code and the Salesforce Extension Pack, working with Salesforce becomes a seamless operation.

As an example, the Command-Shift-P or Windows-Shift-P shortcut provides a quick access to SFDX commands like those shown below:

SFDX commands

Seeing these enhancements first-hand excited me for an opportunity to use VS Code and the Salesforce Extension Pack to build something for the Salesforce platform.

The Calorie Counter Use Case

My avid readers may recall that I have the opportunity to work in a 100% remote role. For the majority of the week, I share our home with my wife, Nicole, and our toddler son, Finny. Nicole is very conscientious about maintaining a good diet, and my love of snacks is a sensitive topic between us. This is basically a nice way of saying that Nicole thinks I snack too much.

What I noticed is that each of these snacks …

Snacks

… has its own unique barcode.

Snacks with Barcodes

Given my current scenario, I decided to create a Lightning Web Component (LWC) for a Salesforce mobile application called Calorie Counter. This application would use the BarcodeScanner API to read the UPC and provide the number of calories for the snack of my choosing.

Long term, I could use this logic to track my snack consumption, helping me to stay within an acceptable range. However, for now, we’ll walk before we run.

Creating a Snack Object

To keep things simple, I created a Snack__c object in Salesforce DX, which contained the following properties:

  • Name (already exists in Salesforce) to describe the snack
  • Calories (as Calories__c) to note the calories per serving
  • Barcode Value (as UPC__c) to serve as a unique key for each snack

Using my snacks (pictured above) I could quickly enter the expected data for this use case:

Salesforce Snack Data

Creating the Calorie Counter Experience

With an understanding of my data structure and simple use case, I outlined the next steps:

  1. Create an LWC to integrate with the BarcodeScanner API.
  2. If a barcode result exists, then use the scanned value to call an Apex Controller in Salesforce.
  3. The Apex Controller makes a call to the Snack__c object using the barcode value.
  4. If a Snack__c result exists for the scanned value, then return the object data to the LWC.
  5. The LWC displays the data on the device making the request.

Creating a Lightning Web Component (LWC)

Within VS Code, a new LWC can be created using the SFDX: Create Lightning Web Component option. I used the name calorieCounter.

First, I wanted to make sure that my new component could be used pretty much anywhere in the Salesforce ecosystem. I updated calorieCounter.js-meta.xml as shown below:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>53.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>
Enter fullscreen mode Exit fullscreen mode

The BarcodeScanner API was added to my new component using the following information contained in the BarcodeScanner API documentation:

import { getBarcodeScanner } from 'lightning/mobileCapabilities';
Enter fullscreen mode Exit fullscreen mode

Next, I added the following method to determine if the client using the component can scan barcodes:

   connectedCallback() {
        this.myScanner = getBarcodeScanner();
        if (this.myScanner == null || !this.myScanner.isAvailable()) {
            this.scanButtonDisabled = true;
        }
    }
Enter fullscreen mode Exit fullscreen mode

Finally, I added the handleBeginScanClick() method to capture a barcode from the device camera. Then, if successful, the results are passed to an Apex controller in Salesforce to attempt to locate a snack. I also added simple error handling.

   handleBeginScanClick(event) {
        // Reset scannedBarcode to empty string before starting new scan
        this.scannedBarcode = '';
        this.resultsFound = false;
        this.snackFound = false;

        // Make sure BarcodeScanner is available before trying to use it
        // Note: We _also_ disable the Scan button if there's no BarcodeScanner
        if (this.myScanner?.isAvailable()) {
            const scanningOptions = {
                barcodeTypes: [ 
                    this.myScanner.barcodeTypes.UPC_E
                ]
            };
            this.myScanner
                .beginCapture(scanningOptions)
                .then((result) => {
                    this.resultsFound = true;
                    this.scannedBarcode =  result.value;
                    this.scannedBarcodeType = result.type;

                    findSnackByUpcEquals({ upcId: this.scannedBarcode })
                    .then((snack) => {
                        this.snackFound = true;
                        this.snackName = snack.Name;
                        this.snackCalories = snack.Calories__c;
                        this.snackUPC = snack.UPC__c;
                        this.error = undefined;
                        this.buttonLabel = 'Scan Another Snack Barcode';
                    })
                    .catch((error) => {
                        throw error;
                    });
                })
                .catch((error) => {
                    // Handle cancellation and unexpected errors here
                    console.error(error);
                    this.snackFound = false;
                    this.buttonLabel = 'Scan Barcode';


                    // Inform the user we ran into something unexpected
                    this.dispatchEvent(
                        new ShowToastEvent({
                            title: 'Barcode Scanner Error',
                            message:
                                'There was a problem scanning the barcode: ' +
                                JSON.stringify(error) +
                                ' Please try again.',
                            variant: 'error',
                            mode: 'sticky'
                        })
                    );
                })
                .finally(() => {

                    // Clean up by ending capture,
                    // whether we completed successfully or had an error
                    this.myScanner.endCapture();
                });
        } else {
            // BarcodeScanner is not available
            // Not running on hardware with a camera, or some other context issue
            // Let user know they need to use a mobile phone with a camera
            this.dispatchEvent(
                new ShowToastEvent({
                    title: 'Barcode Scanner Is Not Available',
                    message:
                        'Try again from the Salesforce app on a mobile device.',
                    variant: 'error'
                })
            );
        }
    }
Enter fullscreen mode Exit fullscreen mode

This is what the template for the simple component UI looks like:

<template>
    <div if:false={resultsFound} class="slds-align_absolute-center slds-text-align_center 
        slds-text-color_weak">
        Click the Scan Barcode button to open a barcode scanner camera view. Position a barcode in the scanner view to scan it.
    </div>

    <div if:true={resultsFound} class="slds-var-m-vertical_large slds-var-p-vertical_medium 
        slds-text-align_center slds-border_top slds-border_bottom">
        <p>Found Barcode = {scannedBarcode} (type = {scannedBarcodeType})</p>
    </div>

    <div if:true={snackFound} class="slds-var-m-vertical_large slds-var-p-vertical_medium 
        slds-text-align_center slds-border_top slds-border_bottom">
        <div class="slds-m-around_medium">
            <p><span class="slds-text-title_bold">Name</span>: {snackName}</p>
            <p><span class="slds-text-title_bold">Calories</span>: {snackCalories}</p>
            <p><span class="slds-text-title_bold">UPC Value</span>: {snackUPC}</p>
        </div>
    </div>

    <div class="slds-text-align_center slds-p-top_xx-small">
        <lightning-button variant="brand" class="slds-var-m-left_x-small" disabled={scanButtonDisabled}
            icon-name="utility:cases" label={buttonLabel} title="Scan a Snack"
            onclick={handleBeginScanClick}>
        </lightning-button>
    </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Accessing Calorie Data Using an Apex Controller

The Apex controller used by the calorie counter component is simple in design as well, basically containing a single Salesforce query:

public with sharing class SnackController {
    @AuraEnabled(cacheable=true)
    public static Snack__c findSnackByUpcEquals(String upcId) {
        return [
            SELECT Name, Calories__c, UPC__c  
            FROM Snack__c 
            WHERE UPC__c = :upcId 
            LIMIT 1
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

The controller receives the upcId from the component and includes the value in the query of the Snack__c object. The result set is limited to one record, which is returned to the component.

Making the Calorie Counter Available via Salesforce Mobile

Once ready, I was able to use Command-Shift-P and the SFDX: Deploy This Source to Org command to push my code to my Salesforce development org. This allowed the snack object, calorie counter component, and Apex controller to be available for use within Salesforce.

Next, I opened the Setup perspective in Salesforce and navigated to the Apps | App Manager page. I clicked the New Lightning App button and created a new application called CalorieCounter:

New Lightning App

Then, I navigated to the User Interface | Lightning App Builder screen. Here, I created a new Lightning Page called Calorie Counter, which was designed as an App Page with a single region.

On the left side of the screen, I could see my calorieCounter LWC under the Custom section. All I had to do was drag that component over and drop it into the single region for the Lightning-based page.

Adding Custom App

After saving the component, I used the activation process to expose the Lightning page for clients to utilize. During the activation phase, I added the Calorie Counter Lightning page to the CalorieCounter app:

Activation

Finally, I visited the Setup | Apps | Mobile Apps | Salesforce Navigation and added the Calorie Counter app near the top of the selected apps:

Mobile Navigation

Calorie Counter in Action

After downloading and launching my Salesforce mobile app, I could see the Calorie Counter application I just created:

Salesforce Mobile App

Next, I tapped the Calorie Counter application, which displayed the following screen with my custom LWC:

App Start Up

I tapped the Scan Barcode button and scanned the UPC for the Hershey bar:

Scanning Hershey Bar

The barcode scanner on my mobile device quickly recognized the barcode and updated the Calorie Counter application as shown below:

Post Scan

Within a matter of seconds, I was able to look up the calories for the Hershey bar and make the decision if that was a snack I was ready to eat. (I was, and I did.)

Conclusion

Starting in 2021, I have been trying to live by the following mission statement, which I feel can apply to any IT professional:

“Focus your time on delivering features/functionality which extends the value of your intellectual property. Leverage frameworks, products, and services for everything else.”

  • J. Vester

The ability to introduce barcode support into a custom application is quite simple when utilizing Lightning Web Components (LWC) and the BarcodeScanner API. In less than an hour, my knowledge of barcodes went from a casual scanner to a developer who just integrated barcodes into a functional application. Clearly, the engineering team at Salesforce is developing solutions that provide real-world value to common challenges… and they also help me live within my current mission statement.

In today’s world, consumers are driven by what they can and cannot do on their mobile devices. If there is a way for barcode technology to give you a competitive advantage, an application platform (like Salesforce) that offers a solid barcode API should be on your short list of providers to consider.

If you are interested in the source code for this article, simply navigate to the following repository on GitLab:

https://gitlab.com/johnjvester/lwc-calorie-counter

Have a really great day!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .