Projucerを使ってiOSおよびmacOS用のアプリを制作する際、iCloud Documentsを使用するためのCapabilityを設定するためのTips。
Custom Plist
iOS/macOSそれぞれのExporterのCustom Plistに下記を追加する。既に何かある場合はうまいことマージする。com.yourcompany.appnameの部分は自分で作ったIDを入れる。
<plist>
<dict>
<key>NSUbiquitousContainers</key>
<dict>
<key>iCloud.com.yourcompany.appname</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
<key>NSUbiquitousContainerName</key>
<string>$(PRODUCT_NAME)</string>
</dict>
</dict>
</dict>
</plist>
Pre-Build Shell Script
iOSは上記のCustom PlistだけでもOkなのだが、macOSの場合はそれだけだとCapabilitiesに追加されないので、スクリプトを使ってentitlementsに加える。/usr/libexec/PlistBuddy というコマンドを使うことでXMLの要素を加えられる。下記をMac用のExporterのPre-Build Shell Scriptに書いておく。そうすると、ビルドの前に*.entitlementsに変更を加えてくれる…のだが、変更されるとビルドエラーになる仕組みだった。なので、初回のビルドは必ずエラーになってしまうが、一旦*.entitlementsの変更が行われれば2度目以降は変更しないので、ビルドをもう一度試せばOK。下記だとApp Groupも設定しているが必要なければその部分は削除でいい。
#!/bin/bash
# 対象となるエンタイトルメントファイルのリスト
# これらのファイル名はProjucerが勝手に決めているのでそれを使う
ENTITLEMENTS_FILES=(
"$PROJECT_DIR/AUv3_AppExtension.entitlements"
"$PROJECT_DIR/Standalone_Plugin.entitlements"
)
# チェックするキーと追加する値
KEY_TO_CHECK="com.apple.security.application-groups"
APP_GROUP="group.com.yourcompany.appname"
iCLOUD_KEY="com.apple.developer.icloud-container-identifiers"
iCLOUD_CONTAINER="iCloud.com.yourcompany.appname"
iCLOUD_SERVICES_KEY="com.apple.developer.icloud-services"
iCLOUD_SERVICES_VALUE="CloudDocuments"
# 各エンタイトルメントファイルを処理
for ENTITLEMENTS_FILE in "${ENTITLEMENTS_FILES[@]}"; do
echo "Processing ${ENTITLEMENTS_FILE}..."
# ファイルが存在しない場合はエラーを出力してスキップ
if [ ! -f "$ENTITLEMENTS_FILE" ]; then
echo "Error: Entitlements file not found: $ENTITLEMENTS_FILE"
continue
fi
# iCloudの設定がない場合、iCloudコンテナ設定を追加
if ! /usr/libexec/PlistBuddy -c "Print ${iCLOUD_KEY}" "$ENTITLEMENTS_FILE" &>/dev/null; then
echo "Adding iCloud container ${iCLOUD_CONTAINER} to ${ENTITLEMENTS_FILE}"
/usr/libexec/PlistBuddy -c "Add ${iCLOUD_KEY} array" "$ENTITLEMENTS_FILE"
/usr/libexec/PlistBuddy -c "Add ${iCLOUD_KEY}:0 string ${iCLOUD_CONTAINER}" "$ENTITLEMENTS_FILE"
if [ $? -ne 0 ]; then
echo "Error: Failed to add iCloud container to $ENTITLEMENTS_FILE"
continue
fi
else
echo "iCloud container ${iCLOUD_CONTAINER} already exists in ${iCLOUD_KEY} in ${ENTITLEMENTS_FILE}"
fi
# iCloudサービスの設定がない場合、CloudDocumentsを追加
if ! /usr/libexec/PlistBuddy -c "Print ${iCLOUD_SERVICES_KEY}" "$ENTITLEMENTS_FILE" &>/dev/null; then
echo "Adding iCloud service ${iCLOUD_SERVICES_VALUE} to ${ENTITLEMENTS_FILE}"
/usr/libexec/PlistBuddy -c "Add ${iCLOUD_SERVICES_KEY} array" "$ENTITLEMENTS_FILE"
/usr/libexec/PlistBuddy -c "Add ${iCLOUD_SERVICES_KEY}:0 string ${iCLOUD_SERVICES_VALUE}" "$ENTITLEMENTS_FILE"
if [ $? -ne 0 ]; then
echo "Error: Failed to add iCloud service to $ENTITLEMENTS_FILE"
continue
fi
else
echo "iCloud service ${iCLOUD_SERVICES_VALUE} already exists in ${iCLOUD_SERVICES_KEY} in ${ENTITLEMENTS_FILE}"
fi
# キーが存在しない場合、新しい配列を追加
if ! /usr/libexec/PlistBuddy -c "Print ${KEY_TO_CHECK}" "$ENTITLEMENTS_FILE" &>/dev/null; then
echo "Adding ${KEY_TO_CHECK} as a new array to ${ENTITLEMENTS_FILE}"
/usr/libexec/PlistBuddy -c "Add ${KEY_TO_CHECK} array" "$ENTITLEMENTS_FILE"
if [ $? -ne 0 ]; then
echo "Error: Failed to add ${KEY_TO_CHECK} as an array in $ENTITLEMENTS_FILE"
continue
fi
fi
# 配列内に値が存在しない場合、値を追加
if ! /usr/libexec/PlistBuddy -c "Print ${KEY_TO_CHECK}" "$ENTITLEMENTS_FILE" | grep -q "$APP_GROUP"; then
echo "Adding ${APP_GROUP} to ${KEY_TO_CHECK} in ${ENTITLEMENTS_FILE}"
/usr/libexec/PlistBuddy -c "Add ${KEY_TO_CHECK}: string $APP_GROUP" "$ENTITLEMENTS_FILE"
if [ $? -ne 0 ]; then
echo "Error: Failed to add ${APP_GROUP} to ${KEY_TO_CHECK} in $ENTITLEMENTS_FILE"
continue
fi
else
echo "${APP_GROUP} already exists in ${KEY_TO_CHECK} in ${ENTITLEMENTS_FILE}"
fi
echo "Successfully updated ${ENTITLEMENTS_FILE}!"
done
echo "All entitlements files processed successfully!"