본문으로 건너뛰기
버전: 4.6.1

문제 해결 & FAQ

NetFUNNEL Android 에이전트 통합에 대한 일반적인 문제, 해결 방법 및 자주 묻는 질문입니다.


목차


설치 문제

AAR 파일이 로드되지 않음

증상:

  • NetFUNNEL 클래스와 관련된 빌드 에러
  • "Cannot resolve symbol" 에러
  • AAR 파일을 찾을 수 없음 에러

해결 방법:

  1. AAR 파일 위치 확인: .aar 파일이 app/libs/ 디렉토리에 있는지 확인
  2. build.gradle 구성 확인: 의존성이 올바르게 추가되었는지 확인
  3. 정리 및 재빌드: 프로젝트 정리 후 재빌드
  4. 파일 권한 확인: AAR 파일이 읽을 수 있는지 확인
// build.gradle.kts에서 확인
dependencies {
implementation(files("libs/netfunnel-android-agent-release-{{latest}}.aar"))
}

외부 의존성이 해결되지 않음

증상:

  • Ktor 또는 Kotlinx Serialization을 찾을 수 없음
  • 외부 라이브러리에 대한 빌드 에러
  • 누락된 의존성 경고

해결 방법:

  1. 필수 의존성 추가: 모든 외부 의존성이 추가되었는지 확인
  2. 버전 확인: 호환 가능한 버전 사용
  3. 프로젝트 동기화: Gradle 파일과 프로젝트 동기화
// 필수 의존성 추가
dependencies {
val ktorVersion = "2.3.12"
val serializationVersion = "1.6.3"

implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-okhttp:$ktorVersion")
implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
implementation("io.ktor:ktor-serialization-gson:$ktorVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
}

빌드 구성 문제

증상:

  • 컴파일 에러
  • 호환되지 않는 API 레벨 에러
  • Java 버전 호환성 문제

해결 방법:

  1. API 레벨 확인: minSdk >= 22targetSdk >= 22인지 확인
  2. Java 버전 확인: Java 1.8 이상 사용
  3. 빌드 기능 확인: viewBinding = true 활성화
// build.gradle.kts 구성 확인
android {
compileSdk = 34

defaultConfig {
minSdk = 22
targetSdk = 34
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = "1.8"
}

buildFeatures {
viewBinding = true
}
}

초기화 문제

에이전트가 초기화되지 않음

증상:

  • Logcat에 NetFUNNEL 로그가 없음
  • 함수를 사용할 수 없음
  • 우회 모드 동작

해결 방법:

  1. 초기화 위치 확인: 초기화가 Application.onCreate()에 있는지 확인
  2. 매개변수 확인: 모든 필수 매개변수가 제공되었는지 확인
  3. 클라이언트 ID 확인: clientId가 올바르고 접근 가능한지 확인
  4. 로깅 활성화: 디버깅을 위해 printLog = true 설정
// 올바른 초기화
class SampleApplication : Application() {
override fun onCreate() {
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
printLog = true // 디버깅을 위해 활성화
)

super.onCreate()
}
}

매니페스트 등록 누락

증상:

  • Application 클래스가 호출되지 않음
  • 초기화가 발생하지 않음
  • 앱 시작 시 크래시

해결 방법:

  1. Application 클래스 등록: AndroidManifest.xml에 추가
  2. 클래스 이름 확인: 올바른 클래스 이름이 사용되었는지 확인
  3. 패키지 확인: 패키지 이름이 일치하는지 확인
<!-- AndroidManifest.xml -->
<application
android:name=".SampleApplication"
android:allowBackup="true">
<!-- Activity들 -->
</application>

우회 모드 (대기실 없음)

증상:

  • 사용자가 대기실 없이 앱에 직접 접근
  • NetFUNNEL 트래픽 제어 없음
  • 함수는 작동하지만 보호 기능 없음

해결 방법:

  1. 클라이언트 ID 확인: clientId가 올바르고 접근 가능한지 확인
  2. 세그먼트 상태 확인: 콘솔에서 세그먼트가 활성화되었는지 확인
  3. 진입 허용 수 확인: 진입 허용 수가 무제한으로 설정되지 않았는지 확인
  4. 로깅 활성화: 초기화 에러에 대한 로그 확인

함수 호출 에러

"Netfunnel is not initialized" 에러

증상:

  • IllegalStateException: Netfunnel is not initialized
  • 함수가 예외를 던짐
  • NetFUNNEL 함수 호출 시 앱 크래시

해결 방법:

  1. 초기화 확인: Netfunnel.initialize()가 먼저 호출되었는지 확인
  2. 타이밍 확인: 초기화 전에 함수를 호출하지 않기
  3. Application 클래스 확인: Application 클래스가 올바르게 등록되었는지 확인
// 함수 호출 전에 초기화되었는지 확인
if (Netfunnel.isInitialized()) {
Netfunnel.nfStart(projectKey, segmentKey, callback, this)
} else {
Log.e("NetFUNNEL", "에이전트가 초기화되지 않음")
// 에러 처리 또는 초기화
}

콜백이 실행되지 않음

증상:

  • nfStart가 호출되었지만 콜백이 실행되지 않음
  • 응답을 받지 못함
  • 콜백을 기다리며 앱이 멈춤

해결 방법:

  1. 네트워크 확인: NetFUNNEL 서버에 대한 네트워크 요청 확인
  2. 로깅 활성화: 디버깅을 위해 printLog = true 설정
  3. 세그먼트 상태 확인: 세그먼트가 Block 상태가 아닌지 확인
  4. 콜백 구현 확인: 콜백이 올바르게 구현되었는지 확인
// 디버깅을 위해 로깅 활성화
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
printLog = true // 로깅 활성화
)

// Logcat에서 NetFUNNEL 메시지 로그 확인

Activity 컨텍스트 문제

증상:

  • IllegalArgumentException: Activity cannot be null
  • 컨텍스트 관련 에러
  • 함수 호출 시 앱 크래시

해결 방법:

  1. Activity 컨텍스트 확인: 유효한 Activity가 전달되었는지 확인
  2. 타이밍 확인: Activity가 소멸된 후 함수를 호출하지 않기
  3. 적절한 생명주기 사용: 적절한 생명주기 메서드에서 함수 호출
// 올바른 사용법
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// 여기서 호출해도 안전함
Netfunnel.nfStart(projectKey, segmentKey, callback, this)
}

// onDestroy 이후 호출하지 않기
override fun onDestroy() {
super.onDestroy()
// 여기서는 NetFUNNEL 함수를 호출하지 않기
}

네트워크 및 연결 문제

네트워크 타임아웃 에러

증상:

  • 상태 코드 1002와 함께 NetworkError 발생
  • 요청이 타임아웃됨
  • 콜백을 받지 못함

해결 방법:

  1. 타임아웃 증가: networkTimeout을 더 높은 값으로 설정 (최대 10000ms)
  2. 재시도 구성: retryCount 증가
  3. 네트워크 복구: useNetworkRecoveryMode = true 활성화
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
networkTimeout = 5000, // 타임아웃 증가
retryCount = 3, // 재시도 증가
errorBypass = false
)

네트워크 연결되지 않음 에러

증상:

  • 상태 코드 1001과 함께 NetworkError 발생
  • 인터넷 연결 없음
  • 네트워크 권한 문제

해결 방법:

  1. 연결 확인: 인터넷 연결 확인
  2. 권한 확인: INTERNET 권한이 부여되었는지 확인
  3. 방화벽 확인: NetFUNNEL 도메인이 차단되지 않았는지 확인
  4. 에러 처리 구현: NetworkError를 적절히 처리
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
// 네트워크 에러 처리
private val callback = object : NetfunnelCallback() {
override fun onNetworkError(statusCode: Int, message: String) {
when (statusCode) {
1001 -> {
// 네트워크 연결되지 않음
showNetworkErrorDialog()
}
1002 -> {
// 네트워크 타임아웃
showTimeoutDialog()
}
}
}
}

서버 통신 문제

증상:

  • NetFUNNEL 서버로부터 응답 없음
  • 로그에 HTTP 에러
  • 인증 실패

해결 방법:

  1. 클라이언트 구성 확인: clientId가 올바른지 확인
  2. 인증 확인: 유효한 clientId 확인
  3. 네트워크 확인: NetFUNNEL 서버에 대한 네트워크 연결 확인
  4. 로그 확인: 상세 에러 메시지를 보기 위해 로깅 활성화

대기실 문제

대기실이 표시되지 않음

증상:

  • 대기실이 나타나지 않음
  • 사용자가 직접 진행함
  • 시각적 피드백 없음

해결 방법:

  1. 진입 허용 수 확인: 테스트를 위해 0으로 설정
  2. 세그먼트 활성화 확인: 세그먼트가 활성화되었는지 확인
  3. 템플릿 설정 확인: useNetfunnelTemplate = true 확인
  4. 콜백 구현 확인: 콜백이 올바르게 구현되었는지 확인
// 디버깅을 위해 로깅 활성화
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
printLog = true // 로깅 활성화
)

대기실이 멈춤 (끝나지 않음)

증상:

  • 대기실이 나타나지만 진입을 허용하지 않음
  • 무한 대기
  • 진행 표시 없음

해결 방법:

  1. 진입 허용 수 확인: 진입 허용 수 값 증가
  2. 세그먼트 상태 확인: 세그먼트가 Block 상태가 아닌지 확인
  3. 네트워크 확인: 네트워크 연결 확인
  4. 서버 상태 확인: NetFUNNEL 서버 상태 확인

사용자 정의 템플릿 문제

증상:

  • 사용자 정의 대기실이 업데이트되지 않음
  • onContinue 콜백이 호출되지 않음
  • UI가 대기열 상태를 반영하지 않음

해결 방법:

  1. 템플릿 비활성화: useNetfunnelTemplate = false 설정
  2. onContinue 구현: onContinue 콜백 처리
  3. 콜백 구현 확인: 올바른 콜백 설정 확인
// 기본 구성
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
errorBypass = false
)

// onContinue 콜백 구현
private val callback = object : NetfunnelCallback() {
override fun onContinue(statusCode: Int, message: String, aheadWait: Int, behindWait: Int, waitTime: String, progressRate: Int) {
// 사용자 정의 대기실 UI 업데이트
updateCustomWaitingRoom(aheadWait, behindWait, waitTime, progressRate)
}
}

키 관리 문제

키가 반환되지 않음

증상:

  • 다음 사용자가 무한정 대기함
  • 대기열이 진행되지 않음
  • 키 관리에 대한 서버 에러

해결 방법:

  1. 항상 nfStop 호출: nfStop/nfStopSection이 호출되었는지 확인
  2. 에러 처리: 에러 시나리오에서도 키 반환
  3. 타이밍 확인: 시작이 완료되기 전에 중지 호출하지 않기
  4. 키 일치 확인: 시작/중지 함수에 동일한 키 사용
// 항상 키 반환
private val callback = object : NetfunnelCallback() {
override fun onSuccess(statusCode: Int, message: String) {
try {
performAction()
} finally {
// 항상 키 반환
Netfunnel.nfStop(projectKey, segmentKey, completeCallback)
}
}

override fun onError(statusCode: Int, message: String) {
// 에러가 발생해도 키 반환
Netfunnel.nfStop(projectKey, segmentKey, completeCallback)
}
}

키 불일치 에러

증상:

  • 잘못된 키에 대한 서버 에러
  • 키를 찾을 수 없음 에러
  • 함수 호출 실패

해결 방법:

  1. 키 일관성: 시작/중지 함수에 동일한 키 사용
  2. 키 범위: 다른 작업에서 키 재사용하지 않기
  3. 타이밍: 시작이 완료되기 전에 중지 호출하지 않기
  4. 콘솔 확인: 키가 콘솔과 정확히 일치하는지 확인
// 일관된 키 사용
val projectKey = "service_1"
val segmentKey = "segKey_123"

// 시작
Netfunnel.nfStart(projectKey, segmentKey, callback, this)

// 중지 (동일한 키를 사용해야 함)
Netfunnel.nfStop(projectKey, segmentKey, completeCallback)

설정 문제

잘못된 프로젝트/세그먼트 키

증상:

  • 함수가 호출되었지만 효과 없음
  • 잘못된 세그먼트 동작
  • 서버 에러

해결 방법:

  1. 콘솔 확인: NetFUNNEL 콘솔에서 키를 다시 확인
  2. 정확히 복사: 콘솔에 표시된 대로 키를 정확히 복사
  3. 환경: 올바른 환경 사용 (프로덕션 vs 스테이징)
  4. 세그먼트 유형 확인: 올바른 세그먼트 유형 사용 (기본 제어 vs 구간 제어)

매개변수 유효성 검사 에러

증상:

  • 초기화 실패
  • IllegalArgumentException 에러
  • 잘못된 매개변수 경고

해결 방법:

  1. 매개변수 범위 확인: 값이 허용된 범위 내에 있는지 확인
  2. 필수 매개변수 확인: 모든 필수 매개변수가 제공되었는지 확인
  3. 매개변수 타입 확인: 올바른 데이터 타입이 사용되었는지 확인
// 유효한 매개변수 범위
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}", // 필수
networkTimeout = 5000, // 100-10000이어야 함
retryCount = 3, // 0-10이어야 함
printLog = true, // Boolean
errorBypass = false // Boolean
)

빌드 및 환경 문제

ProGuard/R8 문제

증상:

  • 디버그에서는 작동하지만 릴리스에서는 작동하지 않음
  • 클래스를 찾을 수 없음 에러
  • 메서드를 찾을 수 없음 에러
  • 릴리스 빌드에서 NetFUNNEL 함수가 작동하지 않음

해결 방법:

  1. ProGuard 규칙 추가: NetFUNNEL 클래스를 ProGuard 규칙에 추가
  2. R8 구성 확인: R8이 NetFUNNEL 클래스를 난독화하지 않도록 확인
  3. 릴리스 빌드 테스트: 릴리스 빌드 구성으로 테스트

필수 ProGuard 규칙:

app/proguard-rules.pro 파일에 다음 규칙을 추가하세요:

# NetFUNNEL Android Agent - 주요 패키지 및 클래스 보호
-keep class com.nf4.** { *; }

# NetFUNNEL Android Agent - 리플렉션 관련 클래스 및 멤버 유지
-keepclassmembers class com.nf4.** { *; }

필수한 이유:

  • 릴리스 빌드는 코드 축소, 난독화 및 최적화를 사용함
  • NetFUNNEL Android Agent는 리플렉션 및 동적 클래스 로딩을 사용함
  • 이러한 규칙 없이는 NetFUNNEL 클래스가 난독화되어 기능이 중단됨
  • 이 구성은 프로덕션 릴리스에 필수입니다

테스트:

  1. 릴리스 APK/Bundle 빌드
  2. 디바이스에 설치
  3. NetFUNNEL 기능 테스트
  4. 클래스 로딩 에러에 대한 Logcat 확인

Android 버전 호환성

증상:

  • 이전 Android 버전에서 앱 크래시
  • API 레벨 호환성 에러
  • 기능을 사용할 수 없음 에러

해결 방법:

  1. minSdk 확인: minSdk >= 22인지 확인
  2. targetSdk 확인: targetSdk >= 22인지 확인
  3. 디바이스에서 테스트: 다른 Android 버전의 실제 디바이스에서 테스트
  4. API 사용 확인: 호환 가능한 API 사용 확인

개발 vs 프로덕션

증상:

  • 개발에서는 작동하지만 프로덕션에서는 작동하지 않음
  • 환경 간 다른 동작
  • 구성 차이

해결 방법:

  1. 환경 구성: 각 환경에 대한 올바른 구성 사용
  2. 콘솔 설정: dev/prod용 별도 세그먼트 설정
  3. 빌드 구성: 올바른 빌드 구성 확인
  4. 테스트: 개발 및 프로덕션 빌드 모두 테스트

FAQ

같은 앱에서 기본 제어와 구간 제어를 모두 사용할 수 있나요?

답변: 예, 같은 애플리케이션에서 두 방법을 모두 사용할 수 있습니다:

// 로그인을 위한 기본 제어
fun handleLogin() {
Netfunnel.nfStart("login_project", "login_segment", loginCallback, this)
}

// 체크아웃을 위한 구간 제어
fun startCheckout() {
Netfunnel.nfStartSection("checkout_project", "checkout_segment", checkoutCallback, this)
}

NetworkError를 어떻게 처리해야 하나요?

답변: 사용자에게 알리고 재시도하거나 원래 로직을 진행하세요:

private val callback = object : NetfunnelCallback() {
override fun onNetworkError(statusCode: Int, message: String) {
when (statusCode) {
1001 -> {
// 네트워크 연결되지 않음
showNetworkErrorDialog()
}
1002 -> {
// 네트워크 타임아웃 - 재시도
retryWithDelay()
}
}
}
}

private fun retryWithDelay() {
Handler(Looper.getMainLooper()).postDelayed({
Netfunnel.nfStart(projectKey, segmentKey, callback, this)
}, 2000)
}

키 반환을 잊어버리면 어떻게 되나요?

답변: 키는 서버 타임아웃에 의해 자동 반환될 수 있지만, 이는 병목 현상을 일으킬 수 있습니다. 항상 명시적으로 반환하세요:

// 좋음: 항상 키 반환
private val callback = object : NetfunnelCallback() {
override fun onSuccess(statusCode: Int, message: String) {
performAction()
.onSuccess {
Netfunnel.nfStop(projectKey, segmentKey, completeCallback)
}
.onFailure {
Netfunnel.nfStop(projectKey, segmentKey, completeCallback) // 에러가 발생해도
}
}
}

NetFUNNEL을 여러 번 초기화할 수 있나요?

답변: 아니요, NetFUNNEL은 Application 클래스에서 한 번만 초기화해야 합니다. 여러 번 초기화하면 예기치 않은 동작이 발생할 수 있습니다.

NetFUNNEL 통합을 어떻게 디버깅하나요?

답변: 로깅을 활성화하고 로그를 확인하세요:

Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
printLog = true // 로깅 활성화
)

그런 다음 Logcat에서 NetFUNNEL 로그 메시지를 확인하세요.

기본 제어와 구간 제어의 차이점은 무엇인가요?

답변:

  • 기본 제어: 진입 속도를 제한함 (사용자가 얼마나 빠르게 진입할 수 있는지)
  • 구간 제어: 고정된 동시 사용자 수를 유지함 (동시에 활성화될 수 있는 사용자 수)

간단한 진입 제한에는 기본 제어를, 특정 동시성 수준 유지에는 구간 제어를 사용하세요.

Fragment에서 NetFUNNEL을 사용할 수 있나요?

답변: 예, 하지만 Activity 컨텍스트를 전달해야 합니다:

class MyFragment : Fragment() {
fun startNetFUNNEL() {
activity?.let { activity ->
Netfunnel.nfStart(projectKey, segmentKey, callback, activity)
}
}
}

도움 받기

여전히 문제가 발생하는 경우:

  1. 로그 확인: printLog = true를 활성화하고 Logcat 확인
  2. 구성 확인: NetFUNNEL 콘솔의 모든 설정을 다시 확인
  3. 간단한 설정으로 테스트: 기본 구성으로 시작하여 점진적으로 복잡성 추가
  4. 지원팀에 문의: 구체적인 에러 세부 정보와 함께 NetFUNNEL 지원팀에 문의

관련 문서