Quests in iOS and Android Apps
Show a quest inside a native app with real SwiftUI and Compose views, inline in a screen or as a sheet.
Add the QaidQuests Swift package or dev.qaid:quests, configure it with your embed key, and drop QaidQuestView (SwiftUI) or QaidQuest (Compose) into a screen, or call QaidQuests.present. Answers save as they’re given, wait on the device when offline, and land under the quest’s Responses like web answers do.
The quests SDK draws a quest with the platform’s own controls: text fields, sliders, date pickers and option lists. It reads the same quest you built for the web, so one quest serves your site and your apps.
What you need
| iOS | Android | |
|---|---|---|
| Package | https://github.com/qaiddev/quests-native, product QaidQuests |
dev.qaid:quests:0.1.0 from Maven Central |
| Minimum | iOS 15, SwiftUI or UIKit | minSdk 26, compileSdk 35, Jetpack Compose |
| Key | Your project’s embed key, under Settings → API Keys | Same key |
The quest must be live. A draft that was never saved as a version answers “Quest is not published”, and the view shows its load error.
The quest’s id is in the editor’s address, /dashboard/projects/…/quests/<quest id>, and in the “Embed loads from” strip as /api/quests/<quest id>/definition.
Add the package
iOS: add the Swift package
In Xcode choose File → Add Package Dependencies, paste
https://github.com/qaiddev/quests-native, and add the QaidQuests product to your app target.Android: add the dependency
Add
implementation("dev.qaid:quests:0.1.0")to your app module. The library is built with Compose, so your app needs the Compose compiler plugin, as any Compose app has.Configure once at launch
Call
QaidQuests.configurein your app delegate,Appinit orApplication.onCreate. Android also takes the application, so answers saved offline can send at the next launch.
import QaidQuests
QaidQuests.configure(QaidQuestsConfiguration(
apiKey: "YOUR_EMBED_KEY",
appName: "My App"
))
QaidQuests.configure(this, QaidQuestsConfig(
apiKey = "YOUR_EMBED_KEY",
appName = "My App",
))
Put a quest in a screen
Inline, the quest sits in your layout like any other view and grows to fit its questions.
QaidQuestView(questId: "QUEST_ID", screen: "Onboarding") { answers in
showNextStep()
}
QaidQuest(
questId = "QUEST_ID",
screen = "Onboarding",
onComplete = { answers -> showNextStep() },
)
A UIKit app embeds QaidQuestViewController(questId:) as a child controller. A View-based Android app adds QaidQuestView to its layout and sets questId on it.
Show it as a sheet
QaidQuests.present(questId: "QUEST_ID", screen: "Settings")
QaidQuests.present(activity, questId = "QUEST_ID", screen = "Settings")
The sheet has a close button. Answers given before closing are already saved on qaid; the response just never gets its submit.
How answers are saved
Each answer goes to qaid a moment after the person gives it, as on the web. When the network is down, or qaid answers with a server error, the SDK keeps the answers on the device and sends them in order later: at the next launch, when the app comes back to the front, or when the network returns. The thank-you screen says they will send later. Up to 20 unsent responses are kept for 7 days.
onComplete gets the submitted answers, keyed by question id, with hidden questions left out. It fires for saved-for-later answers too.
Problems that are not the person’s fault reach QaidQuests.onError, so you can log them:
QaidQuests.onError = { report in
Logger.qaid.error("\(report.operation.rawValue) \(report.questId): \(String(describing: report.error))")
}
Say who answered
Each response carries your app’s name, version and device in its user agent. The thumbs and quests SDKs share one visitor id per install, so a quest and a feedback report from the same phone name the same visitor.
Match your app’s look
The SDK follows the system’s light or dark mode. Use a saved quest theme with themeId, or set colours, font and corner radius in code; code wins over the theme.
QaidQuestsConfig(
apiKey = "YOUR_EMBED_KEY",
appName = "My App",
themeId = "THEME_ID",
theme = QaidQuestTheme(accent = 0xFF0EA5E9.toInt(), cornerRadius = 12f),
)
A theme’s custom CSS has no meaning in a native view and is ignored. Every string the SDK draws or reads aloud, from Next to the validation messages, can be replaced through text, so the quest can match your app’s language. The questions themselves come from the quest you wrote.
Domain Restriction and testing
With no pageUrl, a response names the app as app://<bundle id>, and qaid reads the id back to front: com.example.myapp passes a Domain Restriction of example.com.
To test offline saving, answer a quest in airplane mode, finish it, then turn the network back on and bring the app to the front. The response appears under the quest’s Responses within a few seconds.
Full API lists live in the SDK repository.