DEV Community

Cover image for HarmonyOS NEXT Development Case: QR Code Generation and Recognition
zhongcx
zhongcx

Posted on

HarmonyOS NEXT Development Case: QR Code Generation and Recognition

Image description

This article demonstrates how to implement QR code generation and recognition in HarmonyOS NEXT using ArkUI components and system capabilities. The solution leverages multiple HarmonyOS Kits including ScanKit, MediaLibraryKit, and ImageKit to achieve core functionalities.

Code Structure Overview

import {
  componentSnapshot, // Component snapshot
  promptAction, // System prompt actions
  SegmentButton, // Segmented control component
  SegmentButtonItemTuple, // Type for segment items
  SegmentButtonOptions // Segmented control options
} from '@kit.ArkUI'; // Import ArkUI component library

import { photoAccessHelper } from '@kit.MediaLibraryKit'; // Media library access
import { common } from '@kit.AbilityKit'; // Common abilities
import { fileIo as fs } from '@kit.CoreFileKit'; // File system operations
import { image } from '@kit.ImageKit'; // Image processing
import { BusinessError, pasteboard } from '@kit.BasicServicesKit'; // Clipboard services
import { hilog } from '@kit.PerformanceAnalysisKit'; // Logging system
import { detectBarcode, scanBarcode } from '@kit.ScanKit'; // Barcode handling

@Entry // Application entry
@Component // Custom component
struct QrCodeGeneratorAndScanner {
  // Component state management
  @State private buttonOptions: SegmentButtonOptions = SegmentButtonOptions.capsule({
    buttons: [{ text: 'Generate QR' }, { text: 'Scan QR' }] as SegmentButtonItemTuple,
    multiply: false, // Single selection
    fontColor: Color.White,
    selectedFontColor: Color.White,
    selectedBackgroundColor: Color.Orange,
    backgroundColor: "#d5d5d5",
    backgroundBlurStyle: BlurStyle.BACKGROUND_THICK
  })
  @State private sampleText: string = 'hello world';
  @State private inputText: string = "";
  @State private scanResult: string = "";
  @State @Watch('selectIndexChanged') selectIndex: number = 0
  @State @Watch('selectedIndexesChanged') selectedIndexes: number[] = [0];
  private qrCodeId: string = "qrCodeId"
  @State private scanResultObject: scanBarcode.ScanResult = ({} as scanBarcode.ScanResult)
  //... Other state variables

  // Event handlers
  selectedIndexesChanged() {
    this.selectIndex = this.selectedIndexes[0]
  }

  selectIndexChanged() {
    this.selectedIndexes[0] = this.selectIndex
  }

  private copyToClipboard(text: string): void {
    const pasteboardData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text);
    pasteboard.getSystemPasteboard().setData(pasteboardData);
    promptAction.showToast({ message: 'Copied' });
  }

  build() {
    Column() {
      SegmentButton({
        options: this.buttonOptions,
        selectedIndexes: this.selectedIndexes
      }).width('400lpx').margin({ top: 20 })

      Tabs({ index: this.selectIndex }) {
        // QR Generation Tab
        TabContent() {
          Scroll() {
            Column() {
              // Input section with sample/clear buttons
              QRCode(this.inputText)
                .width('300lpx')
                .aspectRatio(1)
                .id(this.qrCodeId)

              SaveButton().onClick(async () => {
                // Save QR to photo library
                const context = getContext(this) as common.UIAbilityContext;
                let helper = photoAccessHelper.getPhotoAccessHelper(context);
                //... Image capture and saving logic
              })
            }
          }
        }

        // QR Scanning Tab
        TabContent() {
          Scroll() {
            Column() {
              // Camera scan and gallery picker buttons
              Row() {
                Text('Scan').onClick(() => {
                  scanBarcode.startScanForResult(getContext(this), {
                    enableMultiMode: true,
                    enableAlbum: true
                  }, (error, result) => {
                    // Handle scan results
                  });
                })

                Text('Gallery').onClick(() => {
                  // Image selection and decoding logic
                  detectBarcode.decode(inputImage, (error, result) => {
                    // Handle decoding results
                  });
                })
              }

              // Result display sections
              Text(`Result: ${this.scanResult}`)
              Text(JSON.stringify(this.scanResultObject))
            }
          }
        }
      }
    }
    .backgroundColor("#f4f8fb");
  }
}
Enter fullscreen mode Exit fullscreen mode

Key Features Implementation

1. QR Code Generation

  • Dynamic Input Handling: Uses TextArea with state management for real-time QR updates
  • Image Export:
  componentSnapshot.get(this.qrCodeId).then((pixelMap) => {
    const imagePacker = image.createImagePacker();
    imagePacker.packToFile(pixelMap, file.fd, {
      format: 'image/png',
      quality: 100
    });
  });
Enter fullscreen mode Exit fullscreen mode
  • Media Library Integration: Leverages photoAccessHelper for secure storage

2. QR Code Recognition

  • Camera Scanning:
  scanBarcode.startScanForResult(context, {
    enableMultiMode: true,
    enableAlbum: true
  }, (error, result) => {
    // Error handling and result processing
  });
Enter fullscreen mode Exit fullscreen mode
  • Image Decoding:
  detectBarcode.decode({ uri: imageUri }, (error, results) => {
    if (results.length > 0) {
      this.scanResult = results[0].originalValue;
    }
  });
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Permission Handling: Implement proper permission requests for camera and storage access
  2. Error Logging: Use hilog for detailed error tracking
  3. Performance Optimization:
    • Use component visibility control instead of conditional rendering
    • Implement proper resource cleanup in finally blocks
  4. User Experience:
    • Provide visual feedback with click effects
    • Use system clipboard for data sharing
    • Implement loading states for long operations

Conclusion

This implementation demonstrates HarmonyOS NEXT's powerful capabilities in handling modern mobile development requirements. The solution combines:

  • ArkUI's responsive UI components
  • ScanKit's robust scanning features
  • MediaLibraryKit's secure storage access
  • ImageKit's efficient processing capabilities

Developers can extend this foundation with additional features like batch processing, history tracking, or custom QR code styling based on specific application requirements.

Top comments (0)