diff --git a/.github/workflows/docc.yml b/.github/workflows/docc.yml new file mode 100644 index 0000000..3f4bdf4 --- /dev/null +++ b/.github/workflows/docc.yml @@ -0,0 +1,41 @@ +name: Documentation + +on: + push: + branches: [master] + pull_request: + +permissions: + contents: read + +jobs: + docbuild: + name: Build DocC documentation + runs-on: macos-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Emit symbol graph + run: | + mkdir -p .build/symbol-graphs + swift build --target SystemSoundsLibrary \ + -Xswiftc -emit-symbol-graph \ + -Xswiftc -emit-symbol-graph-dir -Xswiftc .build/symbol-graphs + + - name: Convert documentation + run: | + xcrun docc convert Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc \ + --fallback-display-name SystemSoundsLibrary \ + --fallback-bundle-identifier com.github.tuner88.SystemSoundsLibrary \ + --additional-symbol-graph-dir .build/symbol-graphs \ + --output-path .build/SystemSoundsLibrary.doccarchive \ + --warnings-as-errors + + - name: Check that symbols were documented + run: | + ls .build/symbol-graphs + data=.build/SystemSoundsLibrary.doccarchive/data/documentation/systemsoundslibrary + for page in systemsound systemsoundplayer filesound gettingstarted soundsorhaptics appreview; do + test -f "$data/$page.json" || { echo "::error::Missing documentation page $page"; exit 1; } + done + echo "Documented pages: $(find "$data" -name '*.json' | wc -l)" diff --git a/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/AppReview.md b/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/AppReview.md new file mode 100644 index 0000000..62ffa56 --- /dev/null +++ b/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/AppReview.md @@ -0,0 +1,14 @@ +# App Review notes + +Things to consider before you ship system sounds in an App Store app. + +## Overview + +`AudioServicesPlaySystemSound` and `AudioServicesPlayAlertSound` are public APIs. The numeric +IDs and file names in this catalog are not documented by Apple, and Apple notes that +system-supplied alert and UI sounds are not available to iOS apps. Treat them as unofficial. + +App Review Guidelines 2.5.1 (public APIs only) and 2.5.2 (apps may not read or write data +outside their container) apply. Playing a sound by ID with ``SystemSoundPlayer`` doesn't read +any files. ``FileSound`` with a system path and enumerating `/System/Library/Audio/UISounds` are +fine in developer tools, but avoid them in shipping apps. diff --git a/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/GettingStarted.md b/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/GettingStarted.md new file mode 100644 index 0000000..62941cc --- /dev/null +++ b/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/GettingStarted.md @@ -0,0 +1,64 @@ +# Getting started + +Add the package and play your first system sound. + +## Add the package + +In Xcode, choose **File > Add Package Dependencies…** and enter +`https://github.com/TUNER88/iOSSystemSoundsLibrary`. Or add it to `Package.swift`: + +```swift +dependencies: [ + .package(url: "https://github.com/TUNER88/iOSSystemSoundsLibrary", branch: "master"), +], +targets: [ + .target(name: "MyApp", dependencies: [ + .product(name: "SystemSoundsLibrary", package: "iOSSystemSoundsLibrary"), + ]), +] +``` + +## Play a sound + +Use a named constant or look a sound up by its ID: + +```swift +import SystemSoundsLibrary + +SystemSoundPlayer.play(.smsReceived) + +if let sound = SystemSound.sound(withID: 1157) { + SystemSoundPlayer.play(sound) // wheels_of_time.caf +} +``` + +``SystemSoundPlayer/playAndWait(_:)`` suspends until the sound has finished. The completion +handlers of ``SystemSoundPlayer/play(_:completion:)`` are `@Sendable` because AudioToolbox +calls them on an arbitrary thread. Hop to the main actor before you touch UI state: + +```swift +SystemSoundPlayer.play(.mailReceived) { + Task { @MainActor in + model.isPlaying = false + } +} +``` + +## Newer and removed sounds + +Constants for sounds introduced in iOS 16 or later carry `@available` annotations, so the +compiler asks for an `if #available` check. Sounds whose file no longer exists are marked +deprecated. ``SystemSound/confidence`` tells you how reliable a mapping is: + +- term ``SystemSound/Confidence/high``: The iOS 7 table and current sources agree, and the file exists. +- term ``SystemSound/Confidence/medium``: One community source, and the file exists. +- term ``SystemSound/Confidence/low``: Sources conflict, or the file is gone. + +## Play a file + +``FileSound`` creates a `SystemSoundID` from an audio file and disposes of it automatically: + +```swift +let sound = try FileSound(.mailReceived) +await sound.playAndWait() +``` diff --git a/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/SoundsOrHaptics.md b/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/SoundsOrHaptics.md new file mode 100644 index 0000000..e995d22 --- /dev/null +++ b/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/SoundsOrHaptics.md @@ -0,0 +1,18 @@ +# Choosing between system sounds and haptics + +Use the right API for feedback, alerts and notifications. + +## Overview + +System sounds are short, fire-and-forget audio cues. For many use cases, Apple offers a +better-suited API: + +- **Tactile feedback**: use `UIFeedbackGenerator` subclasses, Core Haptics, or SwiftUI's + `.sensoryFeedback(_:trigger:)` (iOS 17+) instead of ``SystemSoundPlayer/vibrate()``. +- **Keyboard clicks**: use `UIDevice.playInputClick()` in a view that adopts + `UIInputViewAudioFeedback`. +- **Notifications**: `UNNotificationSound` only plays files from your app bundle or your app + container's `Library/Sounds` directory, so you can't use these IDs there. +- **Media-volume playback**: system sounds follow the ringer/alert volume. Use `AVAudioPlayer` + if your sound must follow the media volume. +- **watchOS**: System Sound Services isn't available. Use `WKInterfaceDevice.play(_:)`. diff --git a/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/SystemSoundsLibrary.md b/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/SystemSoundsLibrary.md new file mode 100644 index 0000000..a66c9ec --- /dev/null +++ b/Sources/SystemSoundsLibrary/SystemSoundsLibrary.docc/SystemSoundsLibrary.md @@ -0,0 +1,41 @@ +# ``SystemSoundsLibrary`` + +Play iOS system sounds by name, with availability information and Swift 6 concurrency safety. + +## Overview + +`SystemSoundsLibrary` wraps System Sound Services (`AudioToolbox`) with a typed catalog of 418 known +system sounds. The catalog is generated from `data/sounds.json` in the +[iOSSystemSoundsLibrary](https://github.com/TUNER88/iOSSystemSoundsLibrary) repository. + +```swift +import SystemSoundsLibrary + +SystemSoundPlayer.play(.smsReceived) // 1003 +await SystemSoundPlayer.playAndWait(.mailSentMailSent) + +if #available(iOS 17.0, *) { + SystemSoundPlayer.play(.airDropInvitation) // added in iOS 17 +} +``` + +> Important: Apple doesn't document these IDs and file names. They can differ between iOS +> versions, so check ``SystemSound/confidence`` and test on a device. The iOS Simulator doesn't +> play system sounds. + +## Topics + +### Essentials + +- +- ``SystemSound`` +- ``SystemSoundPlayer`` + +### Playing sound files + +- ``FileSound`` + +### Guidance + +- +-