ネットワーク処理とオフラインサポート
概要
SORI SDKはオーディオ認識をデバイス内で処理します。ただし、関連するキャンペーンの受信、関連画像リソースの読み込み、およびWebhookリレーのためにインターネット接続が必要です。オーディオ認識が成功し、その処理時にネットワークが利用できない場合、これを処理するためのいくつかの方法を提供します。
主な機能
- 自動ネットワーク検出: SDKはネットワーク接続の変更をリアルタイムで監視します
- リクエストキューイング: ネットワークの問題で失敗したリクエストはメモリ内のキューに保存されます
- 自動リトライ: ネットワークが利用可能になると、キューに入っているリクエストが自動的に処理されます
- 設定可能な動作: SDKがネットワーク障害を処理する方法をカスタマイズできます
- 時間ベースの有効期限: 10分以上経過したリクエストは自動的に破棄されます
設定
SORIConfig
クラスを使用してネットワーク処理の動作を設定できます:
import com.iplateia.sorisdk.SORIConfig
import com.iplateia.sorisdk.SORIAudioRecognizer
// カスタム設定を作成
val config = SORIConfig(
enableDelayedSending = true, // リクエストキューイングを有効化
maxPendingTimeMillis = 600000L, // 10分(デフォルト)
autoRetryOnNetworkRecovery = true // ネットワーク復旧時に自動リトライ
)
// 認識器に設定を適用
val sori = SORIAudioRecognizer(
"YOUR_SORI_API_KEY",
"YOUR_SORI_SECRET_KEY"
)
sori.setConfig(config)
import com.iplateia.sorisdk.SORIConfig;
import com.iplateia.sorisdk.SORIAudioRecognizer;
// カスタム設定を作成
SORIConfig config = new SORIConfig(
true, // enableDelayedSending
600000L, // maxPendingTimeMillis(10分)
true // autoRetryOnNetworkRecovery
);
// 認識器に設定を適用
SORIAudioRecognizer sori = new SORIAudioRecognizer(
"YOUR_SORI_API_KEY",
"YOUR_SORI_SECRET_KEY"
);
sori.setConfig(config);
ネットワークイベントの処理
SDKはISORIListener
インターフェースを通じて、ネットワーク関連のイベントに対するコールバックを提供します:
import com.iplateia.sorisdk.ISORIListener
import com.iplateia.sorisdk.SORICampaign
class MyListener : ISORIListener {
override fun onReady() {
// SDKの準備完了
}
override fun onStateChanged(state: String) {
// サービスの状態が変更された
}
override fun onError(error: String) {
// エラーが発生した
}
override fun onCampaignFound(campaign: SORICampaign) {
// キャンペーンが正常に検出された
}
override fun onNetworkError(materialId: String, error: String) {
// アクティビティ送信中にネットワークエラーが発生
Log.w("SORI", "素材 $materialId のネットワークエラー: $error")
// ここでユーザーフレンドリーなメッセージを表示できます
}
override fun onRequestQueued(materialId: String, queueCount: Int) {
// リクエストが後で配信するためにキューに追加された
Log.i("SORI", "素材 $materialId のリクエストがキューに追加されました。キューサイズ: $queueCount")
// リクエストが後で送信されることをユーザーに通知できます
}
}
// リスナーを設定
sori.setListener(context, MyListener())
import com.iplateia.sorisdk.ISORIListener;
import com.iplateia.sorisdk.SORICampaign;
import android.util.Log;
public class MyListener implements ISORIListener {
@Override
public void onReady() {
// SDKの準備完了
}
@Override
public void onStateChanged(String state) {
// サービスの状態が変更された
}
@Override
public void onError(String error) {
// エラーが発生した
}
@Override
public void onCampaignFound(SORICampaign campaign) {
// キャンペーンが正常に検出された
}
@Override
public void onNetworkError(String materialId, String error) {
// アクティビティ送信中にネットワークエラーが発生
Log.w("SORI", "素材 " + materialId + " のネットワークエラー: " + error);
// ここでユーザーフレンドリーなメッセージを表示できます
}
@Override
public void onRequestQueued(String materialId, int queueCount) {
// リクエストが後で配信するためにキューに追加された
Log.i("SORI", "素材 " + materialId +
" のリクエストがキューに追加されました。キューサイズ: " + queueCount);
// リクエストが後で送信されることをユーザーに通知できます
}
}
// リスナーを設定
sori.setListener(context, new MyListener());
設定オプション
SORIConfig
パラメータ
パラメータ | 型 | デフォルト | 説明 |
---|---|---|---|
enableDelayedSending | Boolean | true | ネットワークが利用できない時のリクエストキューイングを有効/無効化。false の場合、失敗したリクエストは即座に破棄されます。 |
maxPendingTimeMillis | Long | 600000 (10分) | 保留中のリクエストを破棄するまでの最大保持時間 |
autoRetryOnNetworkRecovery | Boolean | true | ネットワークが利用可能になった時に保留中のリクエストを自動的に再試行。false の場合、リクエストはキューに残りますが手動処理が必要です。enableDelayedSending がtrue の場合のみ有効です。 |
設定オプションの理解
2つのbooleanオプションは異なる目的を持っています:
enableDelayedSending
:ネットワークが利用できない時に失敗したリクエストをキューに保存するかどうかを制御true
:ネットワークが利用できない時に失敗したリクエストを後の配信のために保存false
:ネットワークが利用できない時に失敗したリクエストを即座に破棄- 注意:ネットワークが利用可能な場合、この設定値に関係なくリクエストは常に即座に送信されます
autoRetryOnNetworkRecovery
:ネットワークが復旧した時の動作を制御true
:ネットワーク復旧時にキュー内のリクエストを自動的に処理false
:リクエストをキューに保持するが自動処理しない(手動介入が必要)- 注意:この設定は
enableDelayedSending
がtrue
の場合のみ有効です
動作の概要
ネットワーク状態 | enableDelayedSending | 動作 |
---|---|---|
利用可能 | true または false | 即座に送信 |
利用不可 | true | 後で配信するためにキューに保存 |
利用不可 | false | リクエスト破棄 |
ほとんどのアプリケーションは両方の設定を同じ値で使用します(復元力のある動作のためにtrue
、即座の失敗処理のためにfalse
)。
ベストプラクティス
1. ユーザーフィードバック
ネットワークの問題が発生した場合は、常にユーザーにフィードバックを提供してください:
override fun onNetworkError(materialId: String, error: String) {
runOnUiThread {
Toast.makeText(
context,
"ネットワークが利用できません。接続が復元されたら再試行します。",
Toast.LENGTH_SHORT
).show()
}
}
2. 時間的制約のある操作でのキューイング無効化
即座の配信が必要な場合は、キューイングを無効にできます:
val config = SORIConfig(
enableDelayedSending = false // キューイングを無効化
)
3. キューステータスの監視
ユーザーに通知するために保留中のリクエストを追跡します:
override fun onRequestQueued(materialId: String, queueCount: Int) {
if (queueCount > 5) {
// 多くのリクエストが保留中なので、ユーザーに通知を検討
showPendingRequestsNotification(queueCount)
}
}
動作の仕組み
- 検出フェーズ: オーディオが認識されると、SDKはサーバーにアクティビティを送信しようとします
- ネットワークチェック: 送信前に、SDKはネットワークの可用性を確認します
- 失敗時のキューイング: ネットワークが利用できない場合、リクエストはメモリ内のキューに追加されます
- ネットワーク監視: SDKはAndroidの
ConnectivityManager
を介してネットワーク状態の変更を監視します - 自動リトライ: ネットワークが利用可能になると、キューに入っているリクエストが自動的に処理されます
- 有効期限チェック: 設定されたタイムアウトより古いリクエストは破棄されます
必要な権限
SDKはネットワーク処理のために以下の権限が必要です:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
これらの権限はすでにSDKのマニフェストに含まれており、アプリに自動的にマージされます。
トラブルシューティング
リクエストがキューに追加されない
遅延送信が有効になっていることを確認してください:
val config = SORIConfig(enableDelayedSending = true)
sori.setConfig(config)
キューに入っているリクエストが送信されない
autoRetryOnNetworkRecovery
が有効になっていることを確認- アプリに
ACCESS_NETWORK_STATE
権限があることを確認 - リクエストが期限切れになっていないことを確認(デフォルト:10分以上経過)
メモリに関する考慮事項
リクエストキューはメモリに保持されます。システムによってアプリが終了された場合、キューに入っているリクエストは失われます。重要な操作については、独自の永続ストレージメカニズムの実装を検討してください。
例:完全な実装
ネットワーク処理を実装する完全な例を示します:
class MainActivity : AppCompatActivity() {
private lateinit var sori: SORIAudioRecognizer
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// カスタム設定でSORIを初期化
initializeSori()
}
private fun initializeSori() {
// 設定を作成
val config = SORIConfig(
enableDelayedSending = true,
maxPendingTimeMillis = 600000L, // 10分
autoRetryOnNetworkRecovery = true
)
// 認識器を作成
sori = SORIAudioRecognizer(
BuildConfig.SORI_API_KEY,
BuildConfig.SORI_SECRET_KEY
)
// 設定を適用
sori.setConfig(config)
// リスナーを設定
sori.setListener(this, object : ISORIListener {
override fun onReady() {
Log.d("SORI", "SDKの準備完了")
}
override fun onStateChanged(state: String) {
Log.d("SORI", "状態変更: $state")
}
override fun onError(error: String) {
Log.e("SORI", "エラー: $error")
}
override fun onCampaignFound(campaign: SORICampaign) {
Log.i("SORI", "キャンペーン検出: ${campaign.name}")
// キャンペーンを処理
handleCampaign(campaign)
}
override fun onNetworkError(materialId: String, error: String) {
Log.w("SORI", "ネットワークエラー: $error")
// ユーザーフレンドリーなメッセージを表示
showNetworkErrorMessage()
}
override fun onRequestQueued(materialId: String, queueCount: Int) {
Log.i("SORI", "リクエストキュー追加。保留中の総数: $queueCount")
// 保留状態を表示するようUIを更新
updatePendingRequestsUI(queueCount)
}
})
// 認識を開始
sori.startRecognition(this)
}
private fun handleCampaign(campaign: SORICampaign) {
// キャンペーン処理ロジック
}
private fun showNetworkErrorMessage() {
runOnUiThread {
Toast.makeText(
this,
"ネットワークが利用できません。接続が復元されたらキャンペーンが処理されます。",
Toast.LENGTH_LONG
).show()
}
}
private fun updatePendingRequestsUI(count: Int) {
runOnUiThread {
// 保留中のリクエストを表示するようUIを更新
val pendingIndicator = findViewById<TextView>(R.id.pendingIndicator)
if (count > 0) {
pendingIndicator.visibility = View.VISIBLE
pendingIndicator.text = "$count 件保留中"
} else {
pendingIndicator.visibility = View.GONE
}
}
}
}
public class MainActivity extends AppCompatActivity {
private SORIAudioRecognizer sori;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// カスタム設定でSORIを初期化
initializeSori();
}
private void initializeSori() {
// 設定を作成
SORIConfig config = new SORIConfig(
true, // enableDelayedSending
600000L, // maxPendingTimeMillis(10分)
true // autoRetryOnNetworkRecovery
);
// 認識器を作成
sori = new SORIAudioRecognizer(
BuildConfig.SORI_API_KEY,
BuildConfig.SORI_SECRET_KEY
);
// 設定を適用
sori.setConfig(config);
// リスナーを設定
sori.setListener(this, new ISORIListener() {
@Override
public void onReady() {
Log.d("SORI", "SDKの準備完了");
}
@Override
public void onStateChanged(String state) {
Log.d("SORI", "状態変更: " + state);
}
@Override
public void onError(String error) {
Log.e("SORI", "エラー: " + error);
}
@Override
public void onCampaignFound(SORICampaign campaign) {
Log.i("SORI", "キャンペーン検出: " + campaign.getName());
// キャンペーンを処理
handleCampaign(campaign);
}
@Override
public void onNetworkError(String materialId, String error) {
Log.w("SORI", "ネットワークエラー: " + error);
// ユーザーフレンドリーなメッセージを表示
showNetworkErrorMessage();
}
@Override
public void onRequestQueued(String materialId, int queueCount) {
Log.i("SORI", "リクエストキュー追加。保留中の総数: " + queueCount);
// 保留状態を表示するようUIを更新
updatePendingRequestsUI(queueCount);
}
});
// 認識を開始
sori.startRecognition(this);
}
private void handleCampaign(SORICampaign campaign) {
// キャンペーン処理ロジック
}
private void showNetworkErrorMessage() {
runOnUiThread(() -> {
Toast.makeText(
this,
"ネットワークが利用できません。接続が復元されたらキャンペーンが処理されます。",
Toast.LENGTH_LONG
).show();
});
}
private void updatePendingRequestsUI(int count) {
runOnUiThread(() -> {
// 保留中のリクエストを表示するようUIを更新
TextView pendingIndicator = findViewById(R.id.pendingIndicator);
if (count > 0) {
pendingIndicator.setVisibility(View.VISIBLE);
pendingIndicator.setText(count + " 件保留中");
} else {
pendingIndicator.setVisibility(View.GONE);
}
});
}
}