実装
このガイドはFlutter SDK 0.4.0を対象としています。インストールと更新の手順を参照してください。
AudioRecognition instanceの作成
SORIアプリケーション認証情報を使ってSORIAudioRecognizerを作成します。実際の認証情報を公開ソースコードにハードコードしないでください。リリース設定、セキュアストレージ、環境ごとのビルドプロセスを通じて読み込んでください。
次の例では、ソースコードに機密値が残らないように--dart-define値を使用します。
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環境から値を渡してアプリを実行します。
flutter run \
--dart-define=SORI_APP_ID=your-application-id \
--dart-define=SORI_SECRET_KEY=your-secret-keyWARNING
app_idとsecret_keyは、アプリをSORI API Serverで認証するための値です。実際の値をリポジトリ、サンプルアプリ、Issue、スクリーンショット、公開ドキュメントにコミットしないでください。
Web recognizer
ブラウザビルドには長期有効なSORI secret_keyを含めないでください。インストールでWeb bridgeを準備した後、アプリケーションサーバー上のephemeral key endpointを使用してrecognizerを作成します。
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から取得できます。
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をキャンセルします。
await subscription?.cancel();認識の開始と停止
recognizerの設定が完了し、UIがイベントを受け取る準備ができたら、startRecognition()を呼び出します。
await recognizer.startRecognition(
notification: const SORIAndroidNotificationOptions(
title: 'SORI recognition',
body: 'Listening for SORI audio signals',
),
);notificationオプションはAndroidのforeground-service通知で使用されます。iOSとWebでは無視されます。Webでは、ブラウザがマイク権限を要求できるように、ユーザー操作からstartRecognition()を呼び出してください。
認識を停止するには、次を呼び出します。
await recognizer.stopRecognition();現在のrecorder状態も確認できます。
final isRunning = await recognizer.isRecorderRunning();オーディオマーカー認識の有効化
オーディオマーカー認識はデフォルトで無効です。SORI Consoleの設定でオーディオマーカーを使用する場合にのみ有効にしてください。
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を通じてインタラクションがレポートされ処理されます。
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ではサポートされていません。
final result = await recognizer.updateDatabase();
if (!result.success) {
// Android: result.errorMessageで報告された実際の失敗を処理します。
// iOS: メッセージは更新結果を取得できないことを示します。
}