這篇會介紹我是如何使用Ionic來實現「條碼掃描功能(Barcode Scanner)」,我使用在Capacitor-Community找到的【capacitor-community/barcode-sacnner】插件來做演示。




安裝Plugins

使用命令安裝Barcode Scanner套件並且同步專案
npm install @capacitor-community/barcode-scanner

Android

ionic cap sync android

Ios

ionic cap sync ios



Android設定

找到「Android\app\src\main\AndroidManifest.xml」在裡面加入以下設定

manifest

xmlns:tools="http://schemas.android.com/tools"

application

android:hardwareAccelerated="true"

permission

<uses-permission android:name="android.permission.CAMERA" />

SDK

<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />



Ios設定

我們在Xcode找到「App/App/」底下的Info.plist檔案」「Information Property List」按下「+」符號

找到「Privacy - Camera Usage Description」項目,並且在「Value」的地方填入任何你想要顯示給User的提示訊息




Barcode Scanner設定

在Html和ts裡面加入以下程式碼,範例使用Rxjs來呈現,另外再注入Document和Renderer2來操作DOM元素,最後使用Ionic CLI編譯專案即可

global.scss

body.scanner-active {
  --background: transparent;
  --ion-background-color: transparent;
}

tab1.page.html

<ng-container *ngIf="(scanActive$ | async); else stopScanTemplate">
  <ion-button expand="full" (click)="stopScanner()">停止掃描</ion-button>
</ng-container>
<ng-template #stopScanTemplate>
  <ion-button expand="full" (click)="startScanner()">開始掃描</ion-button>
</ng-template>

tab1.page.ts

private scanActiveSubject$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
private destroy$ = new Subject();
private checkPermission$ = defer(() => from(BarcodeScanner.checkPermission({ force: true }))).pipe(
  map(permissionResult => {
    if (permissionResult.granted) {
      return true;
    }
    return false;
  })
);
private startActiveProgram$ = this.scanActiveSubject$.pipe(
  switchMap(scanActiveResult => {
    if (scanActiveResult) {
      return this.checkPermission$.pipe(
        switchMap(checkPermissionResult => {
          if (checkPermissionResult) {
            return defer(() => from(BarcodeScanner.prepare())).pipe(
              tap(() => this.renderer.addClass(this.document.body, 'scanner-active')),
              switchMap(() => defer(() => from(BarcodeScanner.startScan()))),
tap(barcodeScannerResult => { if (barcodeScannerResult.hasContent) { alert(barcodeScannerResult.content); this.scanActiveSubject$.next(false); } }) ); } return of(checkPermissionResult); }) ) } return defer(() => from(BarcodeScanner.stopScan())).pipe( tap(() => this.renderer.removeClass(this.document.body, 'scanner-active')), ); }), takeUntil(this.destroy$) ); constructor(@Inject(DOCUMENT) private document: Document, private renderer: Renderer2) {} ngOnInit(): void { this.startActiveProgram$.subscribe(); } get scanActive$(): Observable<boolean> { return this.scanActiveSubject$.asObservable(); } ngOnDestroy(): void { this.destroy$.next(''); this.destroy$.complete(); } startScanner() { this.scanActiveSubject$.next(true); } stopScanner() { this.scanActiveSubject$.next(false); }
💡BarcodeScanner.checkPermission是用來判斷和詢問相機的使用權限,這裡範例的關係就簡單寫個判斷呈現而已
💡BarcodeScanner.prepare則是官方宣稱可以提高性能(一點點XD)【點我前往參考
💡Renderer2則是用來替換Body的class(原生相機會呈現在WebView底下因此需要把Body的背景色調整成透明的)



掃描成功!最後來美化一下界面,加入以下CSS

tab1.page.scss

.scan-box {
  position: absolute;
  margin: auto;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: 300px;
  height: 300px;
  border-radius: 10px;
  background:
    linear-gradient(to right, white 10px, transparent 10px) 0 0,
    linear-gradient(to right, white 10px, transparent 10px) 0 100%,
    linear-gradient(to left, white 10px, transparent 10px) 100% 0,
    linear-gradient(to left, white 10px, transparent 10px) 100% 100%,
    linear-gradient(to bottom, white 10px, transparent 10px) 0 0,
    linear-gradient(to bottom, white 10px, transparent 10px) 100% 0,
    linear-gradient(to top, white 10px, transparent 10px) 0 100%,
    linear-gradient(to top, white 10px, transparent 10px) 100% 100%;
  background-repeat: no-repeat;
  background-size: 50px 50px;
  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.3);
}

tab1.page.html

<ng-container *ngIf="(scanActive$ | async); else stopScanTemplate">
  <ion-button expand="full" (click)="stopScanner()">停止掃描</ion-button>
  <div class="scan-box"></div>
</ng-container>
<ng-template #stopScanTemplate>
  <ion-button expand="full" (click)="startScanner()">開始掃描</ion-button>
</ng-template>
完成!加了外框是不是感覺整個專業了許多呢!