├── .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 | ![GitHub tag (latest SemVer)](https://github.com/__GITHUB_USERNAME__/xxPROJECTxNAMExx/actions/workflows/ci.yml/badge.svg?branch=main) 21 | 22 | Screenshot 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: [![TestModule CI](https://github.com/fulldecent/swift6-module-template/actions/workflows/ci.yml/badge.svg)](https://github.com/fulldecent/swift6-module-template/actions/workflows/ci.yml) 4 | 5 | Generated project: [![Swiftlang workflows](https://github.com/fulldecent/swift6-module-template/actions/workflows/swiftlang-workflows.yml/badge.svg?branch=production-test)](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 | ![Swift 6 directory layout](https://github.com/fulldecent/swift6-module-template/assets/382183/1a7965f0-af84-4d00-9bb6-97db76e6e715) 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 | --------------------------------------------------------------------------------