diff --git a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp index 00ed3dfc4..39a2462bb 100644 --- a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp +++ b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp @@ -298,6 +298,10 @@ bool iOSPlatformTools::OnPostProcess(CookingData& data) // TODO: expose event to inject custom post-processing before app packaging (eg. third-party plugins) + // Run code signing for Apple platform + if (EditorUtilities::CodeSignApple(data.DataOutputPath, GetPlatform(), *platformSettings)) + return true; + // Package application const auto buildSettings = BuildSettings::Get(); if (buildSettings->SkipPackaging) diff --git a/Source/Editor/Utilities/EditorUtilities.cpp b/Source/Editor/Utilities/EditorUtilities.cpp index 91c6899aa..a67d5895f 100644 --- a/Source/Editor/Utilities/EditorUtilities.cpp +++ b/Source/Editor/Utilities/EditorUtilities.cpp @@ -15,6 +15,9 @@ #include "Engine/Content/AssetReference.h" #include "Engine/Content/Assets/Texture.h" #include "Engine/Utilities/StringConverter.h" +#if PLATFORM_MAC +#include "Engine/Platform/Apple/ApplePlatformSettings.h" +#endif #include #define MSDOS_SIGNATURE 0x5A4D @@ -749,6 +752,48 @@ bool EditorUtilities::GenerateCertificate(const String& name, const String& outp return false; } +#if PLATFORM_MAC + +bool EditorUtilities::CodeSignApple(const String& appFolder, PlatformType platform, const ApplePlatformSettings& settings) +{ + switch(settings.CodeSigning) + { + case ApplePlatformSettings::CodeSigningMode::None: + break; + case ApplePlatformSettings::CodeSigningMode::WithProvisionFile: + { + LOG(Info, "Code signing with privision file '{0}'", settings.ProvisionFile); + + // Embed privision profile file + String profileLocation = platform == PlatformType::Mac ? TEXT("Contents/embedded.provisionprofile") : TEXT("embedded.mobileprovision"); + String dstPath = appFolder / profileLocation; + if (FileSystem::CopyFile(dstPath, settings.ProvisionFile)) + { + LOG(Error, "Failed to copy privision file from '{}' to '{}'", settings.ProvisionFile, dstPath); + return true; + } + + // Run codesign tool + CreateProcessSettings procSettings; + procSettings.FileName = TEXT("codesign"); + procSettings.Arguments = String::Format(TEXT("-f -s \"{0}\" ."), settings.SignIdenity); + procSettings.HiddenWindow = true; + procSettings.LogOutput = true; + procSettings.WaitForEnd = true; + procSettings.WorkingDirectory = appFolder; + if (Platform::CreateProcess(procSettings) != 0) + { + LOG(Error, "Failed to sign code.'"); + return true; + } + break; + } + } + return false; +} + +#endif + bool EditorUtilities::IsInvalidPathChar(Char c) { char illegalChars[] = diff --git a/Source/Editor/Utilities/EditorUtilities.h b/Source/Editor/Utilities/EditorUtilities.h index cbb344266..62a0c5fce 100644 --- a/Source/Editor/Utilities/EditorUtilities.h +++ b/Source/Editor/Utilities/EditorUtilities.h @@ -53,6 +53,9 @@ public: static bool FindWDKBin(String& outputWdkBinPath); static bool GenerateCertificate(const String& name, const String& outputPfxFilePath); static bool GenerateCertificate(const String& name, const String& outputPfxFilePath, const String& outputCerFilePath, const String& outputPvkFilePath); +#if PLATFORM_MAC + static bool CodeSignApple(const String& appFolder, PlatformType platform, const class ApplePlatformSettings& settings); +#endif public: diff --git a/Source/Engine/Platform/Apple/ApplePlatformSettings.h b/Source/Engine/Platform/Apple/ApplePlatformSettings.h index 20a7ac4e2..a14b4558b 100644 --- a/Source/Engine/Platform/Apple/ApplePlatformSettings.h +++ b/Source/Engine/Platform/Apple/ApplePlatformSettings.h @@ -29,12 +29,46 @@ API_CLASS(abstract, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_AP API_FIELD(Attributes="EditorOrder(1000), EditorDisplay(\"Other\")") SoftObjectReference OverrideIcon; +#if USE_EDITOR + // Package code signing modes. + API_ENUM() enum class CodeSigningMode + { + // No code signing. + None, + // Signing code with Provision File (.mobileprovision). + WithProvisionFile, + }; + + /// + /// App code signing mode. + /// + API_FIELD(Attributes="EditorOrder(2000), EditorDisplay(\"Code Signing\")") + CodeSigningMode CodeSigning = CodeSigningMode::None; + + /// + /// App code signing provision file path (absolute or relative to the project). + /// + API_FIELD(Attributes="EditorOrder(2050), EditorDisplay(\"Code Signing\")") + String ProvisionFile; + + /// + /// App code signing idenity name (from local Mac keychain). Use 'security find-identity -v -p codesigning' to list possible options. + /// + API_FIELD(Attributes="EditorOrder(2080), EditorDisplay(\"Code Signing\")") + String SignIdenity; +#endif + public: // [SettingsBase] void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override { DESERIALIZE(AppIdentifier); DESERIALIZE(OverrideIcon); +#if USE_EDITOR + DESERIALIZE(CodeSigning); + DESERIALIZE(ProvisionFile); + DESERIALIZE(SignIdenity); +#endif } };