基本コントロール統合
コードベース統合を使用してNetFUNNEL iOSエージェントで基本コントロールを実装する完全なガイドです。
これは利用可能な2つの統合方法のうちの1つです。統合方法概要を参照して区間コントロールと比較し、ユースケースに最も適した方法を選択してください。
動作方法
ユーザー体験:
- ユーザーがボタンをクリックするか作業をトリガーします
- 待合室が現在の画面に表示されます
- 進入が許可されると待合室が閉じられ、サービスが継続されます
最適なユースケース:
- ボタンクリック保護 (ログイン、チェックアウト、注文)
- API呼び出し制限
- 特定の作業に対する精密な制御
区間コントロールとの主な違い:
- 基本コントロール: 進入速度を制御します (キーが迅速に返却される)
- 区間コントロール: 固定された同時ユーザー数を維持します (区間終了までキーが保持される)
前提条件
- インストールおよび初期化完了
- NetFUNNELコンソールへのアクセス権限
- iOS開発環境
このガイドはサンプルアプリケーションを使用して基本コントロール統合パターンを示します。実際のアプリケーションコードはここに示された例とは異なります。統合の概念を理解することに集中し、パターンを特定のコードベース、関数名、ビジネスロジックに合わせて調整してください。
💡 練習テンプレート: NetFUNNEL SDK統合の練習のための**iOSアプリケーション (単一ViewController)**テンプレートが準備されたサンプルプロジェクトを確認してください。
ステップ1: セグメント作成
コードベース統合は基本コントロールと区間コントロールの両方をサポートします。このガイドは基本コントロールを使用します。
1.1 新しいセグメントを作成
- NetFUNNELコンソール →
プロジェクト→セグメントに移動します - **
+**ボタンをクリックして新しいセグメントを作成します

1.2 制御タイプを選択
基本コントロールを選択し、次へをクリックします

1.3 セグメント構成
セグメント名: 説明的な名前を入力します (例: "ログインボタン", "チェックアウトプロセス", "API呼び出し保護")

進入状態:
- ✅ セグメントの有効化 有効化
- 進入状態:
待機(ユーザーを待合室に送る)

待合室適用:
- テストのためにデフォルト設定を使用
- ライブメッセージは空のままにします

進入許容数:
- テストのために
0に設定します (誰も許可されない、待合室が常に表示される)

1.4 セグメント作成
作成をクリックしてセグメントを完了します

ステップ2: キー発行統合ポイントの識別 (nfStart)
次の例はデモンストレーション目的でサンプルアプリケーションを使用します。実際のアプリケーションコードはここに示されたものとは自然に異なります。統合パターンを特定のコード構造、ボタンID、関数名、ビジネスロジックに合わせて調整してください。
💡 練習プロジェクトが必要ですか? NetFUNNEL SDK統合の練習のための**iOSアプリケーション (単一ViewController)**テンプレートが準備されたサンプルプロジェクトを確認してください。
サンプルアプリケーションを理解する:
NetFUNNEL保護を適用する必要がある場所を理解するために、サンプルアプリケーションを見てみましょう:
2.1 レイアウトで対象ボタンを識別
// MainView.swift
struct MainView: View {
@StateObject private var navigationManager = NavigationManager.shared
var body: some View {
ScrollView {
VStack(spacing: 0) {
// Hero Section (簡潔性のために省略)
// ... 既存のUI構造 ...
// Cards Section
VStack(spacing: 20) {
// 🎯 対象ボタン: 基本コントロール機能カード
// これがNetFUNNELで保護したいボタンです
Button(action: {
navigationManager.navigateWithDelay(to: .basicControl)
}) {
ModernCard(
icon: "arrow.right.circle.fill",
title: "Basic Control",
subtitle: "Code-based Integration",
description: "Simple linear navigation flow",
accentColor: MaterialColors.lightPrimary
)
}
.buttonStyle(ModernCardButtonStyle())
// 他のボタン - 対象ではない
Button(action: {
navigationManager.navigateWithDelay(to: .sectionControlSection1)
}) {
ModernCard(
icon: "list.bullet.circle.fill",
title: "Section Control",
subtitle: "Code-based Integration",
description: "Multi-step navigation flow",
accentColor: MaterialColors.lightSecondary
)
}
.buttonStyle(ModernCardButtonStyle())
}
.padding(.horizontal, 20)
Spacer(minLength: 40)
}
}
// 追加のUI修飾子は簡潔性のために省略
// ... background, frame, navigationBarHiddenなど ...
}
}
このサンプルに関する仮定:
- "Basic Control"ボタンはリソース集約的な作業を表します
- これは次のいずれかです: ユーザーログイン、決済処理、ファイルアップロード、データエクスポート
- 多くのユーザーが同時にこのボタンをクリックすると、サーバーに過負荷が発生する可能性があります
- 他のボタンは重要性が低く、保護は不要です
2.2 このボタンのクリックリスナーを見つける
クリックリスナーとは何ですか?
クリックリスナー(アクションハンドラーまたはイベントハンドラーとも呼ばれる)は、ユーザーがUI要素と相互作用するときに実行されるコードです。SwiftUIでは、通常Button(action:)クロージャー構文を使用して定義されます。
SwiftUIボタン構造を理解する:
Button(action: {
// 🎯 これがクリックリスナーです
// ユーザーがボタンをタップすると、ここでのコードが実行されます
}) {
// これがボタンの視覚的な外観です
// ボタンがどのように見えるかを定義します
}
サンプルアプリケーションで:
// MainView.swift
struct MainView: View {
@StateObject private var navigationManager = NavigationManager.shared
var body: some View {
ScrollView {
VStack(spacing: 0) {
// Hero Section (簡潔性のために省略)
// ... 既存のUI構造 ...
// Cards Section
VStack(spacing: 20) {
// 🎯 対象ボタン: 基本コントロール機能カード
Button(action: {
// 🎯 クリックリスナー: ここでボタンアクションが定義されます
// ユーザーがボタンをクリックすると実行されるコードです
// 現在: navigationManager.navigateWithDelay(to: .basicControl)
// これをNetFUNNEL保護でラップします
navigationManager.navigateWithDelay(to: .basicControl)
}) {
// 🎨 ボタンの外観: これがボタンがどのように見えるかを定義します
ModernCard(
icon: "arrow.right.circle.fill",
title: "Basic Control",
subtitle: "Code-based Integration",
description: "Simple linear navigation flow",
accentColor: MaterialColors.lightPrimary
)
}
.buttonStyle(ModernCardButtonStyle())
// 他のボタン - 対象ではない (NetFUNNEL保護不要)
Button(action: {
// このボタンはNetFUNNEL保護は不要です
navigationManager.navigateWithDelay(to: .sectionControlSection1)
}) {
ModernCard(
icon: "list.bullet.circle.fill",
title: "Section Control",
subtitle: "Code-based Integration",
description: "Multi-step navigation flow",
accentColor: MaterialColors.lightSecondary
)
}
.buttonStyle(ModernCardButtonStyle())
}
.padding(.horizontal, 20)
Spacer(minLength: 40)
}
}
// 追加のUI修飾子は簡潔性のために省略
// ... background, frame, navigationBarHiddenなど ...
}
}
重要なポイント:
- クリックリスナーの場所:
Button(action:)クロージャー内 - 現在のアクション:
navigationManager.navigateWithDelay(to: .basicControl)が即座に実行されます - 統合対象: ここにNetFUNNEL保護を追加します
2.3 クリックリスナー内で起こっていることを確認
関数が行うこと:
// NavigationManager.swift
func navigateWithDelay(to destination: NavigationDestination, customDelay: TimeInterval? = nil) {
let delay = customDelay ?? appPreferences.getNavigationDelay()
loadingDialogManager.showLoading() // ← ローディングインジケーターを表示
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
self.loadingDialogManager.hideLoading() // ← ローディングインジケーターを非表示
self.navigate(to destination) // ← 対象画面に移動
}
}
要約: ローディング表示 → 待機 → ローディング非表示 → 移動。これはサーバー処理をシミュレートし、NetFUNNEL保護が必要です。
2.4 統合ポイントの識別
- 対象ボタン:
MainViewの"Basic Control"ボタン (リソース集約的なボタン) - クリックリスナー:
Button(action:)クロージャーがクリックハンドラーを設定します - 統合場所:
navigationManager.navigateWithDelay()が呼び出される直前 - ここで行う理由: これはサーバー処理が開始される直前の正確な瞬間です
- 保護戦略: サーバー呼び出し前にNetFUNNELキューを追加します
全体フロー分析:
- ビュー作成:
MainViewbodyがボタンを作成します - ボタン設定:
Button(action:)がボタンのクリックハンドラーを設定します - ユーザーアクション: ユーザーが"Basic Control"ボタンをクリックします
- 現在の動作:
navigationManager.navigateWithDelay()が即座に実行されます - サーバー負荷: これがリソース集約的な作業をトリガーします
ロジック:
- NetFUNNELなし: ボタンクリック → 即座にサーバーリクエスト → 潜在的な過負荷
- NetFUNNEL使用: ボタンクリック → キュー確認 → 制御されたサーバーリクエスト → 成功
ステップ3: キー発行関数の実装 (nfStart)
以下の例は、サンプルアプリケーションのボタンアクションメソッドにNetFUNNELを統合する方法を示します。このパターンを実際のコード構造に合わせて調整してください - 保護が必要な他の関数名、イベントハンドラー、またはビジネスロジックがある可能性があります。
3.1 キーを取得
まず、コンソールでプロジェクトキーとセグメントキーを見つけてください:
- NetFUNNELコンソール →
プロジェクト→セグメントに移動します - セグメントをクリックします
- プロジェクトキーとセグメントキーをコピーします

3.2 nfStart関数を理解する
nfStart関数は次のような基本構造を持ちます:
- Swift
- Objective-C
Netfunnel.shared.nfStart(
projectKey: "your_project_key", // コンソールから取得
segmentKey: "your_segment_key" // コンソールから取得
)
[[Netfunnel shared] nfStartWithProjectKey:@"your_project_key"
segmentKey:@"your_segment_key"];
nfStartパラメータ、デリゲート処理、応答形式の詳細については、APIリファレンスを参照してください。
3.3 現在のコードから開始
現在の実装:
// MainView.swift
Button(action: {
navigationManager.navigateWithDelay(to: .basicControl)
}) {
ModernCard(
icon: "arrow.right.circle.fill",
title: "Basic Control",
subtitle: "Code-based Integration",
description: "Simple linear navigation flow",
accentColor: MaterialColors.lightPrimary
)
}
.buttonStyle(ModernCardButtonStyle())
核心概念:
- ビジネスロジック:
navigationManager.navigateWithDelay(to: .basicControl)はリソース集約的な作業を表します - 統合ポイント: このビジネスロジックをNetFUNNEL保護でラップする必要があります
- ラップ戦略: ビジネスロジックが実行される前に
nfStart()を使用してアクセスを制御します
ここでラップする理由:
- これはサーバー負荷が開始される直前の正確な瞬間です
- ここでラップすると、すべてのダウンストリーム作業が保護されます
- ビジネスロジックは変更されません - キューレイヤーのみが追加されます
3.4 必要なimportを追加
NetFUNNELを実装する前に、SwiftUI Viewに必要なimportを追加してください:
- Swift
- Objective-C
// MainView.swift
import Netfunnel_iOS
// MainViewController.m
#import <Netfunnel_iOS/Netfunnel_iOS.h>
核心Import:
Netfunnel_iOS- メインNetFUNNELフレームワーク
3.5 基本NetFUNNEL保護を追加 (成功のみ)
インストールおよび初期化ステップで既にNetfunnelHandler.swiftが存在する必要があります。 まだそのステップを完了していない場合は、戻って最初に完了してください。
ビジネスロジックをラップ:
// MainView.swift
import SwiftUI
import Netfunnel_iOS
struct MainView: View {
@StateObject private var navigationManager = NavigationManager.shared
var body: some View {
ScrollView {
VStack(spacing: 0) {
// Hero Sectionは簡潔性のために省略
// ... 既存のUI構造 ...
// Cards Section
VStack(spacing: 20) {
// 基本コントロール機能カード - NetFUNNELで保護
Button(action: {
startBasicControl() // NetFUNNEL保護関数を呼び出し
}) {
ModernCard(
icon: "arrow.right.circle.fill",
title: "Basic Control",
subtitle: "Code-based Integration",
description: "Simple linear navigation flow",
accentColor: MaterialColors.lightPrimary
)
}
.buttonStyle(ModernCardButtonStyle())
// 区間コントロール機能カード
Button(action: {
navigationManager.navigateWithDelay(to: .sectionControlSection1)
}) {
ModernCard(
icon: "list.bullet.circle.fill",
title: "Section Control",
subtitle: "Code-based Integration",
description: "Multi-step navigation flow",
accentColor: MaterialColors.lightSecondary
)
}
.buttonStyle(ModernCardButtonStyle())
}
.padding(.horizontal, 20)
Spacer(minLength: 40)
}
}
// 追加のUI修飾子は簡潔性のために省略
// ... background, frame, navigationBarHiddenなど ...
.onAppear {
setupCallbacks()
}
}
private func setupCallbacks() {
// NetFUNNEL応答のためのコールバッククロージャーを設定
NetfunnelHandler.shared.onSuccess = { projectKey, segmentKey, statusCode, message in
NSLog("onSuccess \(statusCode) \(message)")
// NetFUNNELが進入を許可するときに元のビジネスロジックを実行
navigationManager.navigateWithDelay(to: .basicControl)
}
NetfunnelHandler.shared.onError = { projectKey, segmentKey, statusCode, message in
NSLog("onError \(statusCode) \(message)")
}
NetfunnelHandler.shared.onNetworkError = { projectKey, segmentKey, statusCode, message in
NSLog("onNetworkError \(statusCode) \(message)")
}
NetfunnelHandler.shared.onBlock = { projectKey, segmentKey, statusCode, message in
NSLog("onBlock \(statusCode) \(message)")
}
NetfunnelHandler.shared.onClose = { projectKey, segmentKey, statusCode, message in
NSLog("onClose \(statusCode) \(message)")
}
NetfunnelHandler.shared.onContinue = { projectKey, segmentKey, statusCode, message, aheadWait, behindWait, waitTime, progressRate in
NSLog("onContinue \(statusCode) \(message)")
}
}
private func startBasicControl() {
// NetFUNNELキュー保護を開始
Netfunnel.shared.nfStart(
projectKey: "your_project_key",
segmentKey: "your_segment_key"
)
}
// 色計算プロパティは簡潔性のために省略
// private var backgroundColor: Color { ... }
}
変更点:
- ラップ:
navigationManager.navigateWithDelay()が今はonSuccessコールバック内にあります - 条件付き: 特定のボタンのみがNetFUNNEL保護を受けます
- 成功のみ: NetFUNNELが進入を許可するときにのみビジネスロジックが実行されます
- 完全なインターフェース: すべての必須デリゲートメソッドが適切なロギングとともに実装されています
iOSではNetfunnelDelegateはすべてのメソッドを実装する必要があります。 onSuccessのみを実装することはできません - すべてのデリゲートメソッドに対する実装を提供する必要があります。この実装は、すべての応答タイプに対する適切なロギングとともに完全なデリゲート処理を提供します。
実装が正しく動作するかテストしてみましょう。
アプリを実行し、"Basic Control"ボタンをクリックしてください。画面に待合室WebViewが表示される必要があります。すべてが正しく動作していることを確認するには、XcodeコンソールでNetFUNNELログを確認してください。
待合室が表示されない場合は、セグメント構成ステップで進入許容数を0に設定したことを確認してください。この設定は、ユーザーが待合室に送られるか直接進行できるかを制御します。
より良いデバッグのためのNetFUNNELロギングを有効化:
AppDelegate初期化でprintLog = trueを設定してデバッグロギングを有効化し、次にXcodeコンソールを確認してください。詳細な設定手順については、NetFUNNEL初期化テスト)セクションを参照してください。
確認事項:
進入許容数 = 0で"Basic Control"ボタンをクリックすると、次のようなログが表示される必要があります:
[NF4] [2025-09-18 15:17:48.452] Initialization successful. NetFUNNEL Version: 4.3.2-onprem
[NF4] [2025-09-18 15:17:52.331] Sending initialEntry request: https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5101&sid=service_1&aid=test_liam_01
[NF4] [2025-09-18 15:17:52.475] Received initialEntry response: Response(timestamp: Optional(1758176272469), code: 201, key: Optional("000F49F7F52ACADEF43B48BA3B72504953385B97C9B710E930978A54657743A944B31A90F7E4D124D288493C55ED1695BCFD08B8F833299D4D743DBF3C84B6D4E168B227EF3E2A74958D7ED95766B706459E4B85A186035300FD8474FD450E3D342C312C302C302C302C302C30"), nwait: Optional(0), nnext: Optional(0), tps: Optional(0.0), ttl: Optional(1), ip: Optional("nf4-onprem-demo-4525.stclab.com"), port: Optional(443), preBeginTs: nil, preEndTs: nil, postBeginTs: nil, postEndTs: nil, sticky: Optional("nf1"), vwrHtml: Optional("https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html"), liveMessage: nil, chkEnterCnt: Optional(0), waitOrderYn: Optional(0), msg: nil, vwrType: Optional("wait"))
[NF4] [2025-09-18 15:17:53.154] Fetching HTML content from following URL. https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html
[NF4] [2025-09-18 15:17:53.481] Sending reentry request: https://nf4-onprem-demo-4525.stclab.com:443/ts.wseq?opcode=5002&key=000F49F7F52ACADEF43B48BA3B72504953385B97C9B710E930978A54657743A944B31A90F7E4D124D288493C55ED1695BCFD08B8F833299D4D743DBF3C84B6D4E168B227EF3E2A74958D7ED95766B706459E4B85A186035300FD8474FD450E3D342C312C302C302C302C302C30&sticky=nf1
[NF4] [2025-09-18 15:17:53.542] Received reentry response: Response(timestamp: Optional(1758176273542), code: 201, key: Optional("000F49F7F52ACADEF43B48BA3B725049E96705109E9BE7300670B2EB820666F55758079BA9E0833F05741BAB6B0407A3BCFD08B8F833299D4D743DBF3C84B6D4E168B227EF3E2A74958D7ED95766B706459E4B85A186035300FD8474FD450E3D342C312C302C302C302C302C30"), nwait: Optional(0), nnext: Optional(0), tps: Optional(0.0), ttl: Optional(1), ip: Optional("nf4-onprem-demo-4525.stclab.com"), port: Optional(443), preBeginTs: nil, preEndTs: nil, postBeginTs: nil, postEndTs: nil, sticky: Optional("nf1"), vwrHtml: Optional("https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html"), liveMessage: nil, chkEnterCnt: Optional(0), waitOrderYn: Optional(0), msg: nil, vwrType: Optional("wait"))
すべてが動作中であることを示す核心指標:
| ログメッセージ | 意味 | 状態 |
|---|---|---|
[NF4] Initialization successful | NetFUNNELエージェントが正しくロードされた | ✅ 正常 |
[NF4] Sending initialEntry request | nfStart()が正常に呼び出された、NetFUNNELサーバーにリクエストが送信された | ✅ 正常 |
[NF4] Received initialEntry response with code: 201 | サーバーがWAIT状態で応答した | ✅ 正常 |
[NF4] Fetching HTML content | 待合室WebViewがロード中、待合室HTMLがロードされている | ✅ 正常 |
[NF4] Sending reentry request | 定期的な再進入リクエスト (ポーリング) | ✅ 正常 |
[NF4] Received reentry response with code: 201 | サーバーがWAIT状態で応答した | ✅ 正常 |
問題が発生した場合:
- ログが表示されない: 初期化で
printLog = trueが設定されていることを確認してください - 待合室がない: コンソールで進入許容数が0に設定されていることを確認してください
- アプリクラッシュ: すべての必須デリゲートメソッドが正しく実装されていることを確認してください
- ネットワークエラー: サーバーURLとネットワーク接続を確認してください
待合室とログが表示されれば、基本実装が動作中です! これで、より良いエラー管理のためにコールバック処理を改善できます。進入をテストするには、コンソールで進入許容数を1に変更してください。
3.6 完全なコールバック処理を追加
より良いエラー管理とユーザー体験のためにコールバック処理を改善します:
前のステップで、基本ロギングですべてのコールバックメソッドを実装しました。これで、プロダクション環境で堅牢なサービス可用性と最適なユーザー体験を確保するためにエラー処理を改善します。
完全なコールバック処理が必須な理由:
- ユーザー体験: さまざまな応答タイプに対する適切なユーザーフィードバックが必要です
- サービス安定性: エラー状態がユーザーのワークフローを中断してはなりません
- デバッグ: 包括的なロギングが問題を迅速に識別するのに役立ちます
- ビジネス継続性: NetFUNNELに問題が発生してもサービスが継続する必要があります
堅牢なエラー処理でsetupCallbacksを改善:
// MainView.swift - 完全な処理を含む更新されたsetupCallbacks
private func setupCallbacks() {
NetfunnelHandler.shared.onSuccess = { projectKey, segmentKey, statusCode, message in
// ユーザーが進行できる - 元のロジックを実行
NSLog("onSuccess \(statusCode) \(message)")
navigationManager.navigateWithDelay(to: .basicControl)
}
NetfunnelHandler.shared.onError = { projectKey, segmentKey, statusCode, message in
// システムエラーが発生 - 堅牢なサービス可用性のために元のロジックを進行
NSLog("onError \(statusCode) \(message)")
navigationManager.navigateWithDelay(to: .basicControl)
}
NetfunnelHandler.shared.onNetworkError = { projectKey, segmentKey, statusCode, message in
// ネットワークエラーが発生 - デバッグのためにログのみ記録し、ビジネスロジックは実行しない
NSLog("onNetworkError \(statusCode) \(message)")
// 注意: ここではビジネスロジックが実行されない - 以下の説明を参照
}
NetfunnelHandler.shared.onBlock = { projectKey, segmentKey, statusCode, message in
// ユーザーがブロックされた - 適切なメッセージを表示
NSLog("onBlock \(statusCode) \(message)")
}
NetfunnelHandler.shared.onClose = { projectKey, segmentKey, statusCode, message in
// ユーザーが待合室を閉じた - 適切に処理
NSLog("onClose \(statusCode) \(message)")
// メイン画面に維持 - ユーザーがキャンセルした
}
NetfunnelHandler.shared.onContinue = { projectKey, segmentKey, statusCode, message, aheadWait, behindWait, waitTime, progressRate in
NSLog("onContinue \(statusCode) \(message)")
}
}
応答処理戦略:
| 応答タイプ | アクション | ビジネスロジック |
|---|---|---|
| Success | 実行 | ✅ はい |
| Error | 実行 | ✅ はい |
| NetworkError | ログのみ | ❌ いいえ |
| Block | ログのみ | ❌ いいえ |
| Close | ログのみ | ❌ いいえ |
| Continue | ログのみ | ❌ いいえ |
onErrorはビジネスロジックを実行するがonNetworkErrorは実行しない理由:
onError (ステータスコード 500) - サーバーエラー:
- シナリオ: NetFUNNELサーバーが内部エラーに遭遇
- 戦略: サービス可用性を維持するためにビジネスロジックを実行
- 根拠: サーバーエラーは一般的に一時的であり、ユーザーアクセスをブロックすべきではありません
- 結果: NetFUNNELに問題があっても継続する堅牢なサービス
onNetworkError (ステータスコード 1001, 1002) - ネットワーク問題:
- シナリオ: ネットワーク接続問題 (オフライン、タイムアウト)
- 戦略: ログのみ記録し、ビジネスロジックは実行しない
- 根拠: 自動ネットワーク回復のために
useNetworkRecoveryMode = trueを使用 - 結果: ネットワーク問題中にユーザーは待合室に留まり、接続が回復すると自動的に再開されます
ネットワーク回復モードの構成:
最適なネットワークエラー処理のためにAppDelegateでネットワーク回復を有効にします:
// AppDelegate.swift
Netfunnel.initialize(
clientId: "{{CLIENT_ID}}",
delegate: NetfunnelHandler.shared, // selfではなくNetfunnelHandlerを使用
useNetworkRecoveryMode: true // 自動ネットワーク回復を有効化
)
変更点:
- 堅牢なエラー処理:
onErrorが最大サービス可用性のためにビジネスロジックを進行します - スマートネットワーク処理:
onNetworkErrorが手動処理ではなくネットワーク回復モードに依存します - 向上したユーザー体験: さまざまな応答状態に対するより良い処理
- プロダクション準備: 堅牢なエラー処理がNetFUNNELに問題が発生してもサービスが継続することを保証します
- 包括的なロギング: すべての応答タイプおよびデバッグに対する詳細なコンソールメッセージ
すべてのデリゲート応答タイプ、ステータスコード、応答オブジェクト構造、および高度なコールバックパターンの詳細については、APIリファレンスを参照してください。
3.7 核心実装ポイント
- プロジェクト/セグメントキー: NetFUNNELコンソールの正確なキーを使用
- 必須import:
Netfunnel_iOSimportを追加 - デリゲート実装: すべてのコールバックメソッドを実装 (NetfunnelDelegate要件)
- 堅牢なエラー処理:
onSuccessとonErrorはサービス可用性のためにビジネスロジックを実行しますonNetworkErrorはログのみ記録します (自動回復のためにuseNetworkRecoveryMode = trueを使用)
- ビューライフサイクル: 初期化およびUI更新に
onAppearを使用 - 包括的なロギング: デバッグのためにすべてのデリゲート応答をロギング
ステップ4: キー返却統合ポイントの識別 (nfStop)
次の例はデモンストレーション目的でサンプルアプリケーションを使用します。実際のアプリケーションコードはここに示されたものとは自然に異なります。統合パターンを特定のコード構造、ビジネスロジック完了ポイント、キー返却要件に合わせて調整してください。
💡 練習プロジェクトが必要ですか? NetFUNNEL SDK統合の練習のための**iOSアプリケーション (単一ViewController)**テンプレートが準備されたサンプルプロジェクトを確認してください。
サンプルアプリケーションを理解する:
NetFUNNELキーを返却するためにnfStopを呼び出す必要がある場所を理解するために、サンプルアプリケーションを見てみましょう。
4.1 ビジネスロジック完了ポイントの識別
nfStart成功後の現在のフロー:
// ステップ3で - nfStartが成功するとき
NetfunnelHandler.shared.onSuccess = { projectKey, segmentKey, statusCode, message in
NSLog("onSuccess \(statusCode) \(message)")
// NetFUNNELが進入を許可するときに元のビジネスロジックを実行
navigationManager.navigateWithDelay(to: .basicControl)
}
次に起こること:
- ユーザーがBasicControlViewに移動 - SwiftUI Viewライフサイクルが開始されます
- ビューが完全にロードされる -
onAppearがトリガーされます - ユーザーのセッションがアクティブになる - これで保護された機能を使用できます
- キーが返却される必要がある - キューの次のユーザーが進入できるように
nfStop実装に関する重要な注意事項:
nfStopはnfStartが最初に呼び出される必要なく、独立して呼び出すことができます。nfStartが呼び出されなかった場合、NetFUNNELは必要な場合にキー解放を自動的に処理するか、キーがない場合は何も行いません。これにより、条件付きチェックなしでどのシナリオでもnfStopを安全に呼び出すことができ、実装がシンプルになります。
4.2 キー返却のための統合ポイントの識別
統合ポイントオプション:
| 統合ポイント | 使用タイミング | 利点 |
|---|---|---|
| SwiftUI Viewライフサイクル | シンプルなナビゲーションフロー | 実装が簡単で、ほとんどの場合に動作する |
| ビジネスロジック完了 | 複雑な作業 (API呼び出し、処理) | 精密な制御、実際の作業後にキーを返却 |
| ユーザーアクション完了 | ユーザー開始作業 | ユーザーが作業を完了するときにキーを返却 |
4.3 適切な統合ポイントの選択
サンプルアプリケーションの場合:
現在のビジネスロジック: navigationManager.navigateWithDelay(to: .basicControl)
- 機能: BasicControlViewに移動します
- 完了タイミング: BasicControlViewが正常にロードされるとき
- 最適な統合ポイント: SwiftUI Viewライフサイクルイベント (
onAppear)
統合戦略:
- SwiftUI View作成: BasicControlViewが完全にロードされるときにキーを返却
- シンプルで信頼できる: ナビゲーションベースのフローに動作します
- ユーザー体験: ユーザーが実際にサービスを使用できるときにキーが返却されます
4.4 統合ポイントロジックの確認
全体フロー分析:
- ユーザーがボタンをクリック →
nfStart()が呼び出される - 待合室が表示される → ユーザーがキューで待機する
- 進入が許可される →
onSuccessコールバックが発生する - ビジネスロジックが実行される →
navigationManager.navigateWithDelay(to: .basicControl)が実行される - BasicControlViewがロードされる → ユーザーがこれでサービスを使用できる
- キー返却が必要 → キュースロットを解放するために
nfStop()を呼び出す
この統合ポイントが合理的な理由:
- ユーザー体験: ユーザーが実際にサービスを使用できるときにキーが返却されます
- キュー管理: 現在のユーザーが準備できたら、次のユーザーが即座に進入できます
- リソース効率: 不要なキューブロックを防ぎます
- 実装のシンプルさ: 実装およびメンテナンスが簡単です
核心洞察: nfStop統合ポイントは、ユーザーの意図したビジネス作業が真に完了し、キューで待機したサービスの利点を得られる場所である必要があります。
ステップ5: キー返却関数の実装 (nfStop)
以下の例は、キーを返却するさまざまなアプローチを示します。アプリケーションアーキテクチャに最も適したアプローチを選択してください - ViewControllerナビゲーション後、API呼び出し後、または他のビジネスロジック完了後にキーを返却する必要があるかどうかに応じて異なります。
5.1 nfStop関数を理解する
nfStop関数は次のような基本構造を持ちます:
- Swift
- Objective-C
Netfunnel.shared.nfStop(
projectKey: "your_project_key", // nfStartキーと正確に一致する必要がある
segmentKey: "your_segment_key" // nfStartキーと正確に一致する必要がある
)
[[Netfunnel shared] nfStopWithProjectKey:@"your_project_key"
segmentKey:@"your_segment_key"];
核心要件:
- 正確なキー一致: キーは
nfStart()で使用されたものと同じである必要があります - タイミング:
nfStart()直後ではなく、ビジネスロジック完了後に呼び出します
5.2 必要なimportを追加
nfStopを実装する前に、Viewに必要なimportを追加してください:
- Swift
- Objective-C
import SwiftUI
import Netfunnel_iOS
#import <UIKit/UIKit.h>
#import <Netfunnel_iOS/Netfunnel_iOS.h>
核心Import:
Netfunnel_iOS- メインNetFUNNELフレームワーク (nfStartに既にimportされている)
5.3 基本キー返却を追加 (SwiftUI Viewライフサイクル)
BasicControlViewがロードされるときにキーを返却:
// BasicControlView.swift
import SwiftUI
import Netfunnel_iOS
struct BasicControlView: View {
@StateObject private var navigationManager = NavigationManager.shared
var body: some View {
VStack(spacing: 0) {
// 成功セクション
VStack(spacing: 24) {
// 成功アイコンおよびタイトルは簡潔性のために省略
// ... 成功UI要素 ...
Text("Basic Control Complete")
.font(.system(size: 28, weight: .bold, design: .rounded))
.foregroundColor(primaryTextColor)
.multilineTextAlignment(.center)
Text("This is the completion page for Basic Control (Code-based Integration).")
.font(.system(size: 16, weight: .regular, design: .rounded))
.multilineTextAlignment(.center)
.foregroundColor(secondaryTextColor)
.padding(.horizontal, 32)
}
.padding(.top, 60)
.padding(.bottom, 40)
Spacer()
// メインに戻るボタン
Button(action: {
navigationManager.navigateBackWithDelay()
}) {
Text("Back to Main")
}
.buttonStyle(ModernButtonStyle())
}
// 追加のUI修飾子は簡潔性のために省略
// ... background, frame, navigationBarHiddenなど ...
.onAppear {
// SwiftUIビューが完全にロードされるときにNetFUNNELキーを返却
Netfunnel.shared.nfStop(
projectKey: "your_project_key",
segmentKey: "your_segment_key"
)
}
}
// 色計算プロパティは簡潔性のために省略
// private var backgroundColor: Color { ... }
// private var primaryTextColor: Color { ... }
// private var secondaryTextColor: Color { ... }
}
変更点:
- SwiftUI Viewライフサイクル: BasicControlViewが完全にロードされるときにキーを返却
- シンプルなアプローチ: 基本ナビゲーションシナリオに動作します
- 直接呼び出し: NetFUNNELが初期化され、利用可能であると仮定します
キー返却実装が正しく動作するかテストしてみましょう。
アプリを実行し、次のテストシーケンスに従ってください:
- "Basic Control (Code-based Integration)"ボタンをクリック - 待合室が表示される必要があります
- NetFUNNELコンソールで進入許容数を0から1に変更 - これが進入を許可します
- 待合室が閉じることを観察 - 消えてBasicControlViewに移動する必要があります
- Xcodeコンソールでキー返却ログを確認 - 完了ログが表示される必要があります
より良いデバッグのためのNetFUNNELロギングを有効化:
AppDelegate初期化でprintLog = trueを設定してデバッグロギングを有効化し、次にXcodeコンソールを確認してください。詳細な設定手順については、NetFUNNEL初期化テスト)セクションを参照してください。
確認事項:
待合室ステップで進入許容数を0から1に変更すると、次のようなログが表示される必要があります:
[NF4] [2025-09-18 15:26:39.184] Sending initialEntry request: https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5101&sid=service_1&aid=test_liam_01
[NF4] [2025-09-18 15:26:39.265] Received initialEntry response: Response(timestamp: Optional(1758176799306), code: 201, key: Optional("38AED8AD2AB482D3042E4564072A4B01F2FF579E4EB078FCB0C8421263F389F8B9586BFF9617864B33217D368B3B2A1FBCFD08B8F833299D4D743DBF3C84B6D4E168B227EF3E2A74958D7ED95766B706459E4B85A186035300FD8474FD450E3D352C312C312C302C302C302C30"), nwait: Optional(1), nnext: Optional(0), tps: Optional(0.0), ttl: Optional(1), ip: Optional("nf4-onprem-demo-4525.stclab.com"), port: Optional(443), preBeginTs: nil, preEndTs: nil, postBeginTs: nil, postEndTs: nil, sticky: Optional("nf1"), vwrHtml: Optional("https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html"), liveMessage: nil, chkEnterCnt: Optional(0), waitOrderYn: Optional(0), msg: nil, vwrType: Optional("wait"))
[NF4] [2025-09-18 15:26:39.803] Fetching HTML content from following URL. https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html
[NF4] [2025-09-18 15:26:39.871] Sending reentry request: https://nf4-onprem-demo-4525.stclab.com:443/ts.wseq?opcode=5002&key=38AED8AD2AB482D3042E4564072A4B01F2FF579E4EB078FCB0C8421263F389F8B9586BFF9617864B33217D368B3B2A1FBCFD08B8F833299D4D743DBF3C84B6D4E168B227EF3E2A74958D7ED95766B706459E4B85A186035300FD8474FD450E3D352C312C312C302C302C302C30&sticky=nf1
[NF4] [2025-09-18 15:26:39.920] Received reentry response: Response(timestamp: Optional(1758176799970), code: 201, key: Optional("38AED8AD2AB482D3042E4564072A4B014AE7EF0CDA16397B678ED3382A6A8BAF1CEB37B55CCC33944E7335CBCAA4A95FBCFD08B8F833299D4D743DBF3C84B6D4E168B227EF3E2A74958D7ED95766B706459E4B85A186035300FD8474FD450E3D342C312C302C302C302C302C30"), nwait: Optional(0), nnext: Optional(0), tps: Optional(0.0), ttl: Optional(1), ip: Optional("nf4-onprem-demo-4525.stclab.com"), port: Optional(443), preBeginTs: nil, preEndTs: nil, postBeginTs: nil, postEndTs: nil, sticky: Optional("nf1"), vwrHtml: Optional("https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html"), liveMessage: nil, chkEnterCnt: Optional(0), waitOrderYn: Optional(0), msg: nil, vwrType: Optional("wait"))
[NF4] [2025-09-18 15:26:48.450] Received reentry response: Response(timestamp: Optional(1758176808499), code: 200, key: Optional("38AED8AD2AB482D3042E4564072A4B01A6758441574083251F3F4BC91E4E9873D39834BE911F6D95F3EB16E3BE77DBB36AA7C2ADE2FDDEF7523C7393E95B8401DA85D3F8F85FA7FA7B7F120E3C54DAC2071A87CC017BE50129F11B1499A36DF643308DE76E9345037F51A6CCA3A36C6E2C302C302C30"), nwait: Optional(0), nnext: Optional(0), tps: Optional(0.0), ttl: Optional(0), ip: Optional("nf4-onprem-demo-4525.stclab.com"), port: Optional(443), preBeginTs: nil, preEndTs: nil, postBeginTs: nil, postEndTs: nil, sticky: Optional("nf1"), vwrHtml: Optional(""), liveMessage: nil, chkEnterCnt: Optional(1), waitOrderYn: Optional(0), msg: nil, vwrType: Optional(""))
[NF4] [2025-09-18 15:26:50.174] Sending returnKey request: https://nf4-onprem-demo-4525.stclab.com:443/ts.wseq?opcode=5004&key=38AED8AD2AB482D3042E4564072A4B01A6758441574083251F3F4BC91E4E9873D39834BE911F6D95F3EB16E3BE77DBB36AA7C2ADE2FDDEF7523C7393E95B8401DA85D3F8F85FA7FA7B7F120E3C54DAC2071A87CC017BE50129F11B1499A36DF643308DE76E9345037F51A6CCA3A36C6E2C302C302C30&sticky=nf1
[NF4] [2025-09-18 15:26:50.223] Received returnKey response. code=200, key=Optional("38AED8AD2AB482D3042E4564072A4B01A6758441574083251F3F4BC91E4E9873D39834BE911F6D95F3EB16E3BE77DBB36AA7C2ADE2FDDEF7523C7393E95B8401DA85D3F8F85FA7FA7B7F120E3C54DAC2071A87CC017BE50129F11B1499A36DF643308DE76E9345037F51A6CCA3A36C6E2C302C302C30")
すべてが動作中であることを示す核心指標:
| ログメッセージ | 意味 | 状態 |
|---|---|---|
[NF4] Sending initialEntry request | NetFUNNELサーバーに初期リクエストが送信された | ✅ 正常 |
[NF4] Received initialEntry response with code: 201 | サーバーがWAIT状態で応答した | ✅ 正常 |
[NF4] Fetching HTML content | 待合室HTMLがロードされている | ✅ 正常 |
[NF4] Sending reentry request (繰り返し) | 定期的な再進入リクエスト (ポーリング) | ✅ 正常 |
[NF4] Received reentry response with code: 200 | 進入が許可された - 待合室が閉じられる必要がある | ✅ 正常 |
[NF4] Sending returnKey request | サーバーにキー返却リクエストが送信された | ✅ 正常 |
[NF4] Received returnKey response with code=200 | キー返却成功 | ✅ 正常 |
テストシーケンス:
- 進入許容数 = 0で開始: 待合室が表示され、再進入リクエストが繰り返されます
- 進入許容数を1に変更: 再進入応答が
code: 200に変更され、待合室が閉じられます - SwiftUI Viewロード: BasicControlView
onAppearがnfStop()を呼び出します - キー返却: returnKeyリクエスト/応答がキー返却を確認します
問題が発生した場合:
- returnKeyログがない: BasicControlViewで
nfStop()が呼び出されていることを確認してください - キー返却が失敗する:
nfStart()とnfStop()間のプロジェクト/セグメントキーが正確に一致していることを確認してください - SwiftUI Viewがロードされない:
onSuccessコールバックがナビゲーションを正しく実行していることを確認してください - 待合室が閉じない: コンソールで進入許容数が1に設定されていることを確認してください
待合室 → 進入 → SwiftUI viewロード → キー返却の全体フローが表示されれば、実装が正しく動作中です! これで、エラー処理を改善し、より堅牢なコールバック管理を追加できます。
5.4 核心実装ポイント
ビジネスロジックが完了したらNetFUNNELキーを返却してください。NetFUNNELはタイムアウト後に自動的にキーを返却しますが、手動返却はより良いユーザー体験とキュー効率を提供します。
キー返却ルール:
- ✅ 常に: ビジネスロジック完了後にキーを返却 (成功または失敗)
- ⚠️ 自動タイムアウト: 手動で返却しない場合、NetFUNNELは自動的にキーを返却します
- タイミング:
nfStart()直後ではなく、ビジネスロジック完了後に呼び出します
実装チェックリスト:
- 正確なキー一致:
nfStop()のキーはnfStart()と正確に一致する必要があります - SwiftUI Viewライフサイクル: キー返却タイミングに
onAppearを使用 - 一貫したキー: 全体フローで同じプロジェクト/セグメントキーを使用
nfStopパラメータ、応答処理、および高度なキー返却パターンの詳細については、APIリファレンスを参照してください。
ステップ6: 待合室テスト (進入許容数 = 0)
以下のテストステップはサンプルアプリケーションに基づいています。テストプロセスを実際のアプリケーションに合わせて調整してください - ボタン名、ビューコントローラーナビゲーション、確認ステップを特定の実装に合わせて置き換えてください。
6.1 作業をトリガー
-
Xcodeコンソールログをクリア (クリーンな状態で観察したい場合)
- Xcodeでコンソールのゴミ箱アイコンをクリックして以前のログをクリアします
- またはCmd+Kを使用してコンソールをクリアします
-
保護されたボタンをクリック (例: "Basic Control (Code-based Integration)"ボタン)
予想結果: 現在の画面に待合室WebViewが表示されます
6.2 待合室表示の確認
次の要素が正しく表示されていることを確認してください:
進入許容数が0に設定され、1人のユーザーのみが接続されている場合、次を確認してください:
- 私の待機順序: 1
- 予想待機時間: 00:00:00 (時:分:秒)
- 私の後ろの待機者数: 0
6.3 Xcodeコンソールアクティビティの確認
NetFUNNELログを確認:
AppDelegate初期化でprintLog = trueを設定してデバッグロギングを有効化し、次にXcodeコンソールを確認してください。次のようなログが表示される必要があります:
[NF4] [2025-09-18 15:26:39.184] Sending initialEntry request: https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5101&sid=service_1&aid=test_liam_01
[NF4] [2025-09-18 15:26:39.265] Received initialEntry response: Response(timestamp: Optional(1758176799306), code: 201, key: Optional("38AED8AD2AB482D3042E4564072A4B01F2FF579E4EB078FCB0C8421263F389F8B9586BFF9617864B33217D368B3B2A1FBCFD08B8F833299D4D743DBF3C84B6D4E168B227EF3E2A74958D7ED95766B706459E4B85A186035300FD8474FD450E3D352C312C312C302C302C302C30"), nwait: Optional(1), nnext: Optional(0), tps: Optional(0.0), ttl: Optional(1), ip: Optional("nf4-onprem-demo-4525.stclab.com"), port: Optional(443), preBeginTs: nil, preEndTs: nil, postBeginTs: nil, postEndTs: nil, sticky: Optional("nf1"), vwrHtml: Optional("https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html"), liveMessage: nil, chkEnterCnt: Optional(0), waitOrderYn: Optional(0), msg: nil, vwrType: Optional("wait"))
[NF4] [2025-09-18 15:26:39.803] Fetching HTML content from following URL. https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html
[NF4] [2025-09-18 15:26:39.871] Sending reentry request: https://nf4-onprem-demo-4525.stclab.com:443/ts.wseq?opcode=5002&key=38AED8AD2AB482D3042E4564072A4B01F2FF579E4EB078FCB0C8421263F389F8B9586BFF9617864B33217D368B3B2A1FBCFD08B8F833299D4D743DBF3C84B6D4E168B227EF3E2A74958D7ED95766B706459E4B85A186035300FD8474FD450E3D352C312C312C302C302C302C30&sticky=nf1
[NF4] [2025-09-18 15:26:39.920] Received reentry response: Response(timestamp: Optional(1758176799970), code: 201, key: Optional("38AED8AD2AB482D3042E4564072A4B014AE7EF0CDA16397B678ED3382A6A8BAF1CEB37B55CCC33944E7335CBCAA4A95FBCFD08B8F833299D4D743DBF3C84B6D4E168B227EF3E2A74958D7ED95766B706459E4B85A186035300FD8474FD450E3D342C312C302C302C302C302C30"), nwait: Optional(0), nnext: Optional(0), tps: Optional(0.0), ttl: Optional(1), ip: Optional("nf4-onprem-demo-4525.stclab.com"), port: Optional(443), preBeginTs: nil, preEndTs: nil, postBeginTs: nil, postEndTs: nil, sticky: Optional("nf1"), vwrHtml: Optional("https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html"), liveMessage: nil, chkEnterCnt: Optional(0), waitOrderYn: Optional(0), msg: nil, vwrType: Optional("wait"))
すべてが動作中であることを示す核心指標:
| ログメッセージ | 意味 | 状態 |
|---|---|---|
[NF4] Sending initialEntry request | NetFUNNELサーバーに初期リクエストが送信された | ✅ 正常 |
[NF4] Received initialEntry response with code: 201 | サーバーがWAIT状態で応答した | ✅ 正常 |
[NF4] Fetching HTML content | 待合室HTMLがロードされている | ✅ 正常 |
[NF4] Sending reentry request | 定期的な再進入リクエスト (ポーリング) | ✅ 正常 |
[NF4] Received reentry response with code: 201 | サーバーが引き続きWAIT状態で応答している | ✅ 正常 |
応答確認:
- ログで
ts.wseq?opcode=5002リクエストを見つけてください - 応答が
code: 201(WAIT)を表示していることを確認してください 201= WAIT,200= PASS (進入が許可された)- ここでは進入許容数が0であるため、正しい応答は
201です
ステップ7: 進入テスト (進入許容数 = 1)
7.1 セグメント設定を更新
- NetFUNNELコンソールに戻る
- セグメントの
編集ボタンをクリックして編集画面を開く

- 進入許容数を
0から1に変更 - 下部で
確認をクリック

確認をクリックするとすぐに待合室が消え、即座にBasicControlViewControllerに移動します。この瞬間を観察するには、待合室が現在表示されている別の画面を開いておいてください。
7.2 進入確認
予想結果: 待合室が即座に消え、BasicControlViewControllerへのナビゲーションが発生します
Xcodeコンソールで進入確認を確認:
次のようなログが表示される必要があります:
[NF4] [2025-09-18 15:26:48.450] Received reentry response: Response(timestamp: Optional(1758176808499), code: 200, key: Optional("38AED8AD2AB482D3042E4564072A4B01A6758441574083251F3F4BC91E4E9873D39834BE911F6D95F3EB16E3BE77DBB36AA7C2ADE2FDDEF7523C7393E95B8401DA85D3F8F85FA7FA7B7F120E3C54DAC2071A87CC017BE50129F11B1499A36DF643308DE76E9345037F51A6CCA3A36C6E2C302C302C30"), nwait: Optional(0), nnext: Optional(0), tps: Optional(0.0), ttl: Optional(0), ip: Optional("nf4-onprem-demo-4525.stclab.com"), port: Optional(443), preBeginTs: nil, preEndTs: nil, postBeginTs: nil, postEndTs: nil, sticky: Optional("nf1"), vwrHtml: Optional(""), liveMessage: nil, chkEnterCnt: Optional(1), waitOrderYn: Optional(0), msg: nil, vwrType: Optional(""))
成功した進入の核心指標:
| ログメッセージ | 意味 | 状態 |
|---|---|---|
[NF4] Received reentry response with code: 200 | 進入が許可された - 待合室が閉じられる必要がある | ✅ 正常 |
7.3 キー返却確認
成功したキー返却確認:
Xcodeコンソールで次のログを見つけてください:
[NF4] [2025-09-18 15:26:50.174] Sending returnKey request: https://nf4-onprem-demo-4525.stclab.com:443/ts.wseq?opcode=5004&key=38AED8AD2AB482D3042E4564072A4B01A6758441574083251F3F4BC91E4E9873D39834BE911F6D95F3EB16E3BE77DBB36AA7C2ADE2FDDEF7523C7393E95B8401DA85D3F8F85FA7FA7B7F120E3C54DAC2071A87CC017BE50129F11B1499A36DF643308DE76E9345037F51A6CCA3A36C6E2C302C302C30&sticky=nf1
[NF4] [2025-09-18 15:26:50.223] Received returnKey response. code=200, key=Optional("38AED8AD2AB482D3042E4564072A4B01A6758441574083251F3F4BC91E4E9873D39834BE911F6D95F3EB16E3BE77DBB36AA7C2ADE2FDDEF7523C7393E95B8401DA85D3F8F85FA7FA7B7F120E3C54DAC2071A87CC017BE50129F11B1499A36DF643308DE76E9345037F51A6CCA3A36C6E2C302C302C30")
成功したキー返却の核心指標:
| ログメッセージ | 意味 | 状態 |
|---|---|---|
[NF4] Sending returnKey request | サーバーにキー返却リクエストが送信された | ✅ 正常 |
[NF4] Received returnKey response with code=200 | キー返却成功 | ✅ 正常 |
要約
必須事項 (必ず実行)
設定:
- インストールおよび初期化完了およびNetFUNNELエージェントが正しくロードされていることを確認
- コンソールで基本コントロールとしてセグメントを作成
- コンソールでプロジェクトキーとセグメントキーを取得
- テストのために進入許容数を0に、プロダクションのために1以上に設定
統合:
- 必須importを追加:
Netfunnel_iOS - すべてのコールバックメソッドを実装 (NetfunnelDelegate要件)
- アクションメソッドでビジネスロジックを
Netfunnel.shared.nfStart()でラップ - ビジネスロジックを実行するために
onSuccessコールバックを処理 - ビジネスロジック完了後に
Netfunnel.shared.nfStop()を呼び出し nfStart()とnfStop()の両方で同じキーを使用
エラー処理:
onErrorをビジネスロジック進行として処理 (サービス可用性を維持)onNetworkErrorをログのみ記録として処理 (useNetworkRecoveryMode = trueを使用)onBlockを適切なユーザーメッセージ表示として処理onCloseを現在のビューコントローラーに維持として処理 (ユーザーがキャンセルした)- すべてのデリゲート応答に対する包括的なロギングを実装
テスト:
- 進入許容数 = 0で待合室が表示されることをテスト
- 進入許容数 = 1で進入が動作することをテスト
- 完了後にキー返却が発生することを確認
- XcodeコンソールでNetFUNNELログを確認
オプション (あれば良い)
エラー処理の向上:
- 基本ロギングの代わりにユーザーフレンドリーなエラーメッセージを追加
- さまざまな応答タイプに対するカスタムエラー処理戦略を実装
- NetFUNNELイベントに対する分析追跡を追加
コード構成:
- 中央集約的な構成定数を作成
- 再利用可能なNetFUNNELラッパー関数を構築
- 複数のビューコントローラーにわたるモジュール式統合パターンを実装
ベストプラクティス
必須Import
- Swift
- Objective-C
import Netfunnel_iOS
#import <Netfunnel_iOS/Netfunnel_iOS.h>
これらのimportが重要な理由:
- NetFUNNEL統合に必須です
- NetFUNNELを使用するすべてのViewに追加する必要があります
nfStart()とnfStop()関数の両方に必要です
完全なコールバック実装
- Swift
- Objective-C
private func setupCallbacks() {
NetfunnelHandler.shared.onSuccess = { projectKey, segmentKey, statusCode, message in
NSLog("onSuccess \(statusCode) \(message)")
// NetFUNNELが進入を許可するときに元のビジネスロジックを実行
navigationManager.navigateWithDelay(to: .basicControl)
}
NetfunnelHandler.shared.onError = { projectKey, segmentKey, statusCode, message in
NSLog("onError \(statusCode) \(message)")
// システムエラーが発生 - 堅牢なサービス可用性のために元のロジックを進行
navigationManager.navigateWithDelay(to: .basicControl)
}
NetfunnelHandler.shared.onNetworkError = { projectKey, segmentKey, statusCode, message in
NSLog("onNetworkError \(statusCode) \(message)")
// ネットワークエラーが発生 - デバッグのためにログのみ記録し、ビジネスロジックは実行しない
}
NetfunnelHandler.shared.onBlock = { projectKey, segmentKey, statusCode, message in
NSLog("onBlock \(statusCode) \(message)")
// ユーザーがブロックされた - 適切なメッセージを表示
}
NetfunnelHandler.shared.onClose = { projectKey, segmentKey, statusCode, message in
NSLog("onClose \(statusCode) \(message)")
// ユーザーが待合室を閉じた - 適切に処理
}
NetfunnelHandler.shared.onContinue = { projectKey, segmentKey, statusCode, message, aheadWait, behindWait, waitTime, progressRate in
NSLog("onContinue \(statusCode) \(message)")
// 待機進行情報を更新
}
}
- (void)setupCallbacks {
NetfunnelHandler.shared.onSuccess = ^(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message) {
NSLog(@"onSuccess %ld %@", (long)statusCode, message);
// NetFUNNELが進入を許可するときに元のビジネスロジックを実行
[self.navigationManager navigateWithDelayToDestination:NavigationDestinationBasicControl];
};
NetfunnelHandler.shared.onError = ^(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message) {
NSLog(@"onError %ld %@", (long)statusCode, message);
// システムエラーが発生 - 堅牢なサービス可用性のために元のロジックを進行
[self.navigationManager navigateWithDelayToDestination:NavigationDestinationBasicControl];
};
NetfunnelHandler.shared.onNetworkError = ^(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message) {
NSLog(@"onNetworkError %ld %@", (long)statusCode, message);
// ネットワークエラーが発生 - デバッグのためにログのみ記録し、ビジネスロジックは実行しない
};
NetfunnelHandler.shared.onBlock = ^(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message) {
NSLog(@"onBlock %ld %@", (long)statusCode, message);
// ユーザーがブロックされた - 適切なメッセージを表示
};
NetfunnelHandler.shared.onClose = ^(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message) {
NSLog(@"onClose %ld %@", (long)statusCode, message);
// ユーザーが待合室を閉じた - 適切に処理
};
NetfunnelHandler.shared.onContinue = ^(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message, NSInteger aheadWait, NSInteger behindWait, NSString *waitTime, NSInteger progressRate) {
NSLog(@"onContinue %ld %@", (long)statusCode, message);
// 待機進行情報を更新
};
}
核心原則: 常にすべてのコールバックメソッドを実装してください - NetfunnelDelegate要件です。
中央集約的な構成
- Swift
- Objective-C
// キーを1箇所に保存
struct NetFunnelConfig {
static let projectKey = "your_project_key"
static let segmentKey = "your_segment_key"
}
// すべての場所で同じ構成を使用
Netfunnel.shared.nfStart(
projectKey: NetFunnelConfig.projectKey,
segmentKey: NetFunnelConfig.segmentKey
)
Netfunnel.shared.nfStop(
projectKey: NetFunnelConfig.projectKey,
segmentKey: NetFunnelConfig.segmentKey
)
// キーを1箇所に保存
@interface NetFunnelConfig : NSObject
+ (NSString *)projectKey;
+ (NSString *)segmentKey;
@end
@implementation NetFunnelConfig
+ (NSString *)projectKey { return @"your_project_key"; }
+ (NSString *)segmentKey { return @"your_segment_key"; }
@end
// すべての場所で同じ構成を使用
[[Netfunnel shared] nfStartWithProjectKey:[NetFunnelConfig projectKey]
segmentKey:[NetFunnelConfig segmentKey]];
[[Netfunnel shared] nfStopWithProjectKey:[NetFunnelConfig projectKey]
segmentKey:[NetFunnelConfig segmentKey]];
利点:
- アプリ全体でキーを簡単に更新できます
- コピー&ペーストエラーを減らします
- 構成に対する単一のソースです
堅牢なエラー処理戦略
- Swift
- Objective-C
// onErrorはビジネスロジックを実行するがonNetworkErrorは実行しない理由:
NetfunnelHandler.shared.onError = { projectKey, segmentKey, statusCode, message in
NSLog("onError \(statusCode) \(message)")
// シナリオ: NetFUNNELサーバーが内部エラーに遭遇
// 戦略: サービス可用性を維持するためにビジネスロジックを実行
// 根拠: サーバーエラーは一般的に一時的であり、ユーザーアクセスをブロックすべきではありません
// 結果: NetFUNNELに問題があっても継続する堅牢なサービス
navigationManager.navigateWithDelay(to: .basicControl)
}
NetfunnelHandler.shared.onNetworkError = { projectKey, segmentKey, statusCode, message in
NSLog("onNetworkError \(statusCode) \(message)")
// シナリオ: ネットワーク接続問題 (オフライン、タイムアウト)
// 戦略: ログのみ記録し、ビジネスロジックは実行しない
// 根拠: 自動ネットワーク回復のためにuseNetworkRecoveryMode = trueを使用
// 結果: ネットワーク問題中にユーザーは待合室に留まり、接続が回復すると自動的に再開されます
}
// onErrorはビジネスロジックを実行するがonNetworkErrorは実行しない理由:
NetfunnelHandler.shared.onError = ^(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message) {
NSLog(@"onError %ld %@", (long)statusCode, message);
// シナリオ: NetFUNNELサーバーが内部エラーに遭遇
// 戦略: サービス可用性を維持するためにビジネスロジックを実行
// 根拠: サーバーエラーは一般的に一時的であり、ユーザーアクセスをブロックすべきではありません
// 結果: NetFUNNELに問題があっても継続する堅牢なサービス
[self.navigationManager navigateWithDelayToDestination:NavigationDestinationBasicControl];
};
NetfunnelHandler.shared.onNetworkError = ^(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message) {
NSLog(@"onNetworkError %ld %@", (long)statusCode, message);
// シナリオ: ネットワーク接続問題 (オフライン、タイムアウト)
// 戦略: ログのみ記録し、ビジネスロジックは実行しない
// 根拠: 自動ネットワーク回復のためにuseNetworkRecoveryMode = trueを使用
// 結果: ネットワーク問題中にユーザーは待合室に留まり、接続が回復すると自動的に再開されます
};
核心原則: サービス可用性を維持するために、システムエラーで常にビジネスロジックを進行してください。
ネットワーク回復モードの構成
- Swift
- Objective-C
// AppDelegate.swift
Netfunnel.initialize(
clientId: "{{CLIENT_ID}}",
delegate: NetfunnelHandler.shared, // selfではなくNetfunnelHandlerを使用
useNetworkRecoveryMode: true // 自動ネットワーク回復を有効化
)
// AppDelegate.m
[agent initializeWithClientId:@"{{CLIENT_ID}}"
delegate:[NetfunnelHandler sharedInstance] // selfではなくNetfunnelHandlerを使用
useNetworkRecoveryMode:YES]; // 自動ネットワーク回復を有効化
利点:
- ネットワーク接続問題の自動処理
- ネットワークが回復すると、ユーザーが自動的に再開されます
- 手動ネットワークエラー処理の複雑さを減らします
常にキーを返却
- Swift
- Objective-C
// 成功した作業後にキーを返却
struct BasicControlView: View {
var body: some View {
VStack {
// UIコンテンツ
}
.onAppear {
// SwiftUIビューが完全にロードされるときにキーを返却
Netfunnel.shared.nfStop(
projectKey: NetFunnelConfig.projectKey,
segmentKey: NetFunnelConfig.segmentKey
)
}
}
}
// 成功した作業後にキーを返却
- (void)viewDidLoad {
[super viewDidLoad];
// ビューコントローラーが完全にロードされるときにキーを返却
[[Netfunnel shared] nfStopWithProjectKey:[NetFunnelConfig projectKey]
segmentKey:[NetFunnelConfig segmentKey]];
}
キーを返却するとき:
- SwiftUI Viewが完全にロードされた後
- API呼び出し完了後
- ビジネス作業完了後
- 作業が失敗した場合でも
キー一致
- Swift
- Objective-C
// 開始と停止は同じキーを使用する必要がある
let projectKey = "your_project_key"
let segmentKey = "your_segment_key"
Netfunnel.shared.nfStart(
projectKey: projectKey,
segmentKey: segmentKey
)
Netfunnel.shared.nfStop(
projectKey: projectKey, // 正確に一致する必要がある
segmentKey: segmentKey // 正確に一致する必要がある
)
// 開始と停止は同じキーを使用する必要がある
NSString *projectKey = @"your_project_key";
NSString *segmentKey = @"your_segment_key";
[[Netfunnel shared] nfStartWithProjectKey:projectKey
segmentKey:segmentKey];
[[Netfunnel shared] nfStopWithProjectKey:projectKey // 正確に一致する必要がある
segmentKey:segmentKey]; // 正確に一致する必要がある
包括的なロギング
- Swift
- Objective-C
// AppDelegateでデバッグロギングを有効化
Netfunnel.initialize(
clientId: "{{CLIENT_ID}}",
delegate: NetfunnelHandler.shared, // selfではなくNetfunnelHandlerを使用
printLog: true // 詳細なロギングを有効化
)
// Xcodeコンソールでログを確認
// AppDelegateでデバッグロギングを有効化
[agent initializeWithClientId:@"{{CLIENT_ID}}"
delegate:[NetfunnelHandler sharedInstance] // selfではなくNetfunnelHandlerを使用
printLog:YES]; // 詳細なロギングを有効化
// Xcodeコンソールでログを確認
ロギングの利点:
- NetFUNNEL統合の問題を簡単にデバッグできます
- リクエスト/応答フローを追跡できます
- キー返却作業をモニタリングできます
- ネットワーク接続問題を識別できます
一般的な問題およびトラブルシューティング
待合室が表示されない
症状: ボタンクリックが正常に動作するが待合室が表示されない
デバッグステップ:
- XcodeコンソールでiOSエラーを確認:
⌘+Shift+Y→ "Error"でフィルタリング - AppDelegateでNetFUNNEL初期化を確認
- コンソールでセグメントが有効化されていることを確認 (無効化されていない)
- テストのために進入許容数が0に設定されていることを確認
- プロジェクトキーとセグメントキーがコンソールと正確に一致していることを確認 (大文字小文字を区別)
デリゲートが発生しない
症状: nfStart()が呼び出されたが応答を受信しない
デバッグステップ:
- XcodeコンソールでNetFUNNELログを確認: "NetFUNNEL"でフィルタリング
- NetFUNNELサーバーへのネットワーク接続を確認
- セグメントが有効化されていることを確認 (無効化されていない)
- 待合室を強制的に表示するために進入許容数 = 0で試す
- すべてのコールバックメソッドが実装されていることを確認 (NetfunnelDelegate要件)
ユーザーがキューに閉じ込められる
症状: 最初のユーザーは進入するが、2番目のユーザーは通過しない
デバッグステップ:
- ビジネスロジック完了後に
nfStop()が呼び出されていることを確認 nfStop()のキーがnfStart()と正確に一致していることを確認nfStop()実行を妨げるiOSエラーを見つける- Xcodeコンソールで
[NF4] Sending returnKey requestログを確認 - ログに
[NF4] Sending returnKey requestが表示されることを確認
待合室が表示されるが進入を許可しない
症状: 待合室が表示されるがユーザーが通過しない、進入許容数 = 1の場合でも
デバッグステップ:
- コンソールでセグメント状態を確認 - "Block"モードでないことを確認
- 進入許容数が1以上に設定されていることを確認
- Xcodeコンソールで
[NF4] Sending reentry requestを確認 (再進入リクエスト) - NetFUNNELログでエラー応答を見つける
- NetFUNNELサーバーへのネットワーク接続を確認
NetFUNNEL呼び出し時にアプリクラッシュ
症状: nfStart()またはnfStop()呼び出し時にアプリがクラッシュする
デバッグステップ:
- 必須importが追加されていることを確認:
Netfunnel_iOS - AppDelegateでNetFUNNELが初期化されていることを確認
- すべてのコールバックメソッドが実装されていることを確認 (NetfunnelDelegate要件)
- 初期化でデリゲートが正しく設定されていることを確認 (
NetfunnelHandler.shared) - NetFUNNELエージェントが正しくインストールされていることを確認
キー返却が失敗する
症状: nfStop()が呼び出されたがキーが返却されない
デバッグステップ:
nfStop()のキーがnfStart()と正確に一致していることを確認 (大文字小文字を区別)- Xcodeコンソールで
[NF4] Sending returnKey requestメッセージを確認 - ログで
[NF4] Sending returnKey requestを見つける code=200とともに[NF4] Received returnKey responseを確認nfStop()が適切なライフサイクルメソッドで呼び出されていることを確認
ネットワーク回復問題
症状: ネットワーク接続問題中にユーザーが閉じ込められる
デバッグステップ:
- AppDelegate初期化で
useNetworkRecoveryMode = trueを確認 - NetFUNNELサーバーへのネットワーク接続を確認
- ネットワーク問題をシミュレートするために機内モードのオン/オフでテスト
- Xcodeコンソールで
onNetworkErrorデリゲート呼び出しをモニタリング onNetworkErrorがビジネスロジックを実行していないことを確認 (回復モードに依存)
QAチェックリスト
実装前の確認
- プロジェクトキー / セグメントキーがコンソールと正確に一致する (コンソールで再確認)
- AppDelegateでNetFUNNELエージェントが正しく初期化されている
- 必須importが追加されている:
Netfunnel_iOS - すべてのコールバックメソッドが実装されている (NetfunnelDelegate要件)
待合室テスト (進入許容数 = 0)
- 進入許容数 = 0のときに待合室WebViewが正しく表示される
- 待合室が正しい詳細を表示する:
- 私の待機順序: 1
- 予想待機時間: 00:00:00 (時:分:秒)
- 私の後ろの待機者数: 0
- 待機中にXcodeコンソールに**
[NF4] Sending reentry request**が定期的に表示される - **
[NF4] Received reentry responseがcode=201(WAIT)**を表示する
進入テスト (進入許容数 = 1)
- 進入許容数を1に変更するときに
onSuccessデリゲートが発生する -
onSuccessデリゲートが元のビジネスロジックを実行する - 進入時に待合室が即座に消える
- 対象SwiftUI Viewへのナビゲーションが正常に発生する
キー返却確認
- 完了ポイントでキー返却が正しく動作する
- Xcodeコンソールに**
[NF4] Sending returnKey request**が表示される -
[NF4] Sending returnKey requestがHTTP 200とともに発生する - **
[NF4] Received returnKey responseがcode=200**を表示する - キー返却が
nfStart呼び出しごとに正確に1回発生する - キー返却がビジネスロジック完了後に発生する
エラー処理
- すべての必須状態に対してデリゲート分岐が実装されている:
-
onSuccess- 元のロジックを実行 -
onError- システムエラーを適切に処理 (ビジネスロジック進行) -
onNetworkError- ネットワーク問題を適切に処理 (ログのみ) -
onBlock- ブロックされた状態を適切に処理 -
onClose- ユーザーキャンセルを適切に処理 -
onContinue- 待機進行を適切に処理
-
- AppDelegate初期化でネットワーク回復モードが有効化されている
- キー一致 -
nfStartとnfStopでprojectKey/segmentKeyが同じ - すべてのデリゲート応答に対する包括的なロギングが実装されている
Xcodeコンソール確認
- XcodeコンソールにNetFUNNELログが表示される ("NetFUNNEL"でフィルタリング)
- 初期化成功メッセージが表示される
- ボタンクリック時にSending initialEntry requestメッセージが表示される
- Fetching HTML contentメッセージが表示される
- Sending returnKey requestメッセージが表示される
-
code=200とともにReceived returnKey responseが表示される