Xcodeのカスタムテンプレートを作成して他のMacと共有する

公開:2020/12/07
更新:2020/12/10
6 min読了の目安(約5800字TECH技術記事

M1 MacBook Airのバッテリーの持ちが良いので最近はあちこち移動しながらMacBook Airで作業をすることが多くなった。そこでXcodeのカスタムテンプレートも共有したいと思ったので、作成方法も合わせてメモをしておく。

テンプレートの場所

Xcodeのテンプレートは以下の場所にある。

/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/

ここにはFile TemplatesProject Templatesの2つのフォルダがあるが、それぞれフォルダ名の通りファイルのテンプレートとプロジェクトのテンプレートが入っている。
File Templatesの中には新規ファイル作成時に表示されるダイアログのカテゴリ毎にフォルダがあり、その中にファイルのテンプレート1つづつのフォルダが保存されている。

が、カスタムテンプレートはユーザ毎に~/Library/Developer/Xcode/Templatesに入れる方が他のMacとの共有やXcodeのアップデートを考えると良いだろう。

下記はまだTemplatesフォルダを作成していないユーザのXcodeフォルダの内容。

ユーザのTemplatesフォルダは最初に自分で作成する必要がある

カスタムテンプレートのフォルダ構造

Templates以下のフォルダ構造は下記のようになってる。ここではサンプルとしてMetalCIFilterカスタムテンプレートを使って説明する。

  • MetalCIFilterフォルダ Templatesフォルダ直下のフォルダはファイル作成時に表示されるダイアログでのカテゴリ。ここではMetalCIFilterがカテゴリ名になる。ちなみにSourceなどの既存のカテゴリ名のフォルダを作成した場合はそのカテゴリ内に表示される。
  • MetalCIFilter.xctemplateフォルダ 作成するカスタムテンプレートのファイル群を入れるフォルダで拡張子が.xctemplateとなる。

XcodeでNew File...を実行した時に表示されるダイアログではこうなる。

下記3種類がこのサンプルのカスタムテンプレートを構成するファイル。

  • ___FILEBASENAME___.metal, ___FILEBASENAME___.swift これはソースファイルのテンプレート。___FILEBASENAME___がファイル作成時に入力したファイル名に置き換わってソースファイルが作成される。例えばファイル作成時にMyFilterを入力するとMyFilter.metalMyFilter.swiftが作成される。
  • TemplateIcon.pngTemplateIcon@2x.png これはファイルのアイコン画像。

TemplateIconXXX-1016.pngというファイルもあるがなくても大丈夫

  • TemplateInfo.plist カスタムテンプレートのプロパティを設定するプロパティファイル。詳細は下記。

カスタムテンプレートを作成する

説明したカスタムテンプレートを構成するファイルのうち自分で作成する必要があるのはテンプレートファイルとTemplateInfo.plist。アイコンは既存のものをコピーして使って問題ない。(もちろん自作のアイコンを作っても良い。)

___FILEBASENAME___.metal

このファイルが作成されるファイルのテンプレートとなる。___FILEBASENAME___.metalは以下のような内容になっている。

___FILEBASENAME___.metal
//___FILEHEADER___

#include <metal_stdlib>
using namespace metal;
#include <CoreImage/CoreImage.h>

extern "C" { namespace coreimage {

	float4 ___VARIABLE_funcName:identifier___(sample_t s) {
		
		return s;
	}
}}

___FILEHEADER___は新しいファイルを作成した時に現れるプロジェクト名やコピーライトなどが表示されるテンプレートタグ。1行書いておけば全て表示される。

___VARIABLE_funcName:identifier___は後述するプロパティファイルで設定された変数funcNameを使用するテンプレートタグ。例えばこの場合funcNamemyFuncが割り当てられると下記のように展開される。

float4 myFunc(sample_t s) {

___FILEBASENAME___.swiftも基本的に同じように展開/作成される。

TemplateInfo.plist

カスタムテンプレートのプロパティを設定するファイル。MetalCIFilterTemplateInfo.plistは以下のような内容になっている。

TemplateInfo.plist
<?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>AllowedTypes</key>
	<array>
		<string>com.apple.metal</string>
	</array>
	<key>Platforms</key>
	<array>
		<string>com.apple.platform.iphoneos</string>
		<string>com.apple.platform.macosx</string>
	</array>
	<key>DefaultCompletionName</key>
	<string>File</string>
	<key>Description</key>
	<string>A CIKernels in Metal shader source file.</string>
	<key>Kind</key>
	<string>Xcode.IDEFoundation.TextSubstitutionFileTemplateKind</string>
	<key>MainTemplateFile</key>
	<string>___FILEBASENAME___.metal</string>
	<key>Summary</key>
	<string>A CIKernels in Metal shader source file</string>
    <key>SortOrder</key>
    <string>50</string>
    <key>Options</key>
	<array>
		<dict>
			<key>Identifier</key>
			<string>funcName</string>
			<key>Required</key>
			<true/>
			<key>Name</key>
			<string>Function Name:</string>
			<key>Description</key>
			<string>The name of the function in Metal Shader.</string>
			<key>Type</key>
			<string>text</string>
			<key>Default</key>
			<string>myMetalShaderFunc</string>
		</dict>
		<dict>
			<key>Identifier</key>
			<string>resourceName</string>
			<key>Required</key>
			<true/>
			<key>Name</key>
			<string>Resource Name:</string>
			<key>Description</key>
			<string>The name of the Metal resource.</string>
			<key>Type</key>
			<string>text</string>
			<key>Default</key>
			<string>myMetalShader</string>
		</dict>
	</array>
</dict>
</plist>

プロパティの説明

  • AllowedTypes ファイルのUTI情報
  • Platforms テンプレートを使用できるプラットフォームを表す配列。空の場合すべてのプラットフォームで使用できるようになる。指定する場合はcom.apple.platform.iphoneosのようにプラットフォームを指定する。
  • DefaultCompletionName テンプレート選択時の最後に入力するファイル名のデフォルト値
  • Description テンプレートの説明文
  • Kind テンプレートであることを示す値。
  • MainTemplateFile 複数のファイルがテンプレートによって作成される場合、テンプレート作成後にどのファイルを選択するか指定する。
  • Summary テンプレートの説明文
  • SortOrder カテゴリ内での表示順の値

Options以下

ユーザからの入力を要求するプロパティの辞書が配列に入っている。この例では2つのユーザ入力を使用している。

  • Identifier ユーザからの入力を収めるプロパティ(変数)のID。stringで名前をfuncNameとしている。上記___FILEBASENAME___.metal内の___VARIABLE_funcName:identifier___はこのプロパティ(変数)で入力された値が使用される。
  • Required 入力が必須かどうかの論理値。必須とした場合入力をしないとファイル作成時にNextボタンがグレーになって先へ進めない。
  • Name 入力部分のラベルに表示する名称。この例ではテキストボックスの左に表示される文字列。
  • Description 入力の説明。上記Nameなどの上にマウスカーソルを置くと表示される。
  • Type 入力のタイプ。この例ではテキスト。
  • Default 入力値のデフォルト。文字列の入力の場合テキストボックスに入力された状態で表示される。

表示されるユーザ入力のダイアログは以下のようになる。

カスタムテンプレートを共有する

カスタムテンプレートを~/Library/Xcode/Templatesに作成したら後はiCloudにリンクを張って他のMacと共有する。これはカスタムスニペットの時と同じ。

https://zenn.dev/paraches/articles/xcode-add-snipet
手順としては、テンプレートを作ったMacでユーザフォルダ内に作成したTemplatesフォルダをiCloudに移動してiCloudへのリンクを張る。
mv ~/Library/Developer/Xcode/Templates ~/Library/Mobile\ Documents/com\~apple\~CloudDocs/XcodeDocs
ln -s ~/Library/Mobile\ Documents/com\~apple\~CloudDocs/XcodeDocs/Templates ~/Library/Developer/Xcode

後はそれぞれのMacの~/Library/Developer/XcodeフォルダからiCloudのTemplatesへリンクを張ればOK。

サンプル

今回サンプルで作ったMetalCIFilterテンプレートはGitHubに置いてある。

https://github.com/paraches/MetalCIFilter

最後に

スニペット、テンプレートと来たので次はプロジェクトといきたいところだが、まだ必要だと感じる状況ではないのでひとまずはここまで。

それよりもAndroid StudioがM1 Macで動くようになったらしいのでそちらが気になる…。