설치

Swift Package Manager 또는 CocoaPods로 Apple SDK를 추가하고 앱에서 시작하는 방법을 설명합니다.

설치는 패키지를 추가하고 앱 시작 시 Sophonz.start(options:)를 한 번 호출하는 것으로 끝납니다. 계측은 SDK가 설치하는 캡처 서비스가 담당하므로, 화면이나 네트워크 호출마다 코드를 넣을 필요가 없습니다.

Apple SDK 시작하기

빠른 시작

아래에서 수집기 URL, 프로젝트, 앱 키를 입력하고 탭(Swift · Objective-C)을 선택하면 그 값으로 초기화 코드가 생성됩니다. 고급 옵션은 "고급 옵션" 토글 뒤에 있습니다.

// AppDelegate.swift
import SophonzCore

let option = Sophonz.Options(
    project: "sophonz",
    appKey:  "sk_tYtJUa4WweXXedj6lxjSqoPW5O0DnbXz",
    endpoints: Sophonz.Endpoints(collectorURL: "https://in.sophonz.ai"))

Sophonz.setup(options: option)?.start()

NOTE — 앱 키가 없으면 조용히 버려집니다

수집기는 service_key_mode: enforce로 동작합니다. 앱 키가 없거나 등록되지 않은 키로 보낸 텔레메트리는 오류 없이 버려지므로, 키를 넣지 않은 빌드는 정상으로 보이면서 아무것도 남기지 않습니다.

요구 사항

항목요구 사항
iOS13.0 이상
tvOS · macOS13.0 이상
watchOS6.0 이상
Swift5.9 이상
Xcode26 이상 (SDK 빌드 기준)

Swift Package Manager

Xcode의 File > Add Package Dependencies에 저장소 주소를 넣습니다.

https://github.com/sophonz-labs/sophonz-apple-sdk

Package.swift로 관리하는 프로젝트라면 다음과 같습니다.

Package.swift
dependencies: [
  .package(url: "https://github.com/sophonz-labs/sophonz-apple-sdk", from: "1.0.0")
],
targets: [
  .target(
    name: "YourApp",
    dependencies: [
      .product(name: "SophonzIO", package: "sophonz-apple-sdk")
    ]
  )
]

앱이 링크할 것은 SophonzIO 하나입니다. 공개 API인 Sophonz 클래스와 그 옵션이 여기에 있고, 구현은 그 뒤에 있습니다.

NOTE — 나머지 라이브러리 제품

패키지는 SophonzCore, SophonzSemantics, SophonzMacros, SophonzKSCrashBacktraceSupport도 제품으로 내보냅니다. 일반적인 앱은 필요하지 않으며, SophonzIO가 필요한 것을 가져옵니다. 이름이 *Internal인 모듈은 지원 대상 API가 아닙니다.

미리 빌드된 XCFramework

소스에서 빌드하지 않으려면 릴리스에 첨부된 XCFramework를 씁니다. 각 릴리스는 SophonzIO-<버전>.xcframework.zip과 .sha256을 함께 올립니다.

Package.swift
.binaryTarget(
  name: "SophonzIO",
  url: "https://github.com/sophonz-labs/sophonz-apple-sdk/releases/download/v1.0.0/SophonzIO-1.0.0.xcframework.zip",
  checksum: "<.sha256 파일의 내용>"
)

Xcode 프로젝트라면 압축을 풀어 타깃의 Frameworks, Libraries, and Embedded Content에 끌어다 놓고 Embed & Sign으로 둡니다.

CocoaPods

Podfile
use_frameworks!
 
target 'YourApp' do
  pod 'SophonzIO'
end
pod install

podspec은 v 접두사가 붙은 태그(v1.0.0)를 가리킵니다. 아직 트렁크에 게시되지 않았으므로 저장소를 직접 지정합니다.

Podfile
pod 'SophonzIO', :git => 'https://github.com/sophonz-labs/sophonz-apple-sdk.git', :tag => 'v1.0.0'

SDK 시작

Sophonz.start(options:)는 정적 메서드이며 던집니다. 앱 시작 지점에서 메인 스레드에서 한 번 호출합니다.

설정은 타깃의 Sophonz-Info.plist에서 읽는 것을 권장합니다. 앱 키를 소스에 커밋하지 않고 빌드 구성마다 바꿀 수 있습니다.

Sophonz-Info.plist
<key>CollectorURL</key>
<string>https://in.sophonz.ai</string>
<key>AppKey</key>
<string>$(SOPHONZ_APP_KEY)</string>
<key>AppName</key>
<string>내 앱</string>
<key>Project</key>
<string>my-project</string>
<key>DeploymentEnvironment</key>
<string>production</string>
키보내는 값설명
CollectorURL—수집기 기본 주소. /v1/traces 같은 경로는 붙이지 않습니다
AppKeyservice.key포털이 발급한 sk_…
AppNameservice.name포털이 앱을 찾는 키. 등록한 이름과 같아야 합니다
Projectservice.namespace앱을 묶는 논리 단위
DeploymentEnvironmentdeployment.environment.nameproduction, staging 등

CAUTION — AppName은 포털의 조인 키입니다

app.sophonz.ai는 (프로젝트, service.name)으로 앱을 찾습니다. 이 값을 바꾸면 수집기는 계속 데이터를 받는데 포털의 앱 화면만 비어 보입니다 — 전송이 끊긴 것처럼 보이지만 전송은 멀쩡합니다. 포털에 등록한 이름을 그대로 넣으세요.

NOTE — $(…)는 타깃 Info.plist에서만 치환됩니다

Xcode는 빌드 설정을 타깃의 Info.plist에서만 확장합니다. 리소스로 복사되는 설정 plist에 $(SOPHONZ_APP_KEY)를 적으면 그 문자열이 그대로 들어갑니다. 빌드 스크립트에서 치환해 생성하세요. SDK는 치환되지 않은 $(…)와 빈 문자열을 모두 "값 없음"으로 취급합니다.

YourApp.swift
import SwiftUI
import SophonzIO
 
@main
struct YourApp: App {
  init() {
    guard let options = Sophonz.Options.fromPlist() else {
      // 수집기나 키가 없는 빌드입니다. 시작하지 않는 편이 낫습니다.
      return
    }
    do {
      try Sophonz.start(options: options)
    } catch {
      // 시작 실패가 앱을 막지 않도록 합니다. 계측이 없는 것보다
      // 앱이 뜨지 않는 것이 나쁩니다.
      print("[sophonz] 시작 실패: \(error)")
    }
  }
 
  var body: some Scene {
    WindowGroup { ContentView() }
  }
}

UIKit 앱이라면 application(_:didFinishLaunchingWithOptions:)에 같은 코드를 둡니다.

값을 코드로 넘기기

plist 대신 인자로 넘길 수도 있습니다.

try Sophonz.start(options: .withCollector(
  url: "https://in.sophonz.ai",
  appKey: "sk_…",
  appName: "내 앱",
  project: "my-project",
  deploymentEnvironment: "production"
))

시작 이후에는 Sophonz.shared로 접근합니다.

if Sophonz.shared.isSDKEnabled {
  // 수집 중
}

SwiftUI 화면 이름

UIKit 앱은 화면 이름이 자동으로 붙습니다. 뷰 컨트롤러가 곧 화면이기 때문입니다. SwiftUI는 그렇지 않습니다 — NavigationStack 전체가 뷰 컨트롤러 하나(UIKitNavigationController)라서, 이름을 붙이지 않으면 앱의 모든 스팬이 그 이름 하나로 기록되고 화면별 분석이 불가능해집니다.

화면이 스스로 이름을 밝힙니다.

GalleryView()
  .sophonzScreen("Gallery")

sophonzScreen은 화면 이름을 설정하면서 렌더 스팬도 함께 남깁니다. 화면의 일부인 뷰에는 sophonzTrace(_:)를 씁니다. 스팬은 시작 시점의 화면을 기록하므로, 화면을 떠난 뒤 끝나는 요청도 시작한 화면에 남습니다.

텔레메트리가 언제 나가는가

스팬과 로그는 끝나는 즉시 디스크에 쌓이고, 세션 파트가 끝날 때 업로드됩니다 — 앱이 백그라운드로 갈 때, 또는 강제 종료 뒤 다음 실행 때입니다. 주기적인 타이머가 아닙니다.

포그라운드에 10분 동안 떠 있던 앱은 10분치 텔레메트리를 디스크에 갖고 있고 아직 아무것도 보내지 않은 상태입니다. "간헐적으로 들어온다"는 관찰은 대부분 이것이며, 전송 계층의 문제가 아닙니다.

자체 익스포터로 시작

Sophonz 수집기 대신 직접 익스포터를 붙이는 모드입니다. 이 모드에서는 업로드가 아예 만들어지지 않으므로, 데이터가 나가는 유일한 통로가 익스포터입니다. 그래서 otel:이 선택이 아니라 필수 인자입니다.

import SophonzIO
import OpenTelemetrySdk
 
let otel = Sophonz.OTelOptions(
  spanExporters: [myOtlpSpanExporter],
  logExporters: [myOtlpLogExporter]
)
 
try Sophonz.start(options: .withLocalConfiguration(otel: otel))

OTelOptions는 resource, spanProcessors, spanExporters, logProcessors, logExporters를 받습니다. service.name, service.version, telemetry.sdk.language는 SDK가 항상 설정하며 resource로 덮어쓸 수 없습니다.

Objective-C 프로젝트

Swift 모듈이므로 Objective-C에서 쓰려면 브리징 헤더 대신 생성된 인터페이스를 임포트합니다. 시작 코드는 Swift 파일 하나에 두고 Objective-C에서 그 함수를 호출하는 편이 단순합니다.

다음

  • 설정 — 옵션과 캡처 서비스 조정
  • 계측 항목 — 무엇이 자동으로 수집되는지
  • 예제 — 완성된 형태