引越しをしていて間が空いてしまったが、次から通常の更新頻度に戻る予定
在庫管理アプリの開発で商品の画像取得に商品検索(v3) - Yahoo!デベロッパーネットワークのAPIを使ってみたので紹介
PR
実装
実装のイメージは以下の通り - アプリでバーコード読み取り画面を実装 - バーコードのJANコードをbackendに渡して、商品検索(v3)APIで商品の情報を取得
まずはbackendの実装。JANコードから商品情報の取得はYahooが提供している以下のAPIから取得可能。
APIは簡単でような感じで商品情報を取得できる
curl --location 'https://shopping.yahooapis.jp/ShoppingWebService/V3/itemSearch?appid=*****&jan_code=4901777062702&image_size=300'
※appidの部分は自分のアカウントのアプリケーションのClient IDを設定
レスポンスは以下みたいに返ってくる

上記のAPIを使用して以下のPRでbackendのAPIを作成
次にアプリ側の実装。バーコードをスキャンしてJANコードを取得するためにmobile_scannerを使用
実装は以下の通り
■ dart/app/lib/features/item/new/components/barcodeScannerScreen.dart
import 'package:mobile_scanner/mobile_scanner.dart'; (略) @override Widget build(BuildContext context) { final cameraController = useMemoized(() => MobileScannerController()); // アニメーションコントローラを定義(ここでは3秒でスキャンラインが1サイクル) final animationController = useAnimationController( duration: const Duration(seconds: 2), )..repeat(reverse: true); // 繰り返しアニメーションを実行 return Scaffold( appBar: const CommonAppBar(title: ""), body: Stack( children: [ // カメラでのバーコード読み取り MobileScanner( controller: cameraController, onDetect: onScan, // バーコードを読み込んだ時に、onScanを実行 ),
■dart/app/lib/app/items/new/page.dart
Future<void> onScan(BarcodeCapture capture) async {
final List<Barcode> barcodes = capture.barcodes;
final value = barcodes.first.rawValue;
if (value != null && barcodes.first.format == BarcodeFormat.ean13) {
final String code = value;
print('Scanned JAN code: $code'); // ここでスキャンしたバーコード情報からJANコードを取得できる
final result = await client.query<Query$ItemFromQR>(QueryOptions(
document: documentNodeQueryItemFromQR,
variables: {'janCode': code}));
if (result.hasException) {
debugPrint(result.exception.toString());
scan.value = true;
return;
}
defaultValue.value = InputItem(
name: result.data!['itemFromQR']['name'],
imageURL: result.data!['itemFromQR']['imageURL'],
stock: 0,
order: 0,
);
scan.value = true;
}
}
上記でバーコードからJANコードを読み込んで商品情報が取得できるようになった
このままだとカメラ起動時にバーコードを読み取らせている感が薄かったので、ChatGPTにアニメーションを作らせて以下のコードになった
■ dart/app/lib/features/item/new/components/barcodeScannerScreen.dart
import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:stockkeeper/components/appBar/common.dart'; class BarcodeScannerScreen extends HookWidget { final Future<void> Function(BarcodeCapture capture) onScan; const BarcodeScannerScreen({ super.key, required this.onScan, }); @override Widget build(BuildContext context) { final cameraController = useMemoized(() => MobileScannerController()); // アニメーションコントローラを定義(ここでは3秒でスキャンラインが1サイクル) final animationController = useAnimationController( duration: const Duration(seconds: 2), )..repeat(reverse: true); // 繰り返しアニメーションを実行 return Scaffold( appBar: const CommonAppBar(title: ""), body: Stack( children: [ // カメラでのバーコード読み取り MobileScanner( controller: cameraController, onDetect: onScan, ), // スキャンエリアのオーバーレイ CustomPaint( size: MediaQuery.of(context).size, painter: ScannerOverlay(), ), // スキャンラインのアニメーション AnimatedBuilder( animation: animationController, builder: (context, child) { // アニメーションの進行に基づいてスキャンラインの位置を計算 final position = animationController.value * 300; // 0から300まで移動 return Positioned( top: MediaQuery.of(context).size.height * 0.22 + position, left: 40, right: 40, child: child!, ); }, child: Container( height: 2, color: Colors.redAccent, ), ), ], ), ); } } class ScannerOverlay extends CustomPainter { @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.black.withOpacity(0.5) ..style = PaintingStyle.fill; // スクリーン全体を半透明で塗りつぶす canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint); // スキャンエリア(中央部分の透明な四角形) paint.color = Colors.transparent; final scanRect = Rect.fromLTWH(40, size.height / 4, size.width - 80, 300); canvas.drawRect(scanRect, paint); // スキャンエリアの枠線を描く final borderPaint = Paint() ..color = Colors.white ..strokeWidth = 3 ..style = PaintingStyle.stroke; canvas.drawRect(scanRect, borderPaint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; }
これらを実装して以下みたいな動作が完成