Quickstart (native iOS & Android)
This quickstart goes from nothing to a created, syncing wallet. It condenses the first-run portion of the upstream API guide; everything past first-run (activity streaming, sending, receiving, exit, error handling) is covered there.
The wrappers are not published as artifacts yet, so you work from a checkout of the wavelength-mobile repository rather than adding a dependency. Step 1 clones it; the last step covers wiring it into an app of your own.
Get the repo and stage the bindings
The Kotlin and Swift wrappers, the sample apps, and the fetch scripts all live in wavelength-mobile, and the scripts run from its root. Start by cloning it:
git clone https://github.com/lightninglabs/wavelength-mobile.gitcd wavelength-mobileThe wrappers link the Wavewalletdk native bindings, which are not checked in.
The fetch scripts download them from the wavelength GitHub release and stage
them where the build expects:
# Android: stages Wavewalletdk.aar under android/walletkit/libs./scripts/fetch-aar.sh
# iOS: stages Wavewalletdk.xcframework./scripts/fetch-xcframework.shBoth scripts pull the release with the gh CLI, so
sign in with gh auth login first. Toolchain requirements and pinned versions
live in the upstream
Android workflow
doc.
Create a client
Hold one WalletClient for the app’s lifetime (an Android ViewModel field, a
Swift @State value or a stored property). One daemon runs per process, so a
single client serves the whole app. WalletClient is a Swift actor and does
not conform to ObservableObject, so @StateObject does not apply; the
upstream sample holds it in @State.
val client = WalletClient()let client = WalletClient()Boot the wallet
start boots the embedded daemon and returns once it is serving. It blocks
while booting, so both wrappers run it off the main thread for you.
WalletConfig.signet(...) fills in public signet endpoints; override
dataDir per install. Endpoint details are in the upstream
signet doc.
// Inside a coroutine.client.start(WalletConfig.signet(dataDir = "${context.filesDir}/wavewalletdk"))// Inside a Task.let dir = FileManager.default .urls(for: .documentDirectory, in: .userDomainMask)[0] .appendingPathComponent("wavewalletdk").pathtry await client.start(.signet(dataDir: dir))Starting twice before stop throws rather than booting a second daemon.
Create or unlock a wallet
createWallet with an empty mnemonic generates a fresh seed and returns the
words to back up; pass an existing mnemonic to restore. The password encrypts the seed
on disk. On later launches, unlockWallet with the same password.
// First launch: new wallet.val res = client.createWallet(walletPassword = "my-password".toByteArray())saveMnemonic(res.mnemonic)
// Later launches.client.unlockWallet("my-password".toByteArray())// First launch: new wallet.let res = try await client.createWallet( walletPassword: Data("my-password".utf8))saveMnemonic(res.mnemonic)
// Later launches._ = try await client.unlockWallet( walletPassword: Data("my-password".utf8))Watch sync and read the balance
getInfo returns a snapshot: the synced block height, operator connectivity,
and whether the wallet is ready for signing. Poll it to show sync progress,
then read the balance in satoshis.
val info = client.getInfo()if (info.walletReady) { val b = client.balance() println("synced to ${info.blockHeight}: ${b.confirmedSat} sat confirmed")}let info = try await client.getInfo()if info.walletReady { let b = try await client.balance() print("synced to \(info.blockHeight): \(b.confirmedSat) sat confirmed")}Wiring it into your own app
The steps above run against the checkout, which is where the sample apps live and the fastest way to see the wallet working. There is no published Maven artifact or remote Swift package yet, so an app of your own consumes the wrapper as a local module:
- Android: include
android/walletkitas a Gradle module and depend on it withimplementation(project(":walletkit")), the wayandroid/appdoes. - iOS: add
ios/WalletKitas a local Swift package. ItsPackage.swiftdeclares a binary target atFrameworks/Wavewalletdk.xcframework, which is not committed, so the fetch script above has to have staged it first.
Either way the bindings are large native artifacts fetched per checkout rather than resolved by a package manager, so treat staging them as part of your build setup. The upstream Android workflow doc covers the toolchain in full.
That is the whole first-run path. Explore these to go further.
Full API guide
Activity streaming, receiving, sending, exit to chain, and error handling.
Sample apps
A Jetpack Compose app and a SwiftUI app driving the wrappers end to end.
How it works
The in-process daemon, the JSON boundary, and the callback-free API.
Balances and VTXOs
The wallet model this SDK exposes, the same on every platform.