설치 및 초기화
이 가이드는 NetFUNNEL iOS 에이전트를 애플리케이션에 통합하기 위한 필수 설정 단계를 다룹니다.
사전 요구 사항
시스템 요구 사항
| 구성 요소 | 버전 | 참고 |
|---|---|---|
| iOS | 12+ | 활성 iOS 디바이스의 99%를 포함 |
| Storyboard | Objective-C, Swift | UIKit 기반 개발용 |
| SwiftUI | 호환 가능 | SwiftUI 기반 개발용 |
1단계: SDK 다운로드
1.1 NetFUNNEL 콘솔에서 다운로드

- NetFUNNEL 콘솔에 로그인
- 이동: 에이전트 → 모바일 에이전트 → iOS
- 클릭: "Traffic Control Installation File" 버튼
- ZIP 파일 다운로드:
netfunnel-ios-agent-{{version}}.zip
1.2 파일 추출
- ZIP 파일을 추출하여 다음을 얻습니다:
netfunnel-ios-agent-{{version}}/
├── netfunnel-ios-agent-debug/
│ └── netfunnel_ios.xcframework // (개발용)
└── netfunnel-ios-agent-release/
└── netfunnel_ios.xcframework // (프로덕션용)
- 개발: debug xcframework 사용
- 프로덕션: release xcframework 사용
2단계: 의존성 추가
2.1 프레임워크 추가
-
프로젝트 루트에
Frameworks폴더 생성 (.xcodeproj 파일과 같은 레벨) -
적절한 xcframework를
Frameworks/로 복사:프로젝트 구조:
your-project/
├── YourProject/
│ ├── AppDelegate.swift
│ └── ...
├── Frameworks/
│ └── netfunnel_ios.xcframework // (debug 또는 release 폴더에서)
└── YourProject.xcodeproj -
Xcode에서 프레임워크 등록:
- Project Navigator에서 프로젝트 선택
- General → Frameworks, Libraries, and Embedded Content로 이동
- + 클릭 → Add Files… →
netfunnel_ios.xcframework선택 - Add 클릭
- Embed를 Embed & Sign으로 설정

프레임워크가 물음표(?) 없이 나타나는지 확인하세요. 물음표가 보이면 우클릭 → Source Control → Add netfunnel_ios.xcframework
2.2 App Transport Security 구성 (필요한 경우)
NetFUNNEL 서버가 HTTPS 대신 HTTP를 사용하는 경우에만 필요합니다.
- Modern Xcode (SwiftUI Templates)
- Legacy Xcode (UIKit Templates)
Info.plist가 숨겨진 프로젝트용
- Project Navigator에서 앱 Target 선택
- Info 탭으로 이동
- 기존 행을 우클릭 → Add Row
- "App Transport Security Settings" 입력 → Dictionary로 설정
- App Transport Security Settings 확장 → Add Row
- "Allow Arbitrary Loads" 입력 → "YES"로 설정 (Boolean)
Info.plist 파일이 보이는 프로젝트용
Info.plist파일을 우클릭- "Open As" → "Source Code" 선택
- 다음 XML 코드 추가:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
프로덕션 빌드의 경우 App Store 검토 거부를 피하기 위해 특정 서버 도메인과 함께 NSExceptionDomains를 사용하세요.
2.3 설정 확인
- 프로젝트 정리: Product → Clean Build Folder (⌘+Shift+K)
- 프로젝트 빌드: Product → Build (⌘+B)
3단계: 에이전트 초기화
3.1 NetfunnelHandler 클래스 생성
NetFUNNEL을 초기화하기 전에 델리게이트 메서드를 위한 전용 핸들러 클래스를 생성하세요:
- NetfunnelHandler 파일 생성:
- Swift
- Objective-C
- Xcode에서 프로젝트를 우클릭
- New File → Swift File 선택
NetfunnelHandler로 이름 지정- 프롬프트가 나타나면 프로젝트 타겟에 추가
중요: NetfunnelHandler.swift를 생성한 후 프로젝트 타겟에 등록해야 합니다. Xcode가 타겟에 추가할지 묻습니다 - 앱 타겟에 대한 확인란을 선택해야 합니다.
NetfunnelHandler.swift를 AppDelegate.swift와 함께 메인 앱 폴더에 배치하세요.
- Xcode에서 프로젝트를 우클릭
- New File → Cocoa Touch Class 선택
- Class:
NetfunnelHandler - Subclass of:
NSObject - Language: Objective-C
- 프롬프트가 나타나면 프로젝트 타겟에 추가
중요: NetfunnelHandler.h와 NetfunnelHandler.m을 생성한 후 프로젝트 타겟에 등록해야 합니다. Xcode가 타겟에 추가할지 묻습니다 - 앱 타겟에 대한 확인란을 선택해야 합니다.
NetfunnelHandler.h와 NetfunnelHandler.m을 AppDelegate.h와 AppDelegate.m과 함께 메인 앱 폴더에 배치하세요.
- 핸들러 구현 추가:
- Swift
- Objective-C
// NetfunnelHandler.swift
import Foundation
import Netfunnel_iOS
class NetfunnelHandler: NSObject, NetfunnelDelegate {
static let shared = NetfunnelHandler()
var onSuccess: ((String, String, Int, String) -> Void)?
var onError: ((String, String, Int, String) -> Void)?
var onNetworkError: ((String, String, Int, String) -> Void)?
var onContinue: ((String, String, Int, String, Int, Int, String, Int) -> Void)?
var onBlock: ((String, String, Int, String) -> Void)?
var onClose: ((String, String, Int, String) -> Void)?
var onComplete: ((String, String, Int, String) -> Void)?
private override init() {
super.init()
}
func nfSuccess(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
onSuccess?(projectKey, segmentKey, statusCode, message)
}
func nfError(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
onError?(projectKey, segmentKey, statusCode, message)
}
func nfNetworkError(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
onNetworkError?(projectKey, segmentKey, statusCode, message)
}
func nfContinue(projectKey: String, segmentKey: String, statusCode: Int, message: String,
aheadWait: Int, behindWait: Int, waitTime: String, progressRate: Int) {
onContinue?(projectKey, segmentKey, statusCode, message, aheadWait, behindWait, waitTime, progressRate)
}
func nfBlock(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
onBlock?(projectKey, segmentKey, statusCode, message)
}
func nfClose(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
onClose?(projectKey, segmentKey, statusCode, message)
}
func nfComplete(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
onComplete?(projectKey, segmentKey, statusCode, message)
}
}
// NetfunnelHandler.h
#import <Foundation/Foundation.h>
#import <Netfunnel_iOS/Netfunnel_iOS.h>
@interface NetfunnelHandler : NSObject <NetfunnelDelegate>
+ (instancetype)sharedInstance;
@property (nonatomic, copy) void(^onSuccess)(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message);
@property (nonatomic, copy) void(^onError)(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message);
@property (nonatomic, copy) void(^onNetworkError)(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message);
@property (nonatomic, copy) void(^onContinue)(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message, NSInteger aheadWait, NSInteger behindWait, NSString *waitTime, NSInteger progressRate);
@property (nonatomic, copy) void(^onBlock)(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message);
@property (nonatomic, copy) void(^onClose)(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message);
@property (nonatomic, copy) void(^onComplete)(NSString *projectKey, NSString *segmentKey, NSInteger statusCode, NSString *message);
@end
// NetfunnelHandler.m
#import "NetfunnelHandler.h"
@implementation NetfunnelHandler
+ (instancetype)sharedInstance {
static NetfunnelHandler *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void)nfSuccessWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
if (self.onSuccess) {
self.onSuccess(projectKey, segmentKey, statusCode, message);
}
}
- (void)nfErrorWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
if (self.onError) {
self.onError(projectKey, segmentKey, statusCode, message);
}
}
- (void)nfNetworkErrorWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
if (self.onNetworkError) {
self.onNetworkError(projectKey, segmentKey, statusCode, message);
}
}
- (void)nfContinueWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message
aheadWait:(NSInteger)aheadWait
behindWait:(NSInteger)behindWait
waitTime:(NSString *)waitTime
progressRate:(NSInteger)progressRate {
if (self.onContinue) {
self.onContinue(projectKey, segmentKey, statusCode, message, aheadWait, behindWait, waitTime, progressRate);
}
}
- (void)nfBlockWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
if (self.onBlock) {
self.onBlock(projectKey, segmentKey, statusCode, message);
}
}
- (void)nfCloseWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
if (self.onClose) {
self.onClose(projectKey, segmentKey, statusCode, message);
}
}
- (void)nfCompleteWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
if (self.onComplete) {
self.onComplete(projectKey, segmentKey, statusCode, message);
}
}
@end
3.2 NetFUNNEL 콘솔에서 초기화 코드 가져오기
- NetFUNNEL 콘솔에 로그인
- 이동: 에이전트 → 모바일 에이전트 → iOS
- 실제 서버 URL이 포함된 초기화 코드 복사

3.3 AppDelegate에서 초기화
메서드의 시작 부분에서 application(_:didFinishLaunchingWithOptions:)에 초기화하세요. 이 단계를 누락하면 = 우회 모드 (보호 없음).
3.3.1 프로젝트 유형 확인
- UIKit 프로젝트: ✅ 이미 AppDelegate가 있음 - 3.3.3으로 건너뛰기
- SwiftUI 프로젝트: ⚠️ AppDelegate를 생성해야 함 - 3.3.2를 따르세요
3.3.2 AppDelegate 생성 (SwiftUI만 해당)
AppDelegate 파일 생성
- Swift
- Objective-C
- Xcode에서 프로젝트를 우클릭
- New File → Swift File 선택
AppDelegate로 이름 지정
- Xcode에서 프로젝트를 우클릭
- New File → Cocoa Touch Class 선택
- Class:
AppDelegate, Subclass of:NSObject
SwiftUI에 연결
- Swift
- Objective-C
메인 App 파일(예: YourAppNameApp.swift)을 열고 다음을 추가하세요:
// YourAppNameApp.swift
import SwiftUI
@main
struct YourAppNameApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
SwiftUI가 있는 Objective-C 프로젝트의 경우 여전히 Swift App 파일이 필요합니다:
// YourAppNameApp.swift (Objective-C 프로젝트의 Swift 파일)
import SwiftUI
@main
struct YourAppNameApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
3.3.3 초기화 코드 추가
NetFUNNEL 콘솔에서 초기화 코드를 복사하여 AppDelegate 파일에 추가하세요:
- 콘솔에서 복사: NetFUNNEL 콘솔에서 복사한 초기화 코드 사용 (3.2)
- AppDelegate에 추가:
application(_:didFinishLaunchingWithOptions:)메서드에 붙여넣기
- Swift
- Objective-C
AppDelegate.swift를 열고 application(_:didFinishLaunchingWithOptions:) 메서드에 초기화 코드를 추가하세요:
// AppDelegate.swift
import UIKit
import Netfunnel_iOS
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 여기에 NetFUNNEL 콘솔 초기화 코드를 붙여넣으세요
Netfunnel.initialize(
clientId: "{{CLIENT_ID}}",
delegate: self // 델리게이트를 지정된 델리게이트 객체 또는 'self'로 설정합니다
)
return true
}
}
AppDelegate.m을 열고 application:didFinishLaunchingWithOptions: 메서드에 초기화 코드를 추가하세요:
// AppDelegate.m
#import <UIKit/UIKit.h>
#import <Netfunnel_iOS/Netfunnel.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 여기에 NetFUNNEL 콘솔 초기화 코드를 붙여넣으세요
[agent initializeWithClientId:@"{{CLIENT_ID}}"
delegate:self];
return YES;
}
@end
3.3.4 초기화 매개변수 수정
변경해야 하는 중요한 사항:
-
delegate 매개변수 변경:
- 콘솔 코드:
delegate: self(Swift) 또는delegate:self(Objective-C) - 다음으로 변경:
delegate: NetfunnelHandler.shared(Swift) 또는delegate:[NetfunnelHandler sharedInstance](Objective-C)
- 콘솔 코드:
-
테스트를 위해 디버그 로깅 활성화:
- 변경:
printLog: false→printLog: true - 목적: 디버깅을 위해 Xcode Console에서 NetFUNNEL 로그 확인
- 변경:
수정된 AppDelegate 코드:
- Swift
- Objective-C
// AppDelegate.swift - 수정된 버전
import UIKit
import Netfunnel_iOS
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Netfunnel.initialize(
clientId: "{{CLIENT_ID}}",
delegate: NetfunnelHandler.shared // 'self'에서 변경됨
)
return true
}
}
// AppDelegate.m - 수정된 버전
#import <UIKit/UIKit.h>
#import <Netfunnel_iOS/Netfunnel.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[agent initializeWithClientId:@"{{CLIENT_ID}}"
delegate:[NetfunnelHandler sharedInstance]]; // 'self'에서 변경됨
return YES;
}
@end
더 나은 성능과 보안을 위해 프로덕션 빌드에서 printLog: false로 설정하는 것을 기억하세요.
플레이스홀더 {{CLIENT_ID}}를 NetFUNNEL 콘솔의 실제 클라이언트 ID로 교체하세요.
고급: 예외 처리
프로덕션 앱의 경우 try-catch 에러 처리를 추가하고 printLog: false로 설정하세요:
- Swift
- Objective-C
import UIKit
import Netfunnel_iOS
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
do {
try Netfunnel.initialize(
clientId: "{{CLIENT_ID}}",
delegate: NetfunnelHandler.shared
)
} catch {
print("NetFUNNEL initialization failed: \(error)")
// 오류 처리: 오류 화면 표시 또는 앱 종료
}
return true
}
}
#import <UIKit/UIKit.h>
#import <Netfunnel_iOS/Netfunnel.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
@try {
[agent initializeWithClientId:@"{{CLIENT_ID}}"
delegate:[NetfunnelHandler sharedInstance]];
} @catch (NSException *exception) {
NSLog(@"NetFUNNEL initialization failed: %@", exception.reason);
// 오류 처리: 오류 화면 표시 또는 앱 종료
}
return YES;
}
@end
필수 매개변수
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
clientId | String | 예 | NetFUNNEL 콘솔에서 제공하는 클라이언트 ID |
delegate | NetfunnelDelegate | 예 | 프로토콜을 구현하는 델리게이트 객체 |
clientId 누락 = 우회 모드 (대기실 보호 없음)
networkTimeout, retryCount, printLog 등 추가 초기화 매개변수는 설정 옵션 참조를 참조하세요.
4단계: 빌드 및 설치 확인
SDK 설정 및 초기화를 완료했으므로 프로젝트를 빌드하고 NetFUNNEL이 올바르게 작동하는지 확인하겠습니다.
4.1 프로젝트 빌드
동기화 및 빌드
-
프로젝트 정리
Product→Clean Build Folder로 이동- 정리 완료 대기
-
프로젝트 빌드
⌘+B를 누르거나Product→Build로 이동- Issue Navigator에서 에러 모니터링
빌드 성공 확인
-
빌드 출력 확인
- Issue Navigator에 컴파일 에러가 없는지 확인
- 성공적인 프레임워크 링크 메시지 확인
- NetFUNNEL 프레임워크가 올바르게 포함되었는지 확인
-
의존성 확인
- Project Navigator에서 프로젝트 확장
netfunnel_ios.xcframework가 나열되어 있는지 확인- 프레임워크가 물음표 없이 나타나는지 확인
4.2 NetFUNNEL 초기화 테스트
디버그 로깅 활성화
NetFUNNEL이 올바르게 초기화되는지 확인하려면 AppDelegate에서 일시적으로 디버그 로깅을 활성화하세요:
더 나은 성능과 보안을 위해 프로덕션 빌드에서 printLog = false로 설정하는 것을 기억하세요.
- Swift
- Objective-C
// AppDelegate.swift
Netfunnel.initialize(
clientId: "{{CLIENT_ID}}",
delegate: NetfunnelHandler.shared
)
// AppDelegate.m
[agent initializeWithClientId:@"{{CLIENT_ID}}"
delegate:[NetfunnelHandler sharedInstance]];
콘솔 출력 모니터링
-
콘솔 열기
View→Debug Area→Activate Console(⌘+Shift+Y)로 이동- 또는 하단 패널의
Console탭 클릭
-
NetFUNNEL 로그 필터링
- 콘솔 필터 필드에
NetFUNNEL을 입력하여 NetFUNNEL 로그로 필터링 - 이렇게 하면 NetFUNNEL 관련 로그 메시지만 표시됩니다
- 콘솔 필터 필드에
-
앱 실행
- 디바이스 또는 시뮬레이터에서 앱 실행
- Console에서 초기화 성공 메시지 확인:
[NF4] Initialization successful. NetFUNNEL Version: {{version}}
문제 해결
설치 또는 초기화 중 문제가 발생하면 다음을 포함한 일반적인 문제에 대한 상세한 해결 방법이 포함된 포괄적인 문제 해결 & FAQ 가이드를 참조하세요:
- 설치 문제: 프레임워크 로딩, 프로젝트 구성, 빌드 설정
- 초기화 문제: 에이전트가 초기화되지 않음, 델리게이트 등록, 우회 모드
- 함수 호출 에러: 초기화 에러, 콜백 문제, 컨텍스트 문제
- 네트워크 및 연결 문제: 타임아웃 에러, 연결 문제, 서버 통신
- 빌드 및 환경 문제: Xcode 구성, iOS 버전 호환성
일반적인 문제에 대한 즉각적인 도움:
- 콘솔 확인:
NetFUNNEL로 필터링하여 상세 로그 확인 - 구성 확인: 모든 설정이 NetFUNNEL 콘솔과 일치하는지 다시 확인
- 간단한 설정으로 테스트: 먼저 기본 구성으로 시작
- 클라이언트 ID 확인: 클라이언트 ID가 NetFUNNEL 콘솔의 것과 일치하는지 확인