Skip to content
Swingback, home
Docs / iOS

iOS

The Swift SDK shows your feedback widget in your iOS or macOS app: in a sheet, or in a screen of your own, with your user already signed in.

Install#

Add the Swingback package to your app with Swift Package Manager: in Xcode, File → Add Package Dependencies…, with its address, https://github.com/Swingback-dev/swingback-swift. In a Package.swift:

.package(url: "https://github.com/Swingback-dev/swingback-swift", from: "0.1.0")

It works on iOS 16 and macOS 13 and later.

Set it up#

Configure it once, when your app starts, with your portal's address and a way to get the signed-in user's identity token from your server:

import Swingback
import SwiftUI

@main
struct AcmeApp: App {
    init() {
        Swingback.configure(portal: URL(string: "https://acme.example.com")!) {
            // Your server signs the token for the user its session names; nil when nobody is signed in.
            try await AcmeAPI.shared.feedbackToken()
        }
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

The token is asked for each time the widget opens. Your server signs it with your identity secret, which never goes in your app: Signing in your users has the function. Return nil when nobody is signed in, and throw when the token can't be had.

Show the widget#

In SwiftUI, a sheet:

struct SettingsView: View {
    @State private var feedback = false

    var body: some View {
        Button("Send feedback") { feedback = true }
            .swingbackFeedback(isPresented: $feedback)
    }
}

From UIKit, over a view controller:

Swingback.present(from: self, page: .changelog)

Or in a screen of your own, filling the place you give it:

SwingbackWidget(page: .roadmap)

A page is .feedback (the default), .roadmap, .changelog, .new, .post("dark-mode") or .board("ideas"), by the slug in a post's or a board's address.

Its title and its bar#

The sheet's title is the portal's word for the widget, in your reader's language. Give your own, or none, or leave the bar out altogether (a swipe down closes the sheet):

.swingbackFeedback(isPresented: $whatsNew, page: .changelog, title: .text("What's new"))
.swingbackFeedback(isPresented: $feedback, showsBar: false)

Swingback.present(from:page:title:showsBar:) takes the same; title: .hidden keeps the close button alone. On macOS the bar stays: a sheet there closes by its button. For a container of your own, hold the widget alone: SwingbackWidget in SwiftUI, SwingbackViewController in UIKit.

When your user signs in or out#

await Swingback.identify() // another user signed in: a widget on screen asks for a token now
await Swingback.logout() // your user signed out: the widget's session ends, and its cookies go

Events#

configure(portal:token:onEvent:) takes a closure that hears what the widget did: .ready(version:), .identified, .signedOut, .error(code:), and .open and .close for the sheet. An error's code is one of the widget's, or token_unavailable when your closure threw.

Good to know#

  • The widget keeps its session in your app's web data, across launches, until logout().
  • Links that leave the widget open in Safari's view, over your app; a mail address opens Mail.
  • The package carries its privacy manifest: the user's id, email and name from your token, and what they write and attach, collected for your app's functionality and not for tracking. Your app's privacy report includes them.
  • A sandboxed macOS app needs the Outgoing Connections (Client) capability.
  • Your portal's address is https. Against a local stack over plain http, your app needs an App Transport Security exception for localhost with its subdomains.