기본 제어 통합
코드 기반 통합을 사용하여 NetFUNNEL Android 에이전트로 기본 제어를 구현하는 완전한 가이드입니다.
이것은 사용 가능한 두 가지 통합 방법 중 하나입니다. 통합 방법 개요를 참조하여 구간 제어와 비교하고 사용 사례에 가장 적합한 방법을 선택하세요.
작동 방식
사용자 경험:
- 사용자가 버튼을 클릭하거나 작업을 트리거합니다
- 현재 화면에 대기실이 나타납니다
- 진입이 허용되면 대기실이 닫히고 서비스가 계속됩니다
최적 용도:
- 버튼 클릭 보호 (로그인, 결제, 주문)
- API 호출 제한
- 특정 작업에 대한 정밀 제어
구간 제어와의 주요 차이점:
- 기본 제어: 진입 속도를 제어합니다 (키가 빠르게 반환됨)
- 구간 제어: 고정된 동시 사용자 수를 유지합니다 (구간 종료까지 키가 유지됨)
사전 요구사항
- 설치 및 초기화 완료
- NetFUNNEL 콘솔 접근 권한
- Android 개발 환경
이 가이드는 샘플 애플리케이션을 사용하여 기본 제어 통합 패턴을 보여줍니다. 실제 애플리케이션 코드는 표시된 예제와 다를 수 있습니다. 통합 개념을 이해하고 패턴을 특정 코드베이스, 함수 이름, 비즈니스 로직에 맞게 조정하는 데 집중하세요.
💡 연습 템플릿: NetFUNNEL SDK 통합 연습을 위한 Android 애플리케이션 (Single Activity) 템플릿이 준비된 샘플 프로젝트를 확인하세요.
1단계: 세그먼트 생성
코드 기반 통합은 기본 제어와 구간 제어를 모두 지원합니다. 이 가이드는 기본 제어를 사용합니다.
1.1 새 세그먼트 생성
- NetFUNNEL 콘솔 →
프로젝트→세그먼트로 이동합니다 +버튼을 클릭하여 새 세그먼트를 생성합니다

1.2 제어 유형 선택
기본 제어를 선택하고 다음을 클릭합니다

1.3 세그먼트 구성
세그먼트 이름: 설명적인 이름을 입력합니다 (예: "로그인 버튼", "결제 프로세스", "API 호출 보호")

진입 상태:
- ✅ 세그먼트 활성화 활성화됨
- 진입 상태:
대기(사용자를 대기실로 보냄)

대기실 적용:
- 테스트를 위해 기본 설정 사용
- 라이브 메시지는 비워 둡니다

진입 허용 수:
- 테스트를 위해
0으로 설정 (아무도 허용되지 않음, 대기실이 항상 나타남)

1.4 세그먼트 생성
생성을 클릭하여 세그먼트를 완료합니다

2단계: 키 발급 통합 지점 식별 (nfStart)
다음 예제는 데모 목적으로 샘플 애플리케이션을 사용합니다. 실제 애플리케이션 코드는 여기에 표시된 것과 자연스럽게 다를 수 있습니다. 통합 패턴을 특정 코드 구조, 버튼 ID, 함수 이름, 비즈니스 로직에 맞게 조정하세요.
💡 연습 프로젝트가 필요하신가요? NetFUNNEL SDK 통합 연습을 위한 Android 애플리케이션 (Single Activity) 템플릿이 준비된 샘플 프로젝트를 확인하세요.
샘플 애플리케이션 이해:
NetFUNNEL 보호가 적용되어야 하는 위치를 이해하기 위해 샘플 애플리케이션을 살펴보겠습니다:
2.1 레이아웃에서 대상 버튼 식별
<!-- fragment_main.xml -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/card_basic_control_function"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="12dp"
app:cardElevation="4dp"
app:rippleColor="?attr/colorPrimary"
app:strokeColor="?attr/colorPrimary"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/basic_control_function"
android:textAppearance="?attr/textAppearanceTitleLarge"
android:textColor="?attr/colorPrimary" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="@string/basic_control_function_desc"
android:textAppearance="?attr/textAppearanceBodyMedium" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
이 샘플에 대한 가정:
- "기본 제어" 버튼은 리소스 집약적인 작업을 나타냅니다
- 이것은 사용자 로그인, 결제 처리, 파일 업로드 또는 데이터 내보내기일 수 있습니다
- 많은 사용자가 동시에 이 버튼을 클릭하면 서버에 과부하가 발생할 수 있습니다
- 다른 버튼은 덜 중요하며 보호가 필요하지 않습니다
2.2 이 버튼의 클릭 리스너 찾기
클릭 리스너란 무엇인가요?
클릭 리스너(이벤트 핸들러 또는 클릭 핸들러라고도 함)는 사용자가 UI 요소와 상호작용할 때 실행되는 코드입니다. Android에서는 일반적으로 setOnClickListener() 메서드 또는 람다 표현식을 사용하여 정의됩니다.
Android 클릭 리스너 구조 이해:
// 방법 1: 람다 표현식 (가장 일반적)
button.setOnClickListener {
// 🎯 이것이 클릭 리스너입니다
// 사용자가 버튼을 탭할 때 여기 코드가 실행됩니다
}
// 방법 2: 익명 객체 (전통적)
button.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
// 🎯 이것이 클릭 리스너입니다
// 사용자가 버튼을 탭할 때 여기 코드가 실행됩니다
}
})
샘플 애플리케이션에서:
// MainFragment.kt
override fun setupViews() {
// 🎯 대상 버튼: 기본 제어 기능 카드
binding.cardBasicControlFunction.setOnClickListener {
// 🎯 클릭 리스너: 버튼 동작이 정의되는 위치
// 사용자가 버튼을 클릭할 때 실행되는 코드입니다
// 현재: navigationManager.navigateWithDelay()가 즉시 실행됩니다
// 이것을 NetFUNNEL 보호로 감쌀 것입니다
Log.d("MainActivity", "Basic Control (Code-based Integration) button clicked")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}
// 다른 버튼 - 대상이 아님 (NetFUNNEL 보호 불필요)
binding.cardSectionControlFunction.setOnClickListener {
// 이 버튼은 NetFUNNEL 보호가 필요하지 않습니다
Log.d("MainActivity", "Section Control Function button clicked")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_sectionControlSection1Fragment
)
}
}
}
핵심 사항:
- 클릭 리스너 위치:
setOnClickListener람다 내부 - 현재 동작:
navigationManager.navigateWithDelay()가 즉시 실행됨 - 통합 대상: 여기에 NetFUNNEL 보호를 추가할 것입니다
2.3 클릭 리스너 내부에서 발생하는 일 검토
함수가 수행하는 작업:
// NavigationManager.kt
suspend fun navigateWithDelay(
resId: Int,
customDelay: Long? = null
) {
val delay = customDelay ?: appPreferences.getNavigationDelay()
showLoadingIndicator() // ← 로딩 인디케이터 표시
delay(delay) // ← 지정된 시간 대기
hideLoadingIndicator() // ← 로딩 인디케이터 숨김
navController?.navigate(resId) // ← 대상 fragment로 이동
}
요약: 로딩 표시 → 대기 → 로딩 숨김 → 이동. 이것은 서버 처리를 시뮬레이션하며 NetFUNNEL 보호가 필요합니다.
2.4 통합 지점 식별
- 대상 버튼:
card_basic_control_function(리소스 집약적인 버튼) - 클릭 리스너:
setupViews()메서드가 클릭 핸들러를 설정합니다 - 통합 위치:
navigationManager.navigateWithDelay()가 호출되기 직전 - 여기서 하는 이유: 서버 처리가 시작되기 직전의 정확한 시점입니다
- 보호 전략: 서버 호출 전에 NetFUNNEL 큐를 추가합니다
전체 흐름 분석:
- Fragment 생성:
onViewCreated()가setupViews()를 호출합니다 - 버튼 설정:
setupViews()가 각 버튼의 클릭 리스너를 설정합니다 - 사용자 작업: 사용자가 "기본 제어 (코드 기반 통합)" 버튼을 클릭합니다
- 현재 동작:
navigationManager.navigateWithDelay()가 즉시 실행됩니다 - 서버 부하: 이것이 리소스 집약적인 작업을 트리거합니다
로직:
- NetFUNNEL 없이: 버튼 클릭 → 즉시 서버 요청 → 잠재적 과부하
- NetFUNNEL 사용: 버튼 클릭 → 큐 확인 → 제어된 서버 요청 → 성공
3단계: 키 발급 함수 구현 (nfStart)
아래 예제는 샘플 애플리케이션의 MainFragment 클릭 핸들러에 NetFUNNEL을 통합하는 방법을 보여줍니다. 이 패턴을 실제 코드 구조에 맞게 조정하세요 - 보호가 필요한 다른 함수 이름, 이벤트 핸들러 또는 비즈니스 로직이 있을 수 있습니다.
3.1 키 가져오기
먼저 콘솔에서 프로젝트 키와 세그먼트 키를 찾으세요:
- NetFUNNEL 콘솔 →
프로젝트→세그먼트로 이동합니다 - 세그먼트를 클릭합니다
- 프로젝트 키와 세그먼트 키를 복사합니다

3.2 nfStart 함수 이해
nfStart 함수는 다음과 같은 기본 구조를 가집니다:
- Kotlin
- Java
Netfunnel.nfStart(
projectKey = "your_project_key", // 콘솔에서 가져옴
segmentKey = "your_segment_key", // 콘솔에서 가져옴
callback = yourCallback, // 응답을 처리할 콜백
activity = this // 현재 activity 컨텍스트
)
Netfunnel.INSTANCE.nfStart(
"your_project_key", // 콘솔에서 가져옴
"your_segment_key", // 콘솔에서 가져옴
yourCallback, // 응답을 처리할 콜백
this // 현재 activity 컨텍스트
);
nfStart 매개변수, 콜백 처리 및 응답 형식에 대한 자세한 내용은 API 참조를 참조하세요.
3.3 현재 코드로 시작
현재 구현:
// MainFragment.kt
override fun setupViews() {
binding.cardBasicControlFunction.setOnClickListener {
Log.d("MainActivity", "Basic Control (Code-based Integration) button clicked")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}
}
핵심 개념:
- 비즈니스 로직:
navigationManager.navigateWithDelay()는 리소스 집약적 작업을 나타냅니다 - 통합 지점: 이 비즈니스 로직을 NetFUNNEL 보호로 감싸야 합니다
- 감싸기 전략: 비즈니스 로직이 실행되기 전에
nfStart()를 사용하여 액세스를 제어합니다
여기서 감싸는 이유:
- 서버 부하가 시작되기 직전의 정확한 순간입니다
- 여기서 감싸면 전체 다운스트림 작업을 보호합니다
- 비즈니스 로직은 변경되지 않습니다 - 큐 레이어만 추가합니다
3.4 필수 import 추가
NetFUNNEL을 구현하기 전에 Fragment에 필요한 import를 추가합니다:
- Kotlin
- Java
// MainFragment.kt
import com.nf4.Netfunnel
import com.nf4.NetfunnelCallback
// MainFragment.java
import com.nf4.Netfunnel;
import com.nf4.NetfunnelCallback;
핵심 Import:
com.nf4.Netfunnel- 메인 NetFUNNEL 클래스com.nf4.NetfunnelCallback- 응답을 위한 콜백 인터페이스
3.5 기본 NetFUNNEL 보호 추가 (성공만)
비즈니스 로직 감싸기:
// MainFragment.kt
import com.nf4.Netfunnel
import com.nf4.NetfunnelCallback
override fun setupViews() {
binding.cardBasicControlFunction.setOnClickListener {
Log.d("MainActivity", "Basic Control (Code-based Integration) button clicked")
startBasicControl()
}
binding.cardSectionControlFunction.setOnClickListener {
Log.d("MainActivity", "Section Control Function button clicked")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_sectionControlSection1Fragment
)
}
}
}
private fun startBasicControl() {
Netfunnel.nfStart(
projectKey = "your_project_key",
segmentKey = "your_segment_key",
callback = basicControlCallback,
activity = requireActivity()
)
}
private val basicControlCallback = object : NetfunnelCallback() {
override fun onSuccess(statusCode: Int, message: String) {
// 사용자가 진행할 수 있음 - 원래 로직 실행
Log.d("NetFUNNEL", "onSuccess(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}
override fun onBlock(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "onBlock(statusCode=$statusCode, message='$message')")
}
override fun onClose(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "onClose(statusCode=$statusCode, message='$message')")
}
override fun onContinue(
statusCode: Int,
message: String,
aheadWait: Int,
behindWait: Int,
waitTime: String,
progressRate: Int
) {
Log.d("NetFUNNEL", "onContinue(statusCode=$statusCode, message='$message', aheadWait=$aheadWait, behindWait=$behindWait, waitTime='$waitTime', progressRate=$progressRate)")
}
override fun onError(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "onError(statusCode=$statusCode, message='$message')")
}
override fun onNetworkError(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "onNetworkError(statusCode=$statusCode, message='$message')")
}
}
변경 사항:
- 감싸짐:
navigationManager.navigateWithDelay()가 이제onSuccess콜백 내부에 있습니다 - 조건부: 특정 버튼만 NetFUNNEL 보호를 받습니다
- 성공만: NetFUNNEL이 진입을 허용할 때만 비즈니스 로직이 실행됩니다
- 완전한 인터페이스: 모든 필수 콜백 메서드가 적절한 로깅과 함께 구현되었습니다
Android에서 NetfunnelCallback은 모든 메서드를 구현해야 하는 인터페이스입니다. onSuccess만 구현할 수 없습니다 - 모든 콜백 메서드에 대한 구현을 제공해야 합니다. 이 구현은 모든 응답 유형에 대한 적절한 로깅과 함께 완전한 콜백 처리를 제공합니다.
이제 구현을 테스트하여 모든 것이 올바르게 작동하는지 확인하세요.
앱을 실행하고 "기본 제어 (코드 기반 통합)" 버튼을 클릭하세요. 화면에 대기실 WebView가 나타나야 합니다. 모든 것이 올바르게 작동하는지 확인하려면 Logcat에서 NetFUNNEL 로그를 확인하세요.
대기실이 보이지 않으면 세그먼트 구성 단계에서 진입 허용 수를 0으로 설정했는지 확인하세요. 이 설정은 사용자가 대기실로 보내지거나 직접 진행할 수 있는지 제어합니다.
더 나은 디버깅을 위해 NetFUNNEL 로깅 활성화:
Application 클래스에서 printLog = true를 설정하여 디버그 로깅을 활성화한 다음 Logcat을 package:mine NetFUNNEL로 필터링하세요. 자세한 설정 지침은 NetFUNNEL 초기화 테스트) 섹션을 참조하세요.
확인할 사항:
진입 허용 수 = 0으로 기본 제어 버튼을 클릭하면 다음과 같은 로그가 표시됩니다:
2025-09-15 14:21:45.762 5659-5659 NetFUNNEL com...ample_android_single_activity D [NF4] Initialization successful. NetFUNNEL Version: 4.3.3-onprem
2025-09-15 14:21:52.685 5659-5675 NetFUNNEL com...ample_android_single_activity D [NF4] Initial entry detected. Request(5101), Work(projectKey=service_1, segmentKey=test_liam_01), Control(BASIC)
2025-09-15 14:21:52.727 5659-5677 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5101 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5101&sid=service_1&aid=test_liam_01
2025-09-15 14:21:54.177 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5101 response. Response(timestamp=1757913714588, code=201, msg=null, key=A06C985C93A27FA585B6EB31707D8F75560B09C0ABA476E93DAAFF65D8F81E1F2AA6D7A151BC9D46A7A70B04309F5684BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 14:21:54.184 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Loading the virtual room. Work(projectKey=service_1, segmentKey=test_liam_01), Status(WAIT)
2025-09-15 14:21:55.745 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] 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
2025-09-15 14:21:56.368 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=A06C985C93A27FA585B6EB31707D8F75560B09C0ABA476E93DAAFF65D8F81E1F2AA6D7A151BC9D46A7A70B04309F5684BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30&sticky=nf1
2025-09-15 14:21:56.406 5659-5765 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757913717559, code=201, msg=null, key=A06C985C93A27FA585B6EB31707D8F7501186C02D6377624BD336C0B9EABC7B23E0DA90D4459587BF1B066C976432A52BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D31302C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
모든 것이 작동 중임을 나타내는 핵심 지표:
| 로그 메시지 | 의미 | 상태 |
|---|---|---|
[NF4] Initialization successful | NetFUNNEL 에이전트가 올바르게 로드됨 | ✅ 좋음 |
[NF4] Initial entry detected | nfStart()가 성공적으로 호출됨 | ✅ 좋음 |
[NF4] Sending 5101 request | NetFUNNEL 서버로 요청 전송됨 | ✅ 좋음 |
[NF4] Received 5101 response with code=201 | 서버가 WAIT 상태로 응답함 | ✅ 좋음 |
[NF4] Loading the virtual room | 대기실 WebView가 로드 중임 | ✅ 좋음 |
[NF4] Fetching HTML content | 대기실 HTML이 로드 중임 | ✅ 좋음 |
[NF4] Sending 5002 request | 주기적 재진입 요청 (폴링) | ✅ 좋음 |
문제가 발생하는 경우:
- 로그가 나타나지 않음: 초기화에서
printLog = true가 설정되었는지 확인 - 대기실이 없음: 콘솔에서 진입 허용 수가 0으로 설정되었는지 확인
- 앱 크래시: 모든 콜백 메서드가 올바르게 구현되었는지 확인
- 네트워크 오류: clientId 및 네트워크 연결 확인
대기실과 로그가 보이면 기본 구현이 작동 중입니다! 이제 더 나은 오류 관리를 위해 콜백 처리를 향상시킬 수 있습니다. 진입을 테스트하려면 콘솔에서 진입 허용 수를 1로 변경하세요.
3.6 완전한 콜백 처리 추가
이제 더 나은 오류 관리 및 사용자 경험을 위해 콜백 처리를 개선하겠습니다:
이전 단계에서 모든 콜백 메서드를 기본 로깅과 함께 구현했습니다. 이제 프로덕션 환경에서 견고한 서비스 가용성과 최적의 사용자 경험을 보장하기 위해 오류 처리를 향상시키겠습니다.
완전한 콜백 처리가 필수인 이유:
- 사용자 경험: 다양한 응답 유형에 적절한 사용자 피드백이 필요합니다
- 서비스 안정성: 오류 상태가 사용자의 워크플로우를 중단하지 않아야 합니다
- 디버깅: 포괄적인 로깅이 문제를 빠르게 식별하는 데 도움이 됩니다
- 비즈니스 연속성: NetFUNNEL에 문제가 발생해도 서비스가 계속되어야 합니다
견고한 오류 처리로 basicControlCallback 향상:
// MainFragment.kt - 완전한 처리를 포함한 basicControlCallback 업데이트
private val basicControlCallback = object : NetfunnelCallback() {
override fun onSuccess(statusCode: Int, message: String) {
// 사용자가 진행할 수 있음 - 원래 로직 실행
Log.d("NetFUNNEL", "onSuccess(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}
override fun onError(statusCode: Int, message: String) {
// 시스템 오류 발생 - 서비스 가용성을 위해 원래 로직 진행
Log.d("NetFUNNEL", "onError(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}
override fun onNetworkError(statusCode: Int, message: String) {
// 네트워크 오류 발생 - 디버깅을 위해 로깅만 수행, 비즈니스 로직은 실행하지 않음
Log.d("NetFUNNEL", "onNetworkError(statusCode=$statusCode, message='$message')")
// 참고: 비즈니스 로직은 여기서 실행되지 않음 - 아래 설명 참조
}
override fun onBlock(statusCode: Int, message: String) {
// 사용자가 차단됨 - 적절한 메시지 표시
Log.d("NetFUNNEL", "onBlock(statusCode=$statusCode, message='$message')")
}
override fun onClose(statusCode: Int, message: String) {
// 사용자가 대기실을 닫음 - 적절히 처리
Log.d("NetFUNNEL", "onClose(statusCode=$statusCode, message='$message')")
// 메인 fragment에 머뭄 - 사용자가 취소함
}
override fun onContinue(
statusCode: Int,
message: String,
aheadWait: Int,
behindWait: Int,
waitTime: String,
progressRate: Int
) {
Log.d("NetFUNNEL", "onContinue(statusCode=$statusCode, message='$message', aheadWait=$aheadWait, behindWait=$behindWait, waitTime='$waitTime', progressRate=$progressRate)")
}
}
응답 처리 전략:
| 응답 유형 | 동작 | 비즈니스 로직 |
|---|---|---|
| Success | 실행 | ✅ 예 |
| Error | 실행 | ✅ 예 |
| NetworkError | 로깅만 | ❌ 아니오 |
| Block | 로깅만 | ❌ 아니오 |
| Close | 로깅만 | ❌ 아니오 |
| Continue | 로깅만 | ❌ 아니오 |
onError는 비즈니스 로직을 실행하지만 onNetworkError는 실행하지 않는 이유:
onError (상태 코드 500) - 서버 오류:
- 시나리오: NetFUNNEL 서버가 내부 오류를 만남
- 전략: 서비스 가용성을 유지하기 위해 비즈니스 로직 실행
- 근거: 서버 오류는 일반적으로 일시적이며 사용자 액세스를 차단하지 않아야 함
- 결과: NetFUNNEL에 문제가 있어도 계속되는 견고한 서비스
onNetworkError (상태 코드 1001, 1002) - 네트워크 문제:
- 시나리오: 네트워크 연결 문제 (오프라인, 타임아웃)
- 전략: 로깅만 수행, 비즈니스 로직 실행 안 함
- 근거: 자동 네트워크 복구를 위해
useNetworkRecoveryMode = true사용 - 결과: 네트워크 문제 중 사용자가 대기실에 머물고 연결이 복구되면 자동 재개
네트워크 복구 모드 구성:
최적의 네트워크 오류 처리를 위해 Application 클래스에서 네트워크 복구를 활성화합니다:
// SampleApplication.kt
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
useNetworkRecoveryMode = true // 자동 네트워크 복구 활성화
)
변경 사항:
- 견고한 오류 처리:
onError는 최대 서비스 가용성을 위해 비즈니스 로직을 진행합니다 - 스마트 네트워크 처리:
onNetworkError는 수동 처리 대신 네트워크 복구 모드에 의존합니다 - 개선된 사용자 경험: 다양한 응답 상태에 대한 더 나은 처리
- 프로덕션 준비: 견고한 오류 처리는 NetFUNNEL에 문제가 발생해도 서비스가 계속되도록 보장합니다
- 포괄적인 로깅: 모든 응답 유형 및 디버깅에 대한 상세한 콘솔 메시지
모든 콜백 응답 유형, 상태 코드, 응답 객체 구조 및 고급 콜백 패턴에 대한 자세한 정보는 API 참조를 참조하세요.
3.7 주요 구현 포인트
- Project/Segment keys: NetFUNNEL 콘솔에서 정확한 키를 사용합니다
- 필수 import:
com.nf4.Netfunnel및com.nf4.NetfunnelCallbackimport를 추가합니다 - 콜백 구현: 모든 콜백 메서드를 구현합니다 (Android 인터페이스 요구사항)
- 견고한 오류 처리:
onSuccess및onError는 서비스 가용성을 위해 비즈니스 로직을 실행합니다onNetworkError는 로깅만 수행합니다 (자동 복구를 위해useNetworkRecoveryMode = true사용)
- Activity 컨텍스트: 항상 현재 activity 컨텍스트를
nfStart()에 전달합니다 - 포괄적인 로깅: 디버깅을 위해 모든 콜백 응답을 로깅합니다
4단계: 키 반환 통합 지점 식별 (nfStop)
다음 예제는 데모 목적으로 샘플 애플리케이션을 사용합니다. 실제 애플리케이션 코드는 여기에 표시된 것과 자연스럽게 다를 수 있습니다. 통합 패턴을 특정 코드 구조, 비즈니스 로직 완료 지점, 키 반환 요구사항에 맞게 조정하세요.
💡 연습 프로젝트가 필요하신가요? NetFUNNEL SDK 통합 연습을 위한 Android 애플리케이션 (Single Activity) 템플릿이 준비된 샘플 프로젝트를 확인하세요.
샘플 애플리케이션 이해:
NetFUNNEL 키를 반환하기 위해 nfStop을 호출해야 하는 위치를 이해하기 위해 샘플 애플리케이션을 살펴보겠습니다.
4.1 비즈니스 로직 완료 지점 식별
nfStart 성공 후 현재 흐름:
// 3단계에서 - nfStart가 성공할 때
override fun onSuccess(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "onSuccess(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}
다음에 발생하는 일:
- 사용자가 BasicControlFragment로 이동 - Fragment 생명주기가 시작됩니다
- Fragment가 완전히 로드됨 -
onCreateView(),setupViews()완료 - 사용자 세션이 활성화됨 - 이제 보호된 기능을 사용할 수 있습니다
- 키를 반환해야 함 - 대기열의 다음 사용자가 진입할 수 있도록 합니다
nfStop 구현에 대한 중요 참고사항:
nfStop은 nfStart가 먼저 호출될 필요 없이 독립적으로 호출할 수 있습니다. nfStart가 호출되지 않은 경우, NetFUNNEL은 필요시 키 해제를 자동으로 처리하거나 키가 없으면 아무 작업도 수행하지 않습니다. 이로 인해 조건부 확인 없이 어떤 시나리오에서도 nfStop을 안전하게 호출할 수 있어 구현이 단순해집니다.
4.2 키 반환을 위한 통합 지점 식별
통합 지점 옵션:
| 통합 지점 | 사용 시기 | 장점 |
|---|---|---|
| Fragment 생명주기 | 간단한 네비게이션 흐름 | 구현이 쉽고 대부분의 경우에 작동합니다 |
| 비즈니스 로직 완료 | 복잡한 작업 (API 호출, 처리) | 정밀한 제어, 실제 작업 후 키 반환 |
| 사용자 작업 완료 | 사용자 시작 작업 | 사용자가 작업을 완료할 때 키 반환 |
4.3 적절한 통합 지점 선택
샘플 애플리케이션의 경우:
현재 비즈니스 로직: navigationManager.navigateWithDelay()
- 수행하는 작업: 서버 처리를 시뮬레이션하고 BasicControlFragment로 이동합니다
- 완료 시점: BasicControlFragment가 성공적으로 로드될 때
- 최적 통합 지점: Fragment 생명주기 이벤트 (onViewCreated, setupViews)
통합 전략:
- Fragment 생성: BasicControlFragment가 완전히 로드될 때 키 반환
- 간단하고 신뢰할 수 있음: 네비게이션 기반 흐름에 작동합니다
- 사용자 경험: 사용자가 실제로 서비스를 사용할 수 있을 때 키가 반환됩니다
4.4 통합 지점 로직 검증
전체 흐름 분석:
- 사용자가 버튼 클릭 →
nfStart()호출됨 - 대기실 나타남 → 사용자가 대기열에서 대기
- 진입 허용됨 →
onSuccess콜백 발생 - 비즈니스 로직 실행 →
navigationManager.navigateWithDelay()실행 - BasicControlFragment 로드됨 → 사용자가 이제 서비스를 사용할 수 있음
- 키 반환 필요 →
nfStop()을 호출하여 대기열 슬롯 해제
이 통합 지점이 합리적인 이유:
- 사용자 경험: 사용자가 실제로 서비스를 사용할 수 있을 때 키가 반환됩니다
- 대기열 관리: 현재 사용자가 준비되면 다음 사용자가 즉시 진입할 수 있습니다
- 리소스 효율성: 불필요한 대기열 차단을 방지합니다
- 구현 단순성: 구현 및 유지 관리가 쉽습니다
핵심 통찰: nfStop 통합 지점은 사용자의 의도한 비즈니스 작업이 실제로 완료되고 대기한 서비스의 이점을 얻을 수 있는 위치여야 합니다.
5단계: 키 반환 함수 구현 (nfStop)
아래 예제는 키를 반환하는 다양한 접근 방식을 보여줍니다. 애플리케이션 아키텍처에 가장 적합한 접근 방식을 선택하세요 - Fragment 네비게이션, API 호출 또는 기타 비즈니스 로직 완료 후 키를 반환해야 하는지 여부에 따라 다릅니다.
5.1 nfStop 함수 이해
nfStop 함수는 다음과 같은 기본 구조를 가집니다:
Netfunnel.nfStop(
projectKey = "your_project_key", // nfStart 키와 정확히 일치해야 함
segmentKey = "your_segment_key", // nfStart 키와 정확히 일치해야 함
completeCallback = yourCompleteCallback // 완료를 처리할 콜백
)
Java 동등 코드:
Netfunnel.INSTANCE.nfStop(
"your_project_key", // nfStart 키와 정확히 일치해야 함
"your_segment_key", // nfStart 키와 정확히 일치해야 함
yourCompleteCallback // 완료를 처리할 콜백
);
핵심 요구사항:
- 정확한 키 일치: 키는
nfStart()에서 사용된 것과 동일해야 합니다 - 타이밍:
nfStart()직후가 아니라 비즈니스 로직이 완료된 후에 호출합니다 - 콜백: 완료 응답을 처리하기 위해
NetfunnelCompleteCallback을 사용합니다
5.2 필수 import 추가
nfStop을 구현하기 전에 Fragment에 필요한 import를 추가하세요:
// BasicControlFragment.kt
import com.nf4.Netfunnel
import com.nf4.NetfunnelCompleteCallback
핵심 import:
com.nf4.Netfunnel- NetFUNNEL 메인 클래스 (nfStart에 이미 import됨)com.nf4.NetfunnelCompleteCallback- 키 반환 완료를 위한 콜백 인터페이스
5.3 기본 키 반환 추가 (Fragment 생명주기)
BasicControlFragment가 로드될 때 키를 반환합니다:
// BasicControlFragment.kt
import com.nf4.Netfunnel
import com.nf4.NetfunnelCompleteCallback
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Fragment가 완전히 로드될 때 키 반환
Netfunnel.nfStop(
projectKey = "your_project_key",
segmentKey = "your_segment_key",
completeCallback = completeCallback
)
}
private val completeCallback = object : NetfunnelCompleteCallback() {
override fun onComplete(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "Key returned: $message")
}
}
변경 사항:
- Fragment 생명주기: BasicControlFragment가 완전히 로드될 때 키를 반환합니다
- 간단한 접근 방식: 기본 네비게이션 시나리오에 작동합니다
- 직접 호출: NetFUNNEL이 초기화되어 사용 가능하다고 가정합니다
이제 키 반환 구현이 올바르게 작동하는지 테스트해보겠습니다.
앱을 실행하고 다음 테스트 순서를 따르세요:
- "기본 제어 (코드 기반 통합)" 버튼을 클릭합니다 - 대기실이 나타나야 합니다
- NetFUNNEL 콘솔에서 진입 허용 수를 0에서 1로 변경합니다 - 이것은 진입을 허용합니다
- 대기실이 닫히는 것을 관찰합니다 - 사라지고 BasicControlFragment로 이동해야 합니다
- Logcat에서 키 반환 로그를 확인합니다 - 5004 요청 로그가 보여야 합니다
더 나은 디버깅을 위한 NetFUNNEL 로깅 활성화:
Application 클래스에서 printLog = true를 설정하여 디버그 로깅을 활성화한 다음, Logcat에서 package:mine NetFUNNEL로 필터링합니다. 자세한 설정 지침은 NetFUNNEL 초기화 테스트) 섹션을 참조하세요.
확인할 사항:
대기실 단계에서 진입 허용 수를 0에서 1로 변경하면 다음과 같은 로그가 보여야 합니다:
2025-09-15 15:23:33.864 6196-6196 NetFUNNEL com...ample_android_single_activity D [NF4] Initialization successful. NetFUNNEL Version: 4.3.3-onprem
2025-09-15 15:23:46.203 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Initial entry detected. Request(5101), Work(projectKey=service_1, segmentKey=test_liam_01), Control(BASIC)
2025-09-15 15:23:46.227 6196-6211 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5101 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5101&sid=service_1&aid=test_liam_01
2025-09-15 15:23:47.726 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5101 response. Response(timestamp=1757917427984, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB1898D3FBDDED79E1C4979B70CAECA7D2F9071C98595486C24B070C0DFEB954A9C3F4BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D382C312C312C302C302C302C30, nwait=1, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:47.736 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] Loading the virtual room. Work(projectKey=service_1, segmentKey=test_liam_01), Status(WAIT)
2025-09-15 15:23:48.426 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] 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
2025-09-15 15:23:48.817 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB1898D3FBDDED79E1C4979B70CAECA7D2F9071C98595486C24B070C0DFEB954A9C3F4BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D382C312C312C302C302C302C30&sticky=nf1
2025-09-15 15:23:48.887 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917430008, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB189855B40CD9D2F33B8E94212241C974E92C78785D8C84A0E36FBF42A696FD0C9265BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D362C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:49.897 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB189855B40CD9D2F33B8E94212241C974E92C78785D8C84A0E36FBF42A696FD0C9265BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D362C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:49.924 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917431061, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB1898D2071B63927D1DD62706C0078BC432511A923D0082FE30F53FB1965DB63DF0BCBCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D352C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:50.929 6196-6285 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB1898D2071B63927D1DD62706C0078BC432511A923D0082FE30F53FB1965DB63DF0BCBCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D352C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:50.951 6196-6285 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917432090, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB189829DB6FFDBB6FB013CEA7F6599A9C94129D63CE6AE1AB4B557C31685803153728BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D342C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:51.956 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB189829DB6FFDBB6FB013CEA7F6599A9C94129D63CE6AE1AB4B557C31685803153728BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D342C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:51.979 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917433117, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB1898CD1CF597D3764F52F1B11FE6F5A1DA1AB8B301E456A85CF6D2D35F5C17F33784BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D332C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:52.984 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB1898CD1CF597D3764F52F1B11FE6F5A1DA1AB8B301E456A85CF6D2D35F5C17F33784BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D332C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:53.007 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917434146, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB189802E99D6C9B4A367F1C40935A4D05C854DCFC137D2FD253A3CE5B0E8EE2359C11BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:54.012 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB189802E99D6C9B4A367F1C40935A4D05C854DCFC137D2FD253A3CE5B0E8EE2359C11BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:54.044 6196-6289 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917435174, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB1898AA690315A075EC205F9ADE7559D9E5CE2C7130F9371987B6C74547C61F6112E4BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D302C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:55.050 6196-6287 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB1898AA690315A075EC205F9ADE7559D9E5CE2C7130F9371987B6C74547C61F6112E4BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D302C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:55.076 6196-6286 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917436212, code=200, msg=null, key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=0, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=null, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=1)
2025-09-15 15:23:55.088 6196-6286 NetFUNNEL com...ample_android_single_activity D [NF4] "Success" response from NetFUNNEL Server.
2025-09-15 15:23:55.088 6196-6286 NetFUNNEL com...ample_android_single_activity D onSuccess(statusCode=200, message='Success')
2025-09-15 15:23:56.143 6196-6196 VRI[NetfunnelWebView] com...ample_android_single_activity D visibilityChanged oldVisibility=true newVisibility=false
2025-09-15 15:23:56.380 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Key return attempt detected. Work(projectKey=service_1, segmentKey=test_liam_01), Control(BASIC)
2025-09-15 15:23:56.383 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5004 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5004&key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30&sticky=nf1
2025-09-15 15:23:56.441 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5004 response. Response(timestamp=1757917437568, code=200, msg=null, key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=0, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=null, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=1)
2025-09-15 15:23:56.443 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] "Success" response from NetFUNNEL Server.
2025-09-15 15:23:56.448 6196-6288 NetFUNNEL com...ample_android_single_activity D Key returned: Key Return Successful
모든 것이 작동하고 있음을 나타내는 핵심 지표:
| 로그 메시지 | 의미 | 상태 |
|---|---|---|
[NF4] Initial entry detected | nfStart()가 성공적으로 호출됨 | ✅ 정상 |
[NF4] Loading the virtual room | 대기실 WebView가 로드 중 | ✅ 정상 |
[NF4] Sending 5002 request (반복) | 주기적인 재진입 요청 (폴링) | ✅ 정상 |
[NF4] Received 5002 response with code=200 | 진입 허용됨 - 대기실이 닫혀야 함 | ✅ 정상 |
onSuccess(statusCode=200, message='Success') | 성공 콜백 발생 | ✅ 정상 |
visibilityChanged oldVisibility=true newVisibility=false | 대기실 WebView 닫힘 | ✅ 정상 |
[NF4] Key return attempt detected | nfStop()이 호출됨 | ✅ 정상 |
[NF4] Sending 5004 request | 키 반환 요청이 서버로 전송됨 | ✅ 정상 |
[NF4] Received 5004 response with code=200 | 키 반환 성공 | ✅ 정상 |
Key returned: Key Return Successful | 완료 콜백 발생 | ✅ 정상 |
테스트 순서:
- 진입 허용 수 = 0으로 시작: 대기실이 나타나고 5002 요청이 반복됩니다
- 진입 허용 수를 1로 변경: 5002 응답이
code=200으로 변경되고 대기실이 닫힙니다 - Fragment 로드: BasicControlFragment
onViewCreated()가nfStop()을 호출합니다 - 키 반환: 5004 요청/응답이 키 반환을 확인합니다
문제가 발생하는 경우:
- 5004 로그가 없음: BasicControlFragment에서
nfStop()이 호출되는지 확인하세요 - 키 반환 실패:
nfStart()와nfStop()간의 프로젝트/세그먼트 키가 정확히 일치하는지 확인하세요 - Fragment가 로드되지 않음:
onSuccess콜백이 네비게이션을 올바르게 실행하는지 확인하세요 - 대기실이 닫히지 않음: 콘솔에서 진입 허용 수가 1로 설정되어 있는지 확인하세요
대기실 → 진입 → Fragment 로드 → 키 반환의 전체 흐름이 보이면 구현이 올바르게 작동하는 것입니다! 이제 에러 처리를 강화하고 더 견고한 콜백 관리를 추가할 수 있습니다.
5.4 주요 구현 포인트
비즈니스 로직이 완료되면 NetFUNNEL 키를 반환하세요. NetFUNNEL은 타임아웃 후 자동으로 키를 반환하지만, 수동 반환은 더 나은 사용자 경험과 대기열 효율성을 제공합니다.
키 반환 규칙:
- ✅ 항상: 비즈니스 로직이 완료된 후 키를 반환합니다 (성공 또는 실패)
- ⚠️ 자동 타임아웃: 수동으로 반환하지 않으면 NetFUNNEL이 자동으로 키를 반환합니다
- 타이밍:
nfStart()직후가 아니라 비즈니스 로직이 완료된 후에 호출합니다
구현 체크리스트:
- 정확한 키 일치:
nfStop()의 키는nfStart()와 정확히 일치해야 합니다 - Fragment 생명주기: 키 반환 타이밍에
onViewCreated()를 사용합니다 - 완전한 콜백: 완료 처리를 위해 항상
NetfunnelCompleteCallback을 구현합니다 - 일관된 키: 전체 흐름에서 동일한 프로젝트/세그먼트 키를 사용합니다
nfStop 매개변수, 응답 처리 및 고급 키 반환 패턴에 대한 자세한 정보는 API 참조를 참조하세요.
6단계: 대기실 테스트 (진입 허용 수 = 0)
아래 테스트 단계는 샘플 애플리케이션을 기반으로 합니다. 테스트 프로세스를 실제 애플리케이션에 맞게 조정하세요 - 버튼 이름, Fragment 네비게이션 및 확인 단계를 특정 구현에 맞게 교체하세요.
6.1 작업 트리거
-
Logcat 로그 지우기 (깨끗한 상태에서 관찰하려는 경우)
- Android Studio에서 Logcat의 휴지통 아이콘을 클릭하여 이전 로그를 지웁니다
- 또는 명령어 사용:
adb logcat -c
-
보호된 버튼 클릭 (예: "기본 제어 (코드 기반 통합)" 버튼)
예상 결과: 현재 화면에 대기실 WebView가 나타납니다
6.2 대기실 표시 확인
다음 요소들이 올바르게 표시되는지 확인하세요:
진입 허용 수가 0으로 설정되고 한 명의 사용자만 연결된 경우, 다음을 확인하세요:
- 나의 대기 순서: 1
- 예상 대기 시간: 00:00:00 (시:분:초)
- 내 뒤의 대기자 수: 0
6.3 Logcat 활동 확인
NetFUNNEL 로그 확인:
Application 클래스에서 printLog = true를 설정하여 디버그 로깅을 활성화한 다음, Logcat에서 package:mine NetFUNNEL로 필터링합니다. 다음과 같은 로그가 보여야 합니다:
2025-09-15 14:21:45.762 5659-5659 NetFUNNEL com...ample_android_single_activity D [NF4] Initialization successful. NetFUNNEL Version: 4.3.3-onprem
2025-09-15 14:21:52.685 5659-5675 NetFUNNEL com...ample_android_single_activity D [NF4] Initial entry detected. Request(5101), Work(projectKey=service_1, segmentKey=test_liam_01), Control(BASIC)
2025-09-15 14:21:52.727 5659-5677 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5101 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5101&sid=service_1&aid=test_liam_01
2025-09-15 14:21:54.177 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5101 response. Response(timestamp=1757913714588, code=201, msg=null, key=A06C985C93A27FA585B6EB31707D8F75560B09C0ABA476E93DAAFF65D8F81E1F2AA6D7A151BC9D46A7A70B04309F5684BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 14:21:54.184 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Loading the virtual room. Work(projectKey=service_1, segmentKey=test_liam_01), Status(WAIT)
2025-09-15 14:21:55.745 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] 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
2025-09-15 14:21:56.368 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=A06C985C93A27FA585B6EB31707D8F75560B09C0ABA476E93DAAFF65D8F81E1F2AA6D7A151BC9D46A7A70B04309F5684BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30&sticky=nf1
2025-09-15 14:21:56.406 5659-5765 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757913717559, code=201, msg=null, key=A06C985C93A27FA585B6EB31707D8F7501186C02D6377624BD336C0B9EABC7B23E0DA90D4459587BF1B066C976432A52BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D31302C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
모든 것이 작동하고 있음을 나타내는 핵심 지표:
| 로그 메시지 | 의미 | 상태 |
|---|---|---|
[NF4] Initialization successful | NetFUNNEL 에이전트가 올바르게 로드됨 | ✅ 정상 |
[NF4] Initial entry detected | nfStart()가 성공적으로 호출됨 | ✅ 정상 |
[NF4] Sending 5101 request | NetFUNNEL 서버로 요청 전송됨 | ✅ 정상 |
[NF4] Received 5101 response with code=201 | 서버가 WAIT 상태로 응답함 | ✅ 정상 |
[NF4] Loading the virtual room | 대기실 WebView가 로드 중 | ✅ 정상 |
[NF4] Fetching HTML content | 대기실 HTML이 로드 중 | ✅ 정상 |
[NF4] Sending 5002 request | 주기적인 재진입 요청 (폴링) | ✅ 정상 |
[NF4] Received 5002 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로 변경합니다 - 하단의
확인을 클릭합니다

확인을 클릭하자마자 대기실이 사라지고 즉시 BasicControlFragment로 이동합니다. 이 순간을 관찰하려면 대기실이 현재 표시된 다른 화면을 열어 두세요.
7.2 진입 확인
예상 결과: 대기실이 즉시 사라지고 BasicControlFragment로 이동합니다
진입 확인을 위해 Logcat을 확인하세요:
다음과 같은 로그가 보여야 합니다:
2025-09-15 15:23:55.076 6196-6286 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917436212, code=200, msg=null, key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=0, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=null, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=1)
2025-09-15 15:23:55.088 6196-6286 NetFUNNEL com...ample_android_single_activity D [NF4] "Success" response from NetFUNNEL Server.
2025-09-15 15:23:55.088 6196-6286 NetFUNNEL com...ample_android_single_activity D onSuccess(statusCode=200, message='Success')
2025-09-15 15:23:56.143 6196-6196 VRI[NetfunnelWebView] com...ample_android_single_activity D visibilityChanged oldVisibility=true newVisibility=false
성공적인 진입의 핵심 지표:
| 로그 메시지 | 의미 | 상태 |
|---|---|---|
[NF4] Received 5002 response with code=200 | 진입 허용됨 - 대기실이 닫혀야 함 | ✅ 정상 |
[NF4] "Success" response from NetFUNNEL Server | 성공 응답 수신됨 | ✅ 정상 |
onSuccess(statusCode=200, message='Success') | 성공 콜백 발생 | ✅ 정상 |
visibilityChanged oldVisibility=true newVisibility=false | 대기실 WebView 닫힘 | ✅ 정상 |
7.3 키 반환 확인
성공적인 키 반환 확인:
Logcat에서 다음 로그를 찾으세요:
2025-09-15 15:23:56.380 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Key return attempt detected. Work(projectKey=service_1, segmentKey=test_liam_01), Control(BASIC)
2025-09-15 15:23:56.383 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5004 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5004&key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30&sticky=nf1
2025-09-15 15:23:56.441 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5004 response. Response(timestamp=1757917437568, code=200, msg=null, key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=0, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=null, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=1)
2025-09-15 15:23:56.443 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] "Success" response from NetFUNNEL Server.
2025-09-15 15:23:56.448 6196-6288 NetFUNNEL com...ample_android_single_activity D Key returned: Key Return Successful
성공적인 키 반환의 핵심 지표:
| 로그 메시지 | 의미 | 상태 |
|---|---|---|
[NF4] Key return attempt detected | nfStop()이 호출됨 | ✅ 정상 |
[NF4] Sending 5004 request | 키 반환 요청이 서버로 전송됨 | ✅ 정상 |
[NF4] Received 5004 response with code=200 | 키 반환 성공 | ✅ 정상 |
Key returned: Key Return Successful | 완료 콜백 발생 | ✅ 정상 |
요약
필수 사항 (반드시 수행)
설정:
- 설치 및 초기화를 완료하고 NetFUNNEL 에이전트가 올바르게 로드되는지 확인합니다
- 콘솔에서 기본 제어로 세그먼트를 생성합니다
- 콘솔에서 프로젝트 키와 세그먼트 키를 가져옵니다
- 테스트를 위해 진입 허용 수를 0으로 설정하고, 프로덕션에서는 1 이상으로 설정합니다
통합:
- 필수 import 추가:
com.nf4.Netfunnel및com.nf4.NetfunnelCallback - 모든 콜백 메서드를 구현합니다 (Android 인터페이스 요구사항)
- 클릭 핸들러에서 비즈니스 로직을
Netfunnel.nfStart()로 감쌉니다 - 비즈니스 로직을 실행하기 위해
onSuccess콜백을 처리합니다 - 비즈니스 로직이 완료된 후
Netfunnel.nfStop()을 호출합니다 nfStart()와nfStop()모두에서 동일한 키를 사용합니다
에러 처리:
onError를 처리하여 비즈니스 로직을 계속 진행합니다 (서비스 가용성 유지)onNetworkError는 로깅만 수행합니다 (useNetworkRecoveryMode = true사용)onBlock을 처리하여 적절한 사용자 메시지를 표시합니다onClose를 처리하여 현재 Fragment에 머뭅니다 (사용자가 취소함)- 모든 콜백 응답에 대한 포괄적인 로깅을 구현합니다
테스트:
- 진입 허용 수 = 0일 때 대기실이 나타나는지 테스트합니다
- 진입 허용 수 = 1일 때 진입이 작동하는지 테스트합니다
- 완료 후 키 반환이 발생하는지 확인합니다
package:mine NetFUNNEL필터로 Logcat에서 NetFUNNEL 로그를 확인합니다
선택 사항 (있으면 좋음)
에러 처리 강화:
- 기본 로깅 대신 사용자 친화적인 에러 메시지를 추가합니다
- 다양한 응답 유형에 대한 사용자 정의 에러 처리 전략을 구현합니다
- NetFUNNEL 이벤트에 대한 분석 추적을 추가합니다
코드 구성:
- 중앙화된 구성 상수를 생성합니다
- 재사용 가능한 NetFUNNEL 래퍼 함수를 구축합니다
- 여러 Fragment에 걸쳐 모듈식 통합 패턴을 구현합니다
모범 사례
필수 import
import com.nf4.Netfunnel
import com.nf4.NetfunnelCallback
import com.nf4.NetfunnelCompleteCallback
이러한 import가 중요한 이유:
- NetFUNNEL 통합에 필수적입니다
- NetFUNNEL을 사용하는 모든 Fragment/Activity에 추가해야 합니다
nfStart()및nfStop()함수 모두에 필요합니다
완전한 콜백 구현
private val basicControlCallback = object : NetfunnelCallback() {
override fun onSuccess(statusCode: Int, message: String) {
// 진입이 허용되면 비즈니스 로직 실행
Log.d("NetFUNNEL", "onSuccess(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}
override fun onError(statusCode: Int, message: String) {
// 시스템 에러 - 서비스 가용성을 유지하기 위해 계속 진행
Log.d("NetFUNNEL", "onError(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}
override fun onNetworkError(statusCode: Int, message: String) {
// 네트워크 에러 - 로깅만 수행하고 네트워크 복구 모드에 의존
Log.d("NetFUNNEL", "onNetworkError(statusCode=$statusCode, message='$message')")
// 비즈니스 로직은 여기서 실행하지 않음 - 아래 설명 참조
}
override fun onBlock(statusCode: Int, message: String) {
// 사용자가 차단됨 - 적절한 메시지 표시
Log.d("NetFUNNEL", "onBlock(statusCode=$statusCode, message='$message')")
}
override fun onClose(statusCode: Int, message: String) {
// 사용자가 대기실을 닫음 - 적절히 처리
Log.d("NetFUNNEL", "onClose(statusCode=$statusCode, message='$message')")
// 메인 fragment에 머뭄 - 사용자가 취소함
}
override fun onContinue(
statusCode: Int,
message: String,
aheadWait: Int,
behindWait: Int,
waitTime: String,
progressRate: Int
) {
Log.d("NetFUNNEL", "onContinue(statusCode=$statusCode, message='$message', aheadWait=$aheadWait, behindWait=$behindWait, waitTime='$waitTime', progressRate=$progressRate)")
}
}
핵심 원칙: 항상 모든 콜백 메서드를 구현하세요 - Android 인터페이스 요구사항입니다.
중앙화된 구성
// 키를 한 곳에 저장합니다
companion object {
private const val PROJECT_KEY = "your_project_key"
private const val SEGMENT_KEY = "your_segment_key"
}
// 모든 곳에서 동일한 구성을 사용합니다
Netfunnel.nfStart(
projectKey = PROJECT_KEY,
segmentKey = SEGMENT_KEY,
callback = basicControlCallback,
activity = requireActivity()
)
Netfunnel.nfStop(
projectKey = PROJECT_KEY,
segmentKey = SEGMENT_KEY,
completeCallback = completeCallback
)
장점:
- 전체 앱에서 키를 쉽게 업데이트할 수 있습니다
- 복사-붙여넣기 오류를 줄입니다
- 구성의 단일 소스입니다
견고한 에러 처리 전략
// onError는 비즈니스 로직을 실행하지만 onNetworkError는 실행하지 않는 이유:
// onError (상태 코드 500) - 서버 에러
override fun onError(statusCode: Int, message: String) {
// 시나리오: NetFUNNEL 서버가 내부 에러를 만남
// 전략: 서비스 가용성을 유지하기 위해 비즈니스 로직 실행
// 근거: 서버 에러는 일반적으로 일시적이며 사용자 접근을 차단하지 않아야 함
// 결과: NetFUNNEL에 문제가 있어도 계속되는 견고한 서비스
businessLogic()
}
// onNetworkError (상태 코드 1001, 1002) - 네트워크 문제
override fun onNetworkError(statusCode: Int, message: String) {
// 시나리오: 네트워크 연결 문제 (오프라인, 타임아웃)
// 전략: 로깅만 수행하고 비즈니스 로직을 실행하지 않음
// 근거: 자동 네트워크 복구를 위해 useNetworkRecoveryMode = true 사용
// 결과: 네트워크 문제 중에 사용자가 대기실에 머물고 연결이 복구되면 자동으로 재개됨
Log.d("NetFUNNEL", "onNetworkError(statusCode=$statusCode, message='$message')")
}
핵심 원칙: 서비스 가용성을 유지하기 위해 시스템 오류에서 항상 비즈니스 로직을 진행하세요.
네트워크 복구 모드 구성
// SampleApplication.kt
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
useNetworkRecoveryMode = true // 자동 네트워크 복구 활성화
)
장점:
- 네트워크 연결 문제의 자동 처리
- 네트워크가 복구되면 사용자가 자동으로 재개됩니다
- 수동 네트워크 에러 처리 복잡성을 줄입니다
항상 키 반환
// 성공적인 작업 후 키 반환
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Fragment가 완전히 로드될 때 키 반환
Netfunnel.nfStop(
projectKey = PROJECT_KEY,
segmentKey = SEGMENT_KEY,
completeCallback = completeCallback
)
}
private val completeCallback = object : NetfunnelCompleteCallback() {
override fun onComplete(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "Key returned: $message")
}
}
키를 반환할 때:
- Fragment가 완전히 로드된 후
- API 호출이 완료된 후
- 비즈니스 작업이 완료된 후
- 작업이 실패한 경우에도
키 일치
// 시작과 중지는 동일한 키를 사용해야 합니다
const val PROJECT_KEY = "your_project_key"
const val SEGMENT_KEY = "your_segment_key"
Netfunnel.nfStart(
projectKey = PROJECT_KEY,
segmentKey = SEGMENT_KEY,
callback = callback,
activity = requireActivity()
)
Netfunnel.nfStop(
projectKey = PROJECT_KEY, // 정확히 일치해야 합니다
segmentKey = SEGMENT_KEY, // 정확히 일치해야 합니다
completeCallback = completeCallback
)
포괄적인 로깅
// Application 클래스에서 디버그 로깅 활성화
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
printLog = true // 상세 로깅 활성화
)
// Logcat 필터링: package:mine NetFUNNEL
로깅의 장점:
- NetFUNNEL 통합 문제의 쉬운 디버깅
- 요청/응답 흐름 추적
- 키 반환 작업 모니터링
- 네트워크 연결 문제 식별
일반적인 문제 및 문제 해결
대기실이 나타나지 않음
증상: 버튼 클릭은 정상적으로 작동하지만 대기실이 나타나지 않습니다
디버그 단계:
- Android 에러를 위해 Logcat 확인:
adb logcat | grep -i error - Application 클래스에서 NetFUNNEL 초기화 확인
- 콘솔에서 세그먼트가 활성화되어 있는지 확인 (비활성화되지 않음)
- 테스트를 위해 진입 허용 수가 0으로 설정되어 있는지 확인
- 프로젝트 키와 세그먼트 키가 콘솔과 정확히 일치하는지 확인 (대소문자 구분)
콜백이 발생하지 않음
증상: nfStart()가 호출되었지만 응답을 받지 못함
디버그 단계:
- NetFUNNEL 로그를 위해 Logcat 확인:
adb logcat | grep NetFUNNEL - NetFUNNEL 서버에 대한 네트워크 연결 확인
- 세그먼트가 활성화되어 있는지 확인 (비활성화되지 않음)
- 대기실을 강제로 표시하기 위해 진입 허용 수 = 0으로 시도
- 모든 콜백 메서드가 구현되어 있는지 확인 (Android 요구사항)
사용자가 대기열에 갇힘
증상: 첫 번째 사용자는 진입하지만 두 번째 사용자는 절대 통과하지 못함
디버그 단계:
- 비즈니스 로직이 완료된 후
nfStop()이 호출되는지 확인 nfStop()의 키가nfStart()와 정확히 일치하는지 확인nfStop()실행을 방해하는 Android 에러 찾기- Logcat에서
[NF4] Key return attempt detected로그 확인 - 로그에
[NF4] Sending 5004 request가 나타나는지 확인
대기실이 표시되지만 진입을 허용하지 않음
증상: 대기실이 나타나지만 진입 허용 수 = 1이어도 사용자가 절대 통과하지 못함
디버그 단계:
- 콘솔에서 세그먼트 상태 확인 - "차단" 모드가 아닌지 확인
- 진입 허용 수가 1 이상으로 설정되어 있는지 확인
- Logcat에서
[NF4] Sending 5002 request확인 (재진입 요청) - NetFUNNEL 로그에서 에러 응답 찾기
- NetFUNNEL 서버에 대한 네트워크 연결 확인
NetFUNNEL 호출 시 앱 크래시
증상: nfStart() 또는 nfStop() 호출 시 앱이 크래시됨
디버그 단계:
- 필수 import가 추가되었는지 확인:
com.nf4.Netfunnel,com.nf4.NetfunnelCallback - Application 클래스에서 NetFUNNEL이 초기화되었는지 확인
- 모든 콜백 메서드가 구현되어 있는지 확인 (Android 인터페이스 요구사항)
nfStart()에 activity context가 올바르게 전달되는지 확인- NetFUNNEL 에이전트가 올바르게 설치되었는지 확인
키 반환 실패
증상: nfStop()이 호출되었지만 키가 반환되지 않음
디버그 단계:
nfStop()의 키가nfStart()와 정확히 일치하는지 확인 (대소문자 구분)- Logcat에서
[NF4] Key return attempt detected메시지 확인 - 로그에서
[NF4] Sending 5004 request찾기 [NF4] Received 5004 response가code=200인지 확인NetfunnelCompleteCallback이 구현되어 있는지 확인
네트워크 복구 문제
증상: 네트워크 연결 문제 중에 사용자가 갇힘
디버그 단계:
- Application 초기화에서
useNetworkRecoveryMode = true확인 - NetFUNNEL 서버에 대한 네트워크 연결 확인
- 네트워크 문제를 시뮬레이션하기 위해 비행기 모드 켜기/끄기로 테스트
- Logcat에서
onNetworkError콜백 호출 모니터링 onNetworkError가 비즈니스 로직을 실행하지 않는지 확인 (복구 모드에 의존)
QA 체크리스트
구현 전 검증
- 프로젝트 키 / 세그먼트 키가 콘솔과 정확히 일치함 (콘솔에서 재확인)
- Application 클래스에서 NetFUNNEL 에이전트가 올바르게 초기화됨
- 필수 import 추가됨:
com.nf4.Netfunnel,com.nf4.NetfunnelCallback,com.nf4.NetfunnelCompleteCallback - 모든 콜백 메서드 구현됨 (Android 인터페이스 요구사항)
대기실 테스트 (진입 허용 수 = 0)
- 진입 허용 수 = 0일 때 대기실 WebView가 올바르게 표시됨
- 대기실이 올바른 세부 정보를 표시함:
- 나의 대기 순서: 1
- 예상 대기 시간: 00:00:00 (시:분:초)
- 내 뒤의 대기자 수: 0
- 대기 중에 Logcat에 **
[NF4] Sending 5002 request**가 주기적으로 나타남 - **
[NF4] Received 5002 response**가 **code=201(WAIT)**을 표시함
진입 테스트 (진입 허용 수 = 1)
- 진입 허용 수를 1로 변경할 때
onSuccess콜백이 발생함 -
onSuccess콜백이 원래 비즈니스 로직을 실행함 - 진입 시 대기실이 즉시 사라짐
- 대상 Fragment로의 네비게이션이 성공적으로 발생함
키 반환 검증
- 완료 지점에서 키 반환이 올바르게 작동함
- Logcat에 **
[NF4] Key return attempt detected**가 나타남 - **
[NF4] Sending 5004 request**가 HTTP 200으로 발생함 - **
[NF4] Received 5004 response**가 **code=200**을 표시함 - 키 반환이
nfStart호출당 정확히 한 번 발생함 - 키 반환이 비즈니스 로직 완료 후에 발생함
에러 처리
- 콜백 분기가 모든 필수 상태에 대해 구현됨:
-
onSuccess- 원래 로직 실행 -
onError- 시스템 에러를 적절히 처리함 (비즈니스 로직 진행) -
onNetworkError- 네트워크 문제를 적절히 처리함 (로깅만 수행) -
onBlock- 차단 상태를 적절히 처리함 -
onClose- 사용자 취소를 적절히 처리함 -
onContinue- 대기 진행 상황을 적절히 처리함
-
- Application 초기화에서 네트워크 복구 모드 활성화됨
- 키 일치 -
nfStart와nfStop에서projectKey/segmentKey가 동일함 - 모든 콜백 응답에 대한 포괄적인 로깅 구현됨
Logcat 검증
-
package:mine NetFUNNEL필터로 NetFUNNEL 로그가 보임 - 초기화 성공 메시지가 나타남
- 버튼 클릭 시 초기 진입 감지 메시지가 나타남
- 가상 대기실 로드 메시지가 나타남
- 키 반환 시도 감지 메시지가 나타남
- 완료 콜백에 키 반환 성공 메시지가 나타남