We love Projucer!
ProjucerのGUI EditorはDeprecatedになってしまい、JUCE 8.0.1からはなくなってしまった。しかしJUCEを使う上でこんなに便利なRADツールは他にないので、限界まで使い続ける。
生成されたコードのJUCEバージョンチェックを外す
Version 7.0.12のProjucerを使ってVersion 8.x.xとか上のバージョンのJUCE modulesをリスクを承知の上で使う。そのまま使うとバージョンチェックが入ってビルドエラーで止まるので、このチェックを外す。下記のコードの#if、#error、#endifをこのようにコメントアウトするようにする。
if (hasBinaryData && project.shouldIncludeBinaryInJuceHeader())
out << CodeHelpers::createIncludeStatement (project.getBinaryDataHeaderFile(), getAppConfigFile()) << newLine;
out << newLine
<< "//#if defined (JUCE_PROJUCER_VERSION) && JUCE_PROJUCER_VERSION < JUCE_VERSION" << newLine
<< " /** If you've hit this error then the version of the Projucer that was used to generate this project is" << newLine
<< " older than the version of the JUCE modules being included. To fix this error, re-save your project" << newLine
<< " using the latest version of the Projucer or, if you aren't using the Projucer to manage your project," << newLine
<< " remove the JUCE_PROJUCER_VERSION define." << newLine
<< " */" << newLine
<< "// #error \"This project was last saved using an outdated version of the Projucer! Re-save this project with the latest version to fix this error.\"" << newLine
<< "//#endif" << newLine
<< newLine;
if (project.shouldAddUsingNamespaceToJuceHeader())
// snip
Font関連のWarning
ProjucerはComponentのコードに関してこんなコードを書いてくる。
labelProgramName->setFont (juce::Font (17.00f, juce::Font::plain).withTypefaceStyle ("Regular"));
これはJUCE 8ではこうでなければならない。
labelProgramName->setFont (juce::Font (juce::FontOptions (17.0f, juce::Font::plain)));
しかし、これはいくら手動で書き直しても、Projucerがコードを吐き出すたびに戻されてしまうので、Projucerを変更するしかない。
変更前
static String getCompleteFontCode (const Font& font, const String& typefaceName)
{
String s;
s << "juce::Font ("
<< getTypefaceNameCode (typefaceName)
<< CodeHelpers::floatLiteral (font.getHeight(), 2)
<< ", ";
if (font.getAvailableStyles().contains (font.getTypefaceStyle()))
s << "juce::Font::plain).withTypefaceStyle ("
<< CodeHelpers::stringLiteral (font.getTypefaceStyle())
<< ")";
else
s << getFontStyleCode (font)
<< ")";
if (! approximatelyEqual (font.getExtraKerningFactor(), 0.0f))
s << ".withExtraKerningFactor ("
<< CodeHelpers::floatLiteral (font.getExtraKerningFactor(), 3)
<< ")";
return s;
}
変更後
static String getCompleteFontCode (const Font& font, const String& typefaceName)
{
String s;
s << "juce::Font (juce::FontOptions ("
<< CodeHelpers::floatLiteral (font.getHeight(), 2)
<< ", ";
// スタイルの判定
if (typefaceName == "Bold Italic")
s << "juce::Font::bold | juce::Font::italic";
else if (typefaceName == "Bold")
s << "juce::Font::bold";
else if (typefaceName == "Italic")
s << "juce::Font::italic";
else
s << "juce::Font::plain"; // "Regular" に相当
s << "))";
if (! approximatelyEqual (font.getExtraKerningFactor(), 0.0f))
s << ".withExtraKerningFactor ("
<< CodeHelpers::floatLiteral (font.getExtraKerningFactor(), 3)
<< ")";
return s;
}
Mac/iOSのPList変更
Exporterの設定でCustom PListに下記のように書く。これのとの中身を必要に応じて足していく。下記のkeyとvalueはただの例。
<plist>
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.yourcompany.yourproduct</string>
</array>
</dict>
</plist>
App Groups対応
iOSの場合
ExporterのApp Grop CapabilityをEnabledにして、App Group IDにIDを記述。複数ある場合はセミコロンで区切る。
Macの場合
MacのExporterはApp Groupをサポートしてないので自力でやらねばならない。
まずPListに追加。
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.yourcompany.yourproduct</string>
</array>
これだけだとMac/iOS共にCapabilityにApp Groupは足されるけど値にチェックが入らないので(なんでやねん!)、Entitlementsをビルド前に「必要に応じて」書き換える。このためにExporterのPre-Build Shell Scriptに下記を書く。ただしこれのせいでビルド中にEntitlementsが変更されるため、最初の1回だけビルドがエラーでストップしてしまう(運良くならないこともある)。VST、VST3、AudioUnit(v2)はそもそもApp Groupには対応できないのでこれは必要ない。
#!/bin/bash
# 対象となるエンタイトルメントファイルのリスト
ENTITLEMENTS_FILES=(
"$PROJECT_DIR/AUv3_AppExtension.entitlements"
"$PROJECT_DIR/Standalone_Plugin.entitlements"
)
# チェックするキーと追加する値
KEY_TO_CHECK="com.apple.security.application-groups"
APP_GROUP="group.tokyo.studio-r.ifw"
# 各エンタイトルメントファイルを処理
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
# アプリグループの設定
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"
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"
fi
echo "Successfully updated ${ENTITLEMENTS_FILE}!"
done
echo "All entitlements files processed successfully!"
iCloud Documents対応
TBD.
LSSupportsOpeningDocumentsInPlace
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
LSSupportsOpeningDocumentsInPlace
は、iOS/macOSアプリの Info.plist
ファイルに含まれるキーで、アプリケーションがファイルを開く際の挙動を制御します。
このキーを true
に設定すると、アプリケーションは**「その場で(in-place)ドキュメントを開く」**ことをサポートするようになります。具体的には、ユーザーが別の場所(例えば、メールの添付ファイルやiCloud Driveなど)にあるドキュメントを直接編集しようとした際に、アプリは元のファイルのコピーをサンドボックス内に作成するのではなく、元の場所にあるファイルを直接読み書きします。
主な利点
シームレスな編集体験: ユーザーは、ファイルをアプリに読み込む(インポート/エクスポートする)という意識をすることなく、どこにあるファイルでも直接編集し、変更が自動的に元の場所に保存されるという直感的な操作が可能になります。
ストレージの効率化: ファイルのコピーを作成しないため、デバイスのストレージを節約できます。
iCloudとの連携: iCloud Drive上のドキュメントを直接編集・保存できるため、複数のデバイス間での同期がスムーズになります。
通常、この機能は UISupportsDocumentBrowser
キーと組み合わせて使用され、ファイルアプリとの高度な連携を実現します。
LSSupportsOpeningDocumentsInPlace
をOnにしても、iCloud Driveのオフライン機能としてローカルキャッシュは利用されます。この設定のtrue/falseでの違いは、アプリがどのファイルに対して編集を行うかという点にあります。
LSSupportsOpeningDocumentsInPlace = true
これは**「その場で開く (Open in Place)」**モードです。
編集対象: ファイルアプリなどから渡された元のファイルそのものを直接編集します。
ユーザー体験: ユーザーがファイルを編集して保存すると、変更は元の場所に自動的に反映されます。オフラインの場合はローカルキャッシュに保存され、オンラインになったら自動で同期されます。ファイルを書き出す(エクスポートする)といった余計な手間がかからず、シームレスな体験になります。
フロー: 📁 (元のファイル) → ✍️ (直接編集) → 💾 (元の場所に保存)
LSSupportsOpeningDocumentsInPlace = false
これは**「コピーを開く (Open a Copy)」**モードです。
編集対象: 元のファイルは変更せず、ファイルのコピーをアプリ自身の領域(サンドボックス)に作成し、そのコピーを編集します。
ユーザー体験: ユーザーがファイルを編集・保存しても、それはあくまでアプリ内にあるコピーへの変更です。元のファイルは一切変更されません。 変更をiCloud Driveなどに反映させたい場合は、ユーザーが手動で「共有」や「書き出し」メニューから保存場所を選んで、上書き保存または新規保存する必要があります。一手間かかる、古い形式の動作です。
フロー: 📁 (元のファイル) → 📄 (コピー作成) → ✍️ (コピーを編集) → 📤 (書き出して元の場所に保存が必要)
Supported Destinations
iPad用のアプリはデフォルトではMacとApple Visionで動作するように設定されるが、これを外したい場合は下記をiOS用ExporterでDebug/Releaseの両方のCustom Xcode Flagsに入れる。
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO, SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO
dSYMを出力する
iOS、MacのExporterのRelease(もしくはDebug)のCustom Xcode Flagsに下記を追加する。
GCC_GENERATE_DEBUGGING_SYMBOLS=YES, DEPLOYMENT_POSTPROCESSING=NO, DEBUG_INFORMATION_FORMAT=dwarf-with-dsym
この設定でdSYMはビルドされた実行ファイルと同じ場所に作成される。しかし、Product -> Archiveでパッケージ化した場合にパッケージの中のdSYMフォルダにはコピーされない(やり方探したが見つからない)。なので、App Storeに提出の際にはパッケージを作成した後でパッケージを開いてdSYMフォルダにXXX.dSYMファイルを手動でコピーしてから提出する。これも自動にしたい場合はおそらくスクリプトが必要。
iOSのアプリをMacとApple Vision非対応にする
iOSのExporterのCustom Xcode Flagsに下記を追加する。
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD=NO, SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD=NO