App Intent driven development in SwiftUI
Ever since its introduction at WWDC 2018, the App Store Connect API has completely changed the game for automation. It’s no longer just about clicking around in a browser; we can now build custom tools to fetch metadata, manage TestFlight builds, pull sales reports, and even handle customer reviews via the latest 2.0 endpoints.
Because the API follows the OpenAPI specification, it’s incredibly well-documented and predictable. I’ve leveraged these specs to build a dedicated Swift SDK, making it easy to build developer tools directly in Swift. Let’s look at how to get your own tools off the ground.
Getting Started
If you’re new to this, I highly recommend watching the WWDC session "Automating App Store Connect." It’s the gold standard for understanding how Apple intended this system to work. You can also catch the yearly "What’s New" sessions (2019–2022) to stay current on the latest endpoints.
Authentication: The Key to the Kingdom
The API uses JSON Web Tokens (JWT) for security. To get started, you’ll need to head over to the Users and Accesssection of App Store Connect and generate an API Key.
You’ll need three specific pieces of information to sign your requests:
- Issuer ID: A unique ID for your entire organization.
- Key ID: Identifies the specific private key you’re using.
- Private Key: The
.p8file you download from Apple (keep this safe!).
Implementation in Swift
While you could write the JWT signing logic yourself, using the App Store Connect Swift SDK saves a lot of time. You can add it via Swift Package Manager:
dependencies: [
.package(url: "https://github.com/AvdLee/appstoreconnect-swift-sdk.git", .upToNextMajor(from: "2.0.0"))
]The View Model
We’ll create a simple AppsListViewModel that configures the provider and fetches a list of your apps using modern async/await.
final class AppsListViewModel: ObservableObject {
@Published var apps: [AppStoreConnect_Swift_SDK.App] = []
private let configuration = APIConfiguration(
issuerID: "<YOUR ISSUER ID>",
privateKeyID: "<YOUR PRIVATE KEY ID>",
privateKey: "<YOUR PRIVATE KEY CONTENT>"
)
private lazy var provider = APIProvider(configuration: configuration)
func loadApps() {
Task {
let request = APIEndpoint.v1.apps.get(parameters: .init(
sort: [.bundleID],
fieldsApps: [.name, .bundleID],
limit: 5
))
do {
let response = try await provider.request(request)
await MainActor.run { self.apps = response.data }
} catch {
print("Error: \(error)")
}
}
}
final class AppsListViewModel: ObservableObject {
@Published var apps: [AppStoreConnect_Swift_SDK.App] = []
}
The SwiftUI Interface
Now, we just need a clean way to display that data. A standard List does the trick perfectly.
struct AppsListView: View {
@StateObject var viewModel = AppsListViewModel()
var body: some View {
NavigationView {
List(viewModel.apps, id: \.id) { app in
VStack(alignment: .leading) {
Text(app.attributes?.name ?? "Unknown")
.font(.headline)
Text(app.attributes?.bundleID ?? "N/A")
.font(.caption)
}
}
.navigationTitle("My Apps")
}
.onAppear { viewModel.loadApps() }
}
}
What Could You Build?
The possibilities are vast. Think about building:
- Review Dashboards: Read and reply to customers without leaving your custom app.
- User Management: Quickly add or remove TestFlight testers.
- CI/CD Integration: Trigger or monitor Xcode Cloud workflows.
Note: You can release these tools on the App Store! Just remember that users will need to provide their own API keys, as Apple doesn't currently support a standard "Login with Apple" flow for App Store Connect data.