## 背景 iCloud Drive にできる「Tortoise Blocks」フォルダに、アプリのアイコンが表示されない。 原因は、アプリが **自分の ubiquity container を持っていない** こと。`Support/TortoiseBlocks.entitlements` には sandbox と `files.user-selected.read-write` しかなく、`Support/Info.plist` に `NSUbiquitousContainers` もない。いま iCloud Drive にある「Tortoise Blocks」は(おそらく書類ブラウザが代わりに作った)**ただのフォルダ**で、ただのフォルダにアイコンを付ける手段はない。 アイコンが付くのは、アプリ専用コンテナの `Documents/` を iCloud Drive に公開したときだけ。利用者がまだ少ない今のうちに iCloud Documents に対応する。 ## 仕様案 - **iOS / iPadOS / visionOS の**アプリ(`space.hiraku.tortoiseblocks`)に iCloud Documents を足す。コンテナ ID は `iCloud.space.hiraku.tortoiseblocks`。**macOS は対象外**(下記)。 - entitlements: `com.apple.developer.icloud-services` = `CloudDocuments`、`com.apple.developer.icloud-container-identifiers` / `com.apple.developer.ubiquity-container-identifiers` = コンテナ ID - Info.plist: `NSUbiquitousContainers` → `NSUbiquitousContainerIsDocumentScopePublic = YES`、`NSUbiquitousContainerName = Tortoise Blocks`、`NSUbiquitousContainerSupportedFolderLevels = Any` - entitlements はプラットフォームで分ける。`CODE_SIGN_ENTITLEMENTS[sdk=macosx*]` は今の `Support/TortoiseBlocks.entitlements`(sandbox と `user-selected.read-write`)のままにし、iOS / visionOS は iCloud を足した別ファイルを指す。 - QuickLook 拡張(`ThumbnailExtension`)は対象外。今の read-only sandbox のままにする。 - **iCloud を使っていない人は変わらない想定**。コンテナが手に入らないときは、`DocumentGroup` が今までどおり端末内(「この iPad 内」の「Tortoise Blocks」、`UIFileSharingEnabled`)に保存するはず。実装時にサインアウト状態で確かめる。 - **既存のただのフォルダからは自動で移さない**。コンテナは別の場所なので、同じ名前のフォルダが 2 つ並ぶ。アプリが勝手にファイルを動かすことはせず、リリースノートで移し方を案内するだけにする。 - iCloud Drive がメタデータ(フォルダ名・アイコン)を読むのは、新しいビルドを初めて入れたときだけ。Xcode Cloud が `CI_BUILD_NUMBER` でビルド番号を振るので、リリース時に特別な作業はいらない。ローカルで試すときは入れ直す。 - フォルダは `Documents/` にファイルが 1 つ入るまで iCloud Drive に現れない。 ### macOS は iCloud の対象外にする macOS の Debug は ad-hoc 署名(`CODE_SIGN_IDENTITY[sdk=macosx*] = "-"`)で、チームなしで回せることが確認手順(pkill/open)の前提になっている。iCloud の entitlement は provisioning profile がないと起動時に AMFI に止められる可能性が高いので、**Debug / Release ではなくプラットフォームで分け、macOS は Debug でも Release でも iCloud を持たない**。Mac 版の使い勝手はほとんど変わらない見込み。 - iPhone や iPad で作られたコンテナのフォルダは、iCloud Drive が Mac にも同期する。iOS にしかないアプリのフォルダと同じように、Mac の Finder にもアイコン付きで出るはず(要確認) - そのフォルダの書類は、開く・保存パネルやダブルクリックで Mac 版から開けるし、保存もできる(今の `user-selected.read-write` の範囲) - 失うのは「新規書類の既定の保存先がそのフォルダになる」ことだけ。最初の一度だけ、ユーザーが保存先にそのフォルダを選ぶ必要がある - Info.plist は共通(`INFOPLIST_FILE` を分けると UTType の宣言が二重になる)なので、`NSUbiquitousContainers` は macOS の製品にも入る。entitlement がなければ害はないはずだが、確かめる - iOS / visionOS のシミュレータは何でも ad-hoc で署名するので、Debug でもそのまま動くはず(実機はもともとチームが必要) ## やること(コード — Claude) - [x] iOS / visionOS 用の entitlements を作る(今の内容 + iCloud Documents の 3 キー)。名前は実装時に決める - [x] `Support/Info.plist` に `NSUbiquitousContainers` を足す - [x] `CODE_SIGN_ENTITLEMENTS` をプラットフォームで分ける(macOS は今のファイル)。`[sdk=…]` の向きは CLAUDE.md の署名の節と同じ考え方で決め、新しいプラットフォームが来たときに黙って外れない書き方にする - [x] 出来上がった製品の entitlements を確かめる。`codesign -d --entitlements -` で macOS(iCloud なし)/ iOS / visionOS(iCloud あり)、Info.plist は `plutil -p`。`INFOPLIST_KEY_*` と同じで、設定が黙って捨てられていないかは製品を見ないとわからない - [ ] ~~サインアウトしたシミュレータで、新規書類が端末内に保存されることを確かめる~~ (書類ブラウザを UI テストで操作できず未確認。手作業 3 の「iCloud をオフにしても端末内に保存できる」で確かめる) - [ ] ~~iCloud にサインインしたシミュレータで、新規書類の既定の保存先がコンテナになるか見る~~ (Apple ID が要るため手作業 3 で確かめる) - [x] Mac の Debug ビルドが ad-hoc 署名のまま起動し、`NSUbiquitousContainers` が入っていても何も起きないことを確かめる - [x] CI(`CODE_SIGNING_ALLOWED=NO`)が通ることを確かめる(#141) - [x] CLAUDE.md を直す(「この iPad 内」フォルダがギャラリー、という #15 の記述と、署名・entitlements の節。macOS を外した理由も書く) - [x] リリースノート(What's New)に、移し方の案内を下書きする(日英)→ 下のコメント ## やること(手作業) コードでは片付かない作業。**1〜2 はタグを打つ前に必須**。Xcode Cloud の自動署名は profile を発行できても、識別子やコンテナを登録することはできない。拡張のときと同じく「アーカイブは成功してエクスポートで失敗する」形で落ちる(release スキル参照)。 1. [x] Developer ポータル → Identifiers → **iCloud Containers** で `iCloud.space.hiraku.tortoiseblocks` を登録する 2. [x] App ID `space.hiraku.tortoiseblocks` の **iCloud** capability を有効にして(iCloud Documents を含む構成)、1 のコンテナを割り当てる。App ID は Mac 版と共通だが、Mac 版は使わないだけなので作業は変わらない 3. [x] iPhone / iPad の実機の TestFlight ビルドで確かめる(1.5.0-beta.1) - [x] iCloud Drive に **アイコン付きの**「Tortoise Blocks」フォルダが出る - [x] 新規書類がそこに保存され、別の端末から開ける - [x] 設定 → iCloud → iCloud Drive を使用しているアプリ で、Tortoise Blocks をオフにしても端末内に保存できる 4. [x] Mac で確かめる(iOS 側でフォルダができたあと) - [x] Finder の iCloud Drive に、アイコン付きの「Tortoise Blocks」フォルダが出る - [x] そこにある書類を Mac 版で開いて編集・保存でき、iPhone / iPad 側に反映される 5. [x] 自分の端末にある旧「Tortoise Blocks」フォルダ(ただのフォルダ)の書類を新しいフォルダへ移す。リリースノートの案内どおりにできるかの確認も兼ねる 6. [x] リリースノートの文面を確認して、App Store Connect に反映する 7. [x] Xcode Cloud のリリースで、iOS / macOS / visionOS のエクスポートがすべて通ったことを確認する(profile に iCloud entitlement が載っていること) 8. [x] プライバシーポリシー(`site/privacy.html`)が今の記述(「iCloud Drive を選んだ場合は Apple の仕組みで同期」)のままでよいか目を通す。変える必要はない見込み ## 受け入れ条件 - iCloud にサインインしている iPhone / iPad で、iCloud Drive の「Tortoise Blocks」フォルダにアプリのアイコンが出る - Mac の Finder にもそのフォルダが出て、中の書類を Mac 版で開いて保存できる - iCloud を使っていない端末でも、これまでどおり書類を作って保存できる - macOS の製品は Debug も Release も iCloud の entitlement を持たず、Debug はチームなしの ad-hoc 署名のまま起動する - 3 つのアプリビルドと CI が通る 参考: [QA1893 Updating the metadata of iCloud containers for iCloud Drive](https://developer.apple.com/library/archive/qa/qa1893/_index.html)
背景
iCloud Drive にできる「Tortoise Blocks」フォルダに、アプリのアイコンが表示されない。
原因は、アプリが 自分の ubiquity container を持っていない こと。
Support/TortoiseBlocks.entitlementsには sandbox とfiles.user-selected.read-writeしかなく、Support/Info.plistにNSUbiquitousContainersもない。いま iCloud Drive にある「Tortoise Blocks」は(おそらく書類ブラウザが代わりに作った)ただのフォルダで、ただのフォルダにアイコンを付ける手段はない。アイコンが付くのは、アプリ専用コンテナの
Documents/を iCloud Drive に公開したときだけ。利用者がまだ少ない今のうちに iCloud Documents に対応する。仕様案
space.hiraku.tortoiseblocks)に iCloud Documents を足す。コンテナ ID はiCloud.space.hiraku.tortoiseblocks。macOS は対象外(下記)。com.apple.developer.icloud-services=CloudDocuments、com.apple.developer.icloud-container-identifiers/com.apple.developer.ubiquity-container-identifiers= コンテナ IDNSUbiquitousContainers→NSUbiquitousContainerIsDocumentScopePublic = YES、NSUbiquitousContainerName = Tortoise Blocks、NSUbiquitousContainerSupportedFolderLevels = AnyCODE_SIGN_ENTITLEMENTS[sdk=macosx*]は今のSupport/TortoiseBlocks.entitlements(sandbox とuser-selected.read-write)のままにし、iOS / visionOS は iCloud を足した別ファイルを指す。ThumbnailExtension)は対象外。今の read-only sandbox のままにする。DocumentGroupが今までどおり端末内(「この iPad 内」の「Tortoise Blocks」、UIFileSharingEnabled)に保存するはず。実装時にサインアウト状態で確かめる。CI_BUILD_NUMBERでビルド番号を振るので、リリース時に特別な作業はいらない。ローカルで試すときは入れ直す。Documents/にファイルが 1 つ入るまで iCloud Drive に現れない。macOS は iCloud の対象外にする
macOS の Debug は ad-hoc 署名(
CODE_SIGN_IDENTITY[sdk=macosx*] = "-")で、チームなしで回せることが確認手順(pkill/open)の前提になっている。iCloud の entitlement は provisioning profile がないと起動時に AMFI に止められる可能性が高いので、Debug / Release ではなくプラットフォームで分け、macOS は Debug でも Release でも iCloud を持たない。Mac 版の使い勝手はほとんど変わらない見込み。user-selected.read-writeの範囲)INFOPLIST_FILEを分けると UTType の宣言が二重になる)なので、NSUbiquitousContainersは macOS の製品にも入る。entitlement がなければ害はないはずだが、確かめるやること(コード — Claude)
Support/Info.plistにNSUbiquitousContainersを足すCODE_SIGN_ENTITLEMENTSをプラットフォームで分ける(macOS は今のファイル)。[sdk=…]の向きは CLAUDE.md の署名の節と同じ考え方で決め、新しいプラットフォームが来たときに黙って外れない書き方にするcodesign -d --entitlements -で macOS(iCloud なし)/ iOS / visionOS(iCloud あり)、Info.plist はplutil -p。INFOPLIST_KEY_*と同じで、設定が黙って捨てられていないかは製品を見ないとわからないサインアウトしたシミュレータで、新規書類が端末内に保存されることを確かめる(書類ブラウザを UI テストで操作できず未確認。手作業 3 の「iCloud をオフにしても端末内に保存できる」で確かめる)iCloud にサインインしたシミュレータで、新規書類の既定の保存先がコンテナになるか見る(Apple ID が要るため手作業 3 で確かめる)NSUbiquitousContainersが入っていても何も起きないことを確かめるCODE_SIGNING_ALLOWED=NO)が通ることを確かめる(iCloud Drive のフォルダにアプリのアイコンを出す #141)やること(手作業)
コードでは片付かない作業。1〜2 はタグを打つ前に必須。Xcode Cloud の自動署名は profile を発行できても、識別子やコンテナを登録することはできない。拡張のときと同じく「アーカイブは成功してエクスポートで失敗する」形で落ちる(release スキル参照)。
iCloud.space.hiraku.tortoiseblocksを登録するspace.hiraku.tortoiseblocksの iCloud capability を有効にして(iCloud Documents を含む構成)、1 のコンテナを割り当てる。App ID は Mac 版と共通だが、Mac 版は使わないだけなので作業は変わらないsite/privacy.html)が今の記述(「iCloud Drive を選んだ場合は Apple の仕組みで同期」)のままでよいか目を通す。変える必要はない見込み受け入れ条件
参考: QA1893 Updating the metadata of iCloud containers for iCloud Drive