1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-14 00:14:18 +00:00

Introjucer: Added several additional build properties for the Xcode exporter.

This commit is contained in:
Timur Doumler 2016-03-02 17:51:29 +00:00
parent 3f85b04914
commit ca8aef4d3e
2 changed files with 167 additions and 25 deletions

View file

@ -55,6 +55,9 @@ public:
getTargetLocationValue() = getDefaultBuildsRootFolder() + (iOS ? "iOS" : "MacOSX");
initialiseDependencyPathValues();
if (getScreenOrientationValue().toString().isEmpty())
getScreenOrientationValue() = "portraitlandscape";
}
static XCodeProjectExporter* createForSettings (Project& project, const ValueTree& settings)
@ -78,6 +81,25 @@ public:
Value getPreBuildScriptValue() { return getSetting (Ids::prebuildCommand); }
String getPreBuildScript() const { return settings [Ids::prebuildCommand]; }
Value getScreenOrientationValue() { return getSetting (Ids::iosScreenOrientation); }
String getScreenOrientationString() const { return settings [Ids::iosScreenOrientation]; }
Value getCustomResourceFoldersValue() { return getSetting (Ids::customXcodeResourceFolders); }
String getCustomResourceFoldersString() const { return getSettingString (Ids::customXcodeResourceFolders).replaceCharacters ("\r\n", "::"); }
Value getCustomXcassetsFolderValue() { return getSetting (Ids::customXcassetsFolder); }
String getCustomXcassetsFolderString() const { return settings [Ids::customXcassetsFolder]; }
Value getInAppPurchasesValue() { return getSetting (Ids::iosInAppPurchases); }
bool isInAppPurchasesEnabled() const { return settings [Ids::iosInAppPurchases]; }
Value getBackgroundAudioValue() { return getSetting (Ids::iosBackgroundAudio); }
bool isBackgroundAudioEnabled() const { return settings [Ids::iosBackgroundAudio]; }
Value getBackgroundBleValue() { return getSetting (Ids::iosBackgroundBle); }
bool isBackgroundBleEnabled() const { return settings [Ids::iosBackgroundBle]; }
Value getIosDevelopmentTeamIDValue() { return getSetting (Ids::iosDevelopmentTeamID); }
String getIosDevelopmentTeamIDString() const { return settings [Ids::iosDevelopmentTeamID]; }
bool usesMMFiles() const override { return true; }
bool isXcode() const override { return true; }
bool isOSX() const override { return ! iOS; }
@ -85,19 +107,48 @@ public:
void createExporterProperties (PropertyListBuilder& props) override
{
if (projectType.isGUIApplication() && ! iOS)
if (iOS)
{
props.add (new TextPropertyComponent (getSetting ("documentExtensions"), "Document file extensions", 128, false),
"A comma-separated list of file extensions for documents that your app can open. "
"Using a leading '.' is optional, and the extensions are not case-sensitive.");
props.add (new TextPropertyComponent (getCustomXcassetsFolderValue(), "Custom Xcassets folder", 128, false),
"If this field is not empty, your Xcode project will use the custom xcassets folder specified here "
"for the app icons and launchimages, and will ignore the Icon files specified above.");
}
else if (iOS)
props.add (new TextPropertyComponent (getCustomResourceFoldersValue(), "Custom Xcode Resource folders", 8192, true),
"You can specify a list of custom resource folders here (separated by newlines or whitespace). "
"References to these folders will then be added to the Xcode resources. "
"This way you can specify them for OS X and iOS separately, and modify the content of the resource folders "
"without re-saving the Introjucer project.");
if (iOS)
{
static const char* orientations[] = { "Portrait and Landscape", "Portrait", "Landscape", nullptr };
static const char* orientationValues[] = { "portraitlandscape", "portrait", "landscape", nullptr };
props.add (new ChoicePropertyComponent (getScreenOrientationValue(), "Screen orientation",StringArray (orientations), Array<var> (orientationValues)),
"The screen orientations that this app should support");
props.add (new BooleanPropertyComponent (getSetting ("UIFileSharingEnabled"), "File Sharing Enabled", "Enabled"),
"Enable this to expose your app's files to iTunes.");
props.add (new BooleanPropertyComponent (getSetting ("UIStatusBarHidden"), "Status Bar Hidden", "Enabled"),
"Enable this to disable the status bar in your app.");
props.add (new BooleanPropertyComponent (getInAppPurchasesValue(), "In-App purchases capability", "Enabled"),
"Enable this to grant your app the capability for in-app purchases. "
"This option requires that you specify a valid Development Team ID.");
props.add (new BooleanPropertyComponent (getBackgroundAudioValue(), "Audio background capability", "Enabled"),
"Enable this to grant your app the capability to access audio when in background mode.");
props.add (new BooleanPropertyComponent (getBackgroundBleValue(), "Bluetooth MIDI background capability", "Enabled"),
"Enable this to grant your app the capability to connect to Bluetooth LE devices when in background mode.");
}
else if (projectType.isGUIApplication())
{
props.add (new TextPropertyComponent (getSetting ("documentExtensions"), "Document file extensions", 128, false),
"A comma-separated list of file extensions for documents that your app can open. "
"Using a leading '.' is optional, and the extensions are not case-sensitive.");
}
props.add (new TextPropertyComponent (getPListToMergeValue(), "Custom PList", 8192, true),
@ -114,6 +165,14 @@ public:
props.add (new TextPropertyComponent (getPostBuildScriptValue(), "Post-build shell script", 32768, true),
"Some shell-script that will be run after a build completes.");
if (iOS)
{
props.add (new TextPropertyComponent (getIosDevelopmentTeamIDValue(), "Development Team ID", 10, false),
"The Development Team ID to be used for setting up code-signing your iOS app. This is a ten-character "
"string (for example, \"S7B6T5XJ2Q\") that describes the distribution certificate Apple issued to you. "
"You can find this string in the OS X app Keychain Access under \"Certificates\".");
}
}
bool launchProject() override
@ -325,6 +384,7 @@ private:
void createObjects() const
{
addFrameworks();
addCustomResourceFolders();
addMainBuildProduct();
if (xcodeCreatePList)
@ -337,7 +397,14 @@ private:
if (iOS)
{
if (! projectType.isStaticLibrary())
createiOSAssetsFolder();
{
String customXcassetsPath = getCustomXcassetsFolderString();
if (customXcassetsPath.isEmpty())
createXcassetsFolderFromIcons();
else
addCustomResourceFolder (customXcassetsPath, "folder.assetcatalog");
}
}
else
{
@ -662,22 +729,8 @@ private:
// Forcing full screen disables the split screen feature and prevents error ITMS-90475
addPlistDictionaryKeyBool (dict, "UIRequiresFullScreen", true);
static const char* kDefaultiOSOrientationStrings[] =
{
"UIInterfaceOrientationPortrait",
"UIInterfaceOrientationPortraitUpsideDown",
"UIInterfaceOrientationLandscapeLeft",
"UIInterfaceOrientationLandscapeRight",
nullptr
};
StringArray iOSOrientations (kDefaultiOSOrientationStrings);
dict->createNewChildElement ("key")->addTextElement ("UISupportedInterfaceOrientations");
XmlElement* plistStringArray = dict->createNewChildElement ("array");
for (int i = 0; i < iOSOrientations.size(); ++i)
plistStringArray->createNewChildElement ("string")->addTextElement (iOSOrientations[i]);
addIosScreenOrientations (dict);
addIosBackgroundModes (dict);
}
for (int i = 0; i < xcodeExtraPListEntries.size(); ++i)
@ -689,6 +742,36 @@ private:
overwriteFileIfDifferentOrThrow (infoPlistFile, mo);
}
void addIosScreenOrientations (XmlElement* dict) const
{
String screenOrientation = getScreenOrientationString();
StringArray iOSOrientations;
if (screenOrientation.contains ("portrait")) { iOSOrientations.add ("UIInterfaceOrientationPortrait"); }
if (screenOrientation.contains ("landscape")) { iOSOrientations.add ("UIInterfaceOrientationLandscapeLeft"); iOSOrientations.add ("UIInterfaceOrientationLandscapeRight"); }
addArrayToPlist (dict, "UISupportedInterfaceOrientations", iOSOrientations);
}
void addIosBackgroundModes (XmlElement* dict) const
{
StringArray iosBackgroundModes;
if (isBackgroundAudioEnabled()) iosBackgroundModes.add ("audio");
if (isBackgroundBleEnabled()) iosBackgroundModes.add ("bluetooth-central");
addArrayToPlist (dict, "UIBackgroundModes", iosBackgroundModes);
}
static void addArrayToPlist (XmlElement* dict, String arrayKey, const StringArray& arrayElements)
{
dict->createNewChildElement ("key")->addTextElement (arrayKey);
XmlElement* plistStringArray = dict->createNewChildElement ("array");
for (int i = 0; i < arrayElements.size(); ++i)
plistStringArray->createNewChildElement ("string")->addTextElement (arrayElements[i]);
}
void deleteRsrcFiles() const
{
for (DirectoryIterator di (getTargetFolder().getChildFile ("build"), true, "*.rsrc", File::findFiles); di.next();)
@ -981,6 +1064,9 @@ private:
StringArray s (xcodeFrameworks);
s.addTokens (getExtraFrameworksString(), ",;", "\"'");
if (iOS && isInAppPurchasesEnabled())
s.addIfNotAlreadyThere ("StoreKit");
if (project.getConfigFlag ("JUCE_QUICKTIME") == Project::configFlagDisabled)
s.removeString ("QuickTime");
@ -993,6 +1079,31 @@ private:
}
}
void addCustomResourceFolders() const
{
StringArray crf;
crf.addTokens (getCustomResourceFoldersString(), ":", "");
crf.trim();
for (int i = 0; i < crf.size(); ++i)
addCustomResourceFolder (crf[i]);
}
void addCustomResourceFolder (String folderPathRelativeToProjectFolder, const String fileType = "folder") const
{
String folderPath = RelativePath (folderPathRelativeToProjectFolder, RelativePath::projectFolder)
.rebased (projectFolder, getTargetFolder(), RelativePath::buildTargetFolder)
.toUnixStyle();
const String fileRefID (createFileRefID (folderPath));
addFileOrFolderReference (folderPath, "<group>", fileType);
resourceIDs.add (addBuildFile (folderPath, fileRefID, false, false));
resourceFileRefs.add (createFileRefID (folderPath));
}
//==============================================================================
void writeProjectFile (OutputStream& output) const
{
@ -1072,11 +1183,18 @@ private:
sourceTree = "<absolute>";
}
String fileType = getFileType (path);
return addFileOrFolderReference (pathString, sourceTree, fileType);
}
String addFileOrFolderReference (String pathString, String sourceTree, String fileType) const
{
const String fileRefID (createFileRefID (pathString));
ScopedPointer<ValueTree> v (new ValueTree (fileRefID));
v->setProperty ("isa", "PBXFileReference", nullptr);
v->setProperty ("lastKnownFileType", getFileType (path), nullptr);
v->setProperty ("lastKnownFileType", fileType, nullptr);
v->setProperty (Ids::name, pathString.fromLastOccurrenceOf ("/", false, false), nullptr);
v->setProperty ("path", sanitisePath (pathString), nullptr);
v->setProperty ("sourceTree", sourceTree, nullptr);
@ -1332,7 +1450,7 @@ private:
ValueTree* const v = new ValueTree (createID ("__root"));
v->setProperty ("isa", "PBXProject", nullptr);
v->setProperty ("buildConfigurationList", createID ("__projList"), nullptr);
v->setProperty ("attributes", "{ LastUpgradeCheck = 0440; }", nullptr);
v->setProperty ("attributes", getProjectObjectAttributes(), nullptr);
v->setProperty ("compatibilityVersion", "Xcode 3.2", nullptr);
v->setProperty ("hasScannedForEncodings", (int) 0, nullptr);
v->setProperty ("mainGroup", createID ("__mainsourcegroup"), nullptr);
@ -1415,6 +1533,23 @@ private:
return getiOSAssetContents (images);
}
String getProjectObjectAttributes() const
{
String attributes;
attributes << "{ LastUpgradeCheck = 0440; ";
if (iOS && isInAppPurchasesEnabled())
{
attributes << "TargetAttributes = { " << createID ("__target") << " = { ";
attributes << "DevelopmentTeam = " << getIosDevelopmentTeamIDString() << "; ";
attributes << "SystemCapabilities = { com.apple.InAppPurchase = { enabled = 1; }; }; }; };";
}
attributes << "}";
return attributes;
}
//==============================================================================
struct ImageType
{
@ -1502,7 +1637,7 @@ private:
return JSON::toString (var (v));
}
void createiOSAssetsFolder() const
void createXcassetsFolderFromIcons() const
{
const File assets (getTargetFolder().getChildFile (project.getProjectFilenameRoot())
.getChildFile ("Images.xcassets"));

View file

@ -80,6 +80,8 @@ namespace Ids
DECLARE_ID (systemHeaderPath);
DECLARE_ID (libraryPath);
DECLARE_ID (customXcodeFlags);
DECLARE_ID (customXcassetsFolder);
DECLARE_ID (customXcodeResourceFolders);
DECLARE_ID (cppLanguageStandard);
DECLARE_ID (cppLibType);
DECLARE_ID (codeSigningIdentity);
@ -156,6 +158,11 @@ namespace Ids
DECLARE_ID (androidSharedLibraries);
DECLARE_ID (androidNdkPlatformVersion);
DECLARE_ID (androidScreenOrientation);
DECLARE_ID (iosScreenOrientation);
DECLARE_ID (iosInAppPurchases);
DECLARE_ID (iosBackgroundAudio);
DECLARE_ID (iosBackgroundBle);
DECLARE_ID (iosDevelopmentTeamID);
DECLARE_ID (buildToolsVersion);
DECLARE_ID (gradleVersion);
DECLARE_ID (gradleWrapperVersion);