Skip to content

Add Swift bindings using UniFFI similar to Kotlin bindings#22

Merged
ntheile merged 5 commits intomasterfrom
copilot/add-bindings-swift-example
Jan 5, 2026
Merged

Add Swift bindings using UniFFI similar to Kotlin bindings#22
ntheile merged 5 commits intomasterfrom
copilot/add-bindings-swift-example

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 5, 2026

Adds Swift/iOS bindings for LNI using UniFFI, mirroring the existing Kotlin/Android implementation.

Changes

  • bindings/swift/ - New Swift binding package

    • Cargo.toml + uniffi-bindgen.rs - UniFFI bindgen setup
    • build.sh - Generates Swift bindings, builds iOS static libs, creates XCFramework with headers
    • .gitignore - Excludes generated Sources/LNI/, libs/, LNI.xcframework/
  • bindings/swift/example/ - iOS example app (SwiftUI)

    • Xcode project targeting iOS 15+ Simulator
    • UI matching the Kotlin/Android example with Strike, Blink, NWC, CLN, LND, Phoenixd test buttons
    • Placeholder implementations until library is linked
  • Root Cargo.toml - Added bindings/swift to workspace members

Usage

# Generate Swift bindings only
./build.sh --release

# Build for iOS (creates XCFramework)
./build.sh --release --ios
import LNI

let config = StrikeConfig(apiKey: "...", baseUrl: nil, ...)
let node: LightningNode = createStrikeNode(config: config)

let info = try await node.getInfo()
print("Balance: \(info.sendBalanceMsat / 1000) sats")

Generated bindings include all node types (StrikeNode, BlinkNode, NwcNode, ClnNode, LndNode, PhoenixdNode, SpeedNode), the LightningNode protocol, and factory functions for polymorphic access.

Original prompt

can you add a bindings/swift using uniffi similar to how bindings/kotlin works. make sure to make a example swift project that runs on ios simulator


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Summary by CodeRabbit

  • New Features

    • Added Swift bindings for iOS development, enabling integration with the Lightning Node Interface library.
    • Included example iOS application demonstrating Swift binding usage and node operations.
  • Documentation

    • Added comprehensive guides for Swift bindings setup, build procedures, and iOS integration.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 5, 2026

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This pull request adds comprehensive Swift bindings support for the Lightning Node Interface (LNI) library. The changes include a new Rust crate for binding generation, a build script automating UniFFI-based Swift code generation and iOS XCFramework creation, complete documentation, configuration files, and a functional SwiftUI example iOS application demonstrating usage with multiple node types.

Changes

Cohort / File(s) Summary
Workspace Configuration
Cargo.toml
Added "bindings/swift" as new workspace member, extending project composition.
Swift Bindings Build Infrastructure
bindings/swift/Cargo.toml, bindings/swift/uniffi-bindgen.rs
New Rust crate "lni-swift-bindgen" (v0.1.0) with uniffi 0.29.0 dependency and binary target for bindgen CLI. Entry point delegates to uniffi\::\:uniffi\_bindgen\_main().
Build Automation
bindings/swift/build.sh
Shell script orchestrating: host & optional iOS library compilation, uniffi bindgen execution, iOS lipo aggregation, XCFramework generation via xcodebuild; supports --release and --ios flags with error handling.
Configuration & Ignores
bindings/swift/.gitignore
Comprehensive ignore patterns for generated Swift sources, iOS libraries, Xcode artifacts (.xcuserdata, DerivedData), SPM outputs (.build/, .swiftpm/), build outputs (target/, out/), native libraries (\.a, \.dylib, \*.so), IDE files (.idea/, .vscode/), and macOS metadata.
Documentation
bindings/swift/README.md, bindings/swift/example/README.md
Guides for Swift bindings usage, supported nodes, prerequisites, build steps, usage examples (StrikeNode, NWC, polymorphic nodes), iOS integration, and licensing. Example README covers project structure and invocation scenarios.
Example iOS Project Configuration
bindings/swift/example/LNIExample/LNIExample.xcodeproj/project.pbxproj
Complete Xcode project definition with native target (LNIExample), build phases, configurations (Debug/Release), embedded LNI.xcframework, deployment target iPhoneOS 16.0, product identifier com.lni.example.
Example iOS Asset Catalogs
bindings/swift/example/LNIExample/LNIExample/Assets.xcassets/*
Asset catalog metadata (Contents.json files) for AccentColor, AppIcon (1024x1024), and root assets with Xcode authoring metadata.
Example iOS Application
bindings/swift/example/LNIExample/LNIExample/LNIExampleApp.swift, bindings/swift/example/LNIExample/LNIExample/ContentView.swift
SwiftUI app entry point (@main) with WindowGroup root scene. ContentView presents Strike API key input, node test grid (Strike, Blink, NWC, CLN, LND, Phoenixd), async balance fetching, and output display; includes reusable TestButton component and async helper functions.

Sequence Diagram

sequenceDiagram
    participant User
    participant build.sh
    participant Cargo
    participant UniFFI
    participant lipo
    participant xcodebuild
    participant iOS as Output:<br/>XCFramework

    User->>build.sh: ./build.sh [--release] [--ios]
    build.sh->>Cargo: cargo build (host)
    Cargo-->>build.sh: libname.so/.dylib
    alt --ios flag
        build.sh->>Cargo: cargo build --target aarch64-apple-ios
        Cargo-->>build.sh: libs/aarch64-apple-ios
        build.sh->>Cargo: cargo build --target x86_64-apple-ios-sim
        Cargo-->>build.sh: libs/x86_64-apple-ios-sim
        build.sh->>lipo: lipo -create (sim libs)
        lipo-->>build.sh: libname_sim.a
    end
    build.sh->>Cargo: cargo build --bin uniffi-bindgen
    Cargo-->>build.sh: uniffi-bindgen binary
    build.sh->>UniFFI: uniffi-bindgen generate
    UniFFI-->>build.sh: Sources/LNI/*.swift
    alt --ios flag
        rect rgba(144,202,249,0.3)
        note right of build.sh: iOS XCFramework Phase
        build.sh->>xcodebuild: xcodebuild -create-xcframework
        xcodebuild-->>iOS: LNI.xcframework
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Swift bindings hop into sight,
UniFFI threads the code just right,
iOS frameworks leap and bound,
Xcode projects spring around,
LNI shines with binding light!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective of the PR: adding Swift bindings for LNI using UniFFI, paralleling the existing Kotlin bindings implementation.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI and others added 2 commits January 5, 2026 04:24
Co-authored-by: ntheile <1273575+ntheile@users.noreply.github.com>
Co-authored-by: ntheile <1273575+ntheile@users.noreply.github.com>
Copilot AI changed the title [WIP] Add Swift bindings using Uniffi for iOS simulator Add Swift bindings using UniFFI similar to Kotlin bindings Jan 5, 2026
Copilot AI requested a review from ntheile January 5, 2026 04:32
@ntheile ntheile marked this pull request as ready for review January 5, 2026 04:54
@ntheile
Copy link
Copy Markdown
Contributor

ntheile commented Jan 5, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 5, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Fix all issues with AI Agents 🤖
In @bindings/swift/Cargo.toml:
- Around line 11-12: Update the uniffi dependency version in the Cargo.toml from
"0.29.0" to the latest stable "0.30.0" (or at minimum to "0.29.5" if you must
stay on 0.29.x); locate the [dependencies] entry containing uniffi = { version =
"0.29.0", features = ["cli"] } and change the version string accordingly, then
run cargo update / cargo build to verify compatibility and resolve any API or
feature changes introduced in 0.30.0.

In @bindings/swift/example/LNIExample/LNIExample.xcodeproj/project.pbxproj:
- Line 212: The project.pbxproj currently sets IPHONEOS_DEPLOYMENT_TARGET = 16.0
but the PR description says "iOS 15+ Simulator"; update the deployment target or
documentation to match: if you intend to support iOS 15+, change the
IPHONEOS_DEPLOYMENT_TARGET entries (search for IPHONEOS_DEPLOYMENT_TARGET in
project.pbxproj, including the occurrences at the shown spots) to 15.0, or
alternatively update the PR description/README to state iOS 16+ so they are
consistent. Ensure both occurrences (and any other IPHONEOS_DEPLOYMENT_TARGET
keys) are updated to the chosen target.
🧹 Nitpick comments (3)
bindings/swift/example/README.md (1)

57-64: Add language identifier to the project structure code block.

The fenced code block displaying the project directory tree (lines 57–64) lacks a language identifier, which triggers markdown linting. Add text or tree after the opening backticks to resolve this.

-```
+```text
 LNIExample/
 ├── LNIExample.xcodeproj/    # Xcode project
 └── LNIExample/
     ├── LNIExampleApp.swift  # App entry point
     ├── ContentView.swift    # Main UI
     └── Assets.xcassets/     # App assets
-```
+```
bindings/swift/example/LNIExample/LNIExample/ContentView.swift (1)

155-175: Placeholder implementations may confuse users.

The test buttons show configuration documentation but don't perform actual connectivity tests. Consider adding a visual indicator (e.g., different button style or label) to distinguish the functional "Get Balance" from informational "test" buttons, or adding TODO comments to track future implementation.

bindings/swift/build.sh (1)

17-17: Unused variable EXAMPLE_DIR.

This variable is defined but never used. Either remove it or add the intended usage.

🔎 Proposed fix
 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
-EXAMPLE_DIR="$SCRIPT_DIR/example"
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ae942b and 98ecabd.

📒 Files selected for processing (14)
  • Cargo.toml
  • bindings/swift/.gitignore
  • bindings/swift/Cargo.toml
  • bindings/swift/README.md
  • bindings/swift/build.sh
  • bindings/swift/example/LNIExample/LNIExample.xcodeproj/project.pbxproj
  • bindings/swift/example/LNIExample/LNIExample/Assets.xcassets/AccentColor.colorset/Contents.json
  • bindings/swift/example/LNIExample/LNIExample/Assets.xcassets/AppIcon.appiconset/Contents.json
  • bindings/swift/example/LNIExample/LNIExample/Assets.xcassets/Contents.json
  • bindings/swift/example/LNIExample/LNIExample/ContentView.swift
  • bindings/swift/example/LNIExample/LNIExample/LNIExampleApp.swift
  • bindings/swift/example/LNIExample/lni.swift
  • bindings/swift/example/README.md
  • bindings/swift/uniffi-bindgen.rs
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
bindings/swift/example/README.md

57-57: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Shellcheck (0.11.0)
bindings/swift/build.sh

[warning] 17-17: EXAMPLE_DIR appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (19)
bindings/swift/example/LNIExample/LNIExample/Assets.xcassets/AppIcon.appiconset/Contents.json (1)

1-13: Standard iOS asset catalog metadata.

This JSON correctly defines the App Icon asset for the iOS example project.

bindings/swift/README.md (2)

1-49: Comprehensive and clear build documentation.

The prerequisites, build steps, and command examples are well-organized and actionable. The split between basic Swift binding generation and iOS-specific build flags is intuitive.


50-129: Strong usage examples with realistic patterns.

The code examples demonstrate key workflows (node creation, async/await patterns, polymorphic node usage) clearly. The NWC example and factory function pattern help users understand how to work with multiple node types. The forward-looking note about future SPM support is good for setting expectations.

bindings/swift/example/README.md (2)

1-56: Excellent step-by-step setup and integration guidance.

The Prerequisites, multi-step build process, and explicit Xcode linking instructions are clear and reduce friction for new users. The honest note about placeholder implementations (lines 123–125) sets appropriate expectations.


71-119: Practical example code with good commentary.

The Strike node and invoice creation examples are clear, use proper Swift async/await patterns, and show realistic parameter usage. The examples align well with the bindings/swift/README.md examples and reinforce consistent API patterns.

bindings/swift/.gitignore (1)

1-60: LGTM! Comprehensive .gitignore for Swift bindings.

The ignore patterns comprehensively cover all generated artifacts from the UniFFI binding generation workflow, including Swift sources, iOS libraries, XCFrameworks, and standard Xcode/Swift development artifacts.

bindings/swift/example/LNIExample/LNIExample/Assets.xcassets/Contents.json (1)

1-6: LGTM! Standard Xcode asset catalog metadata.

This is standard boilerplate generated by Xcode for the asset catalog.

bindings/swift/uniffi-bindgen.rs (1)

1-3: LGTM! Standard UniFFI bindgen entry point.

The minimal delegation to uniffi_bindgen_main() is the recommended pattern for UniFFI binding generation tools.

bindings/swift/example/LNIExample/LNIExample/Assets.xcassets/AccentColor.colorset/Contents.json (1)

1-11: LGTM! Standard Xcode color asset.

This is standard boilerplate generated by Xcode for the AccentColor asset.

bindings/swift/Cargo.toml (1)

1-12: Package structure looks good.

The crate metadata, binary target configuration, and dependency declaration follow Rust best practices. The publish = false setting is appropriate for internal tooling.

Cargo.toml (1)

7-7: LGTM!

The Swift bindings crate is correctly added to the workspace members, following the same pattern as the existing Kotlin and Node.js bindings.

bindings/swift/example/LNIExample/LNIExample/LNIExampleApp.swift (1)

10-17: LGTM!

Standard SwiftUI app entry point following best practices.

bindings/swift/example/LNIExample/LNIExample/ContentView.swift (3)

124-151: LGTM - Balance retrieval implementation.

The balance calculation is correct: dividing millisatoshis by 1000 for satoshis and by 100 billion for BTC. The async/await pattern and error handling are properly implemented.


268-290: LGTM!

Clean, reusable button component with proper async handling.


10-10: The generated Swift bindings are properly accessible. Both lni.swift and ContentView.swift are compiled into the same LNIExample target (as shown in the build phases), which means they share the same module namespace in Swift. No explicit import statement is needed for files compiled together in the same target—they automatically have access to each other's public types. The code is correct as-is.

Likely an incorrect or invalid review comment.

bindings/swift/example/LNIExample/LNIExample.xcodeproj/project.pbxproj (1)

52-61: Project structure places generated files at root level.

The lni.swift and LNI.xcframework are placed at the project root rather than inside the LNIExample group. This is a valid approach for generated artifacts, keeping them separate from hand-written source files.

bindings/swift/build.sh (3)

48-114: LGTM - iOS build logic.

The iOS build section correctly handles both simulator architectures (arm64 and x86_64), creates a universal library with lipo, and builds for the device target. The || true pattern for rustup target add is appropriate for idempotent operations.


116-143: LGTM - Library detection and binding generation.

The script correctly handles both Linux (.so) and macOS (.dylib) shared libraries, with a clear error message if neither is found.


145-174: LGTM - XCFramework creation.

The XCFramework is correctly assembled with separate library slices for simulator and device, sharing the same headers. The cleanup before creation ensures a clean build.

@ntheile ntheile merged commit 6cdd0e6 into master Jan 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants