Skip to content

Commit 48662c0

Browse files
committed
fix(examples/swift-multiplatform-app): update README for clarity and structure
1 parent 3cc90d7 commit 48662c0

File tree

1 file changed

+15
-171
lines changed

1 file changed

+15
-171
lines changed

examples/swift-multiplatform-app/README.md

Lines changed: 15 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,27 @@
1-
# Load Extension Guide for Swift
1+
# Swift Multiplatform App Example
22

3-
This guide will walk you through setting up SQLite in Swift to load SQLiteAI extensions.
3+
A simple Swift App QuickStart with the SQLite CloudSync extension loading. Now you can build cross-platform apps that sync data seamlessly across devices.
44

5-
## 1. Create a New Swift Project
5+
## 🚀 Quick Start
66

7-
1. Open Xcode
8-
2. Create a new project
9-
3. Select **Multiplatform****App**
7+
1. Open Xcode project
108

11-
## 2. Download and Add CloudSync Framework
12-
13-
1. Download the latest version of `cloudsync-apple-xcframework` from:
9+
2. Download the latest version of `cloudsync-apple-xcframework` from:
1410
https://github.com/sqliteai/sqlite-sync/releases
1511

16-
2. In Xcode, click on your project name in the source tree (top left with the Xcode logo)
12+
3. In Xcode, click on your project name in the source tree (top left with the Xcode logo)
1713

18-
3. In the new tab that opens, navigate to the left column under the **Targets** section and click on the first target
14+
4. In the new tab that opens, navigate to the left column under the **Targets** section and click on the first target
1915

20-
4. You should now be in the **General** tab. Scroll down to **"Frameworks, Libraries, and Embedded Content"**
16+
5. You should now be in the **General** tab. Scroll down to **"Frameworks, Libraries, and Embedded Content"**
2117

22-
5. Click the **+** button → **Add Other...****Add Files...**
18+
6. Click the **+** button → **Add Other...****Add Files...**
2319

24-
6. Select the downloaded `CloudSync.xcframework` folder
20+
7. Select the downloaded `CloudSync.xcframework` folder
2521

26-
7. Switch to the **Build Phases** tab and verify that `CloudSync.xcframework` appears under **Embedded Frameworks**
22+
8. Switch to the **Build Phases** tab and verify that `CloudSync.xcframework` appears under **Embedded Frameworks**
2723

28-
## 3. Handle Security Permissions (macOS)
24+
## Handle Security Permissions (macOS)
2925

3026
When you return to the main ContentView file, you may encounter an Apple security error:
3127

@@ -37,161 +33,9 @@ When you return to the main ContentView file, you may encounter an Apple securit
3733
6. The same error should appear but now with a third button **Open Anyway** - click it
3834
7. If errors persist, try reopening and closing ContentView multiple times or repeat the security steps above
3935

40-
## 4. Set Up SQLite with Extension Loading
41-
42-
You need a version of SQLite that supports loading extensions. You have two options:
43-
44-
### Option A: Download SQLite Amalgamation (Recommended)
45-
1. Download the amalgamation from: https://sqlite.org/download.html
46-
2. Create a new folder called **SQLite** in your Swift project in Xcode
47-
3. Copy `sqlite3.c` and `sqlite3.h` into this folder by dragging them in
48-
4. Enable all targets and confirm
49-
50-
### Option B: Use CocoaPods
51-
52-
## 5. Configure Objective-C Bridging Header
53-
54-
1. When you add the SQLite files, a popup will appear asking **"Would you like to configure an Objective-C bridging header?"**
55-
2. Click **Create Bridging Header**
56-
3. In the newly created bridging header file, import the SQLite headers:
57-
```objc
58-
#import "sqlite3.h"
59-
```
60-
61-
## 6. Test the Setup
62-
63-
To verify that the extension loads correctly in your Swift project, replace your ContentView.swift content with this test code:
64-
65-
```swift
66-
//
67-
// ContentView.swift
68-
// swift-multiplatform-app
69-
//
70-
// Created by Gioele Cantoni on 18/08/25.
71-
//
72-
73-
import SwiftUI
74-
75-
struct ContentView: View {
76-
@State private var statusLines: [String] = []
77-
private var statusText: String { statusLines.joined(separator: "\n") }
78-
79-
var body: some View {
80-
VStack(spacing: 12) {
81-
Image(systemName: "globe")
82-
.imageScale(.large)
83-
.foregroundStyle(.tint)
84-
Text("Hello, world!")
85-
86-
Divider()
87-
88-
Text("Status")
89-
.font(.headline)
90-
91-
ScrollView {
92-
Text(statusText.isEmpty ? "No status yet." : statusText)
93-
.font(.system(.footnote, design: .monospaced))
94-
.frame(maxWidth: .infinity, alignment: .leading)
95-
.textSelection(.enabled)
96-
.padding(.vertical, 4)
97-
}
98-
.frame(maxHeight: 260)
99-
}
100-
.padding()
101-
.task {
102-
log("Starting...")
103-
var db: OpaquePointer?
104-
105-
// Open an in-memory database just for demonstrating status updates.
106-
// Replace with your own URL/path if needed.
107-
var rc = sqlite3_open(":memory:", &db)
108-
if rc != SQLITE_OK {
109-
let msg = db.flatMap { sqlite3_errmsg($0) }.map { String(cString: $0) } ?? "Unknown error"
110-
log("sqlite3_open failed (\(rc)): \(msg)")
111-
if let db { sqlite3_close(db) }
112-
return
113-
}
114-
log("Database opened.")
115-
116-
// Enable loadable extensions
117-
rc = sqlite3_enable_load_extension(db, 1)
118-
log("sqlite3_enable_load_extension rc=\(rc)")
119-
120-
// Locate the extension in the bundle (adjust as needed)
121-
let vendorBundle = Bundle(identifier: "ai.sqlite.cloudsync")
122-
let candidatePaths: [String?] = [
123-
vendorBundle?.path(forResource: "CloudSync", ofType: "dylib"),
124-
vendorBundle?.path(forResource: "CloudSync", ofType: ""),
125-
Bundle.main.path(forResource: "CloudSync", ofType: "dylib"),
126-
Bundle.main.path(forResource: "CloudSync", ofType: "")
127-
]
128-
let cloudsyncPath = candidatePaths.compactMap { $0 }.first
129-
log("cloudsyncPath: \(cloudsyncPath ?? "Not found")")
130-
131-
var loaded = false
132-
if let path = cloudsyncPath {
133-
var errMsg: UnsafeMutablePointer<Int8>? = nil
134-
rc = sqlite3_load_extension(db, path, nil, &errMsg)
135-
if rc != SQLITE_OK {
136-
let message = errMsg.map { String(cString: $0) } ?? String(cString: sqlite3_errmsg(db))
137-
if let e = errMsg { sqlite3_free(e) }
138-
log("sqlite3_load_extension failed rc=\(rc): \(message)")
139-
} else {
140-
loaded = true
141-
log("sqlite3_load_extension succeeded.")
142-
}
143-
144-
// Optionally disable further extension loading
145-
_ = sqlite3_enable_load_extension(db, 0)
146-
} else {
147-
log("Skipping load: extension file not found in bundle.")
148-
}
149-
150-
// Run SELECT cloudsync_version() and log the result
151-
if loaded {
152-
let sql = "SELECT cloudsync_version()"
153-
log("Running query: \(sql)")
154-
var stmt: OpaquePointer?
155-
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nil)
156-
if rc != SQLITE_OK {
157-
let msg = String(cString: sqlite3_errmsg(db))
158-
log("sqlite3_prepare_v2 failed (\(rc)): \(msg)")
159-
} else {
160-
defer { sqlite3_finalize(stmt) }
161-
rc = sqlite3_step(stmt)
162-
if rc == SQLITE_ROW {
163-
if let cstr = sqlite3_column_text(stmt, 0) {
164-
let version = String(cString: cstr)
165-
log("cloudsync_version(): \(version)")
166-
} else {
167-
log("cloudsync_version(): (null)")
168-
}
169-
} else if rc == SQLITE_DONE {
170-
log("cloudsync_version() returned no rows")
171-
} else {
172-
let msg = String(cString: sqlite3_errmsg(db))
173-
log("sqlite3_step failed (\(rc)): \(msg)")
174-
}
175-
}
176-
} else {
177-
log("Extension not loaded; skipping cloudsync_version() query.")
178-
}
179-
180-
if let db { sqlite3_close(db) }
181-
log("Done.")
182-
}
183-
}
184-
185-
@MainActor
186-
private func log(_ line: String) {
187-
statusLines.append(line)
188-
}
189-
}
190-
191-
#Preview {
192-
ContentView()
193-
}
194-
```
36+
## Test the Setup
37+
38+
To verify that the extension loads correctly in your Swift project, run it for iOS or macOS.
19539

19640
## Expected Results
19741

0 commit comments

Comments
 (0)