Install the SDK

Four paths depending on your stack. In every case you install AppwinCore plus the product modules you want: Core carries the device identity, the session and the network client, and the products are only consumers of it.

ProductiOS (SPM)Android (Maven)React NativeFlutter
CoreAppwinCore productio.appwin:appwin-core@appwin/react-nativeappwin_core
SupportAppwinSupport productio.appwin:appwin-supportsameappwin_support
CommunityAppwinCommunity productio.appwin:appwin-communitysameappwin_community
NotificationsAppwinNotifications productio.appwin:appwin-notificationssamethrough appwin_support

Core is installed everywhere except on React Native, where the single package already exposes all four products and there is nothing to add.

On iOS the four are products of a single package: you add one URL, then tick what you import. That is how firebase-ios-sdk works.

Modules of the same platform ship together and share a version: do not let them drift, cross combinations are not tested.

Minimum version
iOS16.0, Xcode 16 (the packages are Swift 6)
Android7.0 (API 24), JDK 17
React Native0.73
Flutter3.3, Dart 3.9.2

Adding the dependencies

Install AppwinCore, then the product modules you want. Same rule in Swift, Kotlin and Dart. React Native is the one exception: a single package exposes the four products there, so there is nothing to break apart.

Technically, every product module already declares Core and makes it reachable from your code: you could leave it out. Declare it anyway. You call AppwinCore.configure in your own code, so it is a direct dependency of your app, not an implementation detail of a product. You see its version in your build, and nothing breaks the day a product changes how it exposes it.

This is the Firebase model: firebase_core is installed explicitly next to firebase_auth, for the same reason.

Swift Package Manager

From Xcode: File → Add Package Dependencies, paste the URL below, then tick the products you want in the list it shows.

Plain text
https://github.com/appwin-dev/appwin-ios

Or declaratively, in your Package.swift:

swift
dependencies: [
  .package(url: "https://github.com/appwin-dev/appwin-ios.git", from: "0.1.0"),
],
targets: [
  .target(name: "MyApp", dependencies: [
    .product(name: "AppwinCore", package: "appwin-ios"),
    // + the product you want: AppwinSupport, AppwinCommunity, AppwinNotifications
    .product(name: "AppwinSupport", package: "appwin-ios"),
  ]),
]

One URL for the four products: you have neither four dependencies to add nor four versions to keep aligned.

The product already links AppwinCore, so import AppwinCore would compile without the first line. It is there because you call configure: a transitive import would break if a product ever stopped depending on Core.

SPM only: it is Apple's dependency manager, built into Xcode, and it asks for neither a separate configuration file nor a manual install step. No Podfile to touch.

iOS 16 minimum, and Xcode 16: the packages are declared in Swift 6. The SDK is built on SwiftUI and async/await, and a lower target does not compile.


Initialising

One call, at launch, before any product is used. It is idempotent: calling it again breaks nothing, and achieves nothing either.

In your AppDelegate or when the scene starts:

swift
import AppwinCore

AppwinCore.configure(projectAppId: "your-app-id")

configure is synchronous: it prepares the device identity and the network client immediately, then opens the session in the background. Your app keeps starting meanwhile.

If a call absolutely needs an open session:

swift
try await AppwinCore.bootstrapSession()

4. Initialise each product

configure prepares the foundation and checks nothing. Each product then has its own initialize(), which asks the server whether it may open. Call it before showing that product's entry point, and gate your own UI on the answer: the SDK cannot hide your tab or your button, it does not own your navigation.

swift
let support = await AppwinSupport.initialize()
print("Appwin Support: \(support)")

It answers rather than throwing, because "not entitled" is a normal outcome of a normal launch. The three products share one round trip and the verdict is cached on disk, so being offline falls back to the last known answer instead of closing a product you pay for.

The full table of results, and what to do with each, is in the quickstart. :::


Which environment it talks to

By default the SDK talks to https://api.appwin.io. There is nothing to configure: your App ID is enough to route requests to your project.

The baseUrl parameter of configure exists for the cases where we give you another entry point, a staging environment for instance. Otherwise, leave it empty.


Checking it works

swift
try await AppwinCore.bootstrapSession()
print(AppwinCore.deviceId ?? "configure was not called")

A non-null device identifier and a bootstrap that does not throw: the foundation is in place, you can wire a product.

It does not work

SymptomLikely cause
"not configured" error on the first callconfigure not called, or called after a product was used
Intermittent 401s at launchTwo configure calls with different App IDs in the same app
403 on every callProduct not enabled on the App ID - enable it from the dashboard
"Coming soon" screenThe product is switched off on the studio's side
The user stays anonymous after identifyBootstrap not replayed: use the product's login
iOS build failsDeployment target below iOS 16, or Xcode older than 16
Android build failsminSdk below 24, or a JDK older than 17
Native module not found on React NativeBuild not rerun after installing, or app launched in Expo Go

Next

  • Quickstart - the whole path, up to a screen on display
  • Identity - anonymous, signed in, shared across products
  • Community - showing the feed