Get StartediOS SDK

Hikotest on iOS

Add the Swift package, connect it with two copy-paste values — no GitHub token — and call over-the-air business logic. Powered by the WasmKit runtime; pure Swift, no native dependencies.

What you'll need

PlatformsiOS 15+ · macOS 12+
ToolchainXcode 15 or newer (Swift 5.9 toolchain)
Package managerSwift Package Manager
RuntimeWasmKit 0.1.5 — pure Swift WebAssembly runtime (resolved automatically)
Concurrencyasync/await — initialization is an async throwing call
To connectYour panel address + Project ID — copy them from Settings → SDK Integration. No GitHub token needed.
New to this? You never compile WebAssembly yourself. Your functions are compiled on the Hikotest side when you deploy from the panel; the SDK downloads the result and runs it. The whole integration is: add the package → paste two values → call your functions.

1Add the package

In Xcode choose File → Add Package Dependencies… and enter the repository URL:

https://github.com/halil9393/HikotestIOSSDK.git

Or declare it in your own Package.swift:

Package.swift
dependencies: [
    .package(url: "https://github.com/halil9393/HikotestIOSSDK.git", branch: "main")
],
targets: [
    .target(
        name: "YourApp",
        dependencies: [.product(name: "HikotestSDK", package: "HikotestIOSSDK")]
    )
]

2Get your panel address and Project ID

In the panel, open your project and go to Settings → SDK Integration. You'll see two values with copy buttons:

Panel addressThe address of your Hikotest panel, e.g. https://your-panel.hikotest.app — this is panelBaseUrl
Project IDA long unique id for your project (a UUID) — this is projectId
These are not secrets. The Project ID is a public, device-facing identifier, so — unlike the old GitHub token — you can put these two values straight in your code. No xcconfig or secret store is needed for the panel path.

3Connect and initialize at launch

Configure once — for example in your App struct or AppDelegate — then initialize. The SDK downloads (or loads the cached) release.wasm from the panel and starts its update loop.

YourApp.swift
import HikotestSDK

@main
struct YourApp: App {
    init() {
        Hikotest.shared.configure(HikotestConfig(
            panelBaseUrl: "https://your-panel.hikotest.app", // from Settings → SDK Integration
            projectId: "your-project-id"                     // from Settings → SDK Integration
        ))
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
                .task {
                    try? await Hikotest.shared.initialize()
                }
        }
    }
}
Why no token? The SDK talks to your panel, not to GitHub. The panel serves updates from its own edge cache and fetches the release files server-side, so no credential ever ships inside your app bundle.

4Call your functions

The recommended path is the generated Swift wrapper. Every deploy writes sdk/swift/HikotestFunctions.swiftinto your project's release — parameter names, types and DocC comments included. Copy it into your app for compile-time-safe calls:

Using the generated wrapper
// Signatures and docs come from your panel deploy
let price = try HikotestFunctions.applyCampaign(1000, "VIP30")

You can also call dynamically. Values travel through the type-safe HikoValue enum (.int / .float / .string / .boolean), with up to five named parameters per function:

Dynamic call
let result = try Hikotest.shared.execute(
    "applyCampaign",
    signature: "(float,string)->float",
    .float(1000), .string("VIP30")
)

Hybrid mode — OTA lock (device-side guarantee)

Some functions (payments, pricing, authorization) should never change over-the-air. Download a release you trust from the panel (release.wasm + manifest.json), ship them as bundle resources and pass them at configure time:

Hybrid setup
Hikotest.shared.configure(HikotestConfig(
    panelBaseUrl: "https://your-panel.hikotest.app",
    projectId: "your-project-id",
    localBundle: LocalBundle(wasmBytes: wasmBytes, manifestJson: manifestJson),
    lockedFunctions: ["applyPayment"] // device-side lock list (optional)
))
  • A function runs from the embedded local bundle when the live manifest marks it ota:false (locked in the panel) or it is in your lockedFunctions set. Everything else keeps hot-reloading from the live OTA bundle.
  • The device wins. The union is one-way: even if the panel unlocks a function remotely, anything in lockedFunctions keeps running from the embedded bundle until you ship an app update.
  • A locked function missing from the embedded bundle throws HikotestError.otaLockedMissing — there is no silent OTA fallback.
  • Fully offline mode: configure only localBundle (no panel, no repo) — the SDK never touches the network.
  • Hikotest.shared.isLocallyPinned(_:) tells you where calls are served from.

How OTA updates behave

  • Every deploy (and rollback) from the panel publishes an immutable release with a bumped bundle version (e.g. v1.0.7).
  • A background task periodically asks the panel for the latest version; when a new one appears, the bundle is downloaded, cached and hot-loaded — no app restart, no App Store review.
  • The last downloaded bundle is cached locally, so the app starts offline with the most recent logic.
  • Wrapper code only changes when a function signature changes; internal logic updates arrive without touching your codebase.

Good to know

  • The runtime is pure Swift (WasmKit) — nothing to notarize, no XCFramework binaries, and swift test style unit tests run on macOS without a simulator.
  • The SDK mirrors the Android SDK API one-to-one, so cross-platform teams share the same mental model: configure → initialize → execute.
  • "Missing export" on string functions means the bundle predates the current string ABI — redeploy the project from the panel.

Connect via GitHub token (legacy)

Older setup — read releases straight from GitHubonly if you were already using it

Before the panel path existed, the SDK read releases directly from your project's build repository on GitHub, which required a GitHub token. It still works, but the panel path above is preferred: no token, no rate-limit worries, nothing secret in your app. Use either the panel values or the GitHub values, never both.

YourApp.swift (legacy config)
Hikotest.shared.configure(HikotestConfig(
    githubToken: Secrets.hikotestToken, // never hardcode
    repoOwner: "your-github-username",
    repoName: "your-project-build-repo"
))
Keep the GitHub token out of source control — load it from a gitignored xcconfig, your CI secret store or a plist excluded from the repository. Minimum token scope: repo for private build repositories, public_repo for public ones. The panel path avoids handling a token at all.
Not ready for over-the-air updates? The standalone guide shows how to ship release.wasm inside your app and call it without the SDK — no network access, no tokens.