Adding Barcode Support to a Salesforce Mobile Application

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

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

My use of technology even extends to frugal shopping approaches where I can scan the barcode of a product of interest to see if the same product is available at a better price. This made me wonder how easy it is to implement barcode technology in a custom app or component.

Barcode support in Salesforce Mobile apps

The engineering team at Salesforce knows that barcodes are a quick and easy way for mobile users to accurately identify information. Both UPC barcodes and QR codes have been around for decades now, and their use is not fading away.

With 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 some common use cases for creating a Lightning Web Component (LWC) which includes the BarcodeScanner API:

  • Perform a search in Salesforce, using the barcode as the primary key.

  • Autofill the form data by reading the contact data inside the QR code.

  • Make an external system call using barcode data, such as tracking a shipment via a third-party API.

In this article, I will explore the first option, where a scanned barcode will search for data stored within 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 consistently. When combined with Visual Studio (VS) code and the Salesforce extension package, working with Salesforce becomes a seamless process.

For example, Command-Shift-P or Windows-Shift-P provides quick access to SFDX commands like the ones shown below:

Seeing these improvements firsthand excited me for the opportunity to use VS Code and the Salesforce Extension Pack to create something for the Salesforce platform.

Calorie Counter Use Case

My avid readers may remember that I have a 100% chance of working in a remote role. Most days of the week, I share our home with my wife Nicole and our young son Vinny. Nicole is very keen on maintaining a good diet, and my love of snacks is a sensitive topic among us. This is basically a nice way of saying that Nicole thinks I snack a lot.

What I noticed is that both of these snacks…

… has its own unique barcode.

Given my current scenario, I decided to build a Lightning Web Component (LWC) for a Salesforce mobile app called Calorie Counter. This app will use the BarcodeScanner API to read the UPC and provide the calorie count for a snack of my choice.

In the long run, I can use this reasoning to track my snack consumption, which helps me stay within an acceptable range. However, for now, we’ll walk before we run.

Create a snack object

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

  • Noun (Already in Salesforce) To describe the snack

  • Calories (as Calories__c) to note the calories per serving

  • barcode value (as UPC__c) to act as a unique key for each snack

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

Create a calorie counter experience

Understanding my data structure and simple use case, I’ve defined the following steps:

  1. Create a LWC to integrate with the BarcodeScanner API.

  2. If there is a barcode result, use the scanned value to call Apex Controller in Salesforce.

  3. Apex Controller makes a call to Snack__c An object using a barcode value.

  4. if it was Snack__c There is a result of the value being scanned, then it returns the object data to LWC.

  5. LWC displays the data on the device making the request.

Create a Lightning Web Component (LWC)

Within VS Code, a new LWC can be created using the SFDX: Lightning Web Component Create 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>

The BarcodeScanner API has been added to my new component with the following information provided in the BarcodeScanner API documentation:

import { getBarcodeScanner } from 'lightning/mobileCapabilities';

Then, 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;
        }
    }

Finally, I added a file handleBeginScanClick() A way to capture a barcode from the device’s camera. Then, if successful, the results are passed to the Apex console in Salesforce to attempt to locate the snack. I’ve also added a simple error handling.

{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”; // Report the user that we encountered something this. unexpected dispatchEvent(New ShowToastEvent({title: “Barcode Scanner Error” , Message: “There was a problem scanning barcode:” + JSON.stringify(error) + “Please try again.” , Alternative: “Error”, mode : ‘sticky’})) ;}). finally (() => { // clean up by ending the capture, // whether we completed successfully or had an error this.myScanner.endCapture();}); } else { // BarcodeScanner is not available // Doesn’t work on devices with a camera, or some other context issue // Let the user know they need to use a mobile phone with this camera this. “,” message: “Try again from the Salesforce app on a mobile device.”, Alternative: “Error” }))); }} “data-lang =” text / javascript “>

   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'
                })
            );
        }
    }

This is what a simple component UI sample 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>

Accessing calorie data using the Apex console

The Apex console that the Calorie Counter component uses is simple in design as well, and basically contains 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
        ];
    }
}

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

Availability of a calorie counter via Salesforce Mobile

Once ready, I was able to use Command-Shift-P and the SFDX: Publish this resource at Org Command to push my code to my Salesforce development organization. This allowed the snack object, calorie counter component, and Apex console to be available for use within Salesforce.

After that, I opened a file prove Perspective in Salesforce and go to Applications | Application manager page. You clicked on a file New Lightning app button and create a new app called CalorieCounter:

Then I moved to User Interface | Lightning App Builder Monitor. Here, I created a file lightning page Call Calorie Counter, which is designed to be Application page in one area.

On the left side of the screen, I could see a file calorieCounter LWC under a dedicated section. All I had to do was drag and drop this component into one area of ​​the Lightning-based page.

After saving the component, I used the activation process to display the Lightning page for customers to use. During the activation phase, I added the Lightning Calorie Counter page to a file CalorieCounter Implementation:

Finally, I visited setting | Applications | Mobile applications | Salesforce Navigation . added Calorie Counter The app is near the top of the selected apps:

Calorie counter at work

After downloading and running the Salesforce mobile app, I was able to see the Calorie Counter app I had just created:

Next, I click on the Calorie Counter app, which brings up the following screen with my custom LWC:

You clicked on a file barcode scanning Button and UPC Scan for Hershey Tape:

The barcode scanner on my mobile device quickly recognized the barcode and updated the calorie counter app as shown below:

Within seconds, I was able to look up the calories of a Hershey bar and decide if this was a snack I was ready to eat. (I was, and I did).

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

Focus your time on offering features/functions that increase the value of your intellectual property. Take advantage of frameworks, products, and services for everything else.”

– J Pfister

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

In today’s world, consumers are paid with what they can and cannot do on their mobile devices. If there is a way that barcode technology can give you a competitive advantage, an application platform (such as Salesforce) that provides a robust barcode API should be on the shortlist of providers to consider.

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

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

Have a really nice day!

.

Leave a Comment