Browse Source

Signing iOS build

Josh Engebretson 10 years ago
parent
commit
34caabce1d

+ 293 - 0
Source/AtomicEditor/Source/Build/BuildIOS.cpp

@@ -0,0 +1,293 @@
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// Please see LICENSE.md in repository root for license information
+// https://github.com/AtomicGameEngine/AtomicGameEngine
+
+#include "AtomicEditor.h"
+#include <Atomic/IO/FileSystem.h>
+#include <Atomic/IO/File.h>
+#include "../AEEditor.h"
+#include "../Project/AEProject.h"
+#include "../Project/ProjectUtils.h"
+
+#include "AEEvents.h"
+
+#include "Subprocess/AESubprocessSystem.h"
+
+#include "BuildIOS.h"
+#include "BuildSystem.h"
+#include "UI/Modal/UIModalOps.h"
+
+
+
+namespace AtomicEditor
+{
+
+BuildIOS::BuildIOS(Context * context) : BuildBase(context)
+{
+
+}
+
+BuildIOS::~BuildIOS()
+{
+
+}
+
+void BuildIOS::Initialize()
+{
+    Editor* editor = GetSubsystem<Editor>();
+    Project* project = editor->GetProject();
+
+    FileSystem* fileSystem = GetSubsystem<FileSystem>();
+
+#ifdef ATOMIC_PLATFORM_WINDOWS
+    String bundleResources = fileSystem->GetProgramDir();
+#else
+    String bundleResources = fileSystem->GetAppBundleResourceFolder();
+#endif
+
+    String projectResources = project->GetResourcePath();
+    String dataFolder = bundleResources + "Data/";
+    String coreDataFolder = bundleResources + "CoreData/";
+
+    AddResourceDir(coreDataFolder);
+    AddResourceDir(dataFolder);
+    AddResourceDir(projectResources);
+
+    BuildResourceEntries();
+
+}
+
+String BuildIOS::GenerateInfoPlist()
+{
+
+    BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
+    IOSBuildSettings settings = buildSystem->GetBuildSettings()->GetIOSSettings();
+
+    String plist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+    plist += "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n";
+    plist += "<plist version=\"1.0\">\n";
+    plist += "<dict>\n";
+
+    plist += "<key>CFBundleDevelopmentRegion</key>\n";
+    plist += "<string>English</string>\n";
+
+    plist += "<key>CFBundleExecutable</key>\n";
+    plist += "<string>AtomicPlayer</string>\n";
+
+    plist += "<key>CFBundleGetInfoString</key>\n";
+    plist += "<string>\"Atomic Player\"</string>\n";
+
+    plist += "<key>CFBundleIconFile</key>\n";
+    plist += "<string></string>\n";
+
+    plist += "<key>CFBundleIdentifier</key>\n";
+    plist.AppendWithFormat("<string>%s</string>\n", settings.package.CString());
+
+    plist += "<key>CFBundleInfoDictionaryVersion</key>\n";
+    plist += "<string>6.0</string>\n";
+
+    plist += "<key>CFBundleLongVersionString</key>\n";
+    plist += "<string></string>\n";
+
+    plist +=  "<key>CFBundleName</key>\n";
+    plist += "<string></string>\n";
+    plist += "<key>CFBundlePackageType</key>\n";
+    plist += "<string>APPL</string>\n";
+    plist += "<key>CFBundleShortVersionString</key>\n";
+    plist += "<string></string>\n";
+    plist += "<key>CFBundleSignature</key>\n";
+    plist += "<string>????</string>\n";
+    plist += "<key>CFBundleVersion</key>\n";
+    plist += "<string></string>\n";
+    plist += "<key>CSResourcesFileMapped</key>\n";
+    plist += "<true/>\n";
+    plist += "<key>LSRequiresCarbon</key>\n";
+    plist += "<true/>\n";
+    plist += "<key>NSHumanReadableCopyright</key>\n";
+    plist += "<string>\"(c) Your Company\"</string>\n";
+    plist += "<key>CFBundleIconFiles</key>\n";
+    plist += "<array>\n";
+    plist += "<string></string>\n";
+    plist += "</array>\n";
+    plist += "</dict>\n";
+    plist += "</plist>\n";
+
+    return plist;
+
+}
+
+String BuildIOS::GenerateEntitlements()
+{
+    BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
+    IOSBuildSettings settings = buildSystem->GetBuildSettings()->GetIOSSettings();
+    String app_identifer = settings.appidPrefix + ".";
+    app_identifer += settings.package;
+
+    String team_identifier = settings.appidPrefix;
+
+    String keychain_access_group = app_identifer;
+
+    String entitlements = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+    entitlements += "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n";
+    entitlements += "<plist version=\"1.0\">\n";
+    entitlements += "<dict>\n";
+    entitlements += "<key>application-identifier</key>\n";
+    entitlements.AppendWithFormat("<string>%s</string>\n", app_identifer.CString());
+    entitlements += "<key>com.apple.developer.team-identifier</key>\n";
+    entitlements.AppendWithFormat("<string>%s</string>\n", team_identifier.CString());
+    entitlements += "<key>get-task-allow</key>\n";
+    entitlements += "<true/>\n";
+    entitlements += "<key>keychain-access-groups</key>\n";
+    entitlements += "<array>\n";
+    entitlements.AppendWithFormat("<string>%s</string>\n", keychain_access_group.CString());
+    entitlements += "</array>\n";
+    entitlements += "</dict>\n";
+    entitlements += "</plist>\n";
+
+    return entitlements;
+}
+
+void BuildIOS::HandleEvent(StringHash eventType, VariantMap& eventData)
+{
+
+    if (eventType == E_SUBPROCESSOUTPUT)
+    {
+
+    }
+
+    if (eventType == E_SUBPROCESSCOMPLETE)
+    {
+        BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
+
+        int code = eventData[SubprocessComplete::P_RETCODE].GetInt();
+
+        if (!code)
+        {
+            // success
+            if (currentBuildPhase_ == ConvertPList)
+            {
+                RunCodeSign();
+            }
+        }
+        else
+        {
+            buildSystem->BuildComplete();
+
+        }
+    }
+}
+
+void BuildIOS::RunConvertPList()
+{
+    SubprocessSystem* subs = GetSubsystem<SubprocessSystem>();
+
+    Vector<String> args = String("-convert binary1 ./AtomicPlayer.app/Info.plist").Split(' ');
+
+    currentBuildPhase_ = ConvertPList;
+    Subprocess* subprocess = subs->Launch("/usr/bin/plutil", args, buildPath_);
+
+    if (!subprocess)
+    {
+        assert(0);
+        // ERROR
+        return;
+    }
+
+    SubscribeToEvent(subprocess, E_SUBPROCESSCOMPLETE, HANDLER(BuildIOS, HandleEvent));
+    SubscribeToEvent(subprocess, E_SUBPROCESSOUTPUT, HANDLER(BuildIOS, HandleEvent));
+
+    UIModalOps* ops = GetSubsystem<UIModalOps>();
+    ops->ShowProgramOutput(subprocess);
+}
+
+void BuildIOS::RunCodeSign()
+{
+    SubprocessSystem* subs = GetSubsystem<SubprocessSystem>();
+
+    Vector<String> args;
+    args.Push("--force");
+    args.Push("--sign");
+    args.Push("iPhone Developer");
+    args.Push("--entitlements");
+    args.Push("./AtomicPlayer.app.xcent");
+    args.Push("./AtomicPlayer.app");
+
+    Poco::Process::Env env;
+    env["CODESIGN_ALLOCATE"] =  "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate";
+
+    currentBuildPhase_ = ConvertPList;
+    Subprocess* subprocess = subs->Launch("/usr/bin/codesign", args, buildPath_, env);
+
+    if (!subprocess)
+    {
+        assert(0);
+        // ERROR
+        return;
+    }
+
+    UIModalOps* ops = GetSubsystem<UIModalOps>();
+    ops->SetProgramOutputSubprocess(subprocess);
+
+    SubscribeToEvent(subprocess, E_SUBPROCESSCOMPLETE, HANDLER(BuildIOS, HandleEvent));
+    SubscribeToEvent(subprocess, E_SUBPROCESSOUTPUT, HANDLER(BuildIOS, HandleEvent));
+
+}
+
+
+
+void BuildIOS::Build(const String& buildPath)
+{
+    buildPath_ = buildPath;
+
+    Initialize();
+
+    FileSystem* fileSystem = GetSubsystem<FileSystem>();
+
+ #ifdef ATOMIC_PLATFORM_WINDOWS
+    String buildSourceDir = fileSystem->GetProgramDir();
+ #else
+    String buildSourceDir = fileSystem->GetAppBundleResourceFolder();
+ #endif
+
+    String buildAppSourceDir = buildSourceDir + "Deployment/IOS/AtomicPlayer.app";
+
+    String buildDestDist = buildPath + "/AtomicPlayer.app";
+
+    fileSystem->CreateDir(buildDestDist);
+
+    String resourcePackagePath = buildDestDist + "/AtomicResources.pak";
+    GenerateResourcePackage(resourcePackagePath);
+
+    fileSystem->Copy(buildAppSourceDir + "/AtomicPlayer", buildDestDist + "/AtomicPlayer");
+    fileSystem->Copy(buildAppSourceDir + "/PkgInfo", buildDestDist + "/PkgInfo");
+
+    BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
+
+    IOSBuildSettings settings = buildSystem->GetBuildSettings()->GetIOSSettings();
+
+    fileSystem->Copy(settings.provisionFile, buildDestDist + "/embedded.mobileprovision");
+
+    String entitlements = GenerateEntitlements();
+    String plist = GenerateInfoPlist();
+
+    File file(context_, buildPath_ + "/AtomicPlayer.app.xcent", FILE_WRITE);
+
+    if (file.IsOpen())
+    {
+        file.Write(entitlements.CString(), entitlements.Length());
+        file.Close();
+    }
+
+    File pfile(context_, buildDestDist + "/Info.plist", FILE_WRITE);
+
+    if (pfile.IsOpen())
+    {
+        pfile.Write(plist.CString(), plist.Length());
+        pfile.Close();
+    }
+
+    RunConvertPList();
+
+}
+
+}

+ 48 - 0
Source/AtomicEditor/Source/Build/BuildIOS.h

@@ -0,0 +1,48 @@
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// Please see LICENSE.md in repository root for license information
+// https://github.com/AtomicGameEngine/AtomicGameEngine
+
+#pragma once
+
+#include "BuildBase.h"
+
+namespace AtomicEditor
+{
+
+class BuildIOS : public BuildBase
+{
+    OBJECT(BuildIOS);
+
+public:
+
+    BuildIOS(Context* context);
+    virtual ~BuildIOS();
+
+    void Build(const String& buildPath);
+
+protected:
+
+    void Initialize();
+
+private:
+
+    void HandleEvent(StringHash eventType, VariantMap& eventData);
+
+    enum BuildPhase
+    {
+        ConvertPList,
+        CodeSign,
+        Deploy,
+    };
+
+    void RunConvertPList();
+    void RunCodeSign();
+
+    String GenerateEntitlements();
+    String GenerateInfoPlist();
+
+    BuildPhase currentBuildPhase_;
+
+};
+
+}

+ 11 - 0
Source/AtomicEditor/Source/Build/BuildSystem.cpp

@@ -12,6 +12,7 @@
 #include "BuildMac.h"
 #include "BuildMac.h"
 #include "BuildWindows.h"
 #include "BuildWindows.h"
 #include "BuildAndroid.h"
 #include "BuildAndroid.h"
+#include "BuildIOS.h"
 #include "BuildWeb.h"
 #include "BuildWeb.h"
 
 
 #include "../AEEvents.h"
 #include "../AEEvents.h"
@@ -65,6 +66,12 @@ void BuildSystem::DoBuildWeb(const String& buildPath)
 
 
 }
 }
 
 
+void BuildSystem::DoBuildIOS(const String& buildPath)
+{
+    currentBuild_ = SharedPtr<BuildBase>(new BuildIOS(context_));
+    currentBuild_->Build(buildPath);
+}
+
 void BuildSystem::LoadBuildSettings(rapidjson::Value::Member* jobject)
 void BuildSystem::LoadBuildSettings(rapidjson::Value::Member* jobject)
 {
 {
     buildSettings_->Load(jobject);
     buildSettings_->Load(jobject);
@@ -107,6 +114,10 @@ void BuildSystem::HandleEditorBuild(StringHash eventType, VariantMap& eventData)
     {
     {
         DoBuildWeb(buildPath);
         DoBuildWeb(buildPath);
     }
     }
+    else if (buildPlatform == "IOS")
+    {
+        DoBuildIOS(buildPath);
+    }
 
 
 }
 }
 
 

+ 1 - 0
Source/AtomicEditor/Source/Build/BuildSystem.h

@@ -35,6 +35,7 @@ private:
     void DoBuildMac(const String& buildPath);
     void DoBuildMac(const String& buildPath);
     void DoBuildWindows(const String& buildPath);
     void DoBuildWindows(const String& buildPath);
     void DoBuildAndroid(const String& buildPath);
     void DoBuildAndroid(const String& buildPath);
+    void DoBuildIOS(const String& buildPath);
     void DoBuildWeb(const String& buildPath);
     void DoBuildWeb(const String& buildPath);
 
 
     SharedPtr<BuildSettings> buildSettings_;
     SharedPtr<BuildSettings> buildSettings_;

+ 7 - 1
Source/AtomicEditor/Source/Subprocess/AESubprocess.cpp

@@ -128,6 +128,12 @@ bool Subprocess::Update(SubprocessSystem* system)
 }
 }
 
 
 bool Subprocess::Launch(const String& command, const Vector<String>& args, const String& initialDirectory)
 bool Subprocess::Launch(const String& command, const Vector<String>& args, const String& initialDirectory)
+{
+    Poco::Process::Env env;
+    return Launch(command, args, initialDirectory, env);
+}
+
+bool Subprocess::Launch(const String& command, const Vector<String>& args, const String& initialDirectory, const Poco::Process::Env& env)
 {
 {
     Poco::Process::Args pargs;
     Poco::Process::Args pargs;
 
 
@@ -138,7 +144,7 @@ bool Subprocess::Launch(const String& command, const Vector<String>& args, const
     std::string pinitialDirectory = initialDirectory.CString();
     std::string pinitialDirectory = initialDirectory.CString();
 
 
     // this can take an ENV as well, may come in useful
     // this can take an ENV as well, may come in useful
-    handle_ = new Poco::ProcessHandle(Poco::Process::launch(pcommand, pargs, pinitialDirectory, &pipeIn_, &pipeOut_, &pipeError_));
+    handle_ = new Poco::ProcessHandle(Poco::Process::launch(pcommand, pargs, pinitialDirectory, &pipeIn_, &pipeOut_, &pipeError_, env));
 
 
     if (!Poco::Process::isRunning(*handle_))
     if (!Poco::Process::isRunning(*handle_))
         return false;
         return false;

+ 1 - 0
Source/AtomicEditor/Source/Subprocess/AESubprocess.h

@@ -52,6 +52,7 @@ private:
 
 
 
 
     bool Launch(const String& command, const Vector<String>& args, const String& initialDirectory = "");
     bool Launch(const String& command, const Vector<String>& args, const String& initialDirectory = "");
+    bool Launch(const String& command, const Vector<String>& args, const String& initialDirectory, const Poco::Process::Env& env);
 
 
     String output_;
     String output_;
     String errorOutput_;
     String errorOutput_;

+ 8 - 1
Source/AtomicEditor/Source/Subprocess/AESubprocessSystem.cpp

@@ -28,10 +28,16 @@ SubprocessSystem::~SubprocessSystem()
 }
 }
 
 
 Subprocess* SubprocessSystem::Launch(const String& command, const Vector<String>& args, const String& initialDirectory)
 Subprocess* SubprocessSystem::Launch(const String& command, const Vector<String>& args, const String& initialDirectory)
+{
+    Poco::Process::Env env;
+    return Launch(command, args, initialDirectory, env);
+}
+
+Subprocess* SubprocessSystem::Launch(const String& command, const Vector<String>& args, const String& initialDirectory, const Poco::Process::Env& env)
 {
 {
     SharedPtr<Subprocess> process(new Subprocess(context_));
     SharedPtr<Subprocess> process(new Subprocess(context_));
 
 
-    if (process->Launch(GetNativePath(command), args, GetNativePath(initialDirectory)))
+    if (process->Launch(GetNativePath(command), args, GetNativePath(initialDirectory), env))
     {
     {
         processes_.Push(process);
         processes_.Push(process);
         return process;
         return process;
@@ -41,6 +47,7 @@ Subprocess* SubprocessSystem::Launch(const String& command, const Vector<String>
 
 
 }
 }
 
 
+
 void SubprocessSystem::HandleUpdate(StringHash eventType, VariantMap& eventData)
 void SubprocessSystem::HandleUpdate(StringHash eventType, VariantMap& eventData)
 {
 {
     Vector<Subprocess*> remove;
     Vector<Subprocess*> remove;

+ 1 - 0
Source/AtomicEditor/Source/Subprocess/AESubprocessSystem.h

@@ -25,6 +25,7 @@ public:
 
 
 
 
     Subprocess* Launch(const String& command, const Vector<String>& args, const String& initialDirectory = "");
     Subprocess* Launch(const String& command, const Vector<String>& args, const String& initialDirectory = "");
+    Subprocess* Launch(const String& command, const Vector<String>& args, const String& initialDirectory, const Poco::Process::Env& env);
 
 
 private:
 private:
 
 

+ 4 - 1
Source/AtomicEditor/Source/UI/Modal/UIBuild.cpp

@@ -58,6 +58,9 @@ UIBuild::UIBuild(Context* context):
         platformIndicator->SetSkinBg(TBIDC("LogoAndroid"));
         platformIndicator->SetSkinBg(TBIDC("LogoAndroid"));
     else if (platform == AE_PLATFORM_HTML5)
     else if (platform == AE_PLATFORM_HTML5)
         platformIndicator->SetSkinBg(TBIDC("LogoHTML5"));
         platformIndicator->SetSkinBg(TBIDC("LogoHTML5"));
+    else if (platform == AE_PLATFORM_IOS)
+        platformIndicator->SetSkinBg(TBIDC("LogoIOS"));
+
 }
 }
 
 
 
 
@@ -116,7 +119,7 @@ bool UIBuild::OnEvent(const TBWidgetEvent &ev)
                 else if (platform == AE_PLATFORM_HTML5)
                 else if (platform == AE_PLATFORM_HTML5)
                     neventData[P_PLATFORM] = "HTML5";
                     neventData[P_PLATFORM] = "HTML5";
                 else if (platform == AE_PLATFORM_IOS)
                 else if (platform == AE_PLATFORM_IOS)
-                    neventData[P_PLATFORM] = "iOS";
+                    neventData[P_PLATFORM] = "IOS";
 
 
                 ops->Hide();
                 ops->Hide();
                 neventData[P_BUILDPATH] = buildPath;
                 neventData[P_BUILDPATH] = buildPath;