3

I am trying to get my feet wet with custom file/project templates in Xcode.

I managed to get a simple project template up and running, but I do have 2 issues with it:

  1. the template files are not automatically added to the existing targets–I have to add them manually
  2. my files are currently grouped the way I want them to be, but they end up in the root directory of the app–I'd rather have them in Shared though.

So I guess what I am asking is this: what are the plist entries missing to 1. add files automatically to the targets and 2. place the group in the Shared group of my app?

Here's the TemplateInfo.plist (Editor view first, the raw code for reference at the bottom):

enter image description here

This results in this file structure:

enter image description here

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Nodes</key>
    <array>
        <string>extensions/Binding+Extensions.swift</string>
        <string>extensions/NavigationLink+Extensions.swift</string>
        <string>extensions/View+Extensions.swift</string>
    </array>
    <key>Definitions</key>
    <dict>
        <key>extensions/Binding+Extensions.swift</key>
        <dict>
            <key>Group</key>
            <string>extensions</string>
            <key>Path</key>
            <string>extensions/Binding+Extensions.swift</string>
            <key>SortOrder</key>
            <integer>99</integer>
        </dict>
        <key>extensions/NavigationLink+Extensions.swift</key>
        <dict>
            <key>Group</key>
            <string>extensions</string>
            <key>Path</key>
            <string>extensions/NavigationLink+Extensions.swift</string>
            <key>SortOrder</key>
            <integer>99</integer>
        </dict>
        <key>extensions/View+Extensions.swift</key>
        <dict>
            <key>Group</key>
            <string>extensions</string>
            <key>Path</key>
            <string>extensions/View+Extensions.swift</string>
            <key>SortOrder</key>
            <integer>99</integer>
        </dict>
    </dict>
    <key>Kind</key>
    <string>Xcode.Xcode3.ProjectTemplateUnitKind</string>
    <key>Identifier</key>
    <string>ch.appfros.dt.unit.multiPlatform.app</string>
    <key>Ancestors</key>
    <array>
        <string>com.apple.dt.unit.base</string>
        <string>com.apple.dt.unit.languageChoice</string>
        <string>com.apple.dt.unit.crossPlatformBase</string>
    </array>
    <key>Concrete</key>
    <true/>
    <key>Description</key>
    <string>This template creates a multi-platform SwiftUI application.</string>
    <key>SortOrder</key>
    <integer>1</integer>
    <key>NameOfInitialFileForEditor</key>
    <string>ContentView.swift</string>
    <key>Image</key>
    <dict>
        <key>BundleImageName</key>
        <string>app</string>
        <key>BundleIdentifier</key>
        <string>com.apple.dt.IDEKit</string>
    </dict>
    <key>Platforms</key>
    <array/>
    <key>Options</key>
    <array>
        <dict>
            <key>Identifier</key>
            <string>languageChoice</string>
            <key>Override</key>
            <string>Swift</string>
        </dict>
        <dict>
            <key>Identifier</key>
            <string>userInterface</string>
            <key>Override</key>
            <string>SwiftUI</string>
        </dict>
        <dict>
            <key>Identifier</key>
            <string>appLifecycle</string>
            <key>Override</key>
            <string>SwiftUI</string>
        </dict>
        <dict>
            <key>Identifier</key>
            <string>hasUnitAndUITests</string>
            <key>Name</key>
            <string>Include Tests</string>
            <key>NotPersisted</key>
            <false/>
            <key>SortOrder</key>
            <integer>300</integer>
            <key>Type</key>
            <string>checkbox</string>
            <key>Default</key>
            <string>true</string>
            <key>Units</key>
            <dict>
                <key>false</key>
                <dict>
                    <key>Components</key>
                    <array>
                        <dict>
                            <key>Identifier</key>
                            <string>com.apple.dt.unit.multiPlatform.app.shared</string>
                            <key>Name</key>
                            <string>Shared</string>
                        </dict>
                        <dict>
                            <key>Identifier</key>
                            <string>com.apple.dt.unit.multiPlatform.app.iOS</string>
                            <key>Name</key>
                            <string>iOS</string>
                        </dict>
                        <dict>
                            <key>Identifier</key>
                            <string>com.apple.dt.unit.multiPlatform.app.macOS</string>
                            <key>Name</key>
                            <string>macOS</string>
                        </dict>
                    </array>
                </dict>
                <key>true</key>
                <dict>
                    <key>Components</key>
                    <array>
                        <dict>
                            <key>Identifier</key>
                            <string>com.apple.dt.unit.multiPlatform.app.shared</string>
                            <key>Name</key>
                            <string>Shared</string>
                        </dict>
                        <dict>
                            <key>Identifier</key>
                            <string>com.apple.dt.unit.multiPlatform.app.iOS</string>
                            <key>Name</key>
                            <string>iOS</string>
                        </dict>
                        <dict>
                            <key>Identifier</key>
                            <string>com.apple.dt.unit.multiPlatform.app.macOS</string>
                            <key>Name</key>
                            <string>macOS</string>
                        </dict>
                        <dict>
                            <key>Identifier</key>
                            <string>com.apple.dt.unit.multiPlatform.app.iOS.tests.ui</string>
                            <key>Name</key>
                            <string>Tests iOS</string>
                        </dict>
                        <dict>
                            <key>Identifier</key>
                            <string>com.apple.dt.unit.multiPlatform.app.macOS.tests.ui</string>
                            <key>Name</key>
                            <string>Tests macOS</string>
                        </dict>
                    </array>
                </dict>
            </dict>
        </dict>
        <dict>
            <key>Identifier</key>
            <string>coreData</string>
            <key>Name</key>
            <string>Use Core Data</string>
            <key>Description</key>
            <string>Whether the application should use the Core Data framework for storage</string>
            <key>SortOrder</key>
            <integer>200</integer>
            <key>Type</key>
            <string>checkbox</string>
            <key>Default</key>
            <string>false</string>
        </dict>
        <dict>
            <key>Identifier</key>
            <string>coreDataCloudKit</string>
            <key>Name</key>
            <string>Host in CloudKit</string>
            <key>Description</key>
            <string>Whether the application should use Core Data with CloudKit</string>
            <key>RequiredOptions</key>
            <dict>
                <key>coreData</key>
                <string>true</string>
            </dict>
            <key>Indented</key>
            <true/>
            <key>SortOrder</key>
            <integer>201</integer>
            <key>Type</key>
            <string>checkbox</string>
            <key>Default</key>
            <string>false</string>
            <key>Values</key>
            <array>
                <string>false</string>
                <string>true</string>
            </array>
            <key>Variables</key>
            <dict>
                <key>false</key>
                <dict>
                    <key>persistentContainerClass</key>
                    <string>NSPersistentContainer</string>
                    <key>usedWithCloudKitModelAttribute</key>
                    <string>false</string>
                </dict>
                <key>true</key>
                <dict>
                    <key>persistentContainerClass</key>
                    <string>NSPersistentCloudKitContainer</string>
                    <key>usedWithCloudKitModelAttribute</key>
                    <string>true</string>
                </dict>
            </dict>
        </dict>
    </array>
</dict>
</plist>

appfrosch
  • 1,146
  • 13
  • 36

1 Answers1

0

To put files into nested folders, the node strings must include all folder names and Group must be an array of the same folder names. Path is the path of the file relative to the template file location. In my case, I put the files in the same folder as the template, so Path is just the file name. template with nested folders Xcode with nested folders

When I modified and ran your template, I didn't get the other files (TestApp, ContentView, Assets...). I'm not sure how you got them to appear. Also, like you said, the files added with your template are not added to the target.

The standard multiPlatform.app template has only one ancestor multiPlatform.app.SwiftUI. If I just use that ancestor, the missing files appear, and all files get added to the target. I have not figured out where in the template hierarchy the targets get assigned, but you have somehow bypassed that template. modified multiPlatform template Xcode with targets

P. Stern
  • 279
  • 1
  • 5