|
1 | | -# Agent guide for Swift and SwiftUI |
| 1 | +# Agent guide for Google MLKit SwiftPM |
2 | 2 |
|
3 | | -This repository contains an Xcode project written with Swift and SwiftUI. Please follow the guidelines below so that the development experience is built on modern, safe API usage. |
| 3 | +This repository wraps Google ML Kit frameworks for Swift Package Manager compatibility. It converts CocoaPods-distributed ML Kit frameworks to XCFrameworks. |
4 | 4 |
|
5 | 5 | ## Role |
6 | 6 |
|
7 | | -You are a **Senior iOS Engineer**, specializing in SwiftUI, SwiftData, and related frameworks. Your code must always adhere to Apple's Human Interface Guidelines and App Review guidelines. |
| 7 | +You are a **Senior iOS Engineer** maintaining a SwiftPM binary distribution package. Your work involves Ruby automation scripts, Makefile build orchestration, and GitHub Actions CI/CD. |
8 | 8 |
|
9 | 9 | ## Core instructions |
10 | 10 |
|
11 | | -- Target iOS 26.0 or later. (Yes, it definitely exists.) |
12 | | -- Swift 6.2 or later, using modern Swift concurrency. |
13 | | -- SwiftUI backed up by `@Observable` classes for shared data. |
| 11 | +- Target iOS 15.0 or later (matches Package.swift platform requirement). |
| 12 | +- Swift tools version 5.9 (matches Package.swift). |
14 | 13 | - Do not introduce third-party frameworks without asking first. |
15 | | -- Avoid UIKit unless requested. |
| 14 | +- This is NOT a typical app project. It is a build/packaging system that produces XCFrameworks from CocoaPods. |
16 | 15 |
|
17 | | -## Swift instructions |
18 | | - |
19 | | -- Always mark `@Observable` classes with `@MainActor`. |
20 | | -- Assume strict Swift concurrency rules are being applied. |
21 | | -- Prefer Swift-native alternatives to Foundation methods where they exist, such as using `replacing("hello", with: "world")` with strings rather than `replacingOccurrences(of: "hello", with: "world")`. |
22 | | -- Prefer modern Foundation API, for example `URL.documentsDirectory` to find the app’s documents directory, and `appending(path:)` to append strings to a URL. |
23 | | -- Never use C-style number formatting such as `Text(String(format: "%.2f", abs(myNumber)))`; always use `Text(abs(change), format: .number.precision(.fractionLength(2)))` instead. |
24 | | -- Prefer static member lookup to struct instances where possible, such as `.circle` rather than `Circle()`, and `.borderedProminent` rather than `BorderedProminentButtonStyle()`. |
25 | | -- Never use old-style Grand Central Dispatch concurrency such as `DispatchQueue.main.async()`. If behavior like this is needed, always use modern Swift concurrency. |
26 | | -- Filtering text based on user-input must be done using `localizedStandardContains()` as opposed to `contains()`. |
27 | | -- Avoid force unwraps and force `try` unless it is unrecoverable. |
28 | | - |
29 | | -## SwiftUI instructions |
30 | | - |
31 | | -- Always use `foregroundStyle()` instead of `foregroundColor()`. |
32 | | -- Always use `clipShape(.rect(cornerRadius:))` instead of `cornerRadius()`. |
33 | | -- Always use the `Tab` API instead of `tabItem()`. |
34 | | -- Never use `ObservableObject`; always prefer `@Observable` classes instead. |
35 | | -- Never use the `onChange()` modifier in its 1-parameter variant; either use the variant that accepts two parameters or accepts none. |
36 | | -- Never use `onTapGesture()` unless you specifically need to know a tap’s location or the number of taps. All other usages should use `Button`. |
37 | | -- Never use `Task.sleep(nanoseconds:)`; always use `Task.sleep(for:)` instead. |
38 | | -- Never use `UIScreen.main.bounds` to read the size of the available space. |
39 | | -- Do not break views up using computed properties; place them into new `View` structs instead. |
40 | | -- Do not force specific font sizes; prefer using Dynamic Type instead. |
41 | | -- Use the `navigationDestination(for:)` modifier to specify navigation, and always use `NavigationStack` instead of the old `NavigationView`. |
42 | | -- If using an image for a button label, always specify text alongside like this: `Button("Tap me", systemImage: "plus", action: myButtonAction)`. |
43 | | -- When rendering SwiftUI views, always prefer using `ImageRenderer` to `UIGraphicsImageRenderer`. |
44 | | -- Don’t apply the `fontWeight()` modifier unless there is good reason. If you want to make some text bold, always use `bold()` instead of `fontWeight(.bold)`. |
45 | | -- Do not use `GeometryReader` if a newer alternative would work as well, such as `containerRelativeFrame()` or `visualEffect()`. |
46 | | -- When making a `ForEach` out of an `enumerated` sequence, do not convert it to an array first. So, prefer `ForEach(x.enumerated(), id: \.element.id)` instead of `ForEach(Array(x.enumerated()), id: \.element.id)`. |
47 | | -- When hiding scroll view indicators, use the `.scrollIndicators(.hidden)` modifier rather than using `showsIndicators: false` in the scroll view initializer. |
48 | | -- Place view logic into view models or similar, so it can be tested. |
49 | | -- Avoid `AnyView` unless it is absolutely required. |
50 | | -- Avoid specifying hard-coded values for padding and stack spacing unless requested. |
51 | | -- Avoid using UIKit colors in SwiftUI code. |
| 16 | +## Project structure |
52 | 17 |
|
53 | | -## SwiftData instructions |
| 18 | +- `Package.swift` - Swift package definition with 17 library products and 30+ binary targets |
| 19 | +- `Podfile` - CocoaPods dependencies for downloading ML Kit frameworks |
| 20 | +- `Makefile` - Build orchestration (bootstrap, build, create-xcframework, archive) |
| 21 | +- `scripts/` - Ruby and shell automation scripts |
| 22 | +- `Resources/` - Info.plist templates for frameworks that lack them |
| 23 | +- `xcframework-maker/` - Submodule for XCFramework conversion tool |
| 24 | +- `Example/` - Reference iOS app demonstrating ML Kit modules |
| 25 | +- `.github/workflows/` - CI/CD for version checking and building |
54 | 26 |
|
55 | | -If SwiftData is configured to use CloudKit: |
| 27 | +## Key workflows |
56 | 28 |
|
57 | | -- Never use `@Attribute(.unique)`. |
58 | | -- Model properties must always either have default values or be marked as optional. |
59 | | -- All relationships must be marked optional. |
| 29 | +1. **Version check**: `check-mlkit-updates.yml` runs daily, creates GitHub issues for new ML Kit versions |
| 30 | +2. **Build**: `build-mlkit.yml` is triggered manually, builds XCFrameworks and creates releases |
| 31 | +3. **Local build**: `./scripts/build_all.sh <version>` for local development |
60 | 32 |
|
61 | | -## Project structure |
| 33 | +## Script conventions |
62 | 34 |
|
63 | | -- Use a consistent project structure, with folder layout determined by app features. |
64 | | -- Follow strict naming conventions for types, properties, methods, and SwiftData models. |
65 | | -- Break different types up into different Swift files rather than placing multiple structs, classes, or enums into a single file. |
66 | | -- Write unit tests for core application logic. |
67 | | -- Only write UI tests if unit tests are not possible. |
68 | | -- Add code comments and documentation comments as needed. |
69 | | -- If the project requires secrets such as API keys, never include them in the repository. |
| 35 | +- Ruby scripts use standard library only (no gems beyond CocoaPods) |
| 36 | +- Shell scripts are POSIX-compatible where possible |
| 37 | +- All scripts should handle errors gracefully and provide clear output |
70 | 38 |
|
71 | 39 | ## PR instructions |
72 | 40 |
|
73 | | -- If installed, make sure SwiftLint returns no warnings or errors before committing. |
| 41 | +- Test automation scripts locally before committing |
| 42 | +- Verify Package.swift syntax: `swift package dump-package` |
| 43 | +- Update documentation if adding new modules or changing build process |
0 commit comments