├── .gitignore
├── .github
├── FUNDING.yml
└── workflows
│ └── ci.yml
├── xxPROJECTxNAMExx
├── Example
│ ├── Sources
│ │ ├── Assets.xcassets
│ │ │ ├── Contents.json
│ │ │ ├── AccentColor.colorset
│ │ │ │ └── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── ExampleApp.swift
│ │ └── ContentView.swift
│ ├── Example.xcodeproj
│ │ ├── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ └── project.pbxproj
│ ├── ExampleTests
│ │ └── ExampleTests.swift
│ └── ExampleUITests
│ │ ├── ExampleUITestsLaunchTests.swift
│ │ └── ExampleUITests.swift
├── .swiftpm
│ └── xcode
│ │ └── package.xcworkspace
│ │ └── contents.xcworkspacedata
├── CHANGELOG.md
├── Tests
│ └── xxPROJECTxNAMExxTests
│ │ └── xxPROJECTxNAMExxTests.swift
├── CONTRIBUTING.md
├── Package.swift
├── Sources
│ └── xxPROJECTxNAMExx
│ │ ├── xxPROJECTxNAMExx.swift
│ │ └── White King.swift
├── LICENSE
├── .github
│ └── workflows
│ │ └── swiftlang-workflows.yml
├── README.md
└── .gitignore
├── LICENSE
├── README.md
├── configure.swift
└── Recipe.md
/.gitignore:
--------------------------------------------------------------------------------
1 | OUTPUT
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [fulldecent]
4 | custom: ["https://www.paypal.me/fulldecent"]
5 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Example/Sources/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Example/Sources/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 | xxPROJECTxNAMExx adheres to [Semantic Versioning](http://semver.org/).
4 |
5 | ## [Main](https://github.com/__GITHUB_USERNAME__/xxPROJECTxNAMExx)
6 | ### Added
7 |
8 | ### Changed
9 |
10 | ### Removed
11 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Example/Sources/ExampleApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleApp.swift
3 | // Example
4 | //
5 | // Created by __AUTHOR_NAME__ on __TODAYS_DATE__.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct ExampleApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | ContentView()
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Example/ExampleTests/ExampleTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleTests.swift
3 | // ExampleTests
4 | //
5 | // Created by __AUTHOR_NAME__ on __TODAYS_DATE__.
6 | //
7 |
8 | import Testing
9 |
10 | @testable import Example
11 |
12 | struct ExampleTests {
13 |
14 | @Test func example() async throws {
15 | // Write your test here and use APIs like `#expect(...)` to check expected conditions.
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Tests/xxPROJECTxNAMExxTests/xxPROJECTxNAMExxTests.swift:
--------------------------------------------------------------------------------
1 | import Testing
2 |
3 | @testable import xxPROJECTxNAMExx
4 |
5 | @Test func testGreeting() async throws {
6 | let greeting = xxPROJECTxNAMExx.greet("World")
7 | #expect(greeting.contains("Hello, World!"))
8 | #expect(greeting.contains(xxPROJECTxNAMExx.name))
9 | }
10 |
11 | @Test func testWhiteKing() async throws {
12 | let king = xxPROJECTxNAMExx.whiteKing()
13 | #expect(king == "♔")
14 | }
15 |
16 | @Test func testModuleName() async throws {
17 | #expect(xxPROJECTxNAMExx.name == "xxPROJECTxNAMExx")
18 | }
19 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Example/Sources/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // iOS Example
4 | //
5 | // Created by __AUTHOR_NAME__ on __TODAYS_DATE__.
6 | //
7 |
8 | import SwiftUI
9 | import xxPROJECTxNAMExx
10 |
11 | struct ContentView: View {
12 | var body: some View {
13 | VStack(alignment: .center, spacing: 20) {
14 | Text(xxPROJECTxNAMExx.whiteKing())
15 | .font(.system(size: 120))
16 |
17 | Text(xxPROJECTxNAMExx.greet("SwiftUI"))
18 | .font(.title2)
19 | .multilineTextAlignment(.center)
20 | .padding()
21 |
22 | Text("Module: \(xxPROJECTxNAMExx.name)")
23 | .font(.caption)
24 | .foregroundColor(.secondary)
25 | }
26 | .padding()
27 | }
28 | }
29 |
30 | #Preview {
31 | ContentView()
32 | }
33 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Example/Sources/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "platform" : "ios",
6 | "size" : "1024x1024"
7 | },
8 | {
9 | "appearances" : [
10 | {
11 | "appearance" : "luminosity",
12 | "value" : "dark"
13 | }
14 | ],
15 | "idiom" : "universal",
16 | "platform" : "ios",
17 | "size" : "1024x1024"
18 | },
19 | {
20 | "appearances" : [
21 | {
22 | "appearance" : "luminosity",
23 | "value" : "tinted"
24 | }
25 | ],
26 | "idiom" : "universal",
27 | "platform" : "ios",
28 | "size" : "1024x1024"
29 | }
30 | ],
31 | "info" : {
32 | "author" : "xcode",
33 | "version" : 1
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | All contributors are welcome. Please use issues and pull requests to contribute to the project. And update [CHANGELOG.md](CHANGELOG.md) when committing.
4 |
5 | ## Making a change
6 |
7 | When you commit a change, please add a note to [CHANGELOG.md](CHANGELOG.md).
8 |
9 | ## Release process
10 |
11 | 1. Confirm the build is [passing in GitHub Actions](https://github.com/__GITHUB_USERNAME__/xxPROJECTxNAMExx/actions)
12 | 2. Push a release commit
13 | 1. Create a new Main section at the top
14 | 2. Rename the old Main section like:
15 | ## [1.0.5](https://github.com/__GITHUB_USERNAME__/xxPROJECTxNAMExx/releases/tag/1.0.5)
16 | Released on 2019-10-15.
17 | 3. Create a GitHub release
18 | 1. Tag the release (like `1.0.5`)
19 | 2. Paste notes from [CHANGELOG.md](CHANGELOG.md)
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 6.2
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "xxPROJECTxNAMExx",
8 | products: [
9 | // Products define the executables and libraries a package produces, making them visible to other packages.
10 | .library(
11 | name: "xxPROJECTxNAMExx",
12 | targets: ["xxPROJECTxNAMExx"]
13 | )
14 | ],
15 | targets: [
16 | // Targets are the basic building blocks of a package, defining a module or a test suite.
17 | // Targets can depend on other targets in this package and products from dependencies.
18 | .target(
19 | name: "xxPROJECTxNAMExx"
20 | ),
21 | .testTarget(
22 | name: "xxPROJECTxNAMExxTests",
23 | dependencies: ["xxPROJECTxNAMExx"]
24 | ),
25 | ]
26 | )
27 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Sources/xxPROJECTxNAMExx/xxPROJECTxNAMExx.swift:
--------------------------------------------------------------------------------
1 | //
2 | // __PROJECT_NAME__.swift
3 | // __PROJECT_NAME__
4 | //
5 | // Created by __AUTHOR_NAME__ on __TODAYS_DATE__.
6 | // Copyright © __TODAYS_YEAR__ __ORGANIZATION_NAME__. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// A simple Swift module for demonstrating the template
12 | public struct xxPROJECTxNAMExx {
13 | /// The name of the module
14 | public static let name = "xxPROJECTxNAMExx"
15 |
16 | /// A simple greeting function
17 | /// - Parameter name: The name to greet
18 | /// - Returns: A greeting message
19 | public static func greet(_ name: String = "World") -> String {
20 | return "Hello, \(name)! This is \(self.name)."
21 | }
22 |
23 | /// Get the white king character
24 | /// - Returns: The white king Unicode character
25 | public static func whiteKing() -> String {
26 | return "♔"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Example/ExampleUITests/ExampleUITestsLaunchTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleUITestsLaunchTests.swift
3 | // ExampleUITests
4 | //
5 | // Created by __AUTHOR_NAME__ on __TODAYS_DATE__.
6 | //
7 |
8 | import XCTest
9 |
10 | final class ExampleUITestsLaunchTests: XCTestCase {
11 |
12 | override class var runsForEachTargetApplicationUIConfiguration: Bool {
13 | true
14 | }
15 |
16 | override func setUpWithError() throws {
17 | continueAfterFailure = false
18 | }
19 |
20 | @MainActor
21 | func testLaunch() throws {
22 | let app = XCUIApplication()
23 | app.launch()
24 |
25 | // Insert steps here to perform after app launch but before taking a screenshot,
26 | // such as logging into a test account or navigating somewhere in the app
27 |
28 | let attachment = XCTAttachment(screenshot: app.screenshot())
29 | attachment.name = "Launch Screen"
30 | attachment.lifetime = .keepAlways
31 | add(attachment)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) __TODAYS_YEAR__ __AUTHOR NAME__
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016-2024 William Entriken
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/.github/workflows/swiftlang-workflows.yml:
--------------------------------------------------------------------------------
1 | name: Swiftlang workflows
2 |
3 | # Adapted from https://github.com/apple/swift-collections/blob/bdfaffbba691f037100b115d9aa801f05e3d7fe8/.github/workflows/pull_request.yml
4 |
5 | on:
6 | push:
7 | pull_request:
8 |
9 | jobs:
10 | tests:
11 | name: Test
12 | uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main
13 | with:
14 | linux_exclude_swift_versions: '[{"swift_version": "5.8"}, {"swift_version": "5.9"}, {"swift_version": "5.10"}, {"swift_version": "6.0"}, {"swift_version": "6.1"}]'
15 | windows_exclude_swift_versions: '[{"swift_version": "5.9"}, {"swift_version": "5.10"}]'
16 | macos_exclude_xcode_versions: '[{"xcode_version": "26.0"}]'
17 | enable_macos_checks: true
18 | enable_wasm_sdk_build: true
19 |
20 | embedded-swift:
21 | name: Build with Embedded Swift
22 | uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main
23 | with:
24 | enable_linux_checks: false
25 | enable_macos_checks: false
26 | enable_windows_checks: false
27 | enable_wasm_sdk_build: false
28 | enable_embedded_wasm_sdk_build: true
29 | swift_flags: --target "xxPROJECTxNAMExx"
30 |
31 | soundness:
32 | name: Soundness
33 | uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
34 | with:
35 | license_header_check_project_name: "xxPROJECTxNAMExx"
36 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Example/ExampleUITests/ExampleUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleUITests.swift
3 | // ExampleUITests
4 | //
5 | // Created by __AUTHOR_NAME__ on __TODAYS_DATE__.
6 | //
7 |
8 | import XCTest
9 |
10 | final class ExampleUITests: XCTestCase {
11 |
12 | override func setUpWithError() throws {
13 | // Put setup code here. This method is called before the invocation of each test method in the class.
14 |
15 | // In UI tests it is usually best to stop immediately when a failure occurs.
16 | continueAfterFailure = false
17 |
18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
19 | }
20 |
21 | override func tearDownWithError() throws {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | @MainActor
26 | func testExample() throws {
27 | // UI tests must launch the application that they test.
28 | let app = XCUIApplication()
29 | app.launch()
30 |
31 | // Use XCTAssert and related functions to verify your tests produce the correct results.
32 | }
33 |
34 | @MainActor
35 | func testLaunchPerformance() throws {
36 | // This measures how long it takes to launch your application.
37 | measure(metrics: [XCTApplicationLaunchMetric()]) {
38 | XCUIApplication().launch()
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: "Swift 6 Module Template CI"
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 |
11 | concurrency:
12 | group: ${{ github.ref_name }}
13 | cancel-in-progress: true
14 |
15 | permissions:
16 | contents: write
17 | actions: write
18 |
19 | jobs:
20 | test-configure-script:
21 | name: Test configure.swift script and generate project
22 | runs-on: macos-latest
23 | timeout-minutes: 10
24 | steps:
25 | - uses: actions/checkout@v5
26 |
27 | - name: Test configure script with environment variables
28 | env:
29 | SMT_XXPROJECTXNAMEXX: "TestModule"
30 | SMT_ORGANIZATION_NAME: "Test Organization"
31 | SMT_COM_AN_ORGANIZATION_IDENTIFIER: "com.test.organization"
32 | SMT_AUTHOR_NAME: "Test Author"
33 | SMT_TODAYS_DATE: "January 1, 2024"
34 | SMT_TODAYS_YEAR: "2024"
35 | SMT_GITHUB_USERNAME: "testuser"
36 | run: |
37 | ./configure.swift
38 | ls -la OUTPUT/
39 |
40 | - name: Verify generated project structure
41 | run: |
42 | cd OUTPUT/TestModule
43 | ls -la
44 | test -f Package.swift
45 | test -f README.md
46 | test -f LICENSE
47 | test -d Sources/TestModule
48 | test -d Tests/TestModuleTests
49 | test -d .github/workflows
50 |
51 | - name: Upload generated project as artifact
52 | uses: actions/upload-artifact@v4
53 | with:
54 | name: generated-project
55 | path: OUTPUT/TestModule/
56 | include-hidden-files: true
57 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/README.md:
--------------------------------------------------------------------------------
1 | # ALMOST DONE :walking_woman: :running_woman: :biking_woman:
2 |
3 | Thank you for using Swift 5 Module Template. Before you release your awesome project to the world, complete the following steps.
4 |
5 | THIS LIST IS EASY, CHECK IT OFF ONE-BY-ONE BABY! ✔️ ✔️ ✔️
6 |
7 | - [ ] Open the project in Xcode and add features to xxPROJECTxNAMExx
8 | - [ ] Make sure you are using Swift 5 (Edit > Convert > To Current Swift Syntax…)
9 | - [ ] Fix all build errors and warnings, add tests (yes really)
10 | - [ ] Add a screenshot or AT LEAST some picture below in this README
11 | - [ ] Delete all this crap up here
12 | - [ ] Make one release (full steps are in [CONTRIBUTING.md] in case you forget)
13 |
14 | THEN YOU'RE DONE, GO STAR [swift6-module-template](https://github.com/fulldecent/swift6-module-template) FOR UPDATES.
15 |
16 | ----
17 |
18 | # xxPROJECTxNAMExx
19 |
20 | 
21 |
22 |
23 |
24 | ## Example
25 |
26 | To run the example project, clone this repo, and open Example.xcworkspace from the iOS Example directory.
27 |
28 | ## Requirements
29 |
30 | ## Installation
31 |
32 | Add this to your project using Swift Package Manager. In Xcode that is simply: File > Swift Packages > Add Package Dependency... and you're done.
33 |
34 | ## Author
35 |
36 | __AUTHOR NAME__
37 |
38 | ## License
39 |
40 | xxPROJECTxNAMExx is available under the MIT license. See [the LICENSE file](LICENSE) for more information.
41 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## Obj-C/Swift specific
9 | *.hmap
10 |
11 | ## App packaging
12 | *.ipa
13 | *.dSYM.zip
14 | *.dSYM
15 |
16 | ## Playgrounds
17 | timeline.xctimeline
18 | playground.xcworkspace
19 |
20 | # Swift Package Manager
21 | #
22 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
23 | # Packages/
24 | # Package.pins
25 | # Package.resolved
26 | # *.xcodeproj
27 | #
28 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
29 | # hence it is not needed unless you have added a package configuration file to your project
30 | # .swiftpm
31 |
32 | .build/
33 |
34 | # CocoaPods
35 | #
36 | # We recommend against adding the Pods directory to your .gitignore. However
37 | # you should judge for yourself, the pros and cons are mentioned at:
38 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
39 | #
40 | # Pods/
41 | #
42 | # Add this line if you want to avoid checking in source code from the Xcode workspace
43 | # *.xcworkspace
44 |
45 | # Carthage
46 | #
47 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
48 | # Carthage/Checkouts
49 |
50 | Carthage/Build/
51 |
52 | # fastlane
53 | #
54 | # It is recommended to not store the screenshots in the git repo.
55 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
56 | # For more information about the recommended setup visit:
57 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
58 |
59 | fastlane/report.xml
60 | fastlane/Preview.html
61 | fastlane/screenshots/**/*.png
62 | fastlane/test_output
63 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Swift 6 Module Template
2 |
3 | Recipe: [](https://github.com/fulldecent/swift6-module-template/actions/workflows/ci.yml)
4 |
5 | Generated project: [](https://github.com/fulldecent/swift6-module-template/actions/workflows/swiftlang-workflows.yml)
6 |
7 | Use this template as a starting point for any Swift 6 module that you want other people to include in their projects.
8 |
9 | :white_check_mark: STATUS: This template is ready and works in production code. See [releases](https://github.com/fulldecent/swift6-module-template/releases) to confirm we support the latest Xcode version.
10 |
11 | 
12 |
13 | ## Features
14 |
15 | Your new Swift module will immediately have working, compilable code, and implement these best practices:
16 |
17 | - Ability to be used from Swift Package Manager
18 | - Clean folder structure
19 | - MIT license
20 | - Testing as a standard
21 | - Turnkey access to GitHub Actions testing recommended by the Swift project
22 | - Semantic versioning and a CHANGELOG
23 | - Included example/demo app using SwiftUI
24 | - Use a Xcode project to manage your code
25 |
26 | ## How to use this
27 |
28 | Clone or [download a release](https://github.com/fulldecent/swift6-module-template/releases) and run the `./configure.swift` program. It will ask you some questions and generate a project.
29 |
30 | You then add all the interesting features you want your module to have.
31 |
32 | ### Automating the configure script
33 |
34 | To skip interactive prompts in the `./configure.swift` script, use these environment variables:
35 |
36 | | Template variable | Environment variable |
37 | | -------------------------------- | ---------------------------------------- |
38 | | `__PROJECT_NAME__` | `SMT_PROJECT_NAME` |
39 | | `__ORGANIZATION NAME__` | `SMT_ORGANIZATION_NAME` |
40 | | `com.AN.ORGANIZATION.IDENTIFIER` | `SMT_COM_AN_ORGANIZATION_IDENTIFIER` |
41 | | `__AUTHOR NAME__` | `SMT_AUTHOR_NAME` |
42 | | `__TODAYS_DATE__` | `SMT_TODAYS_DATE` |
43 | | `__TODAYS_YEAR__` | `SMT_TODAYS_YEAR` |
44 | | `__GITHUB_USERNAME__` | `SMT_GITHUB_USERNAME` |
45 |
46 | For example, you may use: `export SMT_ORGANIZATION_NAME='Awesome Org'` before running `./configure.swift`.
47 |
48 | ## How it works
49 |
50 | ```mermaid
51 | graph LR
52 | subgraph Contributors to this project
53 | X[Use Xcode] --> R[Update Recipe.md]
54 | R --> T[Update template]
55 | end
56 | T --> C
57 | subgraph End users of this project
58 | C[Run ./configure.swift] --> M[Use your own module]
59 | end
60 | ```
61 |
62 | ## Deployment test
63 |
64 | After updating the recipe and template xxPROJECTxNAMExx, also validate the GitHub Actions template for the inside project.
65 |
66 | :information_source: This process is a workaround for a GitHub Actions system restriction that prevents one GitHub Action (the one for this template repository) from editing and kicking off another GitHub Action (the one inside the new xxPROJECTxNAMExx to test.
67 |
68 | ```sh
69 | git clone git@github.com:fulldecent/swift6-module-template.git ~/Desktop/swift6-module-template
70 | cd ~/Desktop/swift6-module-template
71 | export SMT_XXPROJECTXNAMEXX="TestModule"
72 | export SMT_ORGANIZATION_NAME="Test Organization"
73 | export SMT_COM_AN_ORGANIZATION_IDENTIFIER="com.test.organization"
74 | export SMT_AUTHOR_NAME="Test Author"
75 | export SMT_TODAYS_DATE="January 1, 2024"
76 | export SMT_TODAYS_YEAR="2024"
77 | export SMT_GITHUB_USERNAME="testuser"
78 | ./configure.swift
79 | # ℹ️ Now OUTPUT/TestModule is is a complete project you could publish
80 | cp -r OUTPUT/TestModule ~/Desktop/swift6-module-template-production-test
81 | cd ~/Desktop/swift6-module-template-production-test
82 | git init
83 | git remote add origin git@github.com:fulldecent/swift6-module-template.git
84 | git add .
85 | git commit -m "Initial commit for production-test branch with TestModule contents"
86 | git push --force origin HEAD:production-test
87 | ```
88 |
89 | ## Contributing
90 |
91 | See the file [Recipe.md](Recipe.md) for the complete steps (e.g. Open Xcode, make new project, click here, type that, …) of how we made the template.
92 |
--------------------------------------------------------------------------------
/configure.swift:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env swift
2 |
3 | import Foundation
4 |
5 | func promptForVariable(variable: String, defaultValue: String) -> String {
6 | if variable == "__PROJECT_NAME__", CommandLine.arguments.count == 2 {
7 | return CommandLine.arguments[1]
8 | }
9 | print("Please enter a value for \(variable) (default: \"\(defaultValue)\")")
10 | if let answer = readLine(), !answer.isEmpty {
11 | return answer
12 | }
13 | return defaultValue
14 | }
15 |
16 | func replaceVariablesInFiles(substitutions: [(from: String, to: String)]) {
17 | let fileManager = FileManager.default
18 | let enumerator = fileManager.enumerator(atPath: ".")
19 |
20 | while let fileName = enumerator?.nextObject() as? String {
21 | var isDirectory: ObjCBool = false
22 | if fileManager.fileExists(atPath: fileName, isDirectory: &isDirectory), !isDirectory.boolValue {
23 | do {
24 | var text = try String(contentsOfFile: fileName, encoding: .utf8)
25 | for substitution in substitutions {
26 | text = text.replacingOccurrences(of: substitution.from, with: substitution.to)
27 | }
28 | try text.write(toFile: fileName, atomically: true, encoding: .utf8)
29 | } catch {
30 | // Skip this file if it isn’t valid UTF-8
31 | }
32 | }
33 | }
34 | }
35 |
36 | func replaceVariablesInFileNames(substitutions: [(from: String, to: String)]) {
37 | let fileManager = FileManager.default
38 | let contents = try! fileManager.contentsOfDirectory(atPath: ".")
39 |
40 | for fileName in contents {
41 | if fileName == "." || fileName == ".." {
42 | continue
43 | }
44 | var newFileName = fileName
45 | for substitution in substitutions {
46 | newFileName = newFileName.replacingOccurrences(of: substitution.from, with: substitution.to)
47 | }
48 | if newFileName != fileName {
49 | try! fileManager.moveItem(atPath: fileName, toPath: newFileName)
50 | }
51 | var isDirectory: ObjCBool = false
52 | if fileManager.fileExists(atPath: newFileName, isDirectory: &isDirectory), isDirectory.boolValue
53 | {
54 | fileManager.changeCurrentDirectoryPath(newFileName)
55 | replaceVariablesInFileNames(substitutions: substitutions)
56 | fileManager.changeCurrentDirectoryPath("..")
57 | }
58 | }
59 | }
60 |
61 | struct Env {
62 | static let ENV_VARIABLE_PREFIX = "SMT"
63 |
64 | static func fetchSMT(
65 | templateVarName: String, defaultValue: String, prompt: (String, String) -> String
66 | ) -> String {
67 | let environmentVarName = nameFor(templateVarName: templateVarName)
68 | if let value = ProcessInfo.processInfo.environment[environmentVarName] {
69 | return value
70 | }
71 | return prompt(templateVarName, defaultValue)
72 | }
73 |
74 | static func nameFor(templateVarName: String) -> String {
75 | return "\(ENV_VARIABLE_PREFIX)_\(sanitize(templateVarName: templateVarName))"
76 | }
77 |
78 | private static func sanitize(templateVarName: String) -> String {
79 | return
80 | templateVarName
81 | .uppercased()
82 | .replacingOccurrences(of: "\\W", with: "_", options: .regularExpression)
83 | .trimmingCharacters(in: CharacterSet(charactersIn: "_"))
84 | }
85 | }
86 |
87 | let yearFormatter = DateFormatter()
88 | yearFormatter.dateFormat = "yyyy"
89 |
90 | var substitutionPairs: [(from: String, to: String)] = [
91 | (from: "xxPROJECTxNAMExx", to: "MyProject"),
92 | (from: "__ORGANIZATION_NAME__", to: "Awesome Org"),
93 | (from: "com.AN.ORGANIZATION.IDENTIFIER", to: "com.awesome"),
94 | (from: "__AUTHOR_NAME__", to: "Mr McAwesome"),
95 | (
96 | from: "__TODAYS_DATE__",
97 | to: DateFormatter.localizedString(from: Date(), dateStyle: .medium, timeStyle: .none)
98 | ),
99 | (from: "__TODAYS_YEAR__", to: yearFormatter.string(from: Date())),
100 | (from: "__GITHUB_USERNAME__", to: "awesome_octocat"),
101 | ]
102 |
103 | // Update the values through environment variables or prompts
104 | substitutionPairs = substitutionPairs.map { pair in
105 | (
106 | from: pair.from,
107 | to: Env.fetchSMT(templateVarName: pair.from, defaultValue: pair.to, prompt: promptForVariable)
108 | )
109 | }
110 |
111 | let fileManager = FileManager.default
112 | fileManager.changeCurrentDirectoryPath(fileManager.currentDirectoryPath)
113 |
114 | // Create OUTPUT folder and copy your template folder
115 | try! fileManager.createDirectory(
116 | atPath: "OUTPUT", withIntermediateDirectories: true, attributes: nil)
117 | try! fileManager.copyItem(atPath: "xxPROJECTxNAMExx", toPath: "OUTPUT/xxPROJECTxNAMExx")
118 |
119 | // Move into OUTPUT and do variable replacement
120 | fileManager.changeCurrentDirectoryPath("OUTPUT")
121 | replaceVariablesInFiles(substitutions: substitutionPairs)
122 | replaceVariablesInFileNames(substitutions: substitutionPairs)
123 |
124 | print("Done, your project is now ready to use in the OUTPUT/ folder")
125 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Sources/xxPROJECTxNAMExx/White King.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | let whiteKing = Data(
4 | base64Encoded:
5 | "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",
6 | options: NSData.Base64DecodingOptions())!
7 |
--------------------------------------------------------------------------------
/Recipe.md:
--------------------------------------------------------------------------------
1 | # Recipe
2 |
3 | This recipe cites all best practices we follow and documents exactly how we created the Swift 6 Module Template which is the [xxPROJECTxNAMExx folder](./xxPROJECTxNAMExx) in this repo.
4 |
5 | Please follow along and you should create a template that is identical to the one we provided. If this recipe is not perfect (or your result is different from our template in any way) then please submit an issue or pull request.
6 |
7 | This recipe may also be useful for other scenarios, for example maybe you want to make a project that has the Example app using storyboards instead of SwiftUI.
8 |
9 | ## Ingredients
10 |
11 | During the steps of this recipe we enter specific values where needed. These are chosen carefully so that the `./configure.swift` script can later find and replace these values in the template to create your project.
12 |
13 | - `xxPROJECTxNAMExx`
14 | - This must be a valid C99 extended identifier (otherwise the Xcode check dependencies step fails). It cannot contain spaces.
15 | - This must also be a Uniform Target Identifier (``/^[a-zA-Z0-9-.]+$/``).
16 | - If this contains the characters `-` or `.` then they will be transliterated to `_` for file names.
17 |
18 | - `__ORGANIZATION_NAME__`
19 | - This intentionally has a space which causes Xcode to use double quotes in its project configuration files.
20 |
21 | - `com.AN.ORGANIZATION.IDENTIFIER`
22 |
23 | - `__AUTHOR_NAME__`
24 | - This intentionally has a space which causes Xcode to use double quotes in its project configuration files.
25 |
26 | - `__TODAYS_DATE__`
27 |
28 | - `__TODAYS_YEAR__`
29 |
30 | - `__GITHUB_USERNAME__`
31 |
32 | ## Steps
33 |
34 | Complete all these instructions on the same calendar day.
35 |
36 | Use Xcode version 26.0.1 (17A400). *This is the latest publicly released or Gold Master version.*
37 |
38 | A previous version of this recipe is also demonstrated in a YouTube flyover at (15 minutes).
39 |
40 | ### I. Create a package for your module
41 |
42 | 1. In Xcode, choose File > New > Package…
43 | 1. Choose Multiplatform > Library > Library, and click "Next"
44 | 2. For testing system, select Swift Testing, and click "Next"
45 | 3. Navigate to your Desktop folder
46 | 4. Type the name `xxPROJECTxNAMExx`
47 | 5. Ensure "Create Git repository on my Mac" is unchecked
48 | 6. Click “Create"
49 |
50 | ### II. Add some functionality to the module
51 |
52 | 1. Use Terminal.app to insert some files into the project
53 |
54 | ```sh
55 | cd ~/Desktop/xxPROJECTxNAMExx/Sources/xxPROJECTxNAMExx/
56 | curl 'https://raw.githubusercontent.com/fulldecent/swift6-module-template/main/xxPROJECTxNAMExx/Sources/xxPROJECTxNAMExx/xxPROJECTxNAMExx.swift' -o xxPROJECTxNAMExx.swift
57 | curl 'https://raw.githubusercontent.com/fulldecent/swift6-module-template/main/xxPROJECTxNAMExx/Sources/xxPROJECTxNAMExx/White%20King.swift' -o White\ King.swift
58 | curl 'https://raw.githubusercontent.com/fulldecent/swift6-module-template/refs/heads/main/xxPROJECTxNAMExx/Tests/xxPROJECTxNAMExxTests/xxPROJECTxNAMExxTests.swift' -o ../../Tests/xxPROJECTxNAMExxTests/xxPROJECTxNAMExxTests.swift
59 | ```
60 |
61 | 2. Quit Xcode
62 | :information_source: This is a workaround for a bug introduced in Xcode 16.4 (16F6) where opening a Swift package then also opening a project containing that package at the same time produces the error:
63 |
64 | > Compiled module was created by a different version of the compiler '6.1.0.110.21'
65 |
66 | :information_source: This is also a separate workaround for a separate bug introduced in Xcode 16.4 (16F6) which reproducibly crashes the program at this step if you attempt to build the Example project and then close that window.
67 |
68 | ### III. Create a Swift project for your Example application
69 |
70 | 1. In Xcode, choose File > New > Project…
71 | 1. *Choose a template*
72 | 1. Click iOS > Application > App, and click "Next"
73 | 2. *Set the project options*
74 | 1. Set Product Name to "Example"
75 | 2. Set Team to "None"
76 | 3. Set Organization Identifier to `com.AN.ORGANIZATION.IDENTIFIER`
77 | 4. Set User Interface to "SwiftUI"
78 | 5. Set Language to "Swift"
79 | 6. Set Testing System to "Swift Testing with XCTest UI Tests"
80 | 7. Set Storage to "None"
81 | 8. Ensure "Host in CloudKit" is not selected
82 | 9. Click “Next"
83 | 3. *Create the project*
84 | 1. Ensure “Create Git Repository on my Mac" is not selected
85 | 2. Ensure "Add to" is “Don’t add to any project or workspace"
86 | 3. Select the folder `xxPROJECTxNAMExx` on the desktop (don't double click it)
87 | 4. Click “Create"
88 |
89 | ### IV. Use the directory layout structure like Alamofire
90 |
91 | 1. *Move Example source code to a folder named "Sources"*
92 | :information_source: The Alamofire project uses [the folder name "Source"](https://github.com/Alamofire/Alamofire/tree/master/Example/Source) but we choose "Sources" here to be consistent with [the default of Swift Package Manager](https://github.com/swiftlang/swift-package-manager/blob/e1183984b08c76480406e134a6ec116888cf2e67/Sources/Workspace/InitPackage.swift#L596).
93 | 1. Open the file Example.xcodeproj in Xcode (it's on your desktop, in the xxPROJECTxNAMExx > Example folder)
94 |
95 | 2. Show the Project navigator on the left (folder icon)
96 |
97 | 3. Use the Project navigator to select the "Example" folder (blue icon)
98 |
99 | 4. From the Project navigator, rename this folder as "Sources"
100 |
101 | ### V. Add some functionality to your Example application
102 |
103 | 1. Use Terminal.app to insert some files into the project
104 |
105 | ```sh
106 | cd ~/Desktop/xxPROJECTxNAMExx/Example/Sources
107 | curl 'https://raw.githubusercontent.com/fulldecent/swift6-module-template/main/xxPROJECTxNAMExx/Example/Sources/ContentView.swift' -o ContentView.swift
108 | ```
109 |
110 | :information_source: You will see "Module compiled with Swift 6.1.2 cannot be imported by the Swift 6.2 compiler", but we will resolve this in the step "make your example application depend on your module" below.
111 |
112 | ### VI. Make your example application depend on your module
113 |
114 | 1. Open Example.xcodeproj in Xcode
115 | 2. In Xcode, choose File > Add Package Dependencies...
116 | 1. Click "Add Local..."
117 | 2. Select the folder `xxPROJECTxNAMExx` on the desktop (don't double click it)
118 | 3. Click "Add Package"
119 | 4. In the choose package products, set the "add to target" to "Example", and click "Add Package"
120 |
121 | ### VII. Add additional project management files to the module
122 |
123 | *These files represent best practices which every open source Swift module author should adopt for published code.*
124 |
125 | 1. Use Terminal.app to add additional files to the project
126 |
127 | ```sh
128 | cd ~/Desktop/xxPROJECTxNAMExx/
129 | curl 'https://raw.githubusercontent.com/github/gitignore/main/Swift.gitignore' -o .gitignore
130 | mkdir -p .github/workflows
131 | curl 'https://raw.githubusercontent.com/fulldecent/swift6-module-template/main/xxPROJECTxNAMExx/.github/workflows/ci.yml' -o .github/workflows/ci.yml
132 | curl 'https://raw.githubusercontent.com/fulldecent/swift6-module-template/main/xxPROJECTxNAMExx/LICENSE' -o LICENSE
133 | curl 'https://raw.githubusercontent.com/fulldecent/swift6-module-template/main/xxPROJECTxNAMExx/README.md' -o README.md
134 | curl 'https://raw.githubusercontent.com/fulldecent/swift6-module-template/main/xxPROJECTxNAMExx/CHANGELOG.md' -o CHANGELOG.md
135 | curl 'https://raw.githubusercontent.com/fulldecent/swift6-module-template/main/xxPROJECTxNAMExx/CONTRIBUTING.md' -o CONTRIBUTING.md
136 | ```
137 |
138 | ### VIII. Remove identifying parts of your project
139 |
140 | *This step allows everybody to achieve byte-for-byte consistency with [the published Swift 6 Module Template](https://github.com/fulldecent/swift6-module-template/tree/main/xxPROJECTxNAMExx) but otherwise provides no value to you.*
141 |
142 | 1. Use Terminal.app to find and replace all occurrences of hard-coded strings with template variables
143 |
144 | ```sh
145 | find -E ~/Desktop/xxPROJECTxNAMExx \
146 | -type f -name '*.swift' -exec sed -i '' -E -e '
147 | s-(// +Created by ).*( on ).*\.-\1__AUTHOR_NAME__\2__TODAYS_DATE__.-
148 | s-(// +Copyright © ).*-\1__TODAYS_YEAR__ __ORGANIZATION_NAME__. All rights reserved.-' \
149 | '{}' \;
150 | ```
151 |
152 | ## Taste testing
153 |
154 | 1. Open Example.xcodeproj in Xcode
155 |
156 | 2. Use the scheme navigator to select Example and the latest iPhone version simulator
157 |
158 | 3. Choose Product > Run
159 | :white_check_mark: You should see a big white king (♔) after a few moments. That means it worked!
160 |
161 | :information_source: You may see a nag screen in your app about Apple Intelligence. This advertisement is installed by Apple and Apple prevents you from removing it.
162 |
163 | 4. *Compare with the distributed Swift 6 Module Template repository*
164 |
165 | 1. Use Terminal.app to clone the repository to your Developer folder
166 |
167 | ```sh
168 | git clone https://github.com/fulldecent/swift6-module-template.git ~/Developer/swift6-module-template
169 | ```
170 |
171 | 2. Compare the distributed version with your version
172 |
173 | ```sh
174 | cd ~/Developer/swift6-module-template
175 | rm -rf xxPROJECTxNAMExx
176 | cp -r ~/Desktop/xxPROJECTxNAMExx .
177 | git diff
178 | ```
179 |
180 | - :white_check_mark: You should see an empty screen indicating no differences (press q to close)
181 | - :mega: If you see differences, please raise an issue in the project repository
182 |
--------------------------------------------------------------------------------
/xxPROJECTxNAMExx/Example/Example.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 77;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D913DBF42E8979CE00D05716 /* xxPROJECTxNAMExx in Frameworks */ = {isa = PBXBuildFile; productRef = D913DBF32E8979CE00D05716 /* xxPROJECTxNAMExx */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXContainerItemProxy section */
14 | D913DBCA2E8978B500D05716 /* PBXContainerItemProxy */ = {
15 | isa = PBXContainerItemProxy;
16 | containerPortal = D913DBB42E8978B400D05716 /* Project object */;
17 | proxyType = 1;
18 | remoteGlobalIDString = D913DBBB2E8978B400D05716;
19 | remoteInfo = Example;
20 | };
21 | D913DBD42E8978B500D05716 /* PBXContainerItemProxy */ = {
22 | isa = PBXContainerItemProxy;
23 | containerPortal = D913DBB42E8978B400D05716 /* Project object */;
24 | proxyType = 1;
25 | remoteGlobalIDString = D913DBBB2E8978B400D05716;
26 | remoteInfo = Example;
27 | };
28 | /* End PBXContainerItemProxy section */
29 |
30 | /* Begin PBXFileReference section */
31 | D913DBBC2E8978B400D05716 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
32 | D913DBC92E8978B500D05716 /* ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
33 | D913DBD32E8978B500D05716 /* ExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
34 | /* End PBXFileReference section */
35 |
36 | /* Begin PBXFileSystemSynchronizedRootGroup section */
37 | D913DBBE2E8978B400D05716 /* Sources */ = {
38 | isa = PBXFileSystemSynchronizedRootGroup;
39 | path = Sources;
40 | sourceTree = "";
41 | };
42 | D913DBCC2E8978B500D05716 /* ExampleTests */ = {
43 | isa = PBXFileSystemSynchronizedRootGroup;
44 | path = ExampleTests;
45 | sourceTree = "";
46 | };
47 | D913DBD62E8978B500D05716 /* ExampleUITests */ = {
48 | isa = PBXFileSystemSynchronizedRootGroup;
49 | path = ExampleUITests;
50 | sourceTree = "";
51 | };
52 | /* End PBXFileSystemSynchronizedRootGroup section */
53 |
54 | /* Begin PBXFrameworksBuildPhase section */
55 | D913DBB92E8978B400D05716 /* Frameworks */ = {
56 | isa = PBXFrameworksBuildPhase;
57 | buildActionMask = 2147483647;
58 | files = (
59 | D913DBF42E8979CE00D05716 /* xxPROJECTxNAMExx in Frameworks */,
60 | );
61 | runOnlyForDeploymentPostprocessing = 0;
62 | };
63 | D913DBC62E8978B500D05716 /* Frameworks */ = {
64 | isa = PBXFrameworksBuildPhase;
65 | buildActionMask = 2147483647;
66 | files = (
67 | );
68 | runOnlyForDeploymentPostprocessing = 0;
69 | };
70 | D913DBD02E8978B500D05716 /* Frameworks */ = {
71 | isa = PBXFrameworksBuildPhase;
72 | buildActionMask = 2147483647;
73 | files = (
74 | );
75 | runOnlyForDeploymentPostprocessing = 0;
76 | };
77 | /* End PBXFrameworksBuildPhase section */
78 |
79 | /* Begin PBXGroup section */
80 | D913DBB32E8978B400D05716 = {
81 | isa = PBXGroup;
82 | children = (
83 | D913DBBE2E8978B400D05716 /* Sources */,
84 | D913DBCC2E8978B500D05716 /* ExampleTests */,
85 | D913DBD62E8978B500D05716 /* ExampleUITests */,
86 | D913DBBD2E8978B400D05716 /* Products */,
87 | );
88 | sourceTree = "";
89 | };
90 | D913DBBD2E8978B400D05716 /* Products */ = {
91 | isa = PBXGroup;
92 | children = (
93 | D913DBBC2E8978B400D05716 /* Example.app */,
94 | D913DBC92E8978B500D05716 /* ExampleTests.xctest */,
95 | D913DBD32E8978B500D05716 /* ExampleUITests.xctest */,
96 | );
97 | name = Products;
98 | sourceTree = "";
99 | };
100 | /* End PBXGroup section */
101 |
102 | /* Begin PBXNativeTarget section */
103 | D913DBBB2E8978B400D05716 /* Example */ = {
104 | isa = PBXNativeTarget;
105 | buildConfigurationList = D913DBDD2E8978B500D05716 /* Build configuration list for PBXNativeTarget "Example" */;
106 | buildPhases = (
107 | D913DBB82E8978B400D05716 /* Sources */,
108 | D913DBB92E8978B400D05716 /* Frameworks */,
109 | D913DBBA2E8978B400D05716 /* Resources */,
110 | );
111 | buildRules = (
112 | );
113 | dependencies = (
114 | );
115 | fileSystemSynchronizedGroups = (
116 | D913DBBE2E8978B400D05716 /* Sources */,
117 | );
118 | name = Example;
119 | packageProductDependencies = (
120 | D913DBF32E8979CE00D05716 /* xxPROJECTxNAMExx */,
121 | );
122 | productName = Example;
123 | productReference = D913DBBC2E8978B400D05716 /* Example.app */;
124 | productType = "com.apple.product-type.application";
125 | };
126 | D913DBC82E8978B500D05716 /* ExampleTests */ = {
127 | isa = PBXNativeTarget;
128 | buildConfigurationList = D913DBE02E8978B500D05716 /* Build configuration list for PBXNativeTarget "ExampleTests" */;
129 | buildPhases = (
130 | D913DBC52E8978B500D05716 /* Sources */,
131 | D913DBC62E8978B500D05716 /* Frameworks */,
132 | D913DBC72E8978B500D05716 /* Resources */,
133 | );
134 | buildRules = (
135 | );
136 | dependencies = (
137 | D913DBCB2E8978B500D05716 /* PBXTargetDependency */,
138 | );
139 | fileSystemSynchronizedGroups = (
140 | D913DBCC2E8978B500D05716 /* ExampleTests */,
141 | );
142 | name = ExampleTests;
143 | packageProductDependencies = (
144 | );
145 | productName = ExampleTests;
146 | productReference = D913DBC92E8978B500D05716 /* ExampleTests.xctest */;
147 | productType = "com.apple.product-type.bundle.unit-test";
148 | };
149 | D913DBD22E8978B500D05716 /* ExampleUITests */ = {
150 | isa = PBXNativeTarget;
151 | buildConfigurationList = D913DBE32E8978B500D05716 /* Build configuration list for PBXNativeTarget "ExampleUITests" */;
152 | buildPhases = (
153 | D913DBCF2E8978B500D05716 /* Sources */,
154 | D913DBD02E8978B500D05716 /* Frameworks */,
155 | D913DBD12E8978B500D05716 /* Resources */,
156 | );
157 | buildRules = (
158 | );
159 | dependencies = (
160 | D913DBD52E8978B500D05716 /* PBXTargetDependency */,
161 | );
162 | fileSystemSynchronizedGroups = (
163 | D913DBD62E8978B500D05716 /* ExampleUITests */,
164 | );
165 | name = ExampleUITests;
166 | packageProductDependencies = (
167 | );
168 | productName = ExampleUITests;
169 | productReference = D913DBD32E8978B500D05716 /* ExampleUITests.xctest */;
170 | productType = "com.apple.product-type.bundle.ui-testing";
171 | };
172 | /* End PBXNativeTarget section */
173 |
174 | /* Begin PBXProject section */
175 | D913DBB42E8978B400D05716 /* Project object */ = {
176 | isa = PBXProject;
177 | attributes = {
178 | BuildIndependentTargetsInParallel = 1;
179 | LastSwiftUpdateCheck = 2600;
180 | LastUpgradeCheck = 2600;
181 | TargetAttributes = {
182 | D913DBBB2E8978B400D05716 = {
183 | CreatedOnToolsVersion = 26.0.1;
184 | };
185 | D913DBC82E8978B500D05716 = {
186 | CreatedOnToolsVersion = 26.0.1;
187 | TestTargetID = D913DBBB2E8978B400D05716;
188 | };
189 | D913DBD22E8978B500D05716 = {
190 | CreatedOnToolsVersion = 26.0.1;
191 | TestTargetID = D913DBBB2E8978B400D05716;
192 | };
193 | };
194 | };
195 | buildConfigurationList = D913DBB72E8978B400D05716 /* Build configuration list for PBXProject "Example" */;
196 | developmentRegion = en;
197 | hasScannedForEncodings = 0;
198 | knownRegions = (
199 | en,
200 | Base,
201 | );
202 | mainGroup = D913DBB32E8978B400D05716;
203 | minimizedProjectReferenceProxies = 1;
204 | packageReferences = (
205 | D913DBF22E8979CE00D05716 /* XCLocalSwiftPackageReference "../../xxPROJECTxNAMExx" */,
206 | );
207 | preferredProjectObjectVersion = 77;
208 | productRefGroup = D913DBBD2E8978B400D05716 /* Products */;
209 | projectDirPath = "";
210 | projectRoot = "";
211 | targets = (
212 | D913DBBB2E8978B400D05716 /* Example */,
213 | D913DBC82E8978B500D05716 /* ExampleTests */,
214 | D913DBD22E8978B500D05716 /* ExampleUITests */,
215 | );
216 | };
217 | /* End PBXProject section */
218 |
219 | /* Begin PBXResourcesBuildPhase section */
220 | D913DBBA2E8978B400D05716 /* Resources */ = {
221 | isa = PBXResourcesBuildPhase;
222 | buildActionMask = 2147483647;
223 | files = (
224 | );
225 | runOnlyForDeploymentPostprocessing = 0;
226 | };
227 | D913DBC72E8978B500D05716 /* Resources */ = {
228 | isa = PBXResourcesBuildPhase;
229 | buildActionMask = 2147483647;
230 | files = (
231 | );
232 | runOnlyForDeploymentPostprocessing = 0;
233 | };
234 | D913DBD12E8978B500D05716 /* Resources */ = {
235 | isa = PBXResourcesBuildPhase;
236 | buildActionMask = 2147483647;
237 | files = (
238 | );
239 | runOnlyForDeploymentPostprocessing = 0;
240 | };
241 | /* End PBXResourcesBuildPhase section */
242 |
243 | /* Begin PBXSourcesBuildPhase section */
244 | D913DBB82E8978B400D05716 /* Sources */ = {
245 | isa = PBXSourcesBuildPhase;
246 | buildActionMask = 2147483647;
247 | files = (
248 | );
249 | runOnlyForDeploymentPostprocessing = 0;
250 | };
251 | D913DBC52E8978B500D05716 /* Sources */ = {
252 | isa = PBXSourcesBuildPhase;
253 | buildActionMask = 2147483647;
254 | files = (
255 | );
256 | runOnlyForDeploymentPostprocessing = 0;
257 | };
258 | D913DBCF2E8978B500D05716 /* Sources */ = {
259 | isa = PBXSourcesBuildPhase;
260 | buildActionMask = 2147483647;
261 | files = (
262 | );
263 | runOnlyForDeploymentPostprocessing = 0;
264 | };
265 | /* End PBXSourcesBuildPhase section */
266 |
267 | /* Begin PBXTargetDependency section */
268 | D913DBCB2E8978B500D05716 /* PBXTargetDependency */ = {
269 | isa = PBXTargetDependency;
270 | target = D913DBBB2E8978B400D05716 /* Example */;
271 | targetProxy = D913DBCA2E8978B500D05716 /* PBXContainerItemProxy */;
272 | };
273 | D913DBD52E8978B500D05716 /* PBXTargetDependency */ = {
274 | isa = PBXTargetDependency;
275 | target = D913DBBB2E8978B400D05716 /* Example */;
276 | targetProxy = D913DBD42E8978B500D05716 /* PBXContainerItemProxy */;
277 | };
278 | /* End PBXTargetDependency section */
279 |
280 | /* Begin XCBuildConfiguration section */
281 | D913DBDB2E8978B500D05716 /* Debug */ = {
282 | isa = XCBuildConfiguration;
283 | buildSettings = {
284 | ALWAYS_SEARCH_USER_PATHS = NO;
285 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
286 | CLANG_ANALYZER_NONNULL = YES;
287 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
288 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
289 | CLANG_ENABLE_MODULES = YES;
290 | CLANG_ENABLE_OBJC_ARC = YES;
291 | CLANG_ENABLE_OBJC_WEAK = YES;
292 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
293 | CLANG_WARN_BOOL_CONVERSION = YES;
294 | CLANG_WARN_COMMA = YES;
295 | CLANG_WARN_CONSTANT_CONVERSION = YES;
296 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
297 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
298 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
299 | CLANG_WARN_EMPTY_BODY = YES;
300 | CLANG_WARN_ENUM_CONVERSION = YES;
301 | CLANG_WARN_INFINITE_RECURSION = YES;
302 | CLANG_WARN_INT_CONVERSION = YES;
303 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
304 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
305 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
306 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
307 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
308 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
309 | CLANG_WARN_STRICT_PROTOTYPES = YES;
310 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
311 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
312 | CLANG_WARN_UNREACHABLE_CODE = YES;
313 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
314 | COPY_PHASE_STRIP = NO;
315 | DEBUG_INFORMATION_FORMAT = dwarf;
316 | ENABLE_STRICT_OBJC_MSGSEND = YES;
317 | ENABLE_TESTABILITY = YES;
318 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
319 | GCC_C_LANGUAGE_STANDARD = gnu17;
320 | GCC_DYNAMIC_NO_PIC = NO;
321 | GCC_NO_COMMON_BLOCKS = YES;
322 | GCC_OPTIMIZATION_LEVEL = 0;
323 | GCC_PREPROCESSOR_DEFINITIONS = (
324 | "DEBUG=1",
325 | "$(inherited)",
326 | );
327 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
328 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
329 | GCC_WARN_UNDECLARED_SELECTOR = YES;
330 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
331 | GCC_WARN_UNUSED_FUNCTION = YES;
332 | GCC_WARN_UNUSED_VARIABLE = YES;
333 | IPHONEOS_DEPLOYMENT_TARGET = 26.0;
334 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
335 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
336 | MTL_FAST_MATH = YES;
337 | ONLY_ACTIVE_ARCH = YES;
338 | SDKROOT = iphoneos;
339 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
340 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
341 | };
342 | name = Debug;
343 | };
344 | D913DBDC2E8978B500D05716 /* Release */ = {
345 | isa = XCBuildConfiguration;
346 | buildSettings = {
347 | ALWAYS_SEARCH_USER_PATHS = NO;
348 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
349 | CLANG_ANALYZER_NONNULL = YES;
350 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
351 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
352 | CLANG_ENABLE_MODULES = YES;
353 | CLANG_ENABLE_OBJC_ARC = YES;
354 | CLANG_ENABLE_OBJC_WEAK = YES;
355 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
356 | CLANG_WARN_BOOL_CONVERSION = YES;
357 | CLANG_WARN_COMMA = YES;
358 | CLANG_WARN_CONSTANT_CONVERSION = YES;
359 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
360 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
361 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
362 | CLANG_WARN_EMPTY_BODY = YES;
363 | CLANG_WARN_ENUM_CONVERSION = YES;
364 | CLANG_WARN_INFINITE_RECURSION = YES;
365 | CLANG_WARN_INT_CONVERSION = YES;
366 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
367 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
368 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
369 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
370 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
371 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
372 | CLANG_WARN_STRICT_PROTOTYPES = YES;
373 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
374 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
375 | CLANG_WARN_UNREACHABLE_CODE = YES;
376 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
377 | COPY_PHASE_STRIP = NO;
378 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
379 | ENABLE_NS_ASSERTIONS = NO;
380 | ENABLE_STRICT_OBJC_MSGSEND = YES;
381 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
382 | GCC_C_LANGUAGE_STANDARD = gnu17;
383 | GCC_NO_COMMON_BLOCKS = YES;
384 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
385 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
386 | GCC_WARN_UNDECLARED_SELECTOR = YES;
387 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
388 | GCC_WARN_UNUSED_FUNCTION = YES;
389 | GCC_WARN_UNUSED_VARIABLE = YES;
390 | IPHONEOS_DEPLOYMENT_TARGET = 26.0;
391 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
392 | MTL_ENABLE_DEBUG_INFO = NO;
393 | MTL_FAST_MATH = YES;
394 | SDKROOT = iphoneos;
395 | SWIFT_COMPILATION_MODE = wholemodule;
396 | VALIDATE_PRODUCT = YES;
397 | };
398 | name = Release;
399 | };
400 | D913DBDE2E8978B500D05716 /* Debug */ = {
401 | isa = XCBuildConfiguration;
402 | buildSettings = {
403 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
404 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
405 | CODE_SIGN_STYLE = Automatic;
406 | CURRENT_PROJECT_VERSION = 1;
407 | ENABLE_PREVIEWS = YES;
408 | GENERATE_INFOPLIST_FILE = YES;
409 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
410 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
411 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
412 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
413 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
414 | LD_RUNPATH_SEARCH_PATHS = (
415 | "$(inherited)",
416 | "@executable_path/Frameworks",
417 | );
418 | MARKETING_VERSION = 1.0;
419 | PRODUCT_BUNDLE_IDENTIFIER = com.AN.ORGANIZATION.IDENTIFIER.Example;
420 | PRODUCT_NAME = "$(TARGET_NAME)";
421 | STRING_CATALOG_GENERATE_SYMBOLS = YES;
422 | SWIFT_APPROACHABLE_CONCURRENCY = YES;
423 | SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
424 | SWIFT_EMIT_LOC_STRINGS = YES;
425 | SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
426 | SWIFT_VERSION = 5.0;
427 | TARGETED_DEVICE_FAMILY = "1,2";
428 | };
429 | name = Debug;
430 | };
431 | D913DBDF2E8978B500D05716 /* Release */ = {
432 | isa = XCBuildConfiguration;
433 | buildSettings = {
434 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
435 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
436 | CODE_SIGN_STYLE = Automatic;
437 | CURRENT_PROJECT_VERSION = 1;
438 | ENABLE_PREVIEWS = YES;
439 | GENERATE_INFOPLIST_FILE = YES;
440 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
441 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
442 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
443 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
444 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
445 | LD_RUNPATH_SEARCH_PATHS = (
446 | "$(inherited)",
447 | "@executable_path/Frameworks",
448 | );
449 | MARKETING_VERSION = 1.0;
450 | PRODUCT_BUNDLE_IDENTIFIER = com.AN.ORGANIZATION.IDENTIFIER.Example;
451 | PRODUCT_NAME = "$(TARGET_NAME)";
452 | STRING_CATALOG_GENERATE_SYMBOLS = YES;
453 | SWIFT_APPROACHABLE_CONCURRENCY = YES;
454 | SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
455 | SWIFT_EMIT_LOC_STRINGS = YES;
456 | SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
457 | SWIFT_VERSION = 5.0;
458 | TARGETED_DEVICE_FAMILY = "1,2";
459 | };
460 | name = Release;
461 | };
462 | D913DBE12E8978B500D05716 /* Debug */ = {
463 | isa = XCBuildConfiguration;
464 | buildSettings = {
465 | BUNDLE_LOADER = "$(TEST_HOST)";
466 | CODE_SIGN_STYLE = Automatic;
467 | CURRENT_PROJECT_VERSION = 1;
468 | GENERATE_INFOPLIST_FILE = YES;
469 | IPHONEOS_DEPLOYMENT_TARGET = 26.0;
470 | MARKETING_VERSION = 1.0;
471 | PRODUCT_BUNDLE_IDENTIFIER = com.AN.ORGANIZATION.IDENTIFIER.ExampleTests;
472 | PRODUCT_NAME = "$(TARGET_NAME)";
473 | STRING_CATALOG_GENERATE_SYMBOLS = NO;
474 | SWIFT_APPROACHABLE_CONCURRENCY = YES;
475 | SWIFT_EMIT_LOC_STRINGS = NO;
476 | SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
477 | SWIFT_VERSION = 5.0;
478 | TARGETED_DEVICE_FAMILY = "1,2";
479 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Example";
480 | };
481 | name = Debug;
482 | };
483 | D913DBE22E8978B500D05716 /* Release */ = {
484 | isa = XCBuildConfiguration;
485 | buildSettings = {
486 | BUNDLE_LOADER = "$(TEST_HOST)";
487 | CODE_SIGN_STYLE = Automatic;
488 | CURRENT_PROJECT_VERSION = 1;
489 | GENERATE_INFOPLIST_FILE = YES;
490 | IPHONEOS_DEPLOYMENT_TARGET = 26.0;
491 | MARKETING_VERSION = 1.0;
492 | PRODUCT_BUNDLE_IDENTIFIER = com.AN.ORGANIZATION.IDENTIFIER.ExampleTests;
493 | PRODUCT_NAME = "$(TARGET_NAME)";
494 | STRING_CATALOG_GENERATE_SYMBOLS = NO;
495 | SWIFT_APPROACHABLE_CONCURRENCY = YES;
496 | SWIFT_EMIT_LOC_STRINGS = NO;
497 | SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
498 | SWIFT_VERSION = 5.0;
499 | TARGETED_DEVICE_FAMILY = "1,2";
500 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Example";
501 | };
502 | name = Release;
503 | };
504 | D913DBE42E8978B500D05716 /* Debug */ = {
505 | isa = XCBuildConfiguration;
506 | buildSettings = {
507 | CODE_SIGN_STYLE = Automatic;
508 | CURRENT_PROJECT_VERSION = 1;
509 | GENERATE_INFOPLIST_FILE = YES;
510 | MARKETING_VERSION = 1.0;
511 | PRODUCT_BUNDLE_IDENTIFIER = com.AN.ORGANIZATION.IDENTIFIER.ExampleUITests;
512 | PRODUCT_NAME = "$(TARGET_NAME)";
513 | STRING_CATALOG_GENERATE_SYMBOLS = NO;
514 | SWIFT_APPROACHABLE_CONCURRENCY = YES;
515 | SWIFT_EMIT_LOC_STRINGS = NO;
516 | SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
517 | SWIFT_VERSION = 5.0;
518 | TARGETED_DEVICE_FAMILY = "1,2";
519 | TEST_TARGET_NAME = Example;
520 | };
521 | name = Debug;
522 | };
523 | D913DBE52E8978B500D05716 /* Release */ = {
524 | isa = XCBuildConfiguration;
525 | buildSettings = {
526 | CODE_SIGN_STYLE = Automatic;
527 | CURRENT_PROJECT_VERSION = 1;
528 | GENERATE_INFOPLIST_FILE = YES;
529 | MARKETING_VERSION = 1.0;
530 | PRODUCT_BUNDLE_IDENTIFIER = com.AN.ORGANIZATION.IDENTIFIER.ExampleUITests;
531 | PRODUCT_NAME = "$(TARGET_NAME)";
532 | STRING_CATALOG_GENERATE_SYMBOLS = NO;
533 | SWIFT_APPROACHABLE_CONCURRENCY = YES;
534 | SWIFT_EMIT_LOC_STRINGS = NO;
535 | SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
536 | SWIFT_VERSION = 5.0;
537 | TARGETED_DEVICE_FAMILY = "1,2";
538 | TEST_TARGET_NAME = Example;
539 | };
540 | name = Release;
541 | };
542 | /* End XCBuildConfiguration section */
543 |
544 | /* Begin XCConfigurationList section */
545 | D913DBB72E8978B400D05716 /* Build configuration list for PBXProject "Example" */ = {
546 | isa = XCConfigurationList;
547 | buildConfigurations = (
548 | D913DBDB2E8978B500D05716 /* Debug */,
549 | D913DBDC2E8978B500D05716 /* Release */,
550 | );
551 | defaultConfigurationIsVisible = 0;
552 | defaultConfigurationName = Release;
553 | };
554 | D913DBDD2E8978B500D05716 /* Build configuration list for PBXNativeTarget "Example" */ = {
555 | isa = XCConfigurationList;
556 | buildConfigurations = (
557 | D913DBDE2E8978B500D05716 /* Debug */,
558 | D913DBDF2E8978B500D05716 /* Release */,
559 | );
560 | defaultConfigurationIsVisible = 0;
561 | defaultConfigurationName = Release;
562 | };
563 | D913DBE02E8978B500D05716 /* Build configuration list for PBXNativeTarget "ExampleTests" */ = {
564 | isa = XCConfigurationList;
565 | buildConfigurations = (
566 | D913DBE12E8978B500D05716 /* Debug */,
567 | D913DBE22E8978B500D05716 /* Release */,
568 | );
569 | defaultConfigurationIsVisible = 0;
570 | defaultConfigurationName = Release;
571 | };
572 | D913DBE32E8978B500D05716 /* Build configuration list for PBXNativeTarget "ExampleUITests" */ = {
573 | isa = XCConfigurationList;
574 | buildConfigurations = (
575 | D913DBE42E8978B500D05716 /* Debug */,
576 | D913DBE52E8978B500D05716 /* Release */,
577 | );
578 | defaultConfigurationIsVisible = 0;
579 | defaultConfigurationName = Release;
580 | };
581 | /* End XCConfigurationList section */
582 |
583 | /* Begin XCLocalSwiftPackageReference section */
584 | D913DBF22E8979CE00D05716 /* XCLocalSwiftPackageReference "../../xxPROJECTxNAMExx" */ = {
585 | isa = XCLocalSwiftPackageReference;
586 | relativePath = ../../xxPROJECTxNAMExx;
587 | };
588 | /* End XCLocalSwiftPackageReference section */
589 |
590 | /* Begin XCSwiftPackageProductDependency section */
591 | D913DBF32E8979CE00D05716 /* xxPROJECTxNAMExx */ = {
592 | isa = XCSwiftPackageProductDependency;
593 | productName = xxPROJECTxNAMExx;
594 | };
595 | /* End XCSwiftPackageProductDependency section */
596 | };
597 | rootObject = D913DBB42E8978B400D05716 /* Project object */;
598 | }
599 |
--------------------------------------------------------------------------------