A Swift package providing native desktop application APIs with cross-platform window management, application lifecycle control, and system integration features.
- AppRunner: Application lifecycle management and event loop integration
- Window Management: Create, configure, and control native windows
- Display Management: Multi-display support and screen information
- System Integration: Tray icons, keyboard monitoring, and accessibility features
- Cross-Platform: Support for macOS, with planned support for Windows and Linux
Create a basic native application with just a few lines of code:
import NativeAPI
// Run with default window
letexitCode=runApp()print("App exited with code: \(exitCode)")import NativeAPI
// Configure window options
letoptions=WindowOptions()
_ = options.setTitle("My Swift App")
options.setSize(Size(width:1000, height:700))
options.setMinimumSize(Size(width:500, height:350))
options.setCentered(true)
// Run with custom options
letexitCode=runApp(with: options)print("App exited with code: \(exitCode)")import Foundation
import NativeAPI
@MainActorclassMyApplication{privatevarmainWindow:Window?func initialize()->Bool{returnWindowManager.shared.initialize()}func setupWindow()->Bool{letoptions=WindowOptions()
_ = options.setTitle("Advanced App")
options.setSize(Size(width:1200, height:800))guardlet window =WindowManager.shared.createWindow(with: options)else{returnfalse}self.mainWindow = window
returntrue}func run()->AppExitCode{guardlet window = mainWindow else{return.invalidWindow
}
window.show()returnAppRunner.shared.run(with: window)}}letapp=MyApplication()guard app.initialize() && app.setupWindow()else{exit(1)}letexitCode= app.run()exit(exitCode.rawValue)Add this package to your Package.swift file:
dependencies:[.package(url:"https://github.com/leanflutter/nativeapi-swift", from:"1.0.0")]Or add it through Xcode:
- File → Add Package Dependencies
- Enter the repository URL
- Select the version and add to your target
Manages application lifecycle and runs the native event loop:
// Singleton access
letappRunner=AppRunner.shared
// Check if running
if appRunner.isRunning {print("Application is currently running")}
// Run with window
letexitCode= appRunner.run(with: window)Exit Codes:
.success(0) - Normal exit.failure(1) - Application error.invalidWindow(2) - Invalid window provided
Create and control native windows:
// Create window with options
letoptions=WindowOptions()
_ = options.setTitle("My Window")
options.setSize(Size(width:800, height:600))letwindow=WindowManager.shared.createWindow(with: options)
// Window operations
window?.show()
window?.hide()
window?.minimize()
window?.maximize()
window?.focus()
// Window properties
window?.title ="New Title"
window?.size =Size(width:1000, height:800)
window?.position =Point(x:100, y:100)
window?.opacity =0.9
window?.isAlwaysOnTop =trueMonitor window events:
letcallbackId=WindowManager.shared.registerEventCallback{ event inswitch event.type {case.created:print("Window created")case.closed:print("Window closed")case.focused:print("Window focused")case.moved(let position):print("Window moved to \(position)")case.resized(let size):print("Window resized to \(size)")}}
// Don't forget to unregister
_ =WindowManager.shared.unregisterEventCallback(callbackId)Work with multiple displays:
letdisplayManager=DisplayManager.shared
letdisplays= displayManager.getAllDisplays()fordisplayin displays.displays {print("Display: \(display.name)")print("Resolution: \(display.size.width)x\(display.size.height)")print("Scale: \(display.scaleFactor)")}
// Get primary display
iflet primary = displayManager.getPrimaryDisplay(){print("Primary display: \(primary.name)")}Full support with native Cocoa integration:
#if os(macOS)
// Access native NSWindow
iflet nsWindow = window.nsWindow {
// Perform macOS-specific operations
}#endifPlanned support for future releases.
Each example is its own executable target under Examples/, covering one
module of the API. They print what they do, so running one is the quickest way
to see the shape of a binding.
swift run DisplayExample # displays, work areas, display events
swift run StorageExample # Preferences and SecureStorage
swift run UrlOpenerExample # open a URL with the system handler
swift run WindowExample # window geometry, style, state, events
swift run MenuExample # menu items, accelerators, submenus
swift run TrayIconExample # tray icon, context menu, click events
swift run ShortcutExample # global shortcuts and shortcut events
swift run KeyboardExample # keyboard monitor and modifier events
swift run ApplicationExample # menu bar, primary window, event loop
swift run LaunchAtLoginExample # launch-at-login registration
swift run MessageDialogExample # message dialogs and modality
swift run AccessibilityExample # accessibility permissionSome take arguments:
swift run ApplicationExample --dry-run # skip the blocking event loop
swift run MessageDialogExample --open # actually show the modal dialog
swift run UrlOpenerExample "https://example.com"Notes:
ApplicationExampleopens a window and blocks until you close it; the other examples finish on their own.ShortcutExampleandKeyboardExampleneed accessibility permission on macOS. Without it they report that registration or monitoring failed rather than crashing — runAccessibilityExamplefirst.LaunchAtLoginExamplewrites a real login-item registration and then puts it back the way it found it.Examples/ExampleAppis a separate package showing NativeAPI inside a Shaft UI; build it from its own directory.
Run the test suite:
# Run all tests
swift test# Run specific tests
swift test --filter AppRunnerTests
swift test --filter WindowManagerTestsDetailed documentation is available:
- AppRunner Bindings - Application lifecycle management
- Window Bindings - Window management APIs
- macOS: 10.15 or later
- Swift: 6.0 or later
- Xcode: 16.0 or later (for development)
The package consists of:
- C++ Core Library (
libnativeapi): Cross-platform native implementations - C API Layer (
capi): C interface for Swift interoperability - Swift Bindings: High-level Swift APIs wrapping the C interface
Swift Application
↓
Swift Bindings (NativeAPI)
↓
C API Layer (CNativeAPI)
↓
C++ Core Library (libnativeapi)
↓
Platform APIs (Cocoa, Win32, X11)
Always initialize and cleanup properly:
// Initialize
guardWindowManager.shared.initialize()else{exit(1)}
// Use resources...
// Cleanup
defer{WindowManager.shared.shutdown()}UI operations should be performed on the main thread:
@MainActorclassUIManager{func updateWindow(){
// Safe to call UI methods here
window.show()}}
// Or use DispatchQueue when needed
DispatchQueue.main.async{
window.title ="Updated Title"}Handle failures gracefully:
guardlet window =WindowManager.shared.createWindow(with: options)else{print("Failed to create window")return.failure
}letexitCode=AppRunner.shared.run(with: window)if exitCode !=.success {print("Application exited with error: \(exitCode)")}We welcome contributions! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Update documentation
- Submit a pull request
# Clone the repository
git clone https://github.com/leanflutter/nativeapi-swift
cd nativeapi-swift
# Build the project
swift build
# Run tests
swift test# Run examples
swift run ExampleThis project is licensed under the MIT License - see the LICENSE file for details.
- nativeapi - Core C++ library
- nativeapi-dart - Dart bindings
- Issues - Bug reports and feature requests
- Discussions - Questions and community support
- Documentation - Detailed guides and tutorials