Some of the coolest things to build are apps with physical hardware. In the past I've used Turbo-iOS (and it's predecessor Turbolinks-iOS) to build a full-fledged POS system for Spina Shop. More recently I've created a specialised app for picking orders in our warehouse.
Employees can create an order pick list containing multiple orders. The app then figures out the most efficient way to pick those orders. In order for the app to recognise products you need a form of identification. Luckily, (almost) all products have a barcode (EAN).
We decided to use handheld barcode scanners because of their reliability and ease of use in a warehouse environment. When connected to an iOS device, they are recognised as a keyboard. After scanning a barcode, the scanner enters all characters at once, followed by the return key. You could "catch" this inside a textfield and use that as your input. This works, but this only works when your cursor is focused on a textfield.
It's better to recreate this functionality in Swift. By using keyCommands we can recognise a barcode scanner's input anywhere in our app. Regardless of focus.
Step 1. Create a VisitableViewController
In order to add functionality to our visitable view, we need to have a VisitableViewController. In my app I want to scan barcodes when I'm in a modal, so I'm going to create a ModalController like this:
iOS handles character inputs a bit differently than you might expect. Uppercase and lowercase characters are recognised by literally adding the shift-key as a modifier. That's why we have two separate methods to catch both lowercase and uppercase characters.
overridevar keyCommands: [UIKeyCommand]? {
var commands:[UIKeyCommand] = []
let characters = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
for character in characters {
let txt = character as String
if Int(txt) == nil {
commands.append(UIKeyCommand(input: txt, modifierFlags: [UIKeyModifierFlags.shift], action: #selector(uppercasedKeyPressed(_:))))
commands.append(UIKeyCommand(input: txt, modifierFlags: [], action: #selector(lowercasedKeyPressed(_:))))
} else {
commands.append(UIKeyCommand(input: txt, modifierFlags: [], action: #selector(uppercasedKeyPressed(_:))))
}
}
commands.append(UIKeyCommand(input: "\r", modifierFlags: [], action: #selector(returnPressed)))
return commands
}
@objcfunc lowercasedKeyPressed(_ input: UIKeyCommand) {
// Input lowercase key
}
@objcfunc uppercasedKeyPressed(_ input: UIKeyCommand) {
// Input uppercase key
}
@objcfunc returnPressed() {
// Pressed enter
}
Step 4. Store barcode
Add an array to your class so you can store the barcode characters.
import { Controller } from "stimulus"
export default class extends Controller {
connect() {
this.element[this.identifier] = this
}
scan(code) {
console.log(`My barcode: ${code}!`)
}
}
Bonus: add sound!
There's a neat little Swift library called SwiftySound that makes it dead simple to add sounds to your native code. You can use it to create a helpful sound when scanning products.