SwiftUI Integration
A complete example showing SpendOwl integration in a SwiftUI app.Project Setup
Add SpendOwl Package
In Xcode, go to File → Add Package Dependencies and add:
Copy
https://github.com/spendowl/spendowl-ios
Complete Example
App.swift
Configure SpendOwl when the app launches:Copy
import SwiftUI
import SpendOwl
@main
struct MyApp: App {
init() {
// Enable logging in debug builds
#if DEBUG
SpendOwl.enableLogging = true
#endif
// Configure with your API key
SpendOwl.configure(apiKey: "your-api-key")
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
ContentView.swift
Display attribution data and manage user identity:Copy
import SwiftUI
import SpendOwl
struct ContentView: View {
@State private var attribution: AttributionResult?
@State private var error: SpendOwlError?
@State private var isLoading = false
@State private var userId = ""
var body: some View {
NavigationStack {
List {
// Attribution Section
Section {
if isLoading {
HStack {
ProgressView()
Text("Fetching attribution...")
.foregroundStyle(.secondary)
}
} else if let attribution {
AttributionRow(title: "Status", value: attribution.status.displayName)
AttributionRow(title: "Campaign", value: attribution.campaignName ?? "-")
AttributionRow(title: "Ad Group", value: attribution.adGroupName ?? "-")
AttributionRow(title: "Keyword", value: attribution.keyword ?? "-")
AttributionRow(title: "Country", value: attribution.countryOrRegion ?? "-")
} else if let error {
VStack(alignment: .leading, spacing: 4) {
Text("Error")
.font(.caption)
.foregroundStyle(.secondary)
Text(error.localizedDescription)
.foregroundStyle(.red)
}
}
Button("Fetch Attribution") {
fetchAttribution()
}
.disabled(isLoading)
} header: {
Text("Attribution")
} footer: {
Text("Attribution data from Apple Search Ads.")
}
// User ID Section
Section {
TextField("User ID", text: $userId)
.textContentType(.username)
.autocapitalization(.none)
Button("Set User ID") {
SpendOwl.setUserId(userId)
}
.disabled(userId.isEmpty)
Button("Clear User ID", role: .destructive) {
SpendOwl.clearUserId()
userId = ""
}
} header: {
Text("User Identity")
}
// Status Section
Section {
HStack {
Text("SDK Configured")
Spacer()
Image(systemName: SpendOwl.isConfigured ? "checkmark.circle.fill" : "xmark.circle.fill")
.foregroundStyle(SpendOwl.isConfigured ? .green : .red)
}
HStack {
Text("SDK Version")
Spacer()
Text(SpendOwl.sdkVersion)
.foregroundStyle(.secondary)
}
} header: {
Text("Status")
}
}
.navigationTitle("SpendOwl Demo")
}
}
private func fetchAttribution() {
isLoading = true
error = nil
Task {
do {
attribution = try await SpendOwl.attribution()
} catch let err as SpendOwlError {
error = err
} catch {
self.error = .unknown(error)
}
isLoading = false
}
}
}
struct AttributionRow: View {
let title: String
let value: String
var body: some View {
HStack {
Text(title)
Spacer()
Text(value)
.foregroundStyle(.secondary)
}
}
}
extension AttributionStatus {
var displayName: String {
switch self {
case .attributed: return "Attributed"
case .organic: return "Organic"
case .unknown: return "Unknown"
}
}
}
Key Patterns
Task-based Attribution
Use Swift’sTask to fetch attribution asynchronously:
Copy
.task {
do {
attribution = try await SpendOwl.attribution()
} catch {
// Handle error
}
}
Observable Pattern
For a more robust architecture, use an@Observable class:
Copy
@Observable
class AttributionManager {
var attribution: AttributionResult?
var isLoading = false
var error: SpendOwlError?
func fetch() async {
isLoading = true
do {
attribution = try await SpendOwl.attribution()
} catch let err as SpendOwlError {
error = err
} catch {
error = .unknown(error)
}
isLoading = false
}
}
struct ContentView: View {
@State private var manager = AttributionManager()
var body: some View {
// Use manager.attribution
}
}
Authentication Flow
Set user ID after login:Copy
struct LoginView: View {
@State private var email = ""
@State private var password = ""
var body: some View {
Form {
TextField("Email", text: $email)
SecureField("Password", text: $password)
Button("Login") {
login()
}
}
}
private func login() {
Task {
let user = try await AuthService.login(email: email, password: password)
// Set SpendOwl user ID after successful login
SpendOwl.setUserId(user.id)
// Navigate to main app
}
}
}
Download Example
The complete example project is available on GitHub:SpendOwlDemo-SwiftUI
Download the complete SwiftUI example