Skip to content

Commit 52d7c32

Browse files
committed
Update license info
1 parent 3d8ae5d commit 52d7c32

4 files changed

Lines changed: 131 additions & 3 deletions

File tree

src/content/docs/blog/skip-free-for-free-software.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ There are two halves to the Skip project. The first is SkipStone, our integrated
1919

2020
The other half is Skip's ecosystem of libraries and frameworks, which is free and open-source software. These frameworks constitute the essential building blocks of any modern application, and include low-level adaptors from Darwin's Foundation API to the equivalent Android Java API (`skip-foundation`), as well as the high-level SwiftUI user interface widgets that are manifested by Jetpack Compose views on Android (`skip-ui`). In addition, the growing constellation of community frameworks at [github.com/skiptools](http://github.com/skiptools/) provides essential functionality such as SQL database support, media player components, and more.
2121

22-
These frameworks are free and open-source software whose advancement will rely heavily on community contributions. And so we've made the SkipStone transpiler free, for free software. What this means is that Skip can be used – without cost – for building projects that consist exclusively of source code licensed under one of the General Public Licenses as published by the Free Software Foundation.
22+
These frameworks are free and open-source software whose advancement will rely heavily on community contributions. And so we've made the SkipStone transpiler free, for free software. What this means is that Skip can be used – without cost – for building projects that consist exclusively of source code licensed under free and open source licenses.
2323

2424
This applies not just to framework development, but also to your own app projects: if your iOS app is free software, then Skip can be used to transpile it into an equivalent free Android app. In this way we hope to encourage and support the proliferation of genuinely native dual-platform apps created with the Skip transpiler and powered by the community-supported ecosystem of high-quality libraries and frameworks.
2525

src/content/docs/docs/app-development.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ The key pattern is:
239239
The following example from the [Skip Showcase app](https://github.com/skiptools/skipapp-showcase/blob/main/Sources/Showcase/MapPlayground.swift) demonstrates this pattern by embedding an Apple MapKit `Map` on iOS and a Google Maps `GoogleMap` composable on Android:
240240

241241
```swift
242-
// Copyright 2023–2025 Skip
242+
// Copyright 2023–2026 Skip
243243
import SwiftUI
244244
#if !SKIP
245245
import MapKit

src/content/docs/docs/faq.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ Earlier, Skip would require a license key for non-commercial app development. No
5656

5757
### Which FOSS license is recommended for framework development? {#foss_license_recommendations}
5858

59-
We generally recommend the LGPL, which provides a good balance of flexibility and freedom. LGPL libraries can be embedded in closed-source commercial applications. Many popular software components like WebKit, JavaScriptCore, and Qt are distributed under the LGPL.
59+
The standard license for all Skip libraries is the [Mozilla Public License 2.0 (MPL-2.0)](https://www.mozilla.org/MPL/). The MPL provides a good balance of flexibility and freedom: MPL-licensed libraries can be embedded in closed-source commercial applications, and the license's file-level copyleft is straightforward for developers to comply with.
60+
61+
:::note
62+
Prior to 2026, Skip libraries used the GNU Lesser General Public License (LGPL) with a static linking exception. All Skip libraries have since been harmonized to use the MPL-2.0.
63+
:::
6064

6165
### Can Skip Apps be distributed on the Apple App Store and the Google Play Store? {#appstore}
6266

src/content/docs/docs/modules/skip-zip/index.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,130 @@ let package = Package(
3434
)
3535
```
3636

37+
## Usage
38+
39+
### Local Zip Archives
40+
41+
Use `ZipReader` and `ZipWriter` for working with zip files on disk:
42+
43+
```swift
44+
import SkipZip
45+
46+
// Reading a zip file
47+
if let reader = ZipReader(path: "/path/to/archive.zip") {
48+
try reader.first()
49+
while true {
50+
if let name = try reader.currentEntryName {
51+
print("Entry: \(name)")
52+
}
53+
if let data = try reader.currentEntryData {
54+
// Process entry data...
55+
}
56+
if !(try reader.next()) { break }
57+
}
58+
try reader.close()
59+
}
60+
61+
// Writing a zip file
62+
if let writer = ZipWriter(path: "/path/to/output.zip", append: false) {
63+
try writer.add(path: "hello.txt", data: "Hello, World!".data(using: .utf8)!, compression: 5)
64+
try writer.close()
65+
}
66+
```
67+
68+
### Remote Zip Archives
69+
70+
`RemoteZipReader` allows reading individual entries from a remote zip archive over HTTP
71+
without downloading the entire file. It uses HTTP Range requests to fetch only the
72+
archive's central directory (metadata) and the specific entries you request.
73+
74+
This is useful for selectively extracting files from large remote archives where
75+
downloading the full archive would be impractical.
76+
77+
**Requirements:** The HTTP server must support Range requests (indicated by the
78+
`Accept-Ranges: bytes` header). If the server does not support range requests,
79+
the operation will fail with a descriptive error.
80+
81+
```swift
82+
import SkipZip
83+
84+
// Open a remote zip archive (fetches only the metadata)
85+
let reader = try await RemoteZipReader.open(url: URL(string: "https://example.com/archive.zip")!)
86+
87+
// Browse entries without downloading their data
88+
for entry in reader.entries {
89+
print("\(entry.name): \(entry.uncompressedSize) bytes")
90+
}
91+
92+
// Fetch and decompress a specific entry
93+
let data = try await reader.data(forEntryNamed: "README.md")
94+
print(String(data: data, encoding: .utf8)!)
95+
```
96+
97+
#### Configuration
98+
99+
`RemoteZipConfiguration` controls retry behavior for transient network failures.
100+
Retryable conditions include network errors and HTTP status codes 429, 502, 503, and 504.
101+
102+
```swift
103+
let config = RemoteZipConfiguration(
104+
maxRetries: 5, // Retry up to 5 times (default: 3)
105+
initialBackoffInterval: 1.0, // Wait 1 second before first retry (default: 0.5)
106+
backoffMultiplier: 2.0, // Double the wait time after each retry (default: 2.0)
107+
maxBackoffInterval: 60.0, // Cap backoff at 60 seconds (default: 30.0)
108+
endOfFileReadSize: 131_072 // Read last 128KB to find EOCD (default: 65536)
109+
)
110+
111+
let reader = try await RemoteZipReader.open(
112+
url: archiveURL,
113+
session: myURLSession, // Optional: provide a custom URLSession
114+
configuration: config
115+
)
116+
```
117+
118+
#### Custom URLSession
119+
120+
You can pass a custom `URLSession` for authentication, caching, or proxy configuration:
121+
122+
```swift
123+
let sessionConfig = URLSessionConfiguration.default
124+
sessionConfig.httpAdditionalHeaders = ["Authorization": "Bearer token123"]
125+
let session = URLSession(configuration: sessionConfig)
126+
127+
let reader = try await RemoteZipReader.open(url: archiveURL, session: session)
128+
```
129+
130+
#### Error Handling
131+
132+
All errors are reported as `RemoteZipError` with descriptive messages:
133+
134+
```swift
135+
do {
136+
let reader = try await RemoteZipReader.open(url: archiveURL)
137+
let data = try await reader.data(forEntryNamed: "file.txt")
138+
} catch let error as RemoteZipError {
139+
switch error {
140+
case .serverDoesNotSupportRangeRequests:
141+
print("Server doesn't support Range requests")
142+
case .entryNotFound(let name):
143+
print("Entry '\(name)' not found")
144+
case .retryLimitExceeded(let count, let lastError):
145+
print("Failed after \(count) retries: \(lastError)")
146+
default:
147+
print(error.localizedDescription)
148+
}
149+
}
150+
```
151+
152+
#### Supported Compression Methods
153+
154+
`RemoteZipReader` supports the two most common zip compression methods:
155+
156+
- **STORE** (method 0): No compression; data is returned as-is.
157+
- **DEFLATE** (method 8): Standard zip compression; data is decompressed automatically.
158+
159+
ZIP64 extensions are supported for archives and entries larger than 4 GB.
160+
37161
## Building
38162

39163
This project is a Swift Package Manager module that uses the

0 commit comments

Comments
 (0)