iOS 에이전트 적용
WhaTap 모바일 에이전트를 iOS 앱에 적용하면 앱 시작 성능, 화면 로딩, 네트워크 호출, 크래시, 리소스 사용량, WebView 페이지 성능을 수집할 수 있습니다.
이 문서는 앱 개발자를 대상으로 라이브러리 추가부터 데이터 수집 확인까지 전체 절차를 안내합니다. WebView 안의 웹 페이지까지 수집하려면 웹 담당자의 작업도 필요합니다. 자세한 내용은 WebView 페이지 수집 설정에서 다룹니다.
지원 환경
빌드 환경
| Item | Value |
|---|---|
| iOS | 15.0 이상 |
| Xcode | 16.0 이상 |
| 언어 | Swift 5.9 이상 또는 Objective-C |
배포 타깃
앱의 배포 타깃(IPHONEOS_DEPLOYMENT_TARGET)을 iOS 15.0 이상으로 설정하세요. 배포 패키지의 platforms 선언도 .iOS(.v15)이므로, Swift Package Manager로 추가하면 15.0 미만인 앱은 패키지 해석 단계에서 막힙니다.
XCFramework을 직접 추가한 경우에는 해석 단계의 검사가 없어 링크할 때 경고로만 나타납니다.
building for iOS x.y, but linking with dylib … which was built for newer version 15.0
빌드는 통과하지만 15.0 미만 기기에서의 동작은 보증하지 않습니다.
Xcode 15 이하는 지원하지 않습니다.
모듈 인터페이스가 SwiftUICore를 참조하는데, 이 모듈은 iOS 18 SDK(Xcode 16)에서 분리 신설된 것이라 그 이전 SDK에는 존재하지 않습니다.
WebView 연동 요구 버전
앱 안의 WebView 페이지까지 함께 수집하려면 iOS 에이전트와 브라우저 에이전트가 모두 요구 버전을 충족해야 합니다. 한쪽이라도 버전이 낮으면 일부 항목이 수집되지 않습니다. 이때 앱과 웹 어느 로그에도 오류가 남지 않습니다.
| Component | Minimum version | Owner |
|---|---|---|
| iOS 에이전트 | 2.7.15 | 앱 개발자 |
| 브라우저 에이전트 | 3.2.0 | 웹 개발자 |
2.7.15 미만에서는 웹뷰 데이터가 대시보드에 표시되지 않습니다. 적용을 마친 뒤 대시보드의 agent_version 값에서 실제로 동작 중인 버전을 확인하세요. 파일을 교체하는 것만으로는 새 버전이 반영되었는지 알 수 없습니다.
.zip으로 받은 프레임워크는 체크섬이 안내받은 값과 일치하는지 확인합니다.
swift package compute-checksum WhatapAgent.xcframework.zip
브라우저 에이전트 파일의 버전은 첫 4줄의 배너로 확인합니다.
head -4 whatap-browser-agent.js
콘솔의 iOS WebView 설치 화면은 SPM 패키지 버전을 2.7.3으로, 브라우저 에이전트 스크립트 주소를 v1 경로로 안내합니다. WebView 연동에는 위 요구 버전이 필요하므로 화면의 값을 그대로 따르지 마세요.
에이전트 설치
다음 순서로 진행합니다.
1. 라이브러리 추가
세 가지 방식 중 하나를 선택합니다. Swift Package Manager 방식을 권장합니다.
Swift Package Manager(권장)
-
Xcode에서 프로젝트를 열고 File > Add Package Dependencies 메뉴를 선택하세요.
-
패키지 URL 필드에 다음 주소를 입력하세요.
https://github.com/whatap/WhatapIOSAgent-Release -
Releases에서 최신 버전을 확인해 그 버전을 선택하고 Add Package 버튼을 클릭하세요.
branch를 지정하거나 상한 없는from:을 쓰지 마세요. -
WhatapAgent 라이브러리를 앱 타겟에 추가하세요.
Package.swift로 관리하는 프로젝트라면 다음과 같이 지정합니다.
dependencies: [
.package(url: "https://github.com/whatap/WhatapIOSAgent-Release.git", exact: "<최신 버전>")
],
targets: [
.target(
name: "YourApp",
dependencies: [
.product(name: "WhatapAgent", package: "WhatapIOSAgent-Release")
]
)
]
Swift Package Manager 방식도 CDN 접근이 필요합니다.
GitHub 저장소에는 바이너리가 없고 binaryTarget(url:checksum:)이 CDN을 가리킵니다. 빌드 머신에서 github.com과 repo.whatap-mobile-agent.io가 모두 열려 있어야 합니다. 방화벽으로 CDN이 막혀 있으면 swift package resolve 단계에서 실패합니다. 이 경우 로컬 파일 설치를 사용하세요.
수동 XCFramework 설치
-
XCFramework을 내려받습니다.
<최신 버전>자리에는 Releases에서 확인한 버전을 넣으세요.curl -L -o WhatapAgent.xcframework.zip \
https://repo.whatap-mobile-agent.io/uploads/<최신 버전>/WhatapAgent.xcframework.zip
unzip WhatapAgent.xcframework.zip -
Xcode 프로젝트에 추가합니다.
- 프로젝트 타겟을 선택하고 General 탭을 선택하세요.
- Frameworks, Libraries, and Embedded Content 섹션에서 + 버튼을 클릭하세요.
- Add Other > Add Files를 선택하고
WhatapAgent.xcframework를 선택하세요. - Embed & Sign 설정을 확인하세요.
로컬 파일 설치(폐쇄망, 사내망)
외부 저장소에 접근할 수 없는 환경에서는 와탭이 제공한 zip 파일을 받아 압축을 푼 뒤 프로젝트에 추가합니다. 이후 수동 XCFramework 설치와 같은 방법으로 Xcode에서 Embed & Sign으로 추가하세요.
unzip WhatapAgent.xcframework.zip
mv WhatapAgent.xcframework /path/to/YourApp/
2. Agent 초기화
SDK는 앱이 시작될 때 초기화해야 합니다. 초기화가 늦어지면 pre-main time, 초기 메모리 사용량 등 앱 시작 초기의 성능 데이터를 수집하지 못합니다.
| Framework | 초기화 위치 |
|---|---|
| SwiftUI | @main struct의 init(). 앱 구조체가 만들어지는 시점 |
| UIKit | application:willFinishLaunchingWithOptions:. didFinishLaunching보다 먼저 호출됨 |
build() 뒤에 initialize()를 반드시 호출하세요.
build()는 설정만 구성합니다. initialize()를 호출하지 않아도 setupWebViewBridge()는 그대로 동작해 window.whatapBridge가 주입되므로, 브라우저 에이전트는 브릿지가 정상이라고 판단해 HTTP 폴백도 하지 않습니다. 그 결과 웹과 네이티브 데이터가 모두 유실되고 앱 로그에만 다음 오류가 남습니다.
[ERROR] [WhatapWebviewBridge] WhatapAgent가 초기화되지 않았습니다.
initialize()는 두 번째 호출부터 무시됩니다. 이미 운영 중인 앱에 WebView 연동을 추가한다면 초기화 코드를 새로 만들지 말고 기존 코드를 수정하세요. 초기화를 두 곳에 나누어 넣어도 뒤쪽 호출은 적용되지 않습니다.
Swift
SwiftUI 앱은 @main struct의 init()에서 초기화합니다.
import SwiftUI
import WhatapAgent
@main
struct MyApp: App {
init() {
let agent = WhatapAgentBuilder()
.setProjectKey("<PROJECT_ACCESS_KEY>")
.setPCode(12345)
.setServerUrl("https://<수집 서버 도메인>/m") // 끝의 /m 필수
.build()
agent.initialize()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
UIKit 앱은 AppDelegate의 application:willFinishLaunchingWithOptions:에서 초기화하는 것을 권장합니다.
import UIKit
import WhatapAgent
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let agent = WhatapAgentBuilder()
.setProjectKey("<PROJECT_ACCESS_KEY>")
.setPCode(12345)
.setServerUrl("https://<수집 서버 도메인>/m")
.build()
agent.initialize()
return true
}
}
Objective-C
willFinishLaunchingWithOptions와 didFinishLaunchingWithOptions 중 어느 위치에서 초기화해도 동작합니다. 다음은 didFinishLaunchingWithOptions에서 초기화하는 예제입니다.
#import <WebKit/WebKit.h> // WhatapAgent 헤더보다 먼저
#import <WhatapAgent/WhatapAgent-Swift.h>
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
WhatapAgentBuilder *b = [[WhatapAgentBuilder alloc] init];
(void)[b setProjectKey:@"발급받은 액세스 키"];
(void)[b setPCode:12345];
(void)[b setServerUrl:@"https://수집서버-주소/m"]; // /m 포함, 끝에 / 없이
(void)[b setSamplingRate:1.0]; // 0.0 ~ 1.0 (웹의 0 ~ 100 과 다릅니다)
WhatapIOSAgent *agent = [b build];
[agent initialize]; // 이 호출이 없으면 데이터가 전송되지 않습니다
return YES;
}
헤더를 들여오는 순서. #import <WhatapAgent/WhatapAgent-Swift.h>보다 먼저 #import <WebKit/WebKit.h>를 넣으세요. 생성 헤더는 WKWebView를 전방 선언만 하고 정의를 가져오지 않습니다. 모듈을 끈 프로젝트(CLANG_ENABLE_MODULES = NO)에서는 이 헤더를 import하는 모든 파일이 먼저 WebKit을 import해야 합니다. 그렇지 않으면 cannot find protocol declaration for 'WKNavigationDelegate' 오류가 발생하고 빌드가 실패합니다. WebView를 다루지 않는 AppDelegate도 마찬가지입니다.
@import WhatapAgent; 대신 #import 형태를 사용하세요. @import도 동작하지만, 모듈을 끈 프로젝트에서는 use of '@import' when modules are disabled 오류가 발생해 빌드가 실패합니다. 또한 umbrella 헤더가 공개 대상이 아닌 선언까지 자동완성에 노출합니다.
빌더 setter는 모두 warn_unused_result입니다. 위 예제처럼 체인을 끊어 여러 줄로 작성하면서 (void) 캐스팅을 생략하면 각 줄에서 -Wunused-result 경고가 발생합니다. -Werror를 사용하는 프로젝트에서는 이 경고 때문에 빌드가 실패합니다. 한 줄 체인으로 작성하면 캐스팅이 필요 없습니다.
3. 설치 확인
앱을 실행한 뒤 Xcode Console에서 초기화 로그를 확인하세요. 디버그 빌드에서 로그를 자세히 보려면 다음 설정을 추가합니다.
#if DEBUG
WhatapLogger.isDebug = true
#endif
데이터가 수집되지 않으면 프로젝트 키, PCode, 서버 URL, initialize() 호출, 샘플링 비율과 디스크 버퍼를 확인하세요.
수집 항목
build()와 initialize()를 호출하면 다음 항목을 자동으로 수집합니다.
- 앱 시작 성능(Cold start, Warm start, pre-main)
- 크래시, 예외, 시그널
- CPU, 메모리, 배터리, 열 상태
다음 세 항목은 build()와 initialize()를 호출하는 것만으로는 자동으로 켜지지 않습니다. 별도의 작업이 필요합니다.
| Item | 필요한 작업 |
|---|---|
| 화면별 로딩 시간 | 화면 추적의 네 가지 방법 중 하나 적용 |
| 네트워크 요청, 응답 정보 | 수집과 HTTP 옵션의 setCollectNetwork(true) 지정 |
| WebView 페이지 로드와 성능 정보 | WebView 페이지 수집 설정의 브릿지 등록 |
화면별 로딩 시간은 자동으로 켜지지 않습니다.
UIViewController 생명주기를 기반으로 하는 화면 추적은 기본적으로 꺼져 있습니다. setCollectScreenLoading의 기본값은 true지만, 에이전트의 disableAutoScreenTracking 기본값도 true입니다. Builder가 이 값을 되돌리지 않기 때문에 화면 추적은 자동으로 켜지지 않습니다. 켜는 방법은 화면 추적을 참조하세요.
자동 화면 추적을 켜지 않아도 WebView 데이터는 정상적으로 수집됩니다. initialize()