mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Projucer: Fix the type of the iokit sandbox exception in the Xcode exporter
This commit is contained in:
parent
f0d147a470
commit
ef61128127
8 changed files with 197 additions and 42 deletions
|
|
@ -123,6 +123,17 @@ namespace juce:: build_tools
|
|||
paths += "\n\t</array>";
|
||||
entitlements.set (option.key, paths);
|
||||
}
|
||||
|
||||
if (! appSandboxExceptionIOKit.isEmpty())
|
||||
{
|
||||
String ioKitClasses = "<array>";
|
||||
|
||||
for (const auto& c : appSandboxExceptionIOKit)
|
||||
ioKitClasses += "\n\t\t<string>" + c + "</string>";
|
||||
|
||||
ioKitClasses += "\n\t</array>";
|
||||
entitlements.set ("com.apple.security.temporary-exception.iokit-user-client-class", ioKitClasses);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ namespace juce::build_tools
|
|||
};
|
||||
|
||||
std::vector<KeyAndStringArray> appSandboxTemporaryPaths;
|
||||
StringArray appSandboxExceptionIOKit;
|
||||
|
||||
private:
|
||||
StringPairArray getEntitlements() const;
|
||||
|
|
|
|||
|
|
@ -385,8 +385,6 @@ void MainWindow::openFile (const File& file, std::function<void (bool)> callback
|
|||
|
||||
parent->createProjectContentCompIfNeeded();
|
||||
parent->getProjectContentComponent()->reloadLastOpenDocuments();
|
||||
|
||||
parent->currentProject->updateDeprecatedProjectSettingsInteractively();
|
||||
}
|
||||
|
||||
NullCheckedInvocation::invoke (callback, saveResult);
|
||||
|
|
|
|||
|
|
@ -261,14 +261,6 @@ void Project::updateDeprecatedProjectSettings()
|
|||
exporter->updateDeprecatedSettings();
|
||||
}
|
||||
|
||||
void Project::updateDeprecatedProjectSettingsInteractively()
|
||||
{
|
||||
jassert (! ProjucerApplication::getApp().isRunningCommandLine);
|
||||
|
||||
for (ExporterIterator exporter (*this); exporter.next();)
|
||||
exporter->updateDeprecatedSettingsInteractively();
|
||||
}
|
||||
|
||||
void Project::initialiseMainGroup()
|
||||
{
|
||||
// Create main file group if missing
|
||||
|
|
@ -462,8 +454,8 @@ void Project::removeDefunctExporters()
|
|||
warningMessage << "\n"
|
||||
<< TRANS ("These exporters have been removed from the project. If you save the project they will be also erased from the .jucer file.");
|
||||
|
||||
auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, warningTitle, warningMessage);
|
||||
messageBox = AlertWindow::showScopedAsync (options, nullptr);
|
||||
exporterRemovalMessageBoxOptions = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, warningTitle, warningMessage);
|
||||
messageBoxQueueListenerScope = messageBoxQueue.addListener (*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1169,6 +1161,14 @@ void Project::valueTreeChildAddedOrRemoved (ValueTree& parent, ValueTree& child)
|
|||
changed();
|
||||
}
|
||||
|
||||
void Project::canCreateMessageBox (CreatorFunction f)
|
||||
{
|
||||
messageBox = f (*exporterRemovalMessageBoxOptions, [this] (auto)
|
||||
{
|
||||
messageBoxQueueListenerScope.reset();
|
||||
});
|
||||
}
|
||||
|
||||
void Project::valueTreeChildAdded (ValueTree& parent, ValueTree& child)
|
||||
{
|
||||
valueTreeChildAddedOrRemoved (parent, child);
|
||||
|
|
|
|||
|
|
@ -117,6 +117,64 @@ namespace ProjectMessages
|
|||
using MessageAction = std::pair<String, std::function<void()>>;
|
||||
}
|
||||
|
||||
// Can be shared between multiple classes wanting to create a MessageBox. Ensures that there is one
|
||||
// MessageBox active at a given time.
|
||||
class MessageBoxQueue : private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
struct Listener
|
||||
{
|
||||
using CreatorFunction = std::function<ScopedMessageBox (MessageBoxOptions, std::function<void (int)>)>;
|
||||
|
||||
virtual ~Listener() = default;
|
||||
|
||||
virtual void canCreateMessageBox (CreatorFunction) = 0;
|
||||
};
|
||||
|
||||
void handleAsyncUpdate()
|
||||
{
|
||||
schedule();
|
||||
}
|
||||
|
||||
auto addListener (Listener& l)
|
||||
{
|
||||
triggerAsyncUpdate();
|
||||
return listeners.addScoped (l);
|
||||
}
|
||||
|
||||
private:
|
||||
ScopedMessageBox create (MessageBoxOptions options, std::function<void (int)> callback)
|
||||
{
|
||||
hasActiveMessageBox = true;
|
||||
|
||||
return AlertWindow::showScopedAsync (options, [this, cb = std::move (callback)] (int result)
|
||||
{
|
||||
cb (result);
|
||||
hasActiveMessageBox = false;
|
||||
triggerAsyncUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
void schedule()
|
||||
{
|
||||
if (hasActiveMessageBox)
|
||||
return;
|
||||
|
||||
auto& currentListeners = listeners.getListeners();
|
||||
|
||||
if (! currentListeners.isEmpty())
|
||||
{
|
||||
currentListeners[0]->canCreateMessageBox ([this] (auto o, auto c)
|
||||
{
|
||||
return create (o, c);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ListenerList<Listener> listeners;
|
||||
bool hasActiveMessageBox = false;
|
||||
};
|
||||
|
||||
enum class Async { no, yes };
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -124,7 +182,8 @@ class Project final : public FileBasedDocument,
|
|||
private ValueTree::Listener,
|
||||
private LicenseController::LicenseStateListener,
|
||||
private ChangeListener,
|
||||
private AvailableModulesList::Listener
|
||||
private AvailableModulesList::Listener,
|
||||
private MessageBoxQueue::Listener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
|
|
@ -355,8 +414,6 @@ public:
|
|||
static build_tools::ProjectType::Target::Type getTargetTypeFromFilePath (const File& file, bool returnSharedTargetIfNoValidSuffix);
|
||||
|
||||
//==============================================================================
|
||||
void updateDeprecatedProjectSettingsInteractively();
|
||||
|
||||
StringPairArray getAppConfigDefs();
|
||||
StringPairArray getAudioPluginFlags() const;
|
||||
|
||||
|
|
@ -548,6 +605,8 @@ public:
|
|||
bool isFileModificationCheckPending() const;
|
||||
bool isSaveAndExportDisabled() const;
|
||||
|
||||
MessageBoxQueue messageBoxQueue;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier&) override;
|
||||
|
|
@ -557,6 +616,9 @@ private:
|
|||
|
||||
void valueTreeChildAddedOrRemoved (ValueTree&, ValueTree&);
|
||||
|
||||
//==============================================================================
|
||||
void canCreateMessageBox (CreatorFunction) override;
|
||||
|
||||
//==============================================================================
|
||||
template <typename This>
|
||||
static auto& getEnabledModulesImpl (This&);
|
||||
|
|
@ -667,6 +729,9 @@ private:
|
|||
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
std::unique_ptr<ProjectSaver> saver;
|
||||
|
||||
std::optional<MessageBoxOptions> exporterRemovalMessageBoxOptions;
|
||||
ErasedScopeGuard messageBoxQueueListenerScope;
|
||||
ScopedMessageBox messageBox;
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ xcrun codesign --verify "$JUCE_FULL_PRODUCT_PATH" || xcrun codesign -f -s - "$JU
|
|||
)";
|
||||
|
||||
//==============================================================================
|
||||
class XcodeProjectExporter final : public ProjectExporter
|
||||
class XcodeProjectExporter final : public ProjectExporter,
|
||||
private MessageBoxQueue::Listener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
|
|
@ -97,6 +98,7 @@ public:
|
|||
appSandboxHomeDirRWValue (settings, Ids::appSandboxHomeDirRW, getUndoManager()),
|
||||
appSandboxAbsDirROValue (settings, Ids::appSandboxAbsDirRO, getUndoManager()),
|
||||
appSandboxAbsDirRWValue (settings, Ids::appSandboxAbsDirRW, getUndoManager()),
|
||||
appSandboxExceptionIOKitValue (settings, Ids::appSandboxExceptionIOKit, getUndoManager()),
|
||||
hardenedRuntimeValue (settings, Ids::hardenedRuntime, getUndoManager()),
|
||||
hardenedRuntimeOptionsValue (settings, Ids::hardenedRuntimeOptions, getUndoManager(), Array<var>(), ","),
|
||||
microphonePermissionNeededValue (settings, Ids::microphonePermissionNeeded, getUndoManager()),
|
||||
|
|
@ -144,6 +146,11 @@ public:
|
|||
name = getDisplayNameMac();
|
||||
targetLocationValue.setDefault (getDefaultBuildsRootFolder() + getTargetFolderNameMac());
|
||||
}
|
||||
|
||||
if (needsDisplayMessageBox())
|
||||
{
|
||||
messageBoxQueueListenerScope = project.messageBoxQueue.addListener (*this);
|
||||
}
|
||||
}
|
||||
|
||||
static XcodeProjectExporter* createForSettings (Project& projectToUse, const ValueTree& settingsToUse)
|
||||
|
|
@ -224,6 +231,11 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
StringArray getAppSandboxExceptionIOKitClasses() const
|
||||
{
|
||||
return getCommaOrWhitespaceSeparatedItems (appSandboxExceptionIOKitValue.get());
|
||||
}
|
||||
|
||||
Array<var> getValidArchs() const { return *validArchsValue.get().getArray(); }
|
||||
|
||||
bool isMicrophonePermissionEnabled() const { return microphonePermissionNeededValue.get(); }
|
||||
|
|
@ -510,7 +522,6 @@ public:
|
|||
{ "Temporary Exception: Audio Unit Hosting", "temporary-exception.audio-unit-host" },
|
||||
{ "Temporary Exception: Global Mach Service", "temporary-exception.mach-lookup.global-name" },
|
||||
{ "Temporary Exception: Global Mach Service Dynamic Registration", "temporary-exception.mach-register.global-name" },
|
||||
{ "Temporary Exception: IOKit User Client Class", "temporary-exception.iokit-user-client-class" },
|
||||
{ "Temporary Exception: Shared Preference Domain (Read Only)", "temporary-exception.shared-preference.read-only" },
|
||||
{ "Temporary Exception: Shared Preference Domain (Read/Write)", "temporary-exception.shared-preference.read-write" }
|
||||
};
|
||||
|
|
@ -541,6 +552,14 @@ public:
|
|||
"See Apple's File Access Temporary Exceptions documentation.");
|
||||
}
|
||||
|
||||
props.add (new TextPropertyComponentWithEnablement (appSandboxExceptionIOKitValue,
|
||||
appSandboxValue,
|
||||
"App sandbox temporary exception: additional IOUserClient subclasses",
|
||||
8192,
|
||||
true),
|
||||
"A list of IOUserClient subclasses to open or to set properties on. "
|
||||
"See Apple's IOKit User Client Class Temporary Exception documentation.");
|
||||
|
||||
props.add (new ChoicePropertyComponent (hardenedRuntimeValue, "Use Hardened Runtime"),
|
||||
"Enable this to use the hardened runtime required for app notarization.");
|
||||
|
||||
|
|
@ -781,32 +800,30 @@ public:
|
|||
updateOldOrientationSettings();
|
||||
}
|
||||
|
||||
void updateDeprecatedSettingsInteractively() override
|
||||
{
|
||||
if (hasInvalidPostBuildScript())
|
||||
{
|
||||
String alertWindowText = iOS ? "Your Xcode (iOS) Exporter settings use an invalid post-build script. Click 'Update' to remove it."
|
||||
: "Your Xcode (macOS) Exporter settings use a pre-JUCE 4.2 post-build script to move the plug-in binaries to their plug-in install folders.\n\n"
|
||||
"Since JUCE 4.2, this is instead done using \"AU/VST/VST2/AAX Binary Location\" in the Xcode (OS X) configuration settings.\n\n"
|
||||
"Click 'Update' to remove the script (otherwise your plug-in may not compile correctly).";
|
||||
|
||||
auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::WarningIcon,
|
||||
"Project settings: " + project.getDocumentTitle(),
|
||||
alertWindowText,
|
||||
"Update",
|
||||
"Cancel");
|
||||
messageBox = AlertWindow::showScopedAsync (options, [this] (int result)
|
||||
{
|
||||
if (result != 0)
|
||||
postbuildCommandValue.resetToDefault();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool hasInvalidPostBuildScript() const
|
||||
{
|
||||
// check whether the script is identical to the old one that the Introjucer used to auto-generate
|
||||
return (MD5 (getPostBuildScript().toUTF8()).toHexString() == "265ac212a7e734c5bbd6150e1eae18a1");
|
||||
return ! userAcknowledgedInvalidPostBuildScript
|
||||
&& (MD5 (getPostBuildScript().toUTF8()).toHexString() == "265ac212a7e734c5bbd6150e1eae18a1");
|
||||
}
|
||||
|
||||
bool hasDefunctIOKitSetting() const
|
||||
{
|
||||
auto v = appSandboxOptionsValue.get();
|
||||
|
||||
if (! v.isArray())
|
||||
{
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! userAcknowledgedDefunctIOKitSetting
|
||||
&& v.getArray()->contains ("com.apple.security.temporary-exception.iokit-user-client-class");
|
||||
}
|
||||
|
||||
bool needsDisplayMessageBox() const
|
||||
{
|
||||
return hasInvalidPostBuildScript() || hasDefunctIOKitSetting();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -2082,6 +2099,62 @@ private:
|
|||
|
||||
File getProjectBundle() const { return getTargetFolder().getChildFile (project.getProjectFilenameRootString()).withFileExtension (".xcodeproj"); }
|
||||
|
||||
void canCreateMessageBox (CreatorFunction f) override
|
||||
{
|
||||
if (hasInvalidPostBuildScript())
|
||||
{
|
||||
String alertWindowText = iOS ? "Your Xcode (iOS) Exporter settings use an invalid post-build script. Click 'Update' to remove it."
|
||||
: "Your Xcode (macOS) Exporter settings use a pre-JUCE 4.2 post-build script to move the plug-in binaries to their plug-in install folders.\n\n"
|
||||
"Since JUCE 4.2, this is instead done using \"AU/VST/VST2/AAX Binary Location\" in the Xcode (OS X) configuration settings.\n\n"
|
||||
"Click 'Update' to remove the script (otherwise your plug-in may not compile correctly).";
|
||||
|
||||
auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::WarningIcon,
|
||||
"Project settings: " + project.getDocumentTitle(),
|
||||
alertWindowText,
|
||||
"Update",
|
||||
"Cancel");
|
||||
|
||||
messageBox = f (options, [this] (int result)
|
||||
{
|
||||
userAcknowledgedInvalidPostBuildScript = true;
|
||||
|
||||
if (result != 0)
|
||||
postbuildCommandValue.resetToDefault();
|
||||
|
||||
if (! needsDisplayMessageBox())
|
||||
messageBoxQueueListenerScope.reset();
|
||||
});
|
||||
}
|
||||
else if (hasDefunctIOKitSetting())
|
||||
{
|
||||
String alertWindowText = "Your Xcode (macOS) Exporter settings use a defunct, boolean value for the iokit-user-client-class temporary exception entitlement.\n\n"
|
||||
"If you need this entitlement, add the IOUserClient subclasses to the new IOKit exception related field.\n\n"
|
||||
"For more information see Apple's IOKit User Client Class Temporary Exception documentation.\n\n"
|
||||
"Clicking 'Update' will remove the defunct setting from your project.";
|
||||
|
||||
auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::WarningIcon,
|
||||
"Project settings: " + project.getDocumentTitle(),
|
||||
alertWindowText,
|
||||
"Update",
|
||||
"Cancel");
|
||||
|
||||
messageBox = f (std::move (options), [this] (int result)
|
||||
{
|
||||
userAcknowledgedDefunctIOKitSetting = true;
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
auto v = appSandboxOptionsValue.get();
|
||||
v.getArray()->removeAllInstancesOf ("com.apple.security.temporary-exception.iokit-user-client-class");
|
||||
appSandboxOptionsValue.setValue (v, nullptr);
|
||||
}
|
||||
|
||||
if (! needsDisplayMessageBox())
|
||||
messageBoxQueueListenerScope.reset();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void createObjects() const
|
||||
{
|
||||
|
|
@ -3267,6 +3340,7 @@ private:
|
|||
options.hardenedRuntimeOptions = getHardenedRuntimeOptions();
|
||||
options.appSandboxOptions = getAppSandboxOptions();
|
||||
options.appSandboxTemporaryPaths = getAppSandboxTemporaryPaths();
|
||||
options.appSandboxExceptionIOKit = getAppSandboxExceptionIOKitClasses();
|
||||
|
||||
const auto entitlementsFile = getTargetFolder().getChildFile (target.getEntitlementsFilename());
|
||||
build_tools::overwriteFileIfDifferentOrThrow (entitlementsFile, options.getEntitlementsFileContent());
|
||||
|
|
@ -3748,6 +3822,7 @@ private:
|
|||
iPadScreenOrientationValue, customXcodeResourceFoldersValue, customXcassetsFolderValue,
|
||||
appSandboxValue, appSandboxInheritanceValue, appSandboxOptionsValue,
|
||||
appSandboxHomeDirROValue, appSandboxHomeDirRWValue, appSandboxAbsDirROValue, appSandboxAbsDirRWValue,
|
||||
appSandboxExceptionIOKitValue,
|
||||
hardenedRuntimeValue, hardenedRuntimeOptionsValue,
|
||||
microphonePermissionNeededValue, microphonePermissionsTextValue,
|
||||
cameraPermissionNeededValue, cameraPermissionTextValue,
|
||||
|
|
@ -3757,7 +3832,6 @@ private:
|
|||
iosContentSharingValue, iosBackgroundAudioValue, iosBackgroundBleValue, iosPushNotificationsValue, iosAppGroupsValue, iCloudPermissionsValue,
|
||||
networkingMulticastValue, iosDevelopmentTeamIDValue, iosAppGroupsIDValue, keepCustomXcodeSchemesValue, useHeaderMapValue, customLaunchStoryboardValue,
|
||||
exporterBundleIdentifierValue, suppressPlistResourceUsageValue, useLegacyBuildSystemValue, buildNumber;
|
||||
ScopedMessageBox messageBox;
|
||||
|
||||
struct SandboxFileAccessProperty
|
||||
{
|
||||
|
|
@ -3773,5 +3847,11 @@ private:
|
|||
{ appSandboxAbsDirRWValue, "App sandbox temporary exception: absolute path read/write file access", "absolute-path.read-write" }
|
||||
};
|
||||
|
||||
bool userAcknowledgedInvalidPostBuildScript = false;
|
||||
bool userAcknowledgedDefunctIOKitSetting = false;
|
||||
|
||||
ErasedScopeGuard messageBoxQueueListenerScope;
|
||||
ScopedMessageBox messageBox;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (XcodeProjectExporter)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -101,7 +101,6 @@ public:
|
|||
virtual bool canCopeWithDuplicateFiles() = 0;
|
||||
virtual bool supportsUserDefinedConfigurations() const = 0; // false if exporter only supports two configs Debug and Release
|
||||
virtual void updateDeprecatedSettings() {}
|
||||
virtual void updateDeprecatedSettingsInteractively() {}
|
||||
virtual void initialiseDependencyPathValues() {}
|
||||
|
||||
// IDE targeted by exporter
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ namespace Ids
|
|||
DECLARE_ID (appSandboxHomeDirRW);
|
||||
DECLARE_ID (appSandboxAbsDirRO);
|
||||
DECLARE_ID (appSandboxAbsDirRW);
|
||||
DECLARE_ID (appSandboxExceptionIOKit);
|
||||
DECLARE_ID (hardenedRuntime);
|
||||
DECLARE_ID (hardenedRuntimeOptions);
|
||||
DECLARE_ID (microphonePermissionNeeded);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue