Skip to content

実装 ​

このガイドはFlutter SDK 0.4.0を対象としています。インストールと更新の手順を参照してください。

AudioRecognition instanceの作成 ​

SORIアプリケーション認証情報を使ってSORIAudioRecognizerを作成します。実際の認証情報を公開ソースコードにハードコードしないでください。リリース設定、セキュアストレージ、環境ごとのビルドプロセスを通じて読み込んでください。

次の例では、ソースコードに機密値が残らないように--dart-define値を使用します。

dart
import 'package:sorisdk_flutter/sorisdk_flutter.dart';

const applicationId = String.fromEnvironment('SORI_APP_ID');
const secretKey = String.fromEnvironment('SORI_SECRET_KEY');

final recognizer = SORIAudioRecognizer(
  applicationId: applicationId,
  secretKey: secretKey,
);

await recognizer.configure();

ローカルまたはCI環境から値を渡してアプリを実行します。

bash
flutter run \
  --dart-define=SORI_APP_ID=your-application-id \
  --dart-define=SORI_SECRET_KEY=your-secret-key

WARNING

app_idとsecret_keyは、アプリをSORI API Serverで認証するための値です。実際の値をリポジトリ、サンプルアプリ、Issue、スクリーンショット、公開ドキュメントにコミットしないでください。

Web recognizer ​

ブラウザビルドには長期有効なSORI secret_keyを含めないでください。インストールでWeb bridgeを準備した後、アプリケーションサーバー上のephemeral key endpointを使用してrecognizerを作成します。

dart
final recognizer = SORIAudioRecognizer.web(
  applicationId: applicationId,
  webAuth: SORIWebAuthOptions.ephemeralKeyEndpoint(
    Uri.parse('/api/sori/ephemeral-key'),
    requestCredentials: SORIWebRequestCredentials.sameOrigin,
  ),
);

await recognizer.configure();

endpointは、他のアプリケーションAPIと同じsession、origin、CSRF、rate limit制御で保護してください。長期有効なsecret_keyはサーバーに保持しますが、applicationIdはブラウザアプリケーションにコンパイルされるためsecretではありません。endpointは短期有効なephemeral keyだけをブラウザに返します。Ephemeral Keyを参照してください。

認識イベントの受信 ​

認識を開始する前にrecognizer.eventsを購読します。キャンペーン情報は、ネイティブプラットフォームイベントに応じてevent.campaignまたはイベントpayloadから取得できます。

dart
import 'dart:async';

import 'package:flutter/foundation.dart' show kIsWeb;

import 'package:sorisdk_flutter/sorisdk_flutter.dart';

late final SORIAudioRecognizer recognizer;
StreamSubscription<SORIRecognitionEvent>? subscription;

subscription = recognizer.events.listen((event) {
  if (event.type == SORIRecognitionEventType.stateChanged) {
    final state = event.payload['state'];
    // STARTING、STARTED、stoppedの状態に合わせてUIを更新します。
  }

  final campaign = event.campaign;
  if (campaign != null) {
    // campaign.name、campaign.imageUrl、campaign.actionUrlを表示します。
  }

  if (event.type == SORIRecognitionEventType.audioMarkerStateChanged) {
    final state = event.audioMarkerState;
    // marker専用のUIや状態を更新します。
  }

  if (kIsWeb && event.type == SORIRecognitionEventType.audioMarkerFound) {
    final marker = event.audioMarkerIdentity;
    // Render the Console-resolved marker ID and name on Web.
    // Native current-marker UI uses audioMarkerStateChanged above.
  }

  if (event.type == SORIRecognitionEventType.error ||
      event.type == SORIRecognitionEventType.networkError) {
    // アプリのエラーUIにevent.messageを表示します。
  }
});

現在のアクティビティセグメントの調整 ​

以下は既存のキャンペーンコールバック向けの説明です。SDKが受理を確認した新しいアクティビティ結果には、オーディオマーカーの状態とアクティビティ結果にある正確なIDによる更新規則を使用してください。この結果は対応する過去のアクティビティも更新できます。

キャンペーンイベントと認識イベントはオプションのevent.activityIdを公開し、 キャンペーンにはevent.campaign?.materialIdとevent.campaign?.trait?.markerが 含まれることがあります。最初のキャンペーンイベントはすぐに表示し、アプリケーションの 状態に明示的な現在のセグメントを保持してください。

  • 同じ空でないevent.activityIdを持つ後続イベントは、現在の行だけをリファイン できます。過去の行を検索せず、キャンペーンIDや素材IDからアクティビティの識別子を 導出しないでください。
  • 古いサーバーはnullのアクティビティIDを返すことがあります。素材によるfallbackは、 現在の行の空でないevent.campaign?.materialIdが一致する場合だけ安全です。
  • 現在の行の初回観測時刻、位置、その他のUI metadataを保持してください。nativeと Webのreporterは送信metadataを最初の観測に固定するため、アプリケーションも リファイン後のコールバック時刻で置き換えてはいけません。
  • 後続イベントにmarkerがない場合やキャンペーンデータが不完全な場合も、最初のmarkerと リファイン後のキャンペーンフィールドを保持します。
  • 別の素材のcampaignFoundまたはrecognitionResultイベント、もしくは明示的な認識停止が あればセグメントを閉じます。それ以降に届いた古いアクティビティへの遅延リファインは 無視してください。audioMarkerFoundはセグメントを閉じません。
  • SORIRecognitionEventType.audioMarkerFoundはマーカーの検出を独立して通知します。このイベントだけでアクティビティ行を作成・補完しません。SORI Consoleが解決したIDと名前はevent.audioMarkerIdentityから取得してください。

A(activity-1) -> A'(activity-1, marker) -> A(activity-1, marker miss)は、 markerを維持する1つの行です。A(activity-1) -> B(activity-2) -> delayed A'(activity-1)ではBが現在のままとなり、履歴上のAは変更されません。

ウィジェットまたはアプリケーションscopeが破棄されるときにsubscriptionをキャンセルします。

dart
await subscription?.cancel();

認識の開始と停止 ​

recognizerの設定が完了し、UIがイベントを受け取る準備ができたら、startRecognition()を呼び出します。

dart
await recognizer.startRecognition(
  notification: const SORIAndroidNotificationOptions(
    title: 'SORI recognition',
    body: 'Listening for SORI audio signals',
  ),
);

notificationオプションはAndroidのforeground-service通知で使用されます。iOSとWebでは無視されます。Webでは、ブラウザがマイク権限を要求できるように、ユーザー操作からstartRecognition()を呼び出してください。

認識を停止するには、次を呼び出します。

dart
await recognizer.stopRecognition();

現在のrecorder状態も確認できます。

dart
final isRunning = await recognizer.isRecorderRunning();

オーディオマーカー認識の有効化 ​

オーディオマーカー認識はデフォルトで無効です。SORI Consoleの設定でオーディオマーカーを使用する場合にのみ有効にしてください。

dart
await recognizer.configure(
  config: const SORIRecognitionConfig(audiomarker: true),
);

現在のマーカーUIと後続のアクティビティ補完には、SDKが管理する状態とアクティビティ結果APIを使用してください。SDKが失効、マーカーtrait、同一アクティビティの更新を管理します。既存のキャンペーン・検出コールバックとの互換性は維持されます。

Flutter Webの既存の認識・イベント動作は維持されます。新しい現在状態、失効、独立した遅延マーカー更新の動作はAndroid/iOSに適用されます。WebではgetCurrentAudioMarkerState()がnullを返すため、マーカーが未検出であることの根拠には使用しないでください。

キャンペーンアクションの処理 ​

キャンペーンにaction URLがある場合、まずアプリ側でそのURLを開くかどうかを判断します。アプリがURLを受け入れた後、handleActionUrl()を呼び出すと、SDKを通じてインタラクションがレポートされ処理されます。

dart
final actionUrl = campaign.actionUrl;
if (actionUrl != null && actionUrl.isNotEmpty) {
  await recognizer.handleActionUrl(actionUrl);
}

認識データベースの更新 ​

SDKは、認識を中断せずにネイティブrecognizerへローカル認識データベースの更新をリクエストできます。Androidは更新結果を返します。iOSでは更新をリクエストしますが、native APIは完了結果を公開しないため、説明メッセージを伴うsuccess: falseは更新の失敗ではなく、結果を取得できないことを意味します。

4フィールドのSORIUpdateResult APIは維持されます。updateDatabase()は現在Webではサポートされていません。

dart
final result = await recognizer.updateDatabase();

if (!result.success) {
  // Android: result.errorMessageで報告された実際の失敗を処理します。
  // iOS: メッセージは更新結果を取得できないことを示します。
}