Saltare al contenuto principale

Come costruire uno scanner di codici a barre Ionic con Capacitor

Costruisci uno scanner di codici a barre Ionic con Capacitor 8: configura l'app, aggiungi @capacitor/barcode-scanner, scansione i codici QR e a barre su iOS, Android e web.

Crediti dell'articolo

Martin Donadieu

Scrittore

Valeria

Recensore

Jordan

Curatore

Come costruire uno scanner di codici a barre Ionic con Capacitor

Per creare uno scanner di codici a barre Ionic con Capacitor, crea un'app Ionic con l'integrazione Capacitor e installa il pacchetto ufficiale. @capacitor/barcode-scanner plugin, aumentare le funzionalità di Android minSdkVersion aggiungi la descrizione dell'uso della camera iOS 26 e chiama CapacitorBarcodeScanner.scanBarcode() da un pulsante. Il plugin apre uno scanner a schermo intero nativo su iOS e Android, uno scanner del browser sul web e restituisce il testo decodificato e il formato.

Questa guida costruisce un'applicazione di scanner funzionante in Ionic Angular su Capacitor 8, coprendo poi la filtratura dei formati, l'elaborazione degli errori, gli engine di scansione Android, la scansione continua, gli scanner di hardware aziendali e le comuni fallite.

Cosa costruirai

Un'app Ionic a pagina singola con un pulsante di scansione che:

  • apre lo scanner della camera
  • mostra ogni risultato con il suo formato
  • ti consente di copiare o aprire il valore scansito
  • handles cancel and permission errors cleanly.

L'code utilizza componenti Angular standalone. Le chiamate del plugin sono identiche in React o Vue, quindi cambia solo la sintassi del template.

Requisiti previsti

  • Node.js LTS e Bun.
  • Per Android: Android Studio con un SDK e un dispositivo o un emulatore con una camera.
  • For iOS: un Mac con Xcode 26, che App Store Connect richiede per le pubblicazioni a partire da aprile 2026.
  • Un dispositivo fisico è il meglio. Gli emulatori possono scansionare con una camera virtuale, ma la luce e l'acquisto reale contano per i codici a barre.

Passo 1: Crea l'app Ionic

bunx @ionic/cli start barcode-scanner blank --type=angular-standalone --capacitor
cd barcode-scanner

La Ionic CLI crea la scaffolding dell'app Angular con @capacitor/core e @capacitor/cli già installato. Controlla capacitor.config.ts: appId deve essere il tuo ID di dominio inverso, ad esempio com.example.scanner, e webDir deve corrispondere all'output di compilazione (www per Ionic Angular).

Compila una volta affinché le piattaforme native abbiano qualcosa da copiare:

bun run build

e già installato. Controlla

bun add @capacitor/android @capacitor/ios
bunx cap add android
bunx cap add ios

Capacitor 8 crea nuovi progetti iOS con Package Manager di Swift. Se stai aggiornando un'app più vecchia, segui l' Capacitor 8 guida di aggiornamento primo.

Passo 3: Installa il plugin dello scanner a barre

bun add @capacitor/barcode-scanner
bunx cap sync

@capacitor/barcode-scanner È lo scanner ufficiale del team Capacitor. La versione 3.x supporta Capacitor 8.

Configurazione Android

Il plugin richiede Android API 26 o superiore. Capacitor 8 predefinito è 24, quindi modifica android/variables.gradle:

ext {
    minSdkVersion = 26
    // keep the other values Capacitor generated
}

On Android you can choose the decoding engine per scan: ZXing (default, supports every format the plugin lists) or Google ML Kit (fast on difficult codes, but no MaxiCode, RSS-14, RSS Expanded, or UPC/EAN extension).

Configurazione iOS

Aggiungi una descrizione di utilizzo della camera ios/App/App/Info.plist:

<key>NSCameraUsageDescription</key>
<string>The camera is used to scan barcodes and QR codes.</string>

Without it, iOS terminates the app on the first camera access. Write the sentence for the user, since App Review reads it too. iOS uses Apple’s Vision framework, which supports every listed format except MaxiCode and UPC/EAN extension, and does not distinguish UPC-A from EAN-13.

Passo 4: Scrivi il servizio dello scanner

Tenere le chiamate del plugin in un servizio le rende facili da riutilizzare e da testare.

// src/app/services/scanner.service.ts
import { Injectable } from '@angular/core';
import { Capacitor } from '@capacitor/core';
import {
  CapacitorBarcodeScanner,
  CapacitorBarcodeScannerAndroidScanningLibrary,
  CapacitorBarcodeScannerCameraDirection,
  CapacitorBarcodeScannerScanOrientation,
  CapacitorBarcodeScannerTypeHint,
  CapacitorBarcodeScannerTypeHintALLOption,
} from '@capacitor/barcode-scanner';

export interface ScanResult {
  value: string;
  format: string;
  scannedAt: Date;
}

export type ScanOutcome =
  | { status: 'ok'; result: ScanResult }
  | { status: 'cancelled' }
  | { status: 'denied' }
  | { status: 'error'; message: string };

@Injectable({ providedIn: 'root' })
export class ScannerService {
  async scan(onlyQr = false): Promise<ScanOutcome> {
    try {
      const { ScanResult, format } = await CapacitorBarcodeScanner.scanBarcode({
        hint: onlyQr
          ? CapacitorBarcodeScannerTypeHint.QR_CODE
          : CapacitorBarcodeScannerTypeHintALLOption.ALL,
        scanInstructions: 'Point the camera at a barcode',
        cameraDirection: CapacitorBarcodeScannerCameraDirection.BACK,
        scanOrientation: CapacitorBarcodeScannerScanOrientation.ADAPTIVE,
        cancelButtonAccessibilityLabel: 'Cancel scanning',
        torchButtonOnAccessibilityLabel: 'Turn flashlight off',
        torchButtonOffAccessibilityLabel: 'Turn flashlight on',
        android: {
          scanningLibrary: CapacitorBarcodeScannerAndroidScanningLibrary.MLKIT,
        },
        web: {
          showCameraSelection: true,
        },
      });

      return {
        status: 'ok',
        result: {
          value: ScanResult,
          format: CapacitorBarcodeScannerTypeHint[format] ?? String(format),
          scannedAt: new Date(),
        },
      };
    } catch (err: any) {
      const code: string = err?.code ?? '';
      if (code.endsWith('0006')) return { status: 'cancelled' };
      if (code.endsWith('0007')) return { status: 'denied' };
      return { status: 'error', message: err?.message ?? 'Scan failed' };
    }
  }

  get platform() {
    return Capacitor.getPlatform();
  }
}

Il plugin restituisce gli errori con codici nel formato OS-PLUG-BARC-XXXXSul iOS, 0006 significa che l'utente ha annullato e 0007 significa che l'accesso alla fotocamera è stato negato. Tratta l'annullamento come un esito normale, non come un errore. Registra il code raw su Android durante il testing per confermare la stessa mappatura sui dispositivi target.

La format nel risultato è un valore enum numerico. CapacitorBarcodeScannerTypeHint[format] lo converte nuovamente nel nome come QR_CODE o EAN_13.

Alternativamente, puoi utilizzare

// src/app/home/home.page.ts
import { Component, inject, signal } from '@angular/core';
import { DatePipe } from '@angular/common';
import {
  IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonItem, IonLabel,
  IonFab, IonFabButton, IonIcon, IonToggle, IonNote, ToastController,
} from '@ionic/angular/standalone';
import { addIcons } from 'ionicons';
import { scanOutline } from 'ionicons/icons';
import { ScannerService, ScanResult } from '../services/scanner.service';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  imports: [
    DatePipe, IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonItem,
    IonLabel, IonFab, IonFabButton, IonIcon, IonToggle, IonNote,
  ],
})
export class HomePage {
  private scanner = inject(ScannerService);
  private toast = inject(ToastController);

  results = signal<ScanResult[]>([]);
  onlyQr = signal(false);
  scanning = signal(false);

  constructor() {
    addIcons({ scanOutline });
  }

  async scan() {
    if (this.scanning()) return;
    this.scanning.set(true);
    const outcome = await this.scanner.scan(this.onlyQr());
    this.scanning.set(false);

    if (outcome.status === 'ok') {
      this.results.update((list) => [outcome.result, ...list]);
    } else if (outcome.status === 'denied') {
      await this.show('Camera access is off. Enable it in Settings to scan.');
    } else if (outcome.status === 'error') {
      await this.show(outcome.message);
    }
  }

  private async show(message: string) {
    const t = await this.toast.create({ message, duration: 3000 });
    await t.present();
  }
}
<!-- src/app/home/home.page.html -->
<ion-header>
  <ion-toolbar>
    <ion-title>Barcode Scanner</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <ion-list>
    <ion-item>
      <ion-toggle [checked]="onlyQr()" (ionChange)="onlyQr.set($event.detail.checked)">
        QR codes only
      </ion-toggle>
    </ion-item>

    @for (r of results(); track r.scannedAt) {
      <ion-item>
        <ion-label>
          <h2>{{ r.value }}</h2>
          <p>{{ r.format }} · {{ r.scannedAt | date: 'shortTime' }}</p>
        </ion-label>
      </ion-item>
    } @empty {
      <ion-item lines="none">
        <ion-note>No scans yet. Tap the button to scan.</ion-note>
      </ion-item>
    }
  </ion-list>

  <ion-fab slot="fixed" vertical="bottom" horizontal="end">
    <ion-fab-button (click)="scan()" [disabled]="scanning()" aria-label="Scan a barcode">
      <ion-icon name="scan-outline" aria-hidden="true"></ion-icon>
    </ion-fab-button>
  </ion-fab>
</ion-content>

Passo 5: Costruisci la pagina

bun run build
bunx cap sync
bunx cap run android
bunx cap run ios

Passo 6: Esegui su dispositivi bun run start Serve l'applicazione sul localhost, dove i browser consentono l'accesso alla camera. Per un IP LAN è necessario HTTPS.

To iterare più velocemente, utilizza il live reload su un dispositivo: bunx cap run android --livereload --external Ricarica l'applicazione ogni volta che si salva.

Sottotipi supportati

Sottotipo Android ZXing Kit di sviluppo Android ML IOS
QR Code, Codici a barre Azteco, Data Matrix, PDF417 Sì Sì Sì
EAN-13, EAN-8, UPC-A, UPC-E Sì Sì Sì (UPC-A e EAN-13 trattati allo stesso modo)
Code 128, Code 39, Code 93, Codabar, ITF Sì Sì Sì
RSS-14, RSS Espanso Sì No Sì
MaxiCode Sì No No
Estensione UPC/EAN Sì No No

Se passi un formato non supportato come hintLa gestione dei valori scansionati in modo sicuro

Gestione sicura dei valori scansiti

Seleziona un formato di codice a barre supportato

  • Verifica gli URL prima di aprirli e mostra il dominio all'utente per primo.
  • Non eseguire le stringhe scannee come code o iniettarle nell'HTML.
  • Verifica il dígito di controllo dei codici prodotto prima di chiamare il tuo backend.
  • Limita le richieste al backend se gli utenti possono scansionare velocemente.

Oltre lo scanner di base

scanBarcode è un flusso a schermo intero, a un solo utilizzo. Copre la maggior parte delle app. Altre esigenze richiedono strumenti diversi:

  • Scanning continuo nella tua UI personalizzata. Esegui un feed di camera dietro la tua UI web con @capgo/camera-previewgrabba le frame con captureSamplee decodificali in JavaScript con una libreria come zxing-wasm.
  • Dispositivi di fascia d'impresa robusti. Zebra handhelds have hardware scanners. @capgo/capacitor-zebra-datawedge gestisce i profili DataWedge e i trigger di scansione, che sono più veloci e affidabili rispetto alla camera di quei dispositivi.
  • Captura di documenti. Per ricevute e moduli cartacei, un plugin di scanner di documenti si adatta meglio di un lettore di codici a bar. Vedi il directory dei plugin.

Provenienti da Cordova? La nostra guida al lettore di codici a barre di Cordova copre gli vecchi plugin e un percorso di migrazione.

Troubleshooting

iOS app closes when scanning starts. NSCameraUsageDescription L'applicazione iOS si chiude quando inizia la scansione. Info.plist.

Il build Android fallisce con un errore di fusione del manifesto o minSdk. minSdkVersion rimane 24. Impostalo a 26 in android/variables.gradle e sincronizza.

Lo scanner si apre ma non legge mai il code. Prova l'altra engine Android, migliora la illuminazione, utilizza la torcia e limita hint ai formati che ti aspetti. I codici molto piccoli o danneggiati richiedono la camera più vicina.

Non è autorizzato ogni volta. L'utente ha negato l'accesso alla camera precedentemente. Mostra un messaggio che spiega come abilitarlo nei impostazioni del sistema. L'OS non mostrerà più la richiesta.

Lo scanner web non si avvia. La pagina non è servita su HTTPS o localhost, o un'altra scheda tiene la camera.

Impostazione dell'orientamento ignorata su tablet. A partire dalle app che puntano a Android SDK 36, Android 16 ignora le orientazioni fisse su schermi grandi. Utilizza ADAPTIVE.

Invia riparazioni senza attendere la revisione

Once the scanner is live, most changes, such as new validation rules, UI tweaks, or a different backend lookup, are web code. Aggiornamenti live Capgo pubblica quelle aggiornate nei dispositivi in pochi minuti, mentre gli aggiornamenti dei plugin Info.plist Le modifiche continuano a passare attraverso i negozi. Quando hai bisogno di una nuova build nativa senza un setup Mac locale, Capgo Build genera file binari iOS e Android firmati in cloud.

Wrap-up

Un lettore di codici a barre Ionic su Capacitor 8 richiede un plugin ufficiale, due modifiche di configurazione native (Android) minSdkVersion 26 and the iOS camera usage string), and a single scanBarcode chiamata. Limita i formati quando puoi, trattare gli errori di annullamento e di autorizzazione come esiti normali, validare tutto ciò che si scandisce, e cercare una anteprima della camera o DataWedge quando il flusso a una sola passata non è sufficiente.

Aggiornamenti in tempo reale per le app Capacitor

Quando un bug nel layer web è attivo, invia la correzione attraverso Capgo invece di attendere giorni per l'approvazione della store. Gli utenti ricevono l'aggiornamento in background mentre le modifiche native rimangono nel normale percorso di revisione.

Ultimi articoli dal nostro Blog

Capgo vi dà le migliori informazioni che avete bisogno per creare un'app mobile veramente professionale.