为了在Ionic中创建一个条码扫描器,使用Capacitor,首先创建一个集成了Capacitor的Ionic应用,安装官方的Capacitor条码扫描器插件。 @capacitor/barcode-scanner 该插件在iOS和Android上打开一个原生全屏扫描器,在Web上打开一个浏览器扫描器,并返回解码的文本和格式。 minSdkVersion 本教程在Ionic Angular 8上构建一个工作的扫描器应用,涵盖格式过滤、错误处理、Android扫描引擎、连续扫描、企业硬件扫描器和常见故障。 CapacitorBarcodeScanner.scanBarcode() 您将构建
This tutorial builds a working scanner app in Ionic Angular on Capacitor 8, then covers format filtering, error handling, Android scanning engines, continuous scanning, enterprise hardware scanners, and common failures.
该应用将使用__CAPGO_KEEP_0__扫描条形码,__CAPGO_KEEP_1__将扫描条形码并返回解码的文本和格式。
该应用将使用__CAPGO_KEEP_0__扫描条形码,__CAPGO_KEEP_1__将扫描条形码并返回解码的文本和格式。
- 打开相机扫描器
- 显示每个结果的格式
- 让您复制或打开扫描值
- 清洁地处理取消和权限错误
该code使用Angular独立组件。插件调用在React或Vue中相同,只是模板语法发生了变化。
先决条件
- Node.js LTS和Bun。
- 对于Android:Android Studio与SDK,以及具有摄像头的设备或模拟器。
- 对于iOS:一台Mac,Xcode 26,App Store Connect要求从2026年4月起上传。
- 物理设备最好。模拟器可以使用虚拟摄像头扫描,但真实的照明和焦距对于条形码很重要。
步骤1:创建Ionic应用
bunx @ionic/cli start barcode-scanner blank --type=angular-standalone --capacitor
cd barcode-scanner
The Ionic CLI scaffolds the Angular app with @capacitor/core 和 @capacitor/cli 已经安装。检查 capacitor.config.ts: appId 应该是你的反向域名ID,例如 com.example.scanner,和 webDir 应该与构建输出匹配(www 对于Ionic Angular)。
只需构建一次,使原生平台有东西可以复制:
bun run build
步骤2:添加Android和iOS
bun add @capacitor/android @capacitor/ios
bunx cap add android
bunx cap add ios
Capacitor 8会创建新的iOS项目使用Swift Package Manager。如果您正在升级较旧的应用程序,请遵循 Capacitor 8升级指南 首先。
步骤3:安装条形码扫描器插件
bun add @capacitor/barcode-scanner
bunx cap sync
@capacitor/barcode-scanner 是Capacitor团队的官方扫描器。版本3.x支持Capacitor8。
Android配置
该插件需要AndroidAPI26或更高版本。Capacitor8默认为24,因此编辑 android/variables.gradle:
ext {
minSdkVersion = 26
// keep the other values Capacitor generated
}
在Android上,您可以根据扫描选择解码引擎:ZXing(默认,支持插件列出的所有格式)或Google ML Kit(在困难代码上快速,但不支持MaxiCode、RSS-14、RSS扩展或UPC/EAN扩展)。
iOS配置
添加一个摄像头使用说明到 ios/App/App/Info.plist:
<key>NSCameraUsageDescription</key>
<string>The camera is used to scan barcodes and QR codes.</string>
没有它,iOS会在首次摄像头访问时终止应用。为用户写一句句子,因为App Review也会读它。iOS使用Apple的Vision框架,该框架支持除MaxiCode和UPC/EAN扩展外的所有列出的格式,并且不区分UPC-A和EAN-13。
步骤4:写扫描服务
在页面/区域:Capgo页面。角色:UI标签。见于:关于.astro页面。消息键`about_how_step_label`(关于如何步骤标签)。
// 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();
}
}
将插件调用放在服务中使它们易于重用和测试。 OS-PLUG-BARC-XXXX该插件以代码形式返回错误。 0006 .在iOS上, 0007 means camera access was denied. Treat cancel as a normal outcome, not an error. Log the raw code on Android during testing to confirm the same mapping on your target devices.
在结果中 format 转换回一个数字枚举值 CapacitorBarcodeScannerTypeHint[format] 例如 QR_CODE 或 EAN_13.
在Capacitor live-update替代方案比较页面中,
// 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>
在Appflow比较/迁移营销文案中,
bun run build
bunx cap sync
bunx cap run android
bunx cap run ios
在Capawesome比较页面中, bun run start 在咨询服务页面中,
步骤5:构建页面 bunx cap run android --livereload --external 步骤6:在设备上运行
对于Web版本,
| 格式 | 安卓ZXing | 安卓ML Kit | iOS |
|---|---|---|---|
| 二维码 Code, Aztec, Data Matrix, PDF417 | 是 | 是 | 是 |
| 条形码 | 是 | 是 | 是(UPC-A和EAN-13一样) |
| Code 128, Code 39, Code 93, Codabar, ITF | Yes | Yes | Yes |
| 简易扫描 | Yes | No | Yes |
| No | Yes | No | No |
| UPC/EAN 扩展 | Yes | 是 | 是 |
No hint如果您传入一个不支持的格式作为
,插件会回退到扫描任何格式。
安全处理扫描值
- 扫描的条码是未经信任的输入。 在对其采取行动之前:
- 不要将扫描的字符串作为 code 运行,也不要将它们注入 HTML 中。
- 不要将扫描的字符串作为__CAPGO_KEEP_0__运行或将其注入HTML。
- 对于产品代码,验证校验码之前调用您的后端。
超越基本扫描器
scanBarcode 是一个一次性全屏流程。它覆盖了大多数应用程序。其他需求需要其他工具:
- 在您的UI中进行连续扫描。 在您的Web UI后面运行一个摄像头 feed 与 @capgo/摄像头预览,捕获帧并在JavaScript中使用一个库进行解码
captureSample坚固的企业设备。zxing-wasm. - 泽巴手持设备具有硬件扫描器。 @__CAPGO_KEEP_0__/__CAPGO_KEEP_1__-zebra-datawedge @capgo/capacitor-zebra-datawedge 文档捕获
- __CAPGO_KEEP_0__=Capacitor, __CAPGO_KEEP_1__=DataWedge 对于收据和纸质表格,一个文档扫描插件比条形码扫描器更合适。见到 插件目录.
从Cordova过来的?我们的 cordova条形码扫描器指南 涵盖了旧的插件和迁移路径。
故障排除
iOS 应用程序在扫描开始时关闭。 NSCameraUsageDescription iOS应用程序在扫描开始时关闭。 Info.plist.
缺失于 minSdkVersion Android构建失败,出现manifest合并或minSdk错误。 android/variables.gradle 仍然是24。将其设置为26在
Scanner opens but never reads the code. 尝试使用其他 Android 引擎,改善照明,使用手电筒,并限制 hint 到您期望的格式。非常小或损坏的代码需要摄像头更近。
每次都拒绝权限。 用户之前拒绝了摄像头访问。显示一个解释如何在系统设置中启用它的消息。操作系统不会再次显示提示。
Web 扫描器没有启动。 页面未通过 HTTPS 或 localhost 服务,或者另一个标签持有摄像头。
平板电脑上的方向设置被忽略。 从 Android SDK 36 开始,Android 16 在大屏幕上忽略固定方向。使用 ADAPTIVE.
不必等待审查就可以将修复推送到应用程序
一旦扫描器活跃,几乎所有更改,例如新验证规则、UI 调整或不同的后端查找,都是 web code。 Capgo 实时更新 将这些推送到已安装的应用程序几分钟内,而插件升级和 Info.plist 当您需要一个新的本地构建而不需要本地Mac设置时,变化仍然会通过商店。 Capgo 构建 在云端生成签名的iOS和Android二进制文件
Wrap-up
一款Ionic条形码扫描器在Capacitor 8中只需要一个官方插件,两个本地配置修改(Android 26和iOS摄像头使用字符串),以及一个单独的 minSdkVersion 26和iOS摄像头使用字符串),和一个 scanBarcode Article credits