https://github.com/skiptools/skip-foundation
Foundation module for Skip apps.
https://github.com/skiptools/skip-foundation
Last synced: 3 months ago
JSON representation
Foundation module for Skip apps.
- Host: GitHub
- URL: https://github.com/skiptools/skip-foundation
- Owner: skiptools
- License: other
- Created: 2023-08-19T02:38:00.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2025-08-01T23:16:39.000Z (11 months ago)
- Last Synced: 2025-08-01T23:38:41.512Z (11 months ago)
- Language: Swift
- Homepage: https://skip.tools
- Size: 1.73 MB
- Stars: 15
- Watchers: 4
- Forks: 10
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.LGPL
Awesome Lists containing this project
README
# SkipFoundation
Foundation support for [Skip Lite](https://skip.dev) transpiled Swift.
See what API is currently implemented [here](#foundation-support).
## About
SkipFoundation vends the `skip.foundation` Kotlin package. It is a reimplementation of Foundation for Kotlin on Android. Its goal is to mirror as much of Foundation as possible, allowing Skip developers to use Foundation API with confidence.
SkipFoundation also implements portions of the CryptoKit API.
## Dependencies
SkipFoundation depends on the [skip](https://source.skip.dev/skip) transpiler plugin as well as the [SkipLib](https://github.com/skiptools/skip-lib) package.
SkipFoundation is part of the *Skip Core Frameworks* and is not intended to be imported directly.
The module is transparently adopted through the translation of `import Foundation` into `import skip.foundation.*` by the Skip transpiler.
### Android Libraries
- SkipFoundation includes source code from the [UrlEncoderUtil](https://github.com/ethauvin/urlencoder) library to implement percent escaping.
## Status
SkipFoundation supports many of the Foundation framework's most common APIs, but there are many more that are not yet ported. See [Foundation Support](#foundation-support).
When you want to use a Foundation API that has not been implemented, you have options. You can try to find a workaround using only supported API, embed Kotlin code directly as described in the [Skip docs](https://skip.dev/docs), or [add support to SkipFoundation](#contributing). If you choose to enhance SkipFoundation itself, please consider [contributing](#contributing) your code back for inclusion in the official release.
## Contributing
We welcome contributions to SkipFoundation. The Skip product [documentation](https://skip.dev/docs/contributing/) includes helpful instructions and tips on local Skip library development.
The most pressing need is to implement more of the most-used Foundation APIs.
To help fill in unimplemented API in SkipFoundation:
1. Find unimplemented API.
1. Write an appropriate Kotlin implementation. See [Implementation Strategy](#implementation-strategy) below.
1. Edit the corresponding tests to make sure they are no longer skipped, and that they pass. If there aren't existing tests, write some. See [Tests](#tests).
1. [Submit a PR.](https://github.com/skiptools/skip-foundation/pulls)
Other forms of contributions such as test cases, comments, and documentation are also welcome!
## Implementation Strategy
The goal of SkipFoundation is to mirror the Foundation framework for Android. When possible, `SkipFoundation` types wrap corresponding Kotlin or Java foundation types. When a `SkipFoundation` type wraps a corresponding Kotlin or Java type, please conform to the `skip.lib.KotlinConverting` protocol, which means adding a `.kotlin()` function:
```swift
#if SKIP
extension Calendar: KotlinConverting {
public override func kotlin(nocopy: Bool = false) -> java.util.Calendar {
return nocopy ? platformValue : platformValue.clone() as java.util.Calendar
}
}
#endif
```
You should also implement a constructor that accepts the equivalent Kotlin or Java object.
## Tests
SkipFoundation's `Tests/` folder contains the entire set of official Foundation framework test cases. Through the magic of [SkipUnit](https://github.com/skiptools/skip-unit), this allows us to validate our SkipFoundation API implementations on Android against the same test suite used by the Foundation team on iOS.
It is SkipFoundation's goal to include - and pass - as much of the official test suite as possible.
## Foundation Support
The following table summarizes SkipFoundation's Foundation API support on Android. Anything not listed here is likely not supported. Note that in your iOS-only code - i.e. code within `#if !SKIP` blocks - you can use any Foundation API you want.
Support levels:
- ✅ – Full
- 🟢 – High
- 🟡 – Medium
- 🟠 – Low
SupportAPI
🟠
AttributedString
init()init(stringLiteral: String)init(markdown: String)init(localized keyAndValue: String.LocalizationValue, table: String? = nil, bundle: Bundle? = nil, locale: Locale? = nil, comment: String? = nil)init(localized key: String, table: String? = nil, bundle: Bundle? = nil, locale: Locale = Locale.current, comment: String? = nil)
🟡
Bundle
static var main: Bundlestatic var module: Bundleinit?(path: String)init?(url: URL)init(for forClass: AnyClass)init()var bundleURL: URLvar resourceURL: URL?var bundlePath: Stringvar resourcePath: String?func url(forResource: String? = nil, withExtension: String? = nil, subdirectory: String? = nil, localization: String? = nil) -> URL?func path(forResource: String? = nil, ofType: String? = nil, inDirectory: String? = nil, forLocalization: String? = nil) -> String?var developmentLocalization: Stringvar localizations: [String]func localizedString(forKey key: String, value: String?, table tableName: String?) -> Stringvar localizations: [String]
🟡
Calendar
- Only
.gregorianand.iso8601identifiers are supported init(identifier: Calendar.Identifier)static var current: Calendarvar locale: Localevar timeZone: TimeZonevar identifier: Calendar.Identifiervar eraSymbols: [String]var monthSymbols: [String]var shortMonthSymbols: [String]var weekdaySymbols: [String]var shortWeekdaySymbols: [String]var amSymbol: Stringvar pmSymbol: Stringfunc component(_ component: Calendar.Component, from date: Date) -> Intfunc minimumRange(of component: Calendar.Component) -> Range<Int>?func maximumRange(of component: Calendar.Component) -> Range<Int>?func range(of smaller: Calendar.Component, in larger: Calendar.Component, for date: Date) -> Range<Int>?func dateInterval(of component: Calendar.Component, for date: Date) -> DateInterval?func dateInterval(of component: Calendar.Component, start: inout Date, interval: inout TimeInterval, for date: Date) -> Boolfunc ordinality(of smaller: Calendar.Component, in larger: Calendar.Component, for date: Date) -> Int?func date(from components: DateComponents) -> Date?func date(byAdding components: DateComponents, to date: Date, wrappingComponents: Bool = false) -> Date?func date(byAdding component: Calendar.Component, value: Int, to date: Date, wrappingComponents: Bool = false) -> Date?func date(bySetting component: Calendar.Component, value: Int, of date: Date) -> Date?func date(bySettingHour hour: Int, minute: Int, second: Int, of date: Date, matchingPolicy: Calendar.MatchingPolicy = .nextTime, repeatedTimePolicy: Calendar.RepeatedTimePolicy = .first, direction: Calendar.SearchDirection = .forward) -> Date?func date(_ date: Date, matchesComponents components: DateComponents) -> Boolfunc dateComponents(in zone: TimeZone? = nil, from date: Date) -> DateComponentsfunc dateComponents(_ components: Set<Calendar.Component>, from start: Date, to end: Date) -> DateComponentsfunc dateComponents(_ components: Set<Calendar.Component>, from date: Date) -> DateComponentsfunc startOfDay(for date: Date) -> Datefunc compare(_ date1: Date, to date2: Date, toGranularity component: Calendar.Component) -> ComparisonResultfunc isDate(_ date1: Date, equalTo date2: Date, toGranularity component: Calendar.Component) -> Boolfunc isDate(_ date1: Date, inSameDayAs date2: Date) -> Boolfunc isDateInToday(_ date: Date) -> Boolfunc isDateInWeekend(_ date: Date) -> Boolfunc enumerateDates(startingAfter start: Date, matching components: DateComponents, matchingPolicy: Calendar.MatchingPolicy, repeatedTimePolicy: Calendar.RepeatedTimePolicy = .first, direction: Calendar.SearchDirection = .forward, using block: (_ result: Date?, _ exactMatch: Bool, _ stop: inout Bool) -> Void)func nextDate(after date: Date, matching components: DateComponents, matchingPolicy: Calendar.MatchingPolicy, repeatedTimePolicy: Calendar.RepeatedTimePolicy = .first, direction: Calendar.SearchDirection = .forward) -> Date?)
🟠
CharacterSet
- Vended character sets are not complete
static var whitespaces: CharacterSetstatic var whitespacesAndNewlines: CharacterSetstatic var newlines: CharacterSetstatic var urlHostAllowed: CharacterSetstatic var urlFragmentAllowed: CharacterSetstatic var urlPathAllowed: CharacterSetstatic var urlQueryAllowed: CharacterSetinit()init(charactersIn: String)func insert(_ character: Unicode.Scalar) -> (inserted: Bool, memberAfterInsert: Unicode.Scalar)mutating func insert(charactersIn: String)func update(with character: Unicode.Scalar) -> Unicode.Scalar?func remove(_ character: Unicode.Scalar) -> Unicode.Scalar?mutating func remove(charactersIn: String)func contains(_ member: Unicode.Scalar) -> Boolfunc union(_ other: CharacterSet) -> CharacterSetmutating func formUnion(_ other: CharacterSet)func intersection(_ other: CharacterSet) -> CharacterSetmutating func formIntersection(_ other: CharacterSet)func subtracting(_ other: CharacterSet)mutating func subtract(_ other: CharacterSet)func symmetricDifference(_ other: CharacterSet) -> CharacterSetmutating func formSymmetricDifference(_ other: CharacterSet)func isSuperset(of other: CharacterSet) -> Boolfunc isSubset(of other: CharacterSet) -> Boolfunc isDisjoint(with other: CharacterSet) -> Boolfunc isStrictSubset(of other: CharacterSet) -> Boolfunc isStrictSuperset(of other: CharacterSet) -> Boolvar isEmpty: Bool
✅
CocoaError
✅
ComparisonResult
🟠
CryptoKit
- See the CryptoKit topic for details on supported API.
✅
CustomNSError
🟡
Data
-
Datadoes not conform toCollectionprotocols init()init(count: Int)init(capacity: Int)init(_ data: Data)init(_ bytes: [UInt8], length: Int? = nil)init(_ checksum: Digest)init?(base64Encoded: String, options: Data.Base64DecodingOptions = [])init(contentsOfFile filePath: String) throwsinit(contentsOf url: URL, options: Data.ReadingOptions = [])var count: Intvar isEmpty: Boolvar bytes: [UInt8]var utf8String: String?func base64EncodedString() -> Stringfunc sha256() -> Datafunc subdata(in range: Range) -> Datafunc hex() -> Stringmutating func reserveCapacity(_ minimumCapacity: Int)mutating func append(_ other: Data)mutating func append(contentsOf bytes: [UInt8])mutating func append(contentsOf data: Data)subscript(index: Int) -> UInt8func write(to url: URL, options: Data.WritingOptions = []) throws
🟡
Date
- Formatting functions not supported with the exception of:
func ISO8601Format(_ style: Date.ISO8601FormatStyle = .iso8601) -> Stringfunc formatted(date: Date.FormatStyle.DateStyle, time: Date.FormatStyle.TimeStyle) -> String
🟢
DateComponents
-
nanosecond,yearForWeekOfYearare not supported
🟡
DateFormatter
var dateStyle: DateFormatter.Stylevar timeStyle: DateFormatter.Stylevar isLenient: Boolvar dateFormat: Stringfunc setLocalizedDateFormatFromTemplate(dateFormatTemplate: String)static func dateFormat(fromTemplate: String, options: Int, locale: Locale?) -> String?static func localizedString(from date: Date, dateStyle: DateFormatter.Style, timeStyle: DateFormatter.Style) -> Stringvar timeZone: TimeZone?var locale: Locale?var calendar: Calendar?func date(from string: String) -> Date?func string(from date: Date) -> Stringfunc string(for obj: Any?) -> String?
✅
DateInterval
🟠
Decimal
- Aliased to
java.math.BigDecimal
🟠
DispatchQueue
static let main: DispatchQueuefunc async(execute: () -> Void)func asyncAfter(deadline: DispatchTime, execute: () -> Void)func asyncAfter(wallDeadline: DispatchWallTime, execute: () -> Void)
🟢
FileManager
static let `default`: FileManagerlet temporaryDirectory: URLlet currentDirectoryPath: Stringfunc createSymbolicLink(at url: URL, withDestinationURL destinationURL: URL) throwsfunc createSymbolicLink(atPath path: String, withDestinationPath destinationPath: String) throwsfunc createDirectory(at url: URL, withIntermediateDirectories: Bool, attributes: [FileAttributeKey : Any]? = nil) throwsfunc createDirectory(atPath path: String, withIntermediateDirectories: Bool, attributes: [FileAttributeKey : Any]? = nil) throwsfunc destinationOfSymbolicLink(atPath path: String) throwsfunc attributesOfItem(atPath path: String) throws -> [FileAttributeKey: Any]func setAttributes(_ attributes: [FileAttributeKey : Any], ofItemAtPath path: String) throwsfunc createFile(atPath path: String, contents: Data? = nil, attributes: [FileAttributeKey : Any]? = nil) -> Boolfunc copyItem(atPath path: String, toPath: String) throwsfunc copyItem(at url: URL, to: URL) throwsfunc moveItem(atPath path: String, toPath: String) throwsfunc moveItem(at path: URL, to: URL) throwsfunc subpathsOfDirectory(atPath path: String) throws -> [String]func subpaths(atPath path: String) -> [String]?func removeItem(atPath path: String) throwsfunc removeItem(at url: URL) throwsfunc fileExists(atPath path: String) -> Boolfunc isReadableFile(atPath path: String) -> Boolfunc isExecutableFile(atPath path: String) -> Boolfunc isDeletableFile(atPath path: String) -> Boolfunc isWritableFile(atPath path: String) -> Boolfunc contentsOfDirectory(at url: URL, includingPropertiesForKeys: [URLResourceKey]?) throws -> [URL]func contentsOfDirectory(atPath path: String) throws -> [String]func url(for directory: FileManager.SearchPathDirectory, in domain: FileManager.SearchPathDomainMask, appropriateFor url: URL?, create shouldCreate: Bool) throws -> URL
✅
HTTPURLResponse
🟢
IndexPath
- Cannot assign from an array literal
- Cannot assign to a range subscript
🟡
IndexSet
- This is an inefficient implementation using an internal
Set init(integersIn range: any RangeExpression<Int>)init(integer: Int)init()func integerGreaterThan(_ integer: Int) -> Int?func integerLessThan(_ integer: Int) -> Int?func integerGreaterThanOrEqualTo(_ integer: Int) -> Int?func integerLessThanOrEqualTo(_ integer: Int) -> Int?func count(in range: any RangeExpression<Int>) -> Intfunc contains(integersIn range: any RangeExpression<Int>) -> Boolfunc contains(integersIn indexSet: IntSet) -> Boolfunc intersects(integersIn range: any RangeExpression<Int>) -> Boolmutating func insert(integersIn range: any RangeExpression<Int>)mutating func remove(integersIn range: any RangeExpression<Int>)func filteredIndexSet(in range: any RangeExpression<Int>, includeInteger: (Int) throws -> Bool) rethrows -> IndexSetfunc filteredIndexSet(includeInteger: (Int) throws -> Bool) rethrows -> IndexSet- Supports the full
SetAlgebraprotocol
🟡
ISO8601DateFormatter
static func string(from date: Date, timeZone: TimeZone) -> Stringvar timeZone: TimeZone?func date(from string: String) -> Date?func string(from date: Date) -> Stringfunc string(for obj: Any?) -> String?
✅
JSONDecoder
✅
JSONEncoder
✅
JSONSerialization
✅
Locale
✅
LocalizedError
✅
LocalizedStringResource
✅
OSLog.Logger
Log messages on Android can be viewed with the adb logcat command, or in the Android Studio console
✅
Notification
🟡
NotificationCenter
static let default: NotificationCenterfunc addObserver(forName name: Notification.Name?, object: Any?, queue: OperationQueue?, using block: (Notification) -> Void) -> Anyfunc removeObserver(_ observer: Any)func post(_ notification: Notification)func post(name: Notification.Name, object: Any?, userInfo: [AnyHashable: Any]? = nil)func notifications(named: Notification.Name, object: AnyObject? = nil) -> Notifications- Also see support for
NotificationCenter.publisherin theSkipModelmodule
✅
NSError
✅
NSLock
✅
NSLocalizedString
✅
NSRecursiveLock
🟢
Number
init(value: Int8)init(value: Int16)init(value: Int32)init(value: Int64)init(value: UInt8)init(value: UInt16)init(value: UInt32)init(value: UInt64)init(value: Float)init(value: Double)init(_ value: Int8)init(_ value: Int16)init(_ value: Int32)init(_ value: Int64)init(_ value: UInt8)init(_ value: UInt16)init(_ value: UInt32)init(_ value: UInt64)init(_ value: Float)init(_ value: Double)var doubleValue: Doublevar intValue: Intvar longValue: Int64var int64Value: Int64var int32Value: Int32var int16Value: Int16var int8Value: Int8
🟢
NumberFormatter
- The following styles are supported:
.none, .decimal, .currency, .percent var numberStyle: NumberFormatter.Stylevar locale: Locale?var format: Stringvar groupingSize: Intvar generatesDecimalNumbers: Boolvar alwaysShowsDecimalSeparator: Boolvar usesGroupingSeparator: Boolvar multiplier: NSNumber?var groupingSeparator: String?var percentSymbol: String?var currencySymbol: String?var zeroSymbol: String?var minusSign: String?var exponentSymbol: String?var negativeInfinitySymbol: Stringvar positiveInfinitySymbol: Stringvar internationalCurrencySymbol: String?var decimalSeparator: String?var currencyCode: String?var currencyDecimalSeparator: String?var notANumberSymbol: String?var positiveSuffix: String?var negativeSuffix: String?var positivePrefix: String?var negativePrefix: String?var maximumFractionDigits: Intvar minimumFractionDigits: Intvar maximumIntegerDigits: Intvar minimumIntegerDigits: Intfunc string(from number: NSNumber) -> String?func string(from number: Int) -> String?func string(for object: Any?) -> String?func number(from string: String) -> NSNumber?
🟠
OperationQueue
static let main: OperationQueue
🟢
OSAllocatedUnfairLock
init()init(initialState: State)init(uncheckedState initialState: State)func lock()func unlock()func lockIfAvailable() -> Boolfunc withLockUnchecked<R>(_ body: (inout State) throws -> R) rethrows -> Rfunc func withLockUnchecked<R>(_ body: () throws -> R) rethrows -> Rfunc withLock<R>(_ body: (inout State) throws -> R) rethrows -> Rfunc withLock<R>(_ body: () throws -> R) rethrows -> Rfunc withLockIfAvailableUnchecked<R>(_ body: (inout State) throws -> R) rethrows -> R?func withLockIfAvailableUnchecked<R>(_ body: () throws -> R) rethrows -> R?func withLockIfAvailable<R>(_ body: @Sendable (inout State) throws -> R) rethrows -> R?func withLockIfAvailable<R>(_ body: () throws -> R) rethrows -> R?
✅
POSIXError
🟡
ProcessInfo
static let processInfo: ProcessInfovar globallyUniqueString: Stringvar systemProperties: [String: String]var environment: [String : String]var processIdentifier: Int32var arguments: [String]var hostName: Stringvar processorCount: Intvar operatingSystemVersionString: Stringvar isMacCatalystApp: Boolvar isiOSAppOnMac: Bool
🟠
PropertyListSerialization
static func propertyList(from: Data, options: PropertyListSerialization.ReadOptions = [], format: Any?) throws -> [String: String]?- Ignores any given
optionsandformat
🟠
RelativeDateTimeFormatter
localizedString(from dateComponents: DateComponents) -> Stringfunc localizedString(fromTimeInterval timeInterval: TimeInterval) -> Stringfunc localizedString(for date: Date, relativeTo referenceDate: Date) -> Stringfunc string(for obj: Any?) -> String?
🟠
RunLoop
static let main: RunLoop
✅
RecoverableError
🟢
String
- Core
StringAPI is defined inSkipLib. These extensions are defined inSkipFoundation init(data: Data, encoding: StringEncoding)init(bytes: [UInt8], encoding: StringEncoding)init(contentsOf: URL)var capitalized: Stringvar deletingLastPathComponent: Stringfunc replacingOccurrences(of search: String, with replacement: String) -> Stringfunc components(separatedBy separator: String) -> [String]func trimmingCharacters(in set: CharacterSet) -> Stringfunc addingPercentEncoding(withAllowedCharacters: CharacterSet) -> String?var removingPercentEncoding: String?var utf8Data: Datavar utf8: [UInt8]var utf16: [UInt8]var utf32: [UInt8]var unicodeScalars: [UInt8]func data(using: StringEncoding, allowLossyConversion: Bool = true) -> Data?func write(to url: URL, atomically useAuxiliaryFile: Bool, encoding enc: StringEncoding) throwsfunc write(toFile path: String, atomically useAuxiliaryFile: Bool, encoding enc: StringEncoding) throws
✅
StringLocalizationValue
✅
func strlen(_ string: String) -> Int
✅
func strncmp(_ str1: String, _ str2: String) -> Int
🟡
Thread
currentmainisMainThreadsleep(for: TimeInterval)sleep(until: Date)callStackSymbols- Starting and stopping threads is not implemented, nor is constructing a Thread with a block
🟡
Timer
init(timeInterval: TimeInterval, repeats: Bool, block: (Timer) -> Void)static func scheduledTimer(withTimeInterval interval: TimeInterval, repeats: Bool, block: (Timer) -> Void) -> Timervar timeInterval: TimeIntervalfunc invalidate()var isValid: Boolvar userInfo: Any?- Also see support for
Timer.publishin theSkipModelmodule
🟢
TimeZone
static var current: TimeZonestatic var autoupdatingCurrent: TimeZonestatic var `default`: TimeZonestatic var system: TimeZonestatic var local: TimeZonestatic var gmt: TimeZoneinit?(identifier: String)init?(abbreviation: String)init?(secondsFromGMT seconds: Int)var identifier: Stringfunc abbreviation(for date: Date = Date()) -> String?func secondsFromGMT(for date: Date = Date()) -> Intfunc isDaylightSavingTime(for date: Date = Date()) -> Boolfunc daylightSavingTimeOffset(for date: Date = Date()) -> TimeIntervalvar nextDaylightSavingTimeTransition: Date?func nextDaylightSavingTimeTransition(after date: Date) -> Date?static var knownTimeZoneIdentifiers: [String]static var knownTimeZoneNames: [String]static var abbreviationDictionary: [String : String]func localizedName(for style: NameStyle, locale: Locale?) -> String?
✅
UnknownNSError
🟢
URL
init(_ url: URL)init?(string: String, relativeTo baseURL: URL? = nil)init?(string: String, encodingInvalidCharacters: Bool)init(fileURLWithPath path: String, isDirectory: Bool? = nil, relativeTo base: URL? = nil)static func currentDirectory() -> URLstatic var homeDirectory: URLstatic var temporaryDirectory: URLstatic var cachesDirectory: URLstatic var documentsDirectory: URLlet baseURL: URL?var scheme: String?var host: String?func host(percentEncoded: Bool = true) -> String?var port: Int?var path: String?func path(percentEncoded: Bool = true) -> String?var hasDirectoryPath: Boolvar query: String?func query(percentEncoded: Bool = true) -> String?var fragment: String?func fragment(percentEncoded: Bool = true) -> String?var standardized: URLvar standardizedFileURL: URLmutating func standardize()var absoluteURL: URLvar absoluteString: Stringvar relativePath: Stringvar relativeString: Stringvar pathComponents: [String]var lastPathComponent: Stringvar pathExtension: Stringvar isFileURL: Boolfunc appendingPathComponent(_ pathComponent: String) -> URLmutating func appendPathComponent(_ pathComponent: String)func appendingPathComponent(_ pathComponent: String, isDirectory: Bool) -> URLmutating func appendPathComponent(_ pathComponent: String, isDirectory: Bool)func appendingPathExtension(_ pathExtension: String) -> URLmutating func appendPathExtension(_ pathExtension: String)func deletingLastPathComponent() -> URLmutating func deleteLastPathComponent() -> URLfunc deletingPathExtension() -> URLmutating func deletePathExtension()func resolvingSymlinksInPath() -> URLmutating func resolveSymlinksInPath() -> URLfunc checkResourceIsReachable() throws -> Bool
🟢
URLComponents
init()init?(url: URL, resolvingAgainstBaseURL resolve: Bool)init?(string: String)init?(string: String, encodingInvalidCharacters: Bool)var url: URL?func url(relativeTo base: URL?) -> URL?var string: String?var scheme: String?var host: String?var port: Int?var path: Stringvar fragment: String?var query: String?var queryItems: [URLQueryItem]?var percentEncodedHost: String?var encodedHost: String?var percentEncodedPath: Stringvar percentEncodedQuery: String?var percentEncodedFragment: String?var percentEncodedQueryItems: [URLQueryItem]?
✅
URLError
✅
URLQueryItem
🟡
URLRequest
- Many properties are currently ignored by
URLSession -
httpBodyStreamis not supported
✅
URLResponse
🟡
URLSession
static let shared: URLSessioninit(configuration: URLSessionConfiguration, delegate: URLSessionDelegate? = nil, delegateQueue: OperationQueue? = nil)var configuration: URLSessionConfigurationvar sessionDescription: String?var delegate: URLSessionDelegate?var delegateQueue: OperationQueue?func data(for request: URLRequest, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse)func data(from url: URL, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse)func upload(for request: URLRequest, fromFile fileURL: URL, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse)func upload(for request: URLRequest, from bodyData: Data, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse)func bytes(for request: URLRequest, delegate: URLSessionTaskDelegate? = nil) async throws -> (AsyncBytes, URLResponse)func bytes(from url: URL, delegate: URLSessionTaskDelegate? = nil) async throws -> (AsyncBytes, URLResponse)func dataTask(with url: URL, completionHandler: ((Data?, URLResponse?, Error?) -> Void)? = nil) -> URLSessionDataTaskfunc dataTask(with request: URLRequest, completionHandler: ((Data?, URLResponse?, Error?) -> Void)? = nil) -> URLSessionDataTaskfunc uploadTask(with: URLRequest, from: Data?, completionHandler: ((Data?, URLResponse?, Error?) -> Void)? = nil) -> URLSessionUploadTaskfunc uploadTask(with: URLRequest, fromFile: URL, completionHandler: ((Data?, URLResponse?, Error?) -> Void)?) -> URLSessionUploadTaskfunc webSocketTask(with url: URL) -> URLSessionWebSocketTaskfunc webSocketTask(with request: URLRequest) -> URLSessionWebSocketTaskfunc webSocketTask(with url: URL, protocols: [String]) -> URLSessionWebSocketTaskfunc finishTasksAndInvalidate()func getTasksWithCompletionHandler(_ handler: ([URLSessionDataTask], [URLSessionUploadTask], [URLSessionDownloadTask]) -> Void)var tasks: ([URLSessionDataTask], [URLSessionUploadTask], [URLSessionDownloadTask])func getAllTasks(handler: ([URLSessionTask]) -> Void)var allTasks: [URLSessionTask]func invalidateAndCancel()struct AsyncBytes: AsyncSequence
🟡
URLSessionConfiguration
- Many properties are currently ignored by
URLSession
🟢
URLSessionDataTask
static let defaultPriority: Floatstatic let lowPriority: Floatstatic let highPriority: Floatvar taskIdentifier: Intvar taskDescription: String?var originalRequest: URLRequest?var delegate: URLSessionTaskDelegate?var state: URLSessionTask.Statevar error: Error?var priority: Floatfunc suspend()func resume()func cancel()
🟢
URLSessionUploadTask
static let defaultPriority: Floatstatic let lowPriority: Floatstatic let highPriority: Floatvar taskIdentifier: Intvar taskDescription: String?var originalRequest: URLRequest?var delegate: URLSessionTaskDelegate?var state: URLSessionTask.Statevar error: Error?var priority: Floatfunc suspend()func resume()func cancel()
🟢
URLSessionWebSocketTask
static let defaultPriority: Floatstatic let lowPriority: Floatstatic let highPriority: Floatvar taskIdentifier: Intvar taskDescription: String?var originalRequest: URLRequest?var delegate: URLSessionTaskDelegate?var state: URLSessionTask.Statevar error: Error?var priority: Floatfunc suspend()func resume()func cancel()func cancel(with closeCode: CloseCode, reason: Data?)var maximumMessageSize: Intvar closeCode: CloseCodevar closeReason: Data?func send(_ message: Message) async throws -> Voidfunc receive() async throws -> Message
🟢
UserDefaults
static var standard: UserDefaultsinit(suiteName: String?)func register(defaults registrationDictionary: [String : Any])func set(_ value: Int, forKey defaultName: String)func set(_ value: Boolean, forKey defaultName: String)func set(_ value: Double, forKey defaultName: String)func set(_ value: String, forKey defaultName: String)func set(_ value: Any?, forKey defaultName: String)func removeObject(forKey defaultName: String)func object(forKey defaultName: String) -> Any?func string(forKey defaultName: String) -> String?func double(forKey defaultName: String) -> Double?func integer(forKey defaultName: String) -> Int?func bool(forKey defaultName: String) -> Bool?func url(forKey defaultName: String) -> URL?func data(forKey defaultName: String) -> Data?func dictionaryRepresentation() -> [String : Any]- Array and dictionary values are not supported
🟢
UUID
init()init?(uuidString: String)static func fromString(uuidString: String) -> UUID?var uuidString: String
## Topics
### CryptoKit
SkipFoundation vends portions of the CryptoKit framework by delegating to the built-in Java implementations:
- `SHA256`
- `SHA256Digest`
- `SHA384`
- `SHA384Digest`
- `SHA512`
- `SHA512Digest`
- `Insecure.MD5`
- `Insecure.MD5Digest`
- `Insecure.SHA1`
- `Insecure.SHA1Digest`
- `HMACMD5`
- `HMACSHA1`
- `HMACSHA256`
- `HMACSHA384`
- `HMACSHA512`
Each supported algorithm includes the following API:
```
associatedtype Digest
public static func hash(data: Data) -> Digest
public func update(_ data: DataProtocol)
public func finalize() -> Digest
```
The returned `Digest` in turn acts as a sequence of `UInt8` bytes.
### Files
Skip implements much of `Foundation.FileManager`, which should be
the primary interface for interacting with the file system.
The app-specific folder can be accessed like:
```swift
// on Android, this is Context.getFilesDir()
let folder = URL.documentsDirectory
// which is shorthand for the following:
let folder = try FileManager.default.url(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask, appropriateFor: nil, create: false)
```
And to read and write to the cache folders:
```swift
// on Android, this is Context.getCachesDir()
let caches = URL.cachesDirectory
// which is shorthand for the following:
let caches = try FileManager.default.url(for: FileManager.SearchPathDirectory.cachesDirectory, in: FileManager.SearchPathDomainMask.userDomainMask, appropriateFor: nil, create: false)
```
And the system temporary folder can be accessed with:
```swift
// on Android, this will be the same as Context.getCachesDir()
let tmpdir = URL.temporaryDirectory
// you can also use:
let tmpdir = NSTemporaryDirectory()
```
None of the other `FileManager.SearchPathDirectory` enumerations are implemented in Skip.
Both `Data` and `String` have the ability to read and write to and from URLs and path strings.
## License
This software is licensed under the
[GNU Lesser General Public License v3.0](https://spdx.org/licenses/LGPL-3.0-only.html),
with a [linking exception](https://spdx.org/licenses/LGPL-3.0-linking-exception.html)
to clarify that distribution to restricted environments (e.g., app stores) is permitted.