Browse Source

Introjucer: Refactored the Android exporters; fixed several bugs in Android Studio exporter and added some missing build properties along the way.

tags/2021-05-28
Timur Doumler 9 years ago
parent
commit
c1be347a3d
16 changed files with 1076 additions and 820 deletions
  1. +5
    -1
      extras/Introjucer/Builds/CodeBlocks/The Introjucer.cbp
  2. +4
    -2
      extras/Introjucer/Builds/MacOSX/The Introjucer.xcodeproj/project.pbxproj
  3. +2
    -1
      extras/Introjucer/Builds/VisualStudio2010/The Introjucer.vcxproj
  4. +4
    -1
      extras/Introjucer/Builds/VisualStudio2010/The Introjucer.vcxproj.filters
  5. +2
    -1
      extras/Introjucer/Builds/VisualStudio2012/The Introjucer.vcxproj
  6. +4
    -1
      extras/Introjucer/Builds/VisualStudio2012/The Introjucer.vcxproj.filters
  7. +2
    -1
      extras/Introjucer/Builds/VisualStudio2013/The Introjucer.vcxproj
  8. +4
    -1
      extras/Introjucer/Builds/VisualStudio2013/The Introjucer.vcxproj.filters
  9. +2
    -1
      extras/Introjucer/Builds/VisualStudio2015/The Introjucer.vcxproj
  10. +4
    -1
      extras/Introjucer/Builds/VisualStudio2015/The Introjucer.vcxproj.filters
  11. +4
    -2
      extras/Introjucer/Introjucer.jucer
  12. +459
    -0
      extras/Introjucer/Source/Project Saving/jucer_ProjectExport_AndroidAnt.h
  13. +101
    -501
      extras/Introjucer/Source/Project Saving/jucer_ProjectExport_AndroidBase.h
  14. +473
    -304
      extras/Introjucer/Source/Project Saving/jucer_ProjectExport_AndroidStudio.h
  15. +2
    -1
      extras/Introjucer/Source/Project Saving/jucer_ProjectExporter.cpp
  16. +4
    -1
      extras/Introjucer/Source/Utility/jucer_PresetIDs.h

+ 5
- 1
extras/Introjucer/Builds/CodeBlocks/The Introjucer.cbp View File

@@ -429,7 +429,7 @@
<Option compile="0"/>
<Option link="0"/>
</Unit>
<Unit filename="../../Source/Project Saving/jucer_ProjectExport_Android.h">
<Unit filename="../../Source/Project Saving/jucer_ProjectExport_AndroidBase.h">
<Option compile="0"/>
<Option link="0"/>
</Unit>
@@ -437,6 +437,10 @@
<Option compile="0"/>
<Option link="0"/>
</Unit>
<Unit filename="../../Source/Project Saving/jucer_ProjectExport_AndroidAnt.h">
<Option compile="0"/>
<Option link="0"/>
</Unit>
<Unit filename="../../Source/Project Saving/jucer_ProjectExport_CodeBlocks.h">
<Option compile="0"/>
<Option link="0"/>


+ 4
- 2
extras/Introjucer/Builds/MacOSX/The Introjucer.xcodeproj/project.pbxproj View File

@@ -85,6 +85,7 @@
045B9C5D21C5C86FED140D81 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_mac_CoreGraphicsHelpers.h"; path = "../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h"; sourceTree = "SOURCE_ROOT"; };
0473C3BCB7A43F710B8EE36C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MACAddress.h"; path = "../../../../modules/juce_core/network/juce_MACAddress.h"; sourceTree = "SOURCE_ROOT"; };
04960EE443D073F4CB7121FB = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ToolbarItemFactory.h"; path = "../../../../modules/juce_gui_basics/widgets/juce_ToolbarItemFactory.h"; sourceTree = "SOURCE_ROOT"; };
049A726AFEC564314777C076 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ProjectExport_AndroidBase.h"; path = "../../Source/Project Saving/jucer_ProjectExport_AndroidBase.h"; sourceTree = "SOURCE_ROOT"; };
04C1267B2BD11A6ECCCA654C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ComponentBooleanProperty.h"; path = "../../Source/ComponentEditor/properties/jucer_ComponentBooleanProperty.h"; sourceTree = "SOURCE_ROOT"; };
04F31392CA58A2A434CFF7FA = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_LowLevelGraphicsPostScriptRenderer.cpp"; path = "../../../../modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp"; sourceTree = "SOURCE_ROOT"; };
04F670E070D31FB66C7DCAEB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_LocalisedStrings.cpp"; path = "../../../../modules/juce_core/text/juce_LocalisedStrings.cpp"; sourceTree = "SOURCE_ROOT"; };
@@ -346,6 +347,7 @@
4D698BF12BCD6B0896BCDF17 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_AutoUpdater.h"; path = "../../Source/Application/jucer_AutoUpdater.h"; sourceTree = "SOURCE_ROOT"; };
4D6F99ED00A4D8683AF313B2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ColourGradient.h"; path = "../../../../modules/juce_graphics/colour/juce_ColourGradient.h"; sourceTree = "SOURCE_ROOT"; };
4D7F53313945ED27A7D16B80 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Result.h"; path = "../../../../modules/juce_core/misc/juce_Result.h"; sourceTree = "SOURCE_ROOT"; };
4DB834787369EBFCFF560F46 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ProjectExport_AndroidAnt.h"; path = "../../Source/Project Saving/jucer_ProjectExport_AndroidAnt.h"; sourceTree = "SOURCE_ROOT"; };
4E191CDCE7565DB726CF7065 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_ComponentOverlayComponent.cpp"; path = "../../Source/ComponentEditor/ui/jucer_ComponentOverlayComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
4E259F36C28F1ACDAB4CC73F = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ModalComponentManager.h"; path = "../../../../modules/juce_gui_basics/components/juce_ModalComponentManager.h"; sourceTree = "SOURCE_ROOT"; };
4E3AE065222C8C87691DF2DE = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_KeyListener.h"; path = "../../../../modules/juce_gui_basics/keyboard/juce_KeyListener.h"; sourceTree = "SOURCE_ROOT"; };
@@ -462,7 +464,6 @@
6DFAF945FC3A7D0689C5CEC8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ArrayAllocationBase.h"; path = "../../../../modules/juce_core/containers/juce_ArrayAllocationBase.h"; sourceTree = "SOURCE_ROOT"; };
6DFDC749FF36D8C27C997B3E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Button.cpp"; path = "../../../../modules/juce_gui_basics/buttons/juce_Button.cpp"; sourceTree = "SOURCE_ROOT"; };
6E6140969908E7619F858740 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_CommonHeaders.h"; path = "../../Source/Application/jucer_CommonHeaders.h"; sourceTree = "SOURCE_ROOT"; };
6E7353DFEA8825B515049ABB = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ProjectExport_Android.h"; path = "../../Source/Project Saving/jucer_ProjectExport_Android.h"; sourceTree = "SOURCE_ROOT"; };
6E815592344CAA798C9848BF = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_WeakReference.h"; path = "../../../../modules/juce_core/memory/juce_WeakReference.h"; sourceTree = "SOURCE_ROOT"; };
6E8B46E33BF7A0DD930A5100 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FileTreeComponent.cpp"; path = "../../../../modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
6EE1847181635ED3C0838A4B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LowLevelGraphicsPostScriptRenderer.h"; path = "../../../../modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.h"; sourceTree = "SOURCE_ROOT"; };
@@ -1086,8 +1087,9 @@
66B49F08C5EC3E4974825FF8,
5432B7B9B2CF2EAEC8B66D5C, ); name = ComponentEditor; sourceTree = "<group>"; };
E345840128627D533DF908AC = {isa = PBXGroup; children = (
6E7353DFEA8825B515049ABB,
049A726AFEC564314777C076,
16385D79A30C6E06EFB46B79,
4DB834787369EBFCFF560F46,
DBE0CDE1B017190ABBFF557C,
05076CDF1511A5F8A8E18F1D,
C8A229ACD244F402C57286CD,


+ 2
- 1
extras/Introjucer/Builds/VisualStudio2010/The Introjucer.vcxproj View File

@@ -1141,8 +1141,9 @@
<ClInclude Include="..\..\Source\ComponentEditor\jucer_ObjectTypes.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Android.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidBase.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidAnt.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_MSVC.h"/>


+ 4
- 1
extras/Introjucer/Builds/VisualStudio2010/The Introjucer.vcxproj.filters View File

@@ -1590,12 +1590,15 @@
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h">
<Filter>The Introjucer\ComponentEditor</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Android.h">
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidBase.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidAnt.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>


+ 2
- 1
extras/Introjucer/Builds/VisualStudio2012/The Introjucer.vcxproj View File

@@ -1147,8 +1147,9 @@
<ClInclude Include="..\..\Source\ComponentEditor\jucer_ObjectTypes.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Android.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidBase.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidAnt.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_MSVC.h"/>


+ 4
- 1
extras/Introjucer/Builds/VisualStudio2012/The Introjucer.vcxproj.filters View File

@@ -1590,12 +1590,15 @@
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h">
<Filter>The Introjucer\ComponentEditor</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Android.h">
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidBase.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidAnt.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>


+ 2
- 1
extras/Introjucer/Builds/VisualStudio2013/The Introjucer.vcxproj View File

@@ -1147,8 +1147,9 @@
<ClInclude Include="..\..\Source\ComponentEditor\jucer_ObjectTypes.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Android.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidBase.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidAnt.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_MSVC.h"/>


+ 4
- 1
extras/Introjucer/Builds/VisualStudio2013/The Introjucer.vcxproj.filters View File

@@ -1590,12 +1590,15 @@
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h">
<Filter>The Introjucer\ComponentEditor</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Android.h">
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidBase.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidAnt.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>


+ 2
- 1
extras/Introjucer/Builds/VisualStudio2015/The Introjucer.vcxproj View File

@@ -1147,8 +1147,9 @@
<ClInclude Include="..\..\Source\ComponentEditor\jucer_ObjectTypes.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Android.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidBase.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidAnt.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_MSVC.h"/>


+ 4
- 1
extras/Introjucer/Builds/VisualStudio2015/The Introjucer.vcxproj.filters View File

@@ -1590,12 +1590,15 @@
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h">
<Filter>The Introjucer\ComponentEditor</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Android.h">
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidBase.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidAnt.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h">
<Filter>The Introjucer\Project Saving</Filter>
</ClInclude>


+ 4
- 2
extras/Introjucer/Introjucer.jucer View File

@@ -364,10 +364,12 @@
file="Source/ComponentEditor/jucer_UtilityFunctions.h"/>
</GROUP>
<GROUP id="{579C9644-D5C2-8469-9439-F91C81337531}" name="Project Saving">
<FILE id="TtXohM" name="jucer_ProjectExport_Android.h" compile="0"
resource="0" file="Source/Project Saving/jucer_ProjectExport_Android.h"/>
<FILE id="TtXohM" name="jucer_ProjectExport_AndroidBase.h" compile="0"
resource="0" file="Source/Project Saving/jucer_ProjectExport_AndroidBase.h"/>
<FILE id="AhU3qX" name="jucer_ProjectExport_AndroidStudio.h" compile="0"
resource="0" file="Source/Project Saving/jucer_ProjectExport_AndroidStudio.h"/>
<FILE id="dfcn8d" name="jucer_ProjectExport_AndroidAnt.h" compile="0"
resource="0" file="Source/Project Saving/jucer_ProjectExport_AndroidAnt.h"/>
<FILE id="EkBkj1" name="jucer_ProjectExport_CodeBlocks.h" compile="0"
resource="0" file="Source/Project Saving/jucer_ProjectExport_CodeBlocks.h"/>
<FILE id="mVXrLi" name="jucer_ProjectExport_Make.h" compile="0" resource="0"


+ 459
- 0
extras/Introjucer/Source/Project Saving/jucer_ProjectExport_AndroidAnt.h View File

@@ -0,0 +1,459 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2016 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
class AndroidAntProjectExporter : public AndroidProjectExporterBase
{
public:
//==============================================================================
bool canLaunchProject() override { return false; }
bool launchProject() override { return false; }
bool isAndroid() const override { return true; }
bool usesMMFiles() const override { return false; }
bool canCopeWithDuplicateFiles() override { return false; }
bool isAndroidStudio() override { return false; }
bool isAndroidAnt() override { return true; }
//==============================================================================
static const char* getName() { return "Android Ant Project"; }
static const char* getValueTreeTypeName() { return "ANDROID"; }
//==============================================================================
Value getNDKToolchainVersionValue() { return getSetting (Ids::toolset); }
String getNDKToolchainVersionString() const { return settings [Ids::toolset]; }
Value getStaticLibrariesValue() { return getSetting (Ids::androidStaticLibraries); }
String getStaticLibrariesString() const { return settings [Ids::androidStaticLibraries]; }
Value getSharedLibrariesValue() { return getSetting (Ids::androidSharedLibraries); }
String getSharedLibrariesString() const { return settings [Ids::androidSharedLibraries]; }
//==============================================================================
static AndroidAntProjectExporter* createForSettings (Project& project, const ValueTree& settings)
{
if (settings.hasType (getValueTreeTypeName()))
return new AndroidAntProjectExporter (project, settings);
return nullptr;
}
//==============================================================================
AndroidAntProjectExporter (Project& p, const ValueTree& t)
: AndroidProjectExporterBase (p, t)
{
name = getName();
if (getTargetLocationString().isEmpty())
getTargetLocationValue() = getDefaultBuildsRootFolder() + "Android";
}
//==============================================================================
void createToolchainExporterProperties (PropertyListBuilder& props) override
{
props.add (new TextPropertyComponent (getNDKToolchainVersionValue(), "NDK Toolchain version", 32, false),
"The variable NDK_TOOLCHAIN_VERSION in Application.mk - leave blank for a default value");
}
void createLibraryModuleExporterProperties (PropertyListBuilder& props) override
{
props.add (new TextPropertyComponent (getStaticLibrariesValue(), "Import static library modules", 8192, true),
"Comma or whitespace delimited list of static libraries (.a) defined in NDK_MODULE_PATH.");
props.add (new TextPropertyComponent (getSharedLibrariesValue(), "Import shared library modules", 8192, true),
"Comma or whitespace delimited list of shared libraries (.so) defined in NDK_MODULE_PATH.");
}
//==============================================================================
void create (const OwnedArray<LibraryModule>& modules) const override
{
AndroidProjectExporterBase::create (modules);
const File target (getTargetFolder());
const File jniFolder (target.getChildFile ("jni"));
createDirectoryOrThrow (jniFolder);
createDirectoryOrThrow (target.getChildFile ("res").getChildFile ("values"));
createDirectoryOrThrow (target.getChildFile ("libs"));
createDirectoryOrThrow (target.getChildFile ("bin"));
{
ScopedPointer<XmlElement> manifest (createManifestXML());
writeXmlOrThrow (*manifest, target.getChildFile ("AndroidManifest.xml"), "utf-8", 100, true);
}
writeApplicationMk (jniFolder.getChildFile ("Application.mk"));
writeAndroidMk (jniFolder.getChildFile ("Android.mk"));
{
ScopedPointer<XmlElement> antBuildXml (createAntBuildXML());
writeXmlOrThrow (*antBuildXml, target.getChildFile ("build.xml"), "UTF-8", 100);
}
writeProjectPropertiesFile (target.getChildFile ("project.properties"));
writeLocalPropertiesFile (target.getChildFile ("local.properties"));
writeStringsFile (target.getChildFile ("res/values/strings.xml"));
writeIcons (target.getChildFile ("res"));
}
//==============================================================================
class AndroidBuildConfiguration : public BuildConfiguration
{
public:
AndroidBuildConfiguration (Project& p, const ValueTree& settings, const ProjectExporter& e)
: BuildConfiguration (p, settings, e)
{
if (getArchitectures().isEmpty())
{
if (isDebug())
getArchitecturesValue() = "armeabi x86";
else
getArchitecturesValue() = "armeabi armeabi-v7a x86";
}
}
Value getArchitecturesValue() { return getValue (Ids::androidArchitectures); }
String getArchitectures() const { return config [Ids::androidArchitectures]; }
var getDefaultOptimisationLevel() const override { return var ((int) (isDebug() ? gccO0 : gccO3)); }
void createConfigProperties (PropertyListBuilder& props) override
{
addGCCOptimisationProperty (props);
props.add (new TextPropertyComponent (getArchitecturesValue(), "Architectures", 256, false),
"A list of the ARM architectures to build (for a fat binary).");
}
};
BuildConfiguration::Ptr createBuildConfig (const ValueTree& v) const override
{
return new AndroidBuildConfiguration (project, v, *this);
}
private:
//==============================================================================
String getToolchainVersion() const
{
String v (getNDKToolchainVersionString());
return v.isNotEmpty() ? v : "4.8";
}
//==============================================================================
String getCppFlags() const
{
String flags ("-fsigned-char -fexceptions -frtti");
if (! getNDKToolchainVersionString().startsWithIgnoreCase ("clang"))
flags << " -Wno-psabi";
return flags;
}
String getAppPlatform() const
{
int ndkVersion = getMinimumSDKVersionString().getIntValue();
if (ndkVersion == 9)
ndkVersion = 10; // (doesn't seem to be a version '9')
return "android-" + String (ndkVersion);
}
void writeApplicationMk (const File& file) const
{
MemoryOutputStream mo;
mo << "# Automatically generated makefile, created by the Introjucer" << newLine
<< "# Don't edit this file! Your changes will be overwritten when you re-save the Introjucer project!" << newLine
<< newLine
<< "APP_STL := gnustl_static" << newLine
<< "APP_CPPFLAGS += " << getCppFlags() << newLine
<< "APP_PLATFORM := " << getAppPlatform() << newLine
<< "NDK_TOOLCHAIN_VERSION := " << getToolchainVersion() << newLine
<< newLine
<< "ifeq ($(NDK_DEBUG),1)" << newLine
<< " APP_ABI := " << getABIs<AndroidBuildConfiguration> (true) << newLine
<< "else" << newLine
<< " APP_ABI := " << getABIs<AndroidBuildConfiguration> (false) << newLine
<< "endif" << newLine;
overwriteFileIfDifferentOrThrow (file, mo);
}
struct ShouldFileBeCompiledPredicate
{
bool operator() (const Project::Item& projectItem) const { return projectItem.shouldBeCompiled(); }
};
void writeAndroidMk (const File& file) const
{
Array<RelativePath> files;
for (int i = 0; i < getAllGroups().size(); ++i)
findAllProjectItemsWithPredicate (getAllGroups().getReference(i), files, ShouldFileBeCompiledPredicate());
MemoryOutputStream mo;
writeAndroidMk (mo, files);
overwriteFileIfDifferentOrThrow (file, mo);
}
void writeAndroidMkVariableList (OutputStream& out, const String& variableName, const String& settingsValue) const
{
const StringArray separatedItems (getCommaOrWhitespaceSeparatedItems (settingsValue));
if (separatedItems.size() > 0)
out << newLine << variableName << " := " << separatedItems.joinIntoString (" ") << newLine;
}
void writeAndroidMk (OutputStream& out, const Array<RelativePath>& files) const
{
out << "# Automatically generated makefile, created by the Introjucer" << newLine
<< "# Don't edit this file! Your changes will be overwritten when you re-save the Introjucer project!" << newLine
<< newLine
<< "LOCAL_PATH := $(call my-dir)" << newLine
<< newLine
<< "include $(CLEAR_VARS)" << newLine
<< newLine
<< "ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)" << newLine
<< " LOCAL_ARM_MODE := arm" << newLine
<< "endif" << newLine
<< newLine
<< "LOCAL_MODULE := juce_jni" << newLine
<< "LOCAL_SRC_FILES := \\" << newLine;
for (int i = 0; i < files.size(); ++i)
out << " " << (files.getReference(i).isAbsolute() ? "" : "../")
<< escapeSpaces (files.getReference(i).toUnixStyle()) << "\\" << newLine;
writeAndroidMkVariableList (out, "LOCAL_STATIC_LIBRARIES", getStaticLibrariesString());
writeAndroidMkVariableList (out, "LOCAL_SHARED_LIBRARIES", getSharedLibrariesString());
out << newLine
<< "ifeq ($(NDK_DEBUG),1)" << newLine;
writeConfigSettings (out, true);
out << "else" << newLine;
writeConfigSettings (out, false);
out << "endif" << newLine
<< newLine
<< "include $(BUILD_SHARED_LIBRARY)" << newLine;
StringArray importModules (getCommaOrWhitespaceSeparatedItems (getStaticLibrariesString()));
importModules.addArray (getCommaOrWhitespaceSeparatedItems (getSharedLibrariesString()));
for (int i = 0; i < importModules.size(); ++i)
out << "$(call import-module," << importModules[i] << ")" << newLine;
}
void writeConfigSettings (OutputStream& out, bool forDebug) const
{
for (ConstConfigIterator config (*this); config.next();)
{
if (config->isDebug() == forDebug)
{
const AndroidBuildConfiguration& androidConfig = dynamic_cast<const AndroidBuildConfiguration&> (*config);
String cppFlags;
cppFlags << createCPPFlags (androidConfig)
<< (" " + replacePreprocessorTokens (androidConfig, getExtraCompilerFlagsString()).trim()).trimEnd()
<< newLine
<< getLDLIBS (androidConfig).trimEnd()
<< newLine;
out << " LOCAL_CPPFLAGS += " << cppFlags;
out << " LOCAL_CFLAGS += " << cppFlags;
break;
}
}
}
String getLDLIBS (const AndroidBuildConfiguration& config) const
{
return " LOCAL_LDLIBS :=" + config.getGCCLibraryPathFlags()
+ " -llog -lGLESv2 -landroid -lEGL" + getExternalLibraryFlags (config)
+ " " + replacePreprocessorTokens (config, getExtraLinkerFlagsString());
}
String createIncludePathFlags (const BuildConfiguration& config) const
{
String flags;
StringArray searchPaths (extraSearchPaths);
searchPaths.addArray (config.getHeaderSearchPaths());
searchPaths = getCleanedStringArray (searchPaths);
for (int i = 0; i < searchPaths.size(); ++i)
flags << " -I " << FileHelpers::unixStylePath (replacePreprocessorTokens (config, searchPaths[i])).quoted();
return flags;
}
String createCPPFlags (const BuildConfiguration& config) const
{
StringPairArray defines;
defines.set ("JUCE_ANDROID", "1");
defines.set ("JUCE_ANDROID_API_VERSION", getMinimumSDKVersionString());
defines.set ("JUCE_ANDROID_ACTIVITY_CLASSNAME", getJNIActivityClassName().replaceCharacter ('/', '_'));
defines.set ("JUCE_ANDROID_ACTIVITY_CLASSPATH", "\\\"" + getJNIActivityClassName() + "\\\"");
String flags ("-fsigned-char -fexceptions -frtti");
if (config.isDebug())
{
flags << " -g";
defines.set ("DEBUG", "1");
defines.set ("_DEBUG", "1");
}
else
{
defines.set ("NDEBUG", "1");
}
flags << createIncludePathFlags (config)
<< " -O" << config.getGCCOptimisationFlag();
flags << " -std=gnu++11";
defines = mergePreprocessorDefs (defines, getAllPreprocessorDefs (config));
return flags + createGCCPreprocessorFlags (defines);
}
//==============================================================================
XmlElement* createAntBuildXML() const
{
XmlElement* proj = new XmlElement ("project");
proj->setAttribute ("name", projectName);
proj->setAttribute ("default", "debug");
proj->createNewChildElement ("loadproperties")->setAttribute ("srcFile", "local.properties");
proj->createNewChildElement ("loadproperties")->setAttribute ("srcFile", "project.properties");
{
XmlElement* target = proj->createNewChildElement ("target");
target->setAttribute ("name", "clean");
target->setAttribute ("depends", "android_rules.clean");
target->createNewChildElement ("delete")->setAttribute ("dir", "libs");
target->createNewChildElement ("delete")->setAttribute ("dir", "obj");
XmlElement* executable = target->createNewChildElement ("exec");
executable->setAttribute ("executable", "${ndk.dir}/ndk-build");
executable->setAttribute ("dir", "${basedir}");
executable->setAttribute ("failonerror", "true");
executable->createNewChildElement ("arg")->setAttribute ("value", "clean");
}
{
XmlElement* target = proj->createNewChildElement ("target");
target->setAttribute ("name", "-pre-build");
addDebugConditionClause (target, "makefileConfig", "Debug", "Release");
addDebugConditionClause (target, "ndkDebugValue", "NDK_DEBUG=1", "NDK_DEBUG=0");
String debugABIs, releaseABIs;
for (ConstConfigIterator config (*this); config.next();)
{
const AndroidBuildConfiguration& androidConfig = dynamic_cast<const AndroidBuildConfiguration&> (*config);
if (config->isDebug())
debugABIs = androidConfig.getArchitectures();
else
releaseABIs = androidConfig.getArchitectures();
}
addDebugConditionClause (target, "app_abis", debugABIs, releaseABIs);
XmlElement* executable = target->createNewChildElement ("exec");
executable->setAttribute ("executable", "${ndk.dir}/ndk-build");
executable->setAttribute ("dir", "${basedir}");
executable->setAttribute ("failonerror", "true");
executable->createNewChildElement ("arg")->setAttribute ("value", "--jobs=4");
executable->createNewChildElement ("arg")->setAttribute ("value", "CONFIG=${makefileConfig}");
executable->createNewChildElement ("arg")->setAttribute ("value", "${ndkDebugValue}");
executable->createNewChildElement ("arg")->setAttribute ("value", "APP_ABI=${app_abis}");
target->createNewChildElement ("delete")->setAttribute ("file", "${out.final.file}");
target->createNewChildElement ("delete")->setAttribute ("file", "${out.packaged.file}");
}
proj->createNewChildElement ("import")->setAttribute ("file", "${sdk.dir}/tools/ant/build.xml");
return proj;
}
void addDebugConditionClause (XmlElement* target, const String& property,
const String& debugValue, const String& releaseValue) const
{
XmlElement* condition = target->createNewChildElement ("condition");
condition->setAttribute ("property", property);
condition->setAttribute ("value", debugValue);
condition->setAttribute ("else", releaseValue);
XmlElement* equals = condition->createNewChildElement ("equals");
equals->setAttribute ("arg1", "${ant.project.invoked-targets}");
equals->setAttribute ("arg2", "debug");
}
void writeProjectPropertiesFile (const File& file) const
{
MemoryOutputStream mo;
mo << "# This file is used to override default values used by the Ant build system." << newLine
<< "# It is automatically generated - DO NOT EDIT IT or your changes will be lost!." << newLine
<< newLine
<< "target=" << getAppPlatform() << newLine
<< newLine;
overwriteFileIfDifferentOrThrow (file, mo);
}
void writeLocalPropertiesFile (const File& file) const
{
MemoryOutputStream mo;
mo << "# This file is used to override default values used by the Ant build system." << newLine
<< "# It is automatically generated by the Introjucer - DO NOT EDIT IT or your changes will be lost!." << newLine
<< newLine
<< "sdk.dir=" << escapeSpaces (replacePreprocessorDefs (getAllPreprocessorDefs(), getSDKPathString())) << newLine
<< "ndk.dir=" << escapeSpaces (replacePreprocessorDefs (getAllPreprocessorDefs(), getNDKPathString())) << newLine
<< "key.store=" << getKeyStoreString() << newLine
<< "key.alias=" << getKeyAliasString() << newLine
<< "key.store.password=" << getKeyStorePassString() << newLine
<< "key.alias.password=" << getKeyAliasPassString() << newLine
<< newLine;
overwriteFileIfDifferentOrThrow (file, mo);
}
void writeStringsFile (const File& file) const
{
XmlElement strings ("resources");
XmlElement* resourceName = strings.createNewChildElement ("string");
resourceName->setAttribute ("name", "app_name");
resourceName->addTextElement (projectName);
writeXmlOrThrow (strings, file, "utf-8", 100);
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE (AndroidAntProjectExporter)
};

extras/Introjucer/Source/Project Saving/jucer_ProjectExport_Android.h → extras/Introjucer/Source/Project Saving/jucer_ProjectExport_AndroidBase.h View File

@@ -25,8 +25,19 @@
class AndroidProjectExporterBase : public ProjectExporter
{
public:
//==========================================================================
AndroidProjectExporterBase (Project& p, const ValueTree& t)
: ProjectExporter (p, t)
{
setEmptyPropertiesToDefaultValues();
}
//==========================================================================
virtual bool isAndroidStudio() = 0;
virtual bool isAndroidAnt() = 0;
//==========================================================================
void setEmptyPropertiesToDefaultValues()
{
if (getVersionCodeString().isEmpty())
getVersionCodeValue() = 1;
@@ -47,7 +58,6 @@ public:
if (getKeyStorePassValue().getValue().isVoid()) getKeyStorePassValue() = "android";
if (getKeyAliasValue().getValue().isVoid()) getKeyAliasValue() = "androiddebugkey";
if (getKeyAliasPassValue().getValue().isVoid()) getKeyAliasPassValue() = "android";
if (getCPP11EnabledValue().getValue().isVoid()) getCPP11EnabledValue() = true;
initialiseDependencyPathValues();
@@ -55,12 +65,7 @@ public:
getScreenOrientationValue() = "unspecified";
}
bool canLaunchProject() override { return false; }
bool launchProject() override { return false; }
bool isAndroid() const override { return true; }
bool usesMMFiles() const override { return false; }
bool canCopeWithDuplicateFiles() override { return false; }
//==========================================================================
void create (const OwnedArray<LibraryModule>& modules) const override
{
const String package (getActivityClassPackage());
@@ -70,9 +75,78 @@ public:
copyActivityJavaFiles (modules, target, package);
}
//==========================================================================
// base properties
Value getScreenOrientationValue() { return getSetting (Ids::androidScreenOrientation); }
String getScreenOrientationString() const { return settings [Ids::androidScreenOrientation]; }
Value getActivityClassPathValue() { return getSetting (Ids::androidActivityClass); }
String getActivityClassPath() const { return settings [Ids::androidActivityClass]; }
Value getActivitySubClassPathValue() { return getSetting (Ids::androidActivitySubClassName); }
String getActivitySubClassPath() const { return settings [Ids::androidActivitySubClassName]; }
Value getVersionCodeValue() { return getSetting (Ids::androidVersionCode); }
String getVersionCodeString() const { return settings [Ids::androidVersionCode]; }
Value getSDKPathValue() { return sdkPath; }
String getSDKPathString() const { return sdkPath.toString(); }
Value getNDKPathValue() { return ndkPath; }
String getNDKPathString() const { return ndkPath.toString(); }
Value getMinimumSDKVersionValue() { return getSetting (Ids::androidMinimumSDK); }
String getMinimumSDKVersionString() const { return settings [Ids::androidMinimumSDK]; }
// manifest properties
Value getInternetNeededValue() { return getSetting (Ids::androidInternetNeeded); }
bool getInternetNeeded() const { return settings [Ids::androidInternetNeeded]; }
Value getAudioRecordNeededValue() { return getSetting (Ids::androidMicNeeded); }
bool getAudioRecordNeeded() const { return settings [Ids::androidMicNeeded]; }
Value getBluetoothPermissionsValue() { return getSetting(Ids::androidBluetoothNeeded); }
bool getBluetoothPermissions() const { return settings[Ids::androidBluetoothNeeded]; }
Value getOtherPermissionsValue() { return getSetting (Ids::androidOtherPermissions); }
String getOtherPermissions() const { return settings [Ids::androidOtherPermissions]; }
// code signing properties
Value getKeyStoreValue() { return getSetting (Ids::androidKeyStore); }
String getKeyStoreString() const { return settings [Ids::androidKeyStore]; }
Value getKeyStorePassValue() { return getSetting (Ids::androidKeyStorePass); }
String getKeyStorePassString() const { return settings [Ids::androidKeyStorePass]; }
Value getKeyAliasValue() { return getSetting (Ids::androidKeyAlias); }
String getKeyAliasString() const { return settings [Ids::androidKeyAlias]; }
Value getKeyAliasPassValue() { return getSetting (Ids::androidKeyAliasPass); }
String getKeyAliasPassString() const { return settings [Ids::androidKeyAliasPass]; }
// other properties
Value getThemeValue() { return getSetting (Ids::androidTheme); }
String getThemeString() const { return settings [Ids::androidTheme]; }
//==========================================================================
void createExporterProperties (PropertyListBuilder& props) override
{
addScreenOrientationProperty (props);
createBaseExporterProperties (props);
createToolchainExporterProperties (props);
createManifestExporterProperties (props);
createLibraryModuleExporterProperties (props);
createCodeSigningExporterProperties (props);
createOtherExporterProperties (props);
}
//==========================================================================
enum ScreenOrientation
{
unspecified = 1,
portrait = 2,
landscape = 3
};
//==============================================================================
void createBaseExporterProperties (PropertyListBuilder& props)
{
static const char* orientations[] = { "Portrait and Landscape", "Portrait", "Landscape", nullptr };
static const char* orientationValues[] = { "unspecified", "portrait", "landscape", nullptr };
props.add (new ChoicePropertyComponent (getScreenOrientationValue(), "Screen orientation", StringArray (orientations), Array<var> (orientationValues)),
"The screen orientation that this app should use");
props.add (new TextPropertyComponent (getActivityClassPathValue(), "Android Activity class name", 256, false),
"The full java class name to use for the app's Activity class.");
@@ -92,13 +166,14 @@ public:
props.add (new TextPropertyComponent (getMinimumSDKVersionValue(), "Minimum SDK version", 32, false),
"The number of the minimum version of the Android SDK that the app requires");
}
props.add (new TextPropertyComponent (getNDKToolchainVersionValue(), "NDK Toolchain version", 32, false),
"The variable NDK_TOOLCHAIN_VERSION in Application.mk - leave blank for a default value");
props.add (new BooleanPropertyComponent (getCPP11EnabledValue(), "Enable C++11 features", "Enable the -std=c++11 flag"),
"If enabled, this will set the -std=c++11 flag for the build.");
//==========================================================================
virtual void createToolchainExporterProperties (PropertyListBuilder& props) = 0; // different for ant and Android Studio
//==========================================================================
void createManifestExporterProperties (PropertyListBuilder& props)
{
props.add (new BooleanPropertyComponent (getInternetNeededValue(), "Internet Access", "Specify internet access permission in the manifest"),
"If enabled, this will set the android.permission.INTERNET flag in the manifest.");
@@ -110,100 +185,34 @@ public:
props.add (new TextPropertyComponent (getOtherPermissionsValue(), "Custom permissions", 2048, false),
"A space-separated list of other permission flags that should be added to the manifest.");
}
props.add (new TextPropertyComponent (getStaticLibrariesValue(), "Import static library modules", 8192, true),
"Comma or whitespace delimited list of static libraries (.a) defined in NDK_MODULE_PATH.");
props.add (new TextPropertyComponent (getSharedLibrariesValue(), "Import shared library modules", 8192, true),
"Comma or whitespace delimited list of shared libraries (.so) defined in NDK_MODULE_PATH.");
props.add (new TextPropertyComponent (getThemeValue(), "Android Theme", 256, false),
"E.g. @android:style/Theme.NoTitleBar or leave blank for default");
//==========================================================================
virtual void createLibraryModuleExporterProperties (PropertyListBuilder& props) = 0; // different for ant and Android Studio
//==========================================================================
void createCodeSigningExporterProperties (PropertyListBuilder& props)
{
props.add (new TextPropertyComponent (getKeyStoreValue(), "Key Signing: key.store", 2048, false),
"The key.store value, used when signing the package.");
props.add (new TextPropertyComponent (getKeyStorePassValue(), "Key Signing: key.store.password", 2048, false),
"The key.store password, used when signing the package.");
props.add (new TextPropertyComponent (getKeyAliasValue(), "Key Signing: key.alias", 2048, false),
"The key.alias value, used when signing the package.");
props.add (new TextPropertyComponent (getKeyAliasPassValue(), "Key Signing: key.alias.password", 2048, false),
"The key.alias password, used when signing the package.");
}
enum ScreenOrientation
//==========================================================================
void createOtherExporterProperties (PropertyListBuilder& props)
{
unspecified = 1,
portrait = 2,
landscape = 3
};
void addScreenOrientationProperty (PropertyListBuilder& props)
{
static const char* orientations[] = { "Unspecified",
"Portrait",
"Landscape",
nullptr };
static const char* orientationValues[] = { "unspecified",
"portrait",
"landscape",
0 };
props.add (new ChoicePropertyComponent (getScreenOrientationValue(),
"Screen orientation",
StringArray (orientations),
Array<var> (orientationValues)),
"The screen orientation that this app should use");
props.add (new TextPropertyComponent (getThemeValue(), "Android Theme", 256, false),
"E.g. @android:style/Theme.NoTitleBar or leave blank for default");
}
Value getActivityClassPathValue() { return getSetting (Ids::androidActivityClass); }
String getActivityClassPath() const { return settings [Ids::androidActivityClass]; }
Value getActivitySubClassPathValue() { return getSetting (Ids::androidActivitySubClassName); }
String getActivitySubClassPath() const { return settings [Ids::androidActivitySubClassName]; }
Value getVersionCodeValue() { return getSetting (Ids::androidVersionCode); }
String getVersionCodeString() const { return settings [Ids::androidVersionCode]; }
Value getSDKPathValue() { return sdkPath; }
String getSDKPathString() const { return sdkPath.toString(); }
Value getNDKPathValue() { return ndkPath; }
String getNDKPathString() const { return ndkPath.toString(); }
Value getNDKToolchainVersionValue() { return getSetting (Ids::toolset); }
String getNDKToolchainVersionString() const { return settings [Ids::toolset]; }
Value getKeyStoreValue() { return getSetting (Ids::androidKeyStore); }
String getKeyStoreString() const { return settings [Ids::androidKeyStore]; }
Value getKeyStorePassValue() { return getSetting (Ids::androidKeyStorePass); }
String getKeyStorePassString() const { return settings [Ids::androidKeyStorePass]; }
Value getKeyAliasValue() { return getSetting (Ids::androidKeyAlias); }
String getKeyAliasString() const { return settings [Ids::androidKeyAlias]; }
Value getKeyAliasPassValue() { return getSetting (Ids::androidKeyAliasPass); }
String getKeyAliasPassString() const { return settings [Ids::androidKeyAliasPass]; }
Value getInternetNeededValue() { return getSetting (Ids::androidInternetNeeded); }
bool getInternetNeeded() const { return settings [Ids::androidInternetNeeded]; }
Value getAudioRecordNeededValue() { return getSetting (Ids::androidMicNeeded); }
bool getAudioRecordNeeded() const { return settings [Ids::androidMicNeeded]; }
Value getBluetoothPermissionsValue() { return getSetting(Ids::androidBluetoothNeeded); }
bool getBluetoothPermissions() const { return settings[Ids::androidBluetoothNeeded]; }
Value getMinimumSDKVersionValue() { return getSetting (Ids::androidMinimumSDK); }
String getMinimumSDKVersionString() const { return settings [Ids::androidMinimumSDK]; }
Value getOtherPermissionsValue() { return getSetting (Ids::androidOtherPermissions); }
String getOtherPermissions() const { return settings [Ids::androidOtherPermissions]; }
Value getThemeValue() { return getSetting (Ids::androidTheme); }
String getThemeString() const { return settings [Ids::androidTheme]; }
Value getStaticLibrariesValue() { return getSetting (Ids::androidStaticLibraries); }
String getStaticLibrariesString() const { return settings [Ids::androidStaticLibraries]; }
Value getSharedLibrariesValue() { return getSetting (Ids::androidSharedLibraries); }
String getSharedLibrariesString() const { return settings [Ids::androidSharedLibraries]; }
Value getCPP11EnabledValue() { return getSetting (Ids::androidCpp11); }
bool isCPP11Enabled() const { return settings [Ids::androidCpp11]; }
Value getScreenOrientationValue() { return getSetting (Ids::androidScreenOrientation); }
String getScreenOrientationString() const { return settings [Ids::androidScreenOrientation]; }
//==============================================================================
String createDefaultClassName() const
{
@@ -309,15 +318,6 @@ public:
}
}
String getAppPlatform() const
{
int ndkVersion = getMinimumSDKVersionString().getIntValue();
if (ndkVersion == 9)
ndkVersion = 10; // (doesn't seem to be a version '9')
return "android-" + String (ndkVersion);
}
String getActivityName() const
{
return getActivityClassPath().fromLastOccurrenceOf (".", false, false);
@@ -349,16 +349,6 @@ public:
return nullptr;
}
String getCppFlags() const
{
String flags ("-fsigned-char -fexceptions -frtti");
if (! getNDKToolchainVersionString().startsWithIgnoreCase ("clang"))
flags << " -Wno-psabi";
return flags;
}
StringArray getPermissionsRequired() const
{
StringArray s;
@@ -514,393 +504,3 @@ public:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidProjectExporterBase)
};
//==============================================================================
//==============================================================================
class AndroidAntProjectExporter : public AndroidProjectExporterBase
{
public:
//==============================================================================
static const char* getName() { return "Android Ant Project"; }
static const char* getValueTreeTypeName() { return "ANDROID"; }
static AndroidAntProjectExporter* createForSettings (Project& project, const ValueTree& settings)
{
if (settings.hasType (getValueTreeTypeName()))
return new AndroidAntProjectExporter (project, settings);
return nullptr;
}
//==============================================================================
AndroidAntProjectExporter (Project& p, const ValueTree& t)
: AndroidProjectExporterBase (p, t)
{
name = getName();
if (getTargetLocationString().isEmpty())
getTargetLocationValue() = getDefaultBuildsRootFolder() + "Android";
}
//==============================================================================
void createExporterProperties (PropertyListBuilder& props) override
{
AndroidProjectExporterBase::createExporterProperties (props);
}
void create (const OwnedArray<LibraryModule>& modules) const override
{
AndroidProjectExporterBase::create (modules);
const File target (getTargetFolder());
const File jniFolder (target.getChildFile ("jni"));
createDirectoryOrThrow (jniFolder);
createDirectoryOrThrow (target.getChildFile ("res").getChildFile ("values"));
createDirectoryOrThrow (target.getChildFile ("libs"));
createDirectoryOrThrow (target.getChildFile ("bin"));
{
ScopedPointer<XmlElement> manifest (createManifestXML());
writeXmlOrThrow (*manifest, target.getChildFile ("AndroidManifest.xml"), "utf-8", 100, true);
}
writeApplicationMk (jniFolder.getChildFile ("Application.mk"));
writeAndroidMk (jniFolder.getChildFile ("Android.mk"));
{
ScopedPointer<XmlElement> antBuildXml (createAntBuildXML());
writeXmlOrThrow (*antBuildXml, target.getChildFile ("build.xml"), "UTF-8", 100);
}
writeProjectPropertiesFile (target.getChildFile ("project.properties"));
writeLocalPropertiesFile (target.getChildFile ("local.properties"));
writeStringsFile (target.getChildFile ("res/values/strings.xml"));
writeIcons (target.getChildFile ("res"));
}
//==============================================================================
class AndroidBuildConfiguration : public BuildConfiguration
{
public:
AndroidBuildConfiguration (Project& p, const ValueTree& settings, const ProjectExporter& e)
: BuildConfiguration (p, settings, e)
{
if (getArchitectures().isEmpty())
{
if (isDebug())
getArchitecturesValue() = "armeabi x86";
else
getArchitecturesValue() = "armeabi armeabi-v7a x86";
}
}
Value getArchitecturesValue() { return getValue (Ids::androidArchitectures); }
String getArchitectures() const { return config [Ids::androidArchitectures]; }
var getDefaultOptimisationLevel() const override { return var ((int) (isDebug() ? gccO0 : gccO3)); }
void createConfigProperties (PropertyListBuilder& props) override
{
addGCCOptimisationProperty (props);
props.add (new TextPropertyComponent (getArchitecturesValue(), "Architectures", 256, false),
"A list of the ARM architectures to build (for a fat binary).");
}
};
BuildConfiguration::Ptr createBuildConfig (const ValueTree& v) const override
{
return new AndroidBuildConfiguration (project, v, *this);
}
private:
//==============================================================================
String getToolchainVersion() const
{
String v (getNDKToolchainVersionString());
return v.isNotEmpty() ? v : "4.8";
}
void writeApplicationMk (const File& file) const
{
MemoryOutputStream mo;
mo << "# Automatically generated makefile, created by the Introjucer" << newLine
<< "# Don't edit this file! Your changes will be overwritten when you re-save the Introjucer project!" << newLine
<< newLine
<< "APP_STL := gnustl_static" << newLine
<< "APP_CPPFLAGS += " << getCppFlags() << newLine
<< "APP_PLATFORM := " << getAppPlatform() << newLine
<< "NDK_TOOLCHAIN_VERSION := " << getToolchainVersion() << newLine
<< newLine
<< "ifeq ($(NDK_DEBUG),1)" << newLine
<< " APP_ABI := " << getABIs<AndroidBuildConfiguration> (true) << newLine
<< "else" << newLine
<< " APP_ABI := " << getABIs<AndroidBuildConfiguration> (false) << newLine
<< "endif" << newLine;
overwriteFileIfDifferentOrThrow (file, mo);
}
struct ShouldFileBeCompiledPredicate
{
bool operator() (const Project::Item& projectItem) const { return projectItem.shouldBeCompiled(); }
};
void writeAndroidMk (const File& file) const
{
Array<RelativePath> files;
for (int i = 0; i < getAllGroups().size(); ++i)
findAllProjectItemsWithPredicate (getAllGroups().getReference(i), files, ShouldFileBeCompiledPredicate());
MemoryOutputStream mo;
writeAndroidMk (mo, files);
overwriteFileIfDifferentOrThrow (file, mo);
}
void writeAndroidMkVariableList (OutputStream& out, const String& variableName, const String& settingsValue) const
{
const StringArray separatedItems (getCommaOrWhitespaceSeparatedItems (settingsValue));
if (separatedItems.size() > 0)
out << newLine << variableName << " := " << separatedItems.joinIntoString (" ") << newLine;
}
void writeAndroidMk (OutputStream& out, const Array<RelativePath>& files) const
{
out << "# Automatically generated makefile, created by the Introjucer" << newLine
<< "# Don't edit this file! Your changes will be overwritten when you re-save the Introjucer project!" << newLine
<< newLine
<< "LOCAL_PATH := $(call my-dir)" << newLine
<< newLine
<< "include $(CLEAR_VARS)" << newLine
<< newLine
<< "ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)" << newLine
<< " LOCAL_ARM_MODE := arm" << newLine
<< "endif" << newLine
<< newLine
<< "LOCAL_MODULE := juce_jni" << newLine
<< "LOCAL_SRC_FILES := \\" << newLine;
for (int i = 0; i < files.size(); ++i)
out << " " << (files.getReference(i).isAbsolute() ? "" : "../")
<< escapeSpaces (files.getReference(i).toUnixStyle()) << "\\" << newLine;
writeAndroidMkVariableList (out, "LOCAL_STATIC_LIBRARIES", getStaticLibrariesString());
writeAndroidMkVariableList (out, "LOCAL_SHARED_LIBRARIES", getSharedLibrariesString());
out << newLine
<< "ifeq ($(NDK_DEBUG),1)" << newLine;
writeConfigSettings (out, true);
out << "else" << newLine;
writeConfigSettings (out, false);
out << "endif" << newLine
<< newLine
<< "include $(BUILD_SHARED_LIBRARY)" << newLine;
StringArray importModules (getCommaOrWhitespaceSeparatedItems (getStaticLibrariesString()));
importModules.addArray (getCommaOrWhitespaceSeparatedItems (getSharedLibrariesString()));
for (int i = 0; i < importModules.size(); ++i)
out << "$(call import-module," << importModules[i] << ")" << newLine;
}
void writeConfigSettings (OutputStream& out, bool forDebug) const
{
for (ConstConfigIterator config (*this); config.next();)
{
if (config->isDebug() == forDebug)
{
const AndroidBuildConfiguration& androidConfig = dynamic_cast<const AndroidBuildConfiguration&> (*config);
String cppFlags;
cppFlags << createCPPFlags (androidConfig)
<< (" " + replacePreprocessorTokens (androidConfig, getExtraCompilerFlagsString()).trim()).trimEnd()
<< newLine
<< getLDLIBS (androidConfig).trimEnd()
<< newLine;
out << " LOCAL_CPPFLAGS += " << cppFlags;
out << " LOCAL_CFLAGS += " << cppFlags;
break;
}
}
}
String getLDLIBS (const AndroidBuildConfiguration& config) const
{
return " LOCAL_LDLIBS :=" + config.getGCCLibraryPathFlags()
+ " -llog -lGLESv2 -landroid -lEGL" + getExternalLibraryFlags (config)
+ " " + replacePreprocessorTokens (config, getExtraLinkerFlagsString());
}
String createIncludePathFlags (const BuildConfiguration& config) const
{
String flags;
StringArray searchPaths (extraSearchPaths);
searchPaths.addArray (config.getHeaderSearchPaths());
searchPaths = getCleanedStringArray (searchPaths);
for (int i = 0; i < searchPaths.size(); ++i)
flags << " -I " << FileHelpers::unixStylePath (replacePreprocessorTokens (config, searchPaths[i])).quoted();
return flags;
}
String createCPPFlags (const BuildConfiguration& config) const
{
StringPairArray defines;
defines.set ("JUCE_ANDROID", "1");
defines.set ("JUCE_ANDROID_API_VERSION", getMinimumSDKVersionString());
defines.set ("JUCE_ANDROID_ACTIVITY_CLASSNAME", getJNIActivityClassName().replaceCharacter ('/', '_'));
defines.set ("JUCE_ANDROID_ACTIVITY_CLASSPATH", "\\\"" + getJNIActivityClassName() + "\\\"");
String flags ("-fsigned-char -fexceptions -frtti");
if (config.isDebug())
{
flags << " -g";
defines.set ("DEBUG", "1");
defines.set ("_DEBUG", "1");
}
else
{
defines.set ("NDEBUG", "1");
}
flags << createIncludePathFlags (config)
<< " -O" << config.getGCCOptimisationFlag();
if (isCPP11Enabled())
flags << " -std=c++11 -std=gnu++11"; // these flags seem to enable slightly different things on gcc, and both seem to be needed
defines = mergePreprocessorDefs (defines, getAllPreprocessorDefs (config));
return flags + createGCCPreprocessorFlags (defines);
}
//==============================================================================
XmlElement* createAntBuildXML() const
{
XmlElement* proj = new XmlElement ("project");
proj->setAttribute ("name", projectName);
proj->setAttribute ("default", "debug");
proj->createNewChildElement ("loadproperties")->setAttribute ("srcFile", "local.properties");
proj->createNewChildElement ("loadproperties")->setAttribute ("srcFile", "project.properties");
{
XmlElement* target = proj->createNewChildElement ("target");
target->setAttribute ("name", "clean");
target->setAttribute ("depends", "android_rules.clean");
target->createNewChildElement ("delete")->setAttribute ("dir", "libs");
target->createNewChildElement ("delete")->setAttribute ("dir", "obj");
XmlElement* executable = target->createNewChildElement ("exec");
executable->setAttribute ("executable", "${ndk.dir}/ndk-build");
executable->setAttribute ("dir", "${basedir}");
executable->setAttribute ("failonerror", "true");
executable->createNewChildElement ("arg")->setAttribute ("value", "clean");
}
{
XmlElement* target = proj->createNewChildElement ("target");
target->setAttribute ("name", "-pre-build");
addDebugConditionClause (target, "makefileConfig", "Debug", "Release");
addDebugConditionClause (target, "ndkDebugValue", "NDK_DEBUG=1", "NDK_DEBUG=0");
String debugABIs, releaseABIs;
for (ConstConfigIterator config (*this); config.next();)
{
const AndroidBuildConfiguration& androidConfig = dynamic_cast<const AndroidBuildConfiguration&> (*config);
if (config->isDebug())
debugABIs = androidConfig.getArchitectures();
else
releaseABIs = androidConfig.getArchitectures();
}
addDebugConditionClause (target, "app_abis", debugABIs, releaseABIs);
XmlElement* executable = target->createNewChildElement ("exec");
executable->setAttribute ("executable", "${ndk.dir}/ndk-build");
executable->setAttribute ("dir", "${basedir}");
executable->setAttribute ("failonerror", "true");
executable->createNewChildElement ("arg")->setAttribute ("value", "--jobs=4");
executable->createNewChildElement ("arg")->setAttribute ("value", "CONFIG=${makefileConfig}");
executable->createNewChildElement ("arg")->setAttribute ("value", "${ndkDebugValue}");
executable->createNewChildElement ("arg")->setAttribute ("value", "APP_ABI=${app_abis}");
target->createNewChildElement ("delete")->setAttribute ("file", "${out.final.file}");
target->createNewChildElement ("delete")->setAttribute ("file", "${out.packaged.file}");
}
proj->createNewChildElement ("import")->setAttribute ("file", "${sdk.dir}/tools/ant/build.xml");
return proj;
}
void addDebugConditionClause (XmlElement* target, const String& property,
const String& debugValue, const String& releaseValue) const
{
XmlElement* condition = target->createNewChildElement ("condition");
condition->setAttribute ("property", property);
condition->setAttribute ("value", debugValue);
condition->setAttribute ("else", releaseValue);
XmlElement* equals = condition->createNewChildElement ("equals");
equals->setAttribute ("arg1", "${ant.project.invoked-targets}");
equals->setAttribute ("arg2", "debug");
}
void writeProjectPropertiesFile (const File& file) const
{
MemoryOutputStream mo;
mo << "# This file is used to override default values used by the Ant build system." << newLine
<< "# It is automatically generated - DO NOT EDIT IT or your changes will be lost!." << newLine
<< newLine
<< "target=" << getAppPlatform() << newLine
<< newLine;
overwriteFileIfDifferentOrThrow (file, mo);
}
void writeLocalPropertiesFile (const File& file) const
{
MemoryOutputStream mo;
mo << "# This file is used to override default values used by the Ant build system." << newLine
<< "# It is automatically generated by the Introjucer - DO NOT EDIT IT or your changes will be lost!." << newLine
<< newLine
<< "sdk.dir=" << escapeSpaces (replacePreprocessorDefs (getAllPreprocessorDefs(), getSDKPathString())) << newLine
<< "ndk.dir=" << escapeSpaces (replacePreprocessorDefs (getAllPreprocessorDefs(), getNDKPathString())) << newLine
<< "key.store=" << getKeyStoreString() << newLine
<< "key.alias=" << getKeyAliasString() << newLine
<< "key.store.password=" << getKeyStorePassString() << newLine
<< "key.alias.password=" << getKeyAliasPassString() << newLine
<< newLine;
overwriteFileIfDifferentOrThrow (file, mo);
}
void writeStringsFile (const File& file) const
{
XmlElement strings ("resources");
XmlElement* resourceName = strings.createNewChildElement ("string");
resourceName->setAttribute ("name", "app_name");
resourceName->addTextElement (projectName);
writeXmlOrThrow (strings, file, "utf-8", 100);
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE (AndroidAntProjectExporter)
};

+ 473
- 304
extras/Introjucer/Source/Project Saving/jucer_ProjectExport_AndroidStudio.h View File

@@ -25,7 +25,13 @@
class AndroidStudioProjectExporter : public AndroidProjectExporterBase
{
public:
//==============================================================================
//==========================================================================
bool isAndroid() const override { return true; }
bool usesMMFiles() const override { return false; }
bool canCopeWithDuplicateFiles() override { return false; }
bool isAndroidStudio() override { return true; }
bool isAndroidAnt() override { return false; }
static const char* getName() { return "Android Studio"; }
static const char* getValueTreeTypeName() { return "ANDROIDSTUDIO"; }
@@ -37,15 +43,69 @@ public:
return nullptr;
}
//==============================================================================
Value getGradleVersionValue() { return getSetting (Ids::gradleVersion); }
String getGradleVersionString() const { return settings [Ids::gradleVersion]; }
Value getGradleWrapperVersionValue() { return getSetting (Ids::gradleWrapperVersion); }
String getGradleWrapperVersionString() const { return settings [Ids::gradleWrapperVersion]; }
Value getGradleToolchainValue() { return getSetting (Ids::gradleToolchain); }
String getGradleToolchainString() const { return settings [Ids::gradleToolchain]; }
Value getGradleToolchainVersionValue() { return getSetting (Ids::gradleToolchainVersion); }
String getGradleToolchainVersionString() const { return settings [Ids::gradleToolchainVersion]; }
//==============================================================================
AndroidStudioProjectExporter (Project& p, const ValueTree& t)
: AndroidProjectExporterBase (p, t),
androidStudioExecutable (findAndroidStudioExecutable())
{
name = getName();
setEmptyPropertiesToDefaultValues();
}
//==============================================================================
void setEmptyPropertiesToDefaultValues()
{
if (getTargetLocationString().isEmpty())
getTargetLocationValue() = getDefaultBuildsRootFolder() + "AndroidStudio";
if (getGradleVersionString().isEmpty())
getGradleVersionValue() = "2.10";
if (getGradleWrapperVersionString().isEmpty())
getGradleWrapperVersionValue() = "0.6.0-beta5";
if (getGradleToolchainString().isEmpty())
getGradleToolchainValue() = "clang";
if (getGradleToolchainVersionString().isEmpty())
getGradleToolchainVersionValue() = getGradleToolchainValue() == "clang" ? "3.6" : "4.9";
if (getBuildToolsVersionString().isEmpty())
getBuildToolsVersionValue() = "23.0.1";
}
//==============================================================================
void createToolchainExporterProperties (PropertyListBuilder& props) override
{
props.add (new TextPropertyComponent (getGradleVersionValue(), "gradle version", 32, false),
"The version of gradle that Android Studio should use to build this app");
props.add (new TextPropertyComponent (getGradleWrapperVersionValue(), "gradle-experimental wrapper version", 32, false),
"The version of the gradle-experimental wrapper that Android Studio should use to build this app");
static const char* toolchains[] = { "clang", "gcc", nullptr };
props.add (new ChoicePropertyComponent (getGradleToolchainValue(), "NDK Toolchain", StringArray (toolchains), Array<var> (toolchains)),
"The toolchain that gradle should invoke for NDK compilation (variable model.android.ndk.tooclhain in app/build.gradle)");
props.add (new TextPropertyComponent (getGradleToolchainVersionValue(), "NDK Toolchain version", 32, false),
"The version number of the toolchainthat gradle should invoke for NDK compilation (variable model.android.ndk.tooclhainVersion in app/build.gradle)");
}
void createLibraryModuleExporterProperties (PropertyListBuilder&) override
{
// gradle cannot do native library modules as far as we know...
}
//==============================================================================
@@ -69,33 +129,13 @@ public:
return androidStudioExecutable.startAsProcess ("\"" + targetFolder.getFullPathName() + "\"");
}
void createExporterProperties (PropertyListBuilder& props) override
{
AndroidProjectExporterBase::createExporterProperties (props);
props.add (new TextPropertyComponent (getNDKPlatformVersionValue(), "NDK Platform Version", 32, false),
"The value to use for android$user.ndk.platformVersion in Gradle");
props.add (new TextPropertyComponent (getBuildToolsVersionValue(), "Build Tools Version", 32, false),
"The version of build tools use for build tools in Gradle");
}
Value getNDKPlatformVersionValue() { return getSetting (Ids::androidNdkPlatformVersion); }
String getNDKPlatformVersionString() const { return settings [Ids::androidNdkPlatformVersion]; }
Value getBuildToolsVersionValue() { return getSetting (Ids::buildToolsVersion); }
String getBuildToolsVersionString() const { return settings [Ids::buildToolsVersion]; }
void removeOldFiles (const File& targetFolder) const
{
targetFolder.getChildFile ("app/src").deleteRecursively();
targetFolder.getChildFile ("app/build").deleteRecursively();
targetFolder.getChildFile ("app/build.gradle").deleteFile();
targetFolder.getChildFile ("gradle").deleteRecursively();
targetFolder.getChildFile ("local.properties").deleteFile();
targetFolder.getChildFile ("settings.gradle").deleteFile();
}
//==========================================================================
void create (const OwnedArray<LibraryModule>& modules) const override
{
const File targetFolder (getTargetFolder());
@@ -110,18 +150,36 @@ public:
copyActivityJavaFiles (modules, javaTarget, package);
}
writeSettingsDotGradle (targetFolder);
writeLocalDotProperties (targetFolder);
writeBuildDotGradleRoot (targetFolder);
writeBuildDotGradleApp (targetFolder);
writeGradleWrapperProperties (targetFolder);
writeAndroidManifest (targetFolder);
writeStringsXML (targetFolder);
writeAppIcons (targetFolder);
writeFile (targetFolder, "settings.gradle", getSettingsGradleFileContent());
writeFile (targetFolder, "build.gradle", getProjectBuildGradleFileContent());
writeFile (targetFolder, "app/build.gradle", getAppBuildGradleFileContent());
writeFile (targetFolder, "local.properties", getLocalPropertiesFileContent());
writeFile (targetFolder, "gradle/wrapper/gradle-wrapper.properties", getGradleWrapperPropertiesFileContent());
createSourceSymlinks (targetFolder);
writeAndroidManifest (targetFolder);
writeStringsXML (targetFolder);
writeAppIcons (targetFolder);
createSourceSymlinks (targetFolder);
}
void removeOldFiles (const File& targetFolder) const
{
targetFolder.getChildFile ("app/src").deleteRecursively();
targetFolder.getChildFile ("app/build").deleteRecursively();
targetFolder.getChildFile ("app/build.gradle").deleteFile();
targetFolder.getChildFile ("gradle").deleteRecursively();
targetFolder.getChildFile ("local.properties").deleteFile();
targetFolder.getChildFile ("settings.gradle").deleteFile();
}
void writeFile (const File& gradleProjectFolder, const String& filePath, const String& fileContent) const
{
MemoryOutputStream outStream;
outStream << fileContent;
overwriteFileIfDifferentOrThrow (gradleProjectFolder.getChildFile (filePath), outStream);
}
//==========================================================================
static File findAndroidStudioExecutable()
{
#if JUCE_WINDOWS
@@ -190,12 +248,12 @@ protected:
}
private:
static void createSymboicLinkAndCreateParentFolders (const File& originalFile, const File& linkFile)
static void createSymlinkAndParentFolders (const File& originalFile, const File& linkFile)
{
{
const File linkFileParentDirectory (linkFile.getParentDirectory());
// this will recursively creative the parent directories for the file
// this will recursively creative the parent directories for the file.
// without this, the symlink would fail because it doesn't automatically create
// the folders if they don't exist
if (! linkFileParentDirectory.createDirectory())
@@ -228,7 +286,7 @@ private:
const File originalFile (projectItem.getFile());
const File targetFile (targetFolder.getChildFile (originalFile.getFileName()));
createSymboicLinkAndCreateParentFolders (originalFile, targetFile);
createSymlinkAndParentFolders (originalFile, targetFile);
}
}
}
@@ -259,15 +317,6 @@ private:
writeIcons (folder.getChildFile ("app/src/main/res/"));
}
void writeSettingsDotGradle (const File& folder) const
{
MemoryOutputStream memoryOutputStream;
memoryOutputStream << "include ':app'";
overwriteFileIfDifferentOrThrow (folder.getChildFile ("settings.gradle"), memoryOutputStream);
}
static String sanitisePath (String path)
{
return expandHomeFolderToken (path).replace ("\\", "\\\\");
@@ -281,327 +330,449 @@ private:
.replace ("~", homeFolder);
}
void writeLocalDotProperties (const File& folder) const
//==========================================================================
struct GradleElement
{
MemoryOutputStream memoryOutputStream;
virtual ~GradleElement() {}
String toString() const { return toStringIndented (0); }
virtual String toStringIndented (int indentLevel) const = 0;
memoryOutputStream << "ndk.dir=" << sanitisePath (getNDKPathString()) << newLine
<< "sdk.dir=" << sanitisePath (getSDKPathString());
static String indent (int indentLevel) { return String::repeatedString (" ", indentLevel); }
};
overwriteFileIfDifferentOrThrow (folder.getChildFile ("local.properties"), memoryOutputStream);
}
//==========================================================================
struct GradleStatement : public GradleElement
{
GradleStatement (const String& s) : statement (s) {}
String toStringIndented (int indentLevel) const override { return indent (indentLevel) + statement; }
String statement;
};
//==========================================================================
struct GradleCppFlag : public GradleStatement
{
GradleCppFlag (const String& flag)
: GradleStatement ("cppFlags.add(" + flag.quoted() + ")") {}
};
void writeGradleWrapperProperties (const File& folder) const
struct GradlePreprocessorDefine : public GradleStatement
{
MemoryOutputStream memoryOutputStream;
GradlePreprocessorDefine (const String& define, const String& value)
: GradleStatement ("cppFlags.add(\"-D" + define + "=" + value + "\")") {}
};
memoryOutputStream << "distributionUrl=https\\://services.gradle.org/distributions/gradle-2.10-all.zip";
struct GradleHeaderIncludePath : public GradleStatement
{
GradleHeaderIncludePath (const String& path)
: GradleStatement ("cppFlags.add(\"-I" + sanitisePath (path) + "\".toString())") {}
};
overwriteFileIfDifferentOrThrow (folder.getChildFile ("gradle/wrapper/gradle-wrapper.properties"), memoryOutputStream);
}
struct GradleLibrarySearchPath : public GradleStatement
{
GradleLibrarySearchPath (const String& path)
: GradleStatement ("cppFlags.add(\"-L" + sanitisePath (path) + "\".toString())") {}
};
void writeBuildDotGradleRoot (const File& folder) const
struct GradleLinkerFlag : public GradleStatement
{
MemoryOutputStream memoryOutputStream;
GradleLinkerFlag (const String& flag)
: GradleStatement ("ldFlags.add(" + flag.quoted() + "\")") {}
};
const String indent = getIndentationString();
struct GradleLinkLibrary : public GradleStatement
{
GradleLinkLibrary (const String& lib)
: GradleStatement ("ldLibs.add(" + lib.quoted() + ")") {}
};
// this is needed to make sure the correct version of the gradle build tools is available.
// needs to be kept up to date!
memoryOutputStream << "buildscript {" << newLine
<< indent << "repositories {" << newLine
<< indent << indent << "jcenter()" << newLine
<< indent << "}" << newLine
<< indent << "dependencies {" << newLine
<< indent << indent << "classpath 'com.android.tools.build:gradle-experimental:0.6.0-beta5'" << newLine
<< indent << "}" << newLine
<< "}" << newLine
<< newLine
<< "allprojects {" << newLine
<< indent << "repositories {" << newLine
<< indent << indent << "jcenter()" << newLine
<< indent << "}" << newLine
<< "}";
//==========================================================================
struct GradleValue : public GradleElement
{
template <typename ValueType>
GradleValue (const String& k, const ValueType& v)
: key (k), value (v) {}
overwriteFileIfDifferentOrThrow (folder.getChildFile ("build.gradle"), memoryOutputStream);
}
GradleValue (const String& k, bool boolValue)
: key (k), value (boolValue ? "true" : "false") {}
void writeStringsXML (const File& folder) const
String toStringIndented (int indentLevel) const override
{
return indent (indentLevel) + key + " = " + value;
}
protected:
String key, value;
};
struct GradleString : public GradleValue
{
XmlElement strings ("resources");
XmlElement* resourceName = strings.createNewChildElement ("string");
GradleString (const String& k, const String& str)
: GradleValue (k, str.quoted())
{
if (str.containsAnyOf ("${\"\'"))
value += ".toString()";
}
};
resourceName->setAttribute ("name", "app_name");
resourceName->addTextElement (projectName);
struct GradleFilePath : public GradleValue
{
GradleFilePath (const String& k, const String& path)
: GradleValue (k, "new File(\"" + sanitisePath (path) + "\")") {}
};
writeXmlOrThrow (strings, folder.getChildFile ("app/src/main/res/values/string.xml"), "utf-8", 100, true);
//==========================================================================
struct GradleObject : public GradleElement
{
GradleObject (const String& nm) : name (nm) {}
template <typename GradleType, typename... Args>
void add (Args... args)
{
children.add (new GradleType (std::forward<Args> (args)...));
}
void addChildObject (GradleObject* objectToAdd) noexcept
{
children.add (objectToAdd);
}
String toStringIndented (int indentLevel) const override
{
String result;
result << indent (indentLevel) << name << " {" << newLine;
for (const auto& child : children)
result << child->toStringIndented (indentLevel + 1) << newLine;
result << indent (indentLevel) << "}";
if (indentLevel == 0)
result << newLine;
return result;
}
private:
String name;
OwnedArray<GradleElement> children;
};
//==========================================================================
String getSettingsGradleFileContent() const
{
return "include ':app'";
}
void writeAndroidManifest (const File& folder) const
String getProjectBuildGradleFileContent() const
{
ScopedPointer<XmlElement> manifest (createManifestXML());
String projectBuildGradle;
projectBuildGradle << getGradleBuildScript();
projectBuildGradle << getGradleAllProjects();
writeXmlOrThrow (*manifest, folder.getChildFile ("app/src/main/AndroidManifest.xml"), "utf-8", 100, true);
return projectBuildGradle;
}
String createModelDotAndroid (const String& indent,
const String& minimumSDKVersion,
const String& buildToolsVersion,
const String& bundleIdentifier) const
//==========================================================================
String getGradleBuildScript() const
{
String result;
GradleObject buildScript ("buildscript");
result << "android {" << newLine
<< indent << "compileSdkVersion = " << minimumSDKVersion << newLine
<< indent << "buildToolsVersion = \"" << buildToolsVersion << "\"" << newLine
<< indent << "defaultConfig.with {" << newLine
<< indent << indent << "applicationId = \"" << bundleIdentifier.toLowerCase() << "\"" << newLine
<< indent << indent << "minSdkVersion.apiLevel = " << minimumSDKVersion << newLine
<< indent << indent << "targetSdkVersion.apiLevel = " << minimumSDKVersion << newLine
<< indent << "}" << newLine
<< "}" << newLine;
buildScript.addChildObject (getGradleRepositories());
buildScript.addChildObject (getGradleDependencies());
return result;
return buildScript.toString();
}
String createModelDotAndroidSources (const String& indent) const
GradleObject* getGradleRepositories() const
{
String result;
auto repositories = new GradleObject ("repositories");
repositories->add<GradleStatement> ("jcenter()");
return repositories;
}
result << "android.sources {" << newLine
<< indent << "main {" << newLine
<< indent << indent << "jni {" << newLine
<< indent << indent << indent << "source {" << newLine
<< indent << indent << indent << indent << "exclude \"**/JuceModules/\"" << newLine
<< indent << indent << indent << "}" << newLine
<< indent << indent << "}" << newLine
<< indent << "}" << newLine
<< "}" << newLine;
GradleObject* getGradleDependencies() const
{
auto dependencies = new GradleObject ("dependencies");
return result;
dependencies->add<GradleStatement> ("classpath 'com.android.tools.build:gradle-experimental:"
+ getGradleWrapperVersionString() + "'");
return dependencies;
}
struct ShouldBeAddedToProjectPredicate
String getGradleAllProjects() const
{
bool operator() (const Project::Item& projectItem) const { return projectItem.shouldBeAddedToTargetProject(); }
};
GradleObject allProjects ("allprojects");
allProjects.addChildObject (getGradleRepositories());
return allProjects.toString();
}
StringArray getCPPFlags() const
//==========================================================================
String getAppBuildGradleFileContent() const
{
StringArray result;
String appBuildGradle;
result.add ("\"-fsigned-char\"");
result.add ("\"-fexceptions\"");
result.add ("\"-frtti\"");
appBuildGradle << "apply plugin: 'com.android.model.application'" << newLine;
appBuildGradle << getAndroidModel();
appBuildGradle << getAppDependencies();
if (isCPP11Enabled())
result.add ("\"-std=c++11\"");
return appBuildGradle;
}
StringArray extraFlags (StringArray::fromTokens (getExtraCompilerFlagsString(), " ", ""));
String getAndroidModel() const
{
GradleObject model ("model");
for (int i = 0; i < extraFlags.size(); ++i)
result.add (String ("\"") + extraFlags[i] + "\"");
model.addChildObject (getAndroidObject());
model.addChildObject (getAndroidNdkSettings());
model.addChildObject (getAndroidSources());
model.addChildObject (getAndroidBuildConfigs());
model.addChildObject (getAndroidSigningConfigs());
model.addChildObject (getAndroidProductFlavours());
// include paths
return model.toString();
}
result.add ("\"-I${project.rootDir}/app\".toString()");
result.add ("\"-I${ext.juceRootDir}\".toString()");
result.add ("\"-I${ext.juceModuleDir}\".toString()");
String getAppDependencies() const
{
GradleObject dependencies ("dependencies");
dependencies.add<GradleStatement> ("compile \"com.android.support:support-v4:+\"");
return dependencies.toString();
}
{
Array<RelativePath> cppFiles;
const Array<Project::Item>& groups = getAllGroups();
//==========================================================================
GradleObject* getAndroidObject() const
{
auto android = new GradleObject ("android");
for (int i = 0; i < groups.size(); ++i)
findAllProjectItemsWithPredicate (groups.getReference (i), cppFiles, ShouldBeAddedToProjectPredicate());
android->add<GradleValue> ("compileSdkVersion", getMinimumSDKVersionString().getIntValue());
android->add<GradleString> ("buildToolsVersion", getBuildToolsVersionString());
android->addChildObject (getAndroidDefaultConfig());
for (int i = 0; i < cppFiles.size(); ++i)
{
const RelativePath absoluteSourceFile (cppFiles.getReference (i).rebased (getTargetFolder(),
project.getProjectFolder(),
RelativePath::projectFolder));
return android;
}
const String absoluteIncludeFolder (sanitisePath (project.getProjectFolder().getFullPathName() + "/"
+ absoluteSourceFile.toUnixStyle().upToLastOccurrenceOf ("/", false, false)));
GradleObject* getAndroidDefaultConfig() const
{
const String bundleIdentifier = project.getBundleIdentifier().toString().toLowerCase();
const int minSdkVersion = getMinimumSDKVersionString().getIntValue();
result.addIfNotAlreadyThere ("\"-I" + absoluteIncludeFolder + "\".toString()");
}
}
auto defaultConfig = new GradleObject ("defaultConfig.with");
defaultConfig->add<GradleString> ("applicationId", bundleIdentifier);
defaultConfig->add<GradleValue> ("minSdkVersion.apiLevel", minSdkVersion);
defaultConfig->add<GradleValue> ("targetSdkVersion.apiLevel", minSdkVersion);
return result;
return defaultConfig;
}
StringArray getLDLibs() const
GradleObject* getAndroidNdkSettings() const
{
StringArray result;
const String toolchain = getGradleToolchainString();
const String toolchainVersion = getGradleToolchainVersionString();
const bool isClang = (toolchain == "clang");
result.add ("android");
result.add ("EGL");
result.add ("GLESv2");
result.add ("log");
auto ndkSettings = new GradleObject ("android.ndk");
result.addArray (StringArray::fromTokens(getExternalLibrariesString(), ";", ""));
ndkSettings->add<GradleString> ("moduleName", "juce_jni");
ndkSettings->add<GradleString> ("toolchain", toolchain);
ndkSettings->add<GradleValue> ("toolchainVersion", toolchainVersion);
ndkSettings->add<GradleString> ("stl", isClang ? "c++_static" : "gnustl_static");
ndkSettings->addChildObject (getNdkJuceExtraProperties());
return result;
addAllNdkCompilerSettings (ndkSettings);
return ndkSettings;
}
String createModelDotAndroidNDK (const String& indent) const
GradleObject* getNdkJuceExtraProperties() const
{
String result;
const String platformVersion (getNDKPlatformVersionString());
result << "android.ndk {" << newLine
<< indent << "moduleName = \"juce_jni\"" << newLine
<< indent << "stl = \"c++_static\"" << newLine
<< indent << "toolchain = \"clang\"" << newLine
<< indent << "toolchainVersion = 3.6" << newLine;
auto ext = new GradleObject ("ext");
ext->add<GradleString> ("juceRootDir", "${project.rootDir}/../../../../");
ext->add<GradleString> ("juceModuleDir", "${juceRootDir}/modules");
return ext;
}
if (platformVersion.isNotEmpty())
result << indent << "platformVersion = " << getNDKPlatformVersionString() << newLine;
void addAllNdkCompilerSettings (GradleObject* ndk) const
{
addNdkCppFlags (ndk);
addNdkPreprocessorDefines (ndk);
addNdkHeaderIncludePaths (ndk);
addNdkLinkerFlags (ndk);
addNdkLibraries (ndk);
}
result << indent << "ext {" << newLine
<< indent << indent << "juceRootDir = \"" << "${project.rootDir}/../../../../" << "\".toString()" << newLine
<< indent << indent << "juceModuleDir = \"" << "${juceRootDir}/modules" << "\".toString()" << newLine
<< indent << "}" << newLine;
void addNdkCppFlags (GradleObject* ndk) const
{
StringArray cppFlags { "-fsigned-char", "-fexceptions", "-frtti", "-std=c++11" };
// CPP flags
cppFlags.mergeArray (StringArray::fromTokens (getExtraCompilerFlagsString(), " ", ""));
{
StringArray cppFlags (getCPPFlags());
for (int i = 0; i < cppFlags.size(); ++i)
ndk->add<GradleCppFlag> (cppFlags[i]);
}
for (int i = 0; i < cppFlags.size(); ++i)
result << indent << "cppFlags.add(" << cppFlags[i] << ")" << newLine;
}
void addNdkPreprocessorDefines (GradleObject* ndk) const
{
const auto& defines = getAllPreprocessorDefs();
// libraries
for (int i = 0; i < defines.size(); ++i)
ndk->add<GradlePreprocessorDefine> ( defines.getAllKeys()[i], defines.getAllValues()[i]);
}
{
StringArray libraries (getLDLibs());
void addNdkHeaderIncludePaths (GradleObject* ndk) const
{
StringArray includePaths { "${project.rootDir}/app", "${ext.juceRootDir}", "${ext.juceModuleDir}" };
result << indent << "ldLibs.addAll(";
auto cppFiles = getAllIncludedCppFiles();
for (int i = 0; i < libraries.size(); ++i)
{
result << "\"" << libraries[i] << "\"";
for (const auto& cppFile : cppFiles)
includePaths.addIfNotAlreadyThere (getIncludePathForFile (cppFile));
if (i + 1 != libraries.size())
result << ", ";
}
for (const auto& path : includePaths)
ndk->add<GradleHeaderIncludePath> (path);
}
result << ")" << newLine;
}
Array<RelativePath> getAllIncludedCppFiles() const
{
Array<RelativePath> cppFiles;
const auto& groups = getAllGroups();
result << "}" << newLine;
for (int i = 0; i < groups.size(); ++i)
findAllProjectItemsWithPredicate (groups.getReference (i), cppFiles, ShouldBeAddedToProjectPredicate());
return result;
return cppFiles;
}
String getModelDotAndroidDotBuildTypesFlags (const String& indent, const ConstConfigIterator& config) const
String getIncludePathForFile (const RelativePath& file) const
{
const String configName (config->getName());
return sanitisePath (project.getProjectFolder().getFullPathName() + "/"
+ file.rebased (getTargetFolder(),
project.getProjectFolder(),
RelativePath::projectFolder)
.toUnixStyle()
.upToLastOccurrenceOf ("/", false, false));
}
// there appears to be an issue with build types that have a name other than
// "debug" or "release". Apparently this is hard coded in Android Studio ...
void addNdkLinkerFlags (GradleObject* ndk) const
{
const auto linkerFlags = StringArray::fromTokens (getExtraLinkerFlagsString(), " ", "");
if (configName != "Debug" && configName != "Release")
throw SaveError ("Build configurations other than Debug and Release are not yet support for Android Studio");
for (const auto& flag : linkerFlags)
ndk->add<GradleLinkerFlag> (flag);
StringArray rootFlags; // model.android.buildTypes.debug/release { ... }
StringArray ndkFlags; // model.android.buildTypes.debug/release.ndk.with { ... }
}
void addNdkLibraries (GradleObject* ndk) const
{
StringArray libs {"android", "EGL", "GLESv2", "log"};
libs.addArray (StringArray::fromTokens(getExternalLibrariesString(), ";", ""));
if (config->isDebug())
{
ndkFlags.add ("debuggable = true");
ndkFlags.add ("cppFlags.add(\"-g\")");
ndkFlags.add ("cppFlags.add(\"-DDEBUG=1\")");
ndkFlags.add ("cppFlags.add(\"-D_DEBUG=1\")");
}
else
{
rootFlags.add ("signingConfig = $(\"android.signingConfigs.releaseConfig\")");
ndkFlags.add ("cppFlags.add(\"-DNDEBUG=1\")");
}
for (const auto& lib : libs)
ndk->add<GradleLinkLibrary> (lib);
}
const StringArray& headerSearchPaths = config->getHeaderSearchPaths();
for (int i = 0; i < headerSearchPaths.size(); ++i)
ndkFlags.add ("cppFlags.add(\"-I" + sanitisePath (headerSearchPaths[i]) + "\".toString())");
GradleObject* getAndroidSources() const
{
auto source = new GradleObject ("source"); // app source folder
source->add<GradleStatement> ("exclude \"**/JuceModules/\"");
const StringArray& librarySearchPaths = config->getLibrarySearchPaths();
for (int i = 0; i < librarySearchPaths.size(); ++i)
ndkFlags.add ("cppFlags.add(\"-L" + sanitisePath (librarySearchPaths[i]) + "\".toString())");
auto jni = new GradleObject ("jni"); // all C++ sources for app
jni->addChildObject (source);
{
StringPairArray preprocessorDefinitions = config->getAllPreprocessorDefs();
preprocessorDefinitions.set ("JUCE_ANDROID", "1");
preprocessorDefinitions.set ("JUCE_ANDROID_API_VERSION", getMinimumSDKVersionString());
preprocessorDefinitions.set ("JUCE_ANDROID_ACTIVITY_CLASSNAME", getJNIActivityClassName().replaceCharacter ('/', '_'));
preprocessorDefinitions.set ("JUCE_ANDROID_ACTIVITY_CLASSPATH", "\\\"" + getActivityClassPath().replaceCharacter('.', '/') + "\\\"");
auto main = new GradleObject ("main"); // all sources for app
main->addChildObject (jni);
const StringArray& keys = preprocessorDefinitions.getAllKeys();
auto sources = new GradleObject ("android.sources"); // all sources
sources->addChildObject (main);
return sources;
}
for (int i = 0; i < keys.size(); ++i)
ndkFlags.add (String ("cppFlags.add(\"-D") + keys[i] + String ("=") + preprocessorDefinitions[keys[i]] + "\")");
}
GradleObject* getAndroidBuildConfigs() const
{
auto buildConfigs = new GradleObject ("android.buildTypes");
ndkFlags.add ("cppFlags.add(\"-O" + config->getGCCOptimisationFlag() + "\")");
for (ConstConfigIterator config (*this); config.next();)
buildConfigs->addChildObject (getBuildConfig (*config));
String result;
return buildConfigs;
}
result << configName.toLowerCase() << " {" << newLine;
GradleObject* getBuildConfig (const BuildConfiguration& config) const
{
const String configName (config.getName());
for (int i = 0; i < rootFlags.size(); ++i)
result << indent << rootFlags[i] << newLine;
// Note: at the moment, Android Studio only supports a "debug" and a "release"
// build config, but no custom build configs like Introjucer's other exporters do.
if (configName != "Debug" && configName != "Release")
throw SaveError ("Build configurations other than Debug and Release are not yet support for Android Studio");
result << indent << "ndk.with {" << newLine;
auto gradleConfig = new GradleObject (configName.toLowerCase());
for (int i = 0; i < ndkFlags.size(); ++i)
result << indent << indent << ndkFlags[i] << newLine;
if (! config.isDebug())
gradleConfig->add<GradleValue> ("signingConfig", "$(\"android.signingConfigs.releaseConfig\")");
result << indent << "}" << newLine
<< "}" << newLine;
addConfigNdkSettings (gradleConfig, config);
return result;
return gradleConfig;
}
String createModelDotAndroidDotBuildTypes (const String& indent) const
void addConfigNdkSettings (GradleObject* buildConfig, const BuildConfiguration& config) const
{
String result;
auto ndkSettings = new GradleObject ("ndk.with");
result << "android.buildTypes {" << newLine;
if (config.isDebug())
{
ndkSettings->add<GradleValue> ("debuggable", true);
ndkSettings->add<GradleCppFlag> ("-g");
ndkSettings->add<GradlePreprocessorDefine> ("DEBUG", "1");
ndkSettings->add<GradlePreprocessorDefine> ("_DEBUG", "1");
}
else
{
ndkSettings->add<GradlePreprocessorDefine> ("NDEBUG", "1");
}
for (ConstConfigIterator config (*this); config.next();)
result << CodeHelpers::indent (getModelDotAndroidDotBuildTypesFlags (indent, config), indent.length(), true);
ndkSettings->add<GradleCppFlag> ("-O" + config.getGCCOptimisationFlag());
result << "}" << newLine;
for (const auto& path : config.getHeaderSearchPaths())
ndkSettings->add<GradleHeaderIncludePath> (path);
return result;
}
for (const auto& path : config.getLibrarySearchPaths())
ndkSettings->add<GradleLibrarySearchPath> (path);
String createModelDotAndroidDotSigningConfigs (const String& indent) const
{
String result;
ndkSettings->add<GradlePreprocessorDefine> ("JUCE_ANDROID", "1");
ndkSettings->add<GradlePreprocessorDefine> ("JUCE_ANDROID_API_VERSION", getMinimumSDKVersionString());
ndkSettings->add<GradlePreprocessorDefine> ("JUCE_ANDROID_ACTIVITY_CLASSNAME", getJNIActivityClassName().replaceCharacter ('/', '_'));
ndkSettings->add<GradlePreprocessorDefine> ("JUCE_ANDROID_ACTIVITY_CLASSPATH","\\\"" + getActivityClassPath().replaceCharacter('.', '/') + "\\\"");
result << "android.signingConfigs {" << newLine
<< indent << "create(\"releaseConfig\") {" << newLine
<< indent << indent << "storeFile = new File(\"" << sanitisePath (getKeyStoreString()) << "\")" << newLine
<< indent << indent << "storePassword = \"" << getKeyStorePassString() << "\"" << newLine
<< indent << indent << "keyAlias = \"" << getKeyAliasString() << "\"" << newLine
<< indent << indent << "keyPassword = \"" << getKeyAliasPassString() << "\"" << newLine
<< indent << indent << "storeType = \"jks\"" << newLine
<< indent << "}" << newLine
<< "}" << newLine;
const auto defines = config.getAllPreprocessorDefs();
for (int i = 0; i < defines.size(); ++i)
ndkSettings->add<GradlePreprocessorDefine> (defines.getAllKeys()[i], defines.getAllValues()[i]);
return result;
buildConfig->addChildObject (ndkSettings);
}
String createModelDotAndroidDotProductFlavors (const String& indent) const
GradleObject* getAndroidSigningConfigs() const
{
String result;
auto releaseConfig = new GradleObject ("create(\"releaseConfig\")");
result << "android.productFlavors {" << newLine;
releaseConfig->add<GradleFilePath> ("storeFile", getKeyStoreString());
releaseConfig->add<GradleString> ("storePassword", getKeyStorePassString());
releaseConfig->add<GradleString> ("keyAlias", getKeyAliasString());
releaseConfig->add<GradleString> ("keyPassword", getKeyAliasPassString());
releaseConfig->add<GradleString> ("storeType", "jks");
// TODO! - this needs to be changed so that it generates seperate flags for debug and release ...
// at present, it just generates all ABIs for all build types
auto signingConfigs = new GradleObject ("android.signingConfigs");
signingConfigs->addChildObject (releaseConfig);
// Note: no need to add a debugConfig, Android Studio will use debug.keystore by default
return signingConfigs;
}
GradleObject* getAndroidProductFlavours() const
{
auto flavours = new GradleObject ("android.productFlavors");
StringArray architectures (StringArray::fromTokens (getABIs<AndroidStudioBuildConfiguration> (true), " ", ""));
architectures.mergeArray (StringArray::fromTokens (getABIs<AndroidStudioBuildConfiguration> (false), " ", ""));
@@ -611,73 +782,71 @@ private:
for (int i = 0; i < architectures.size(); ++i)
{
String architecture (architectures[i].trim());
String arch (architectures[i].trim());
if (architecture.isEmpty())
if ((arch).isEmpty())
continue;
result << indent << "create(\"" << architecture << "\") {" << newLine
<< indent << indent << "ndk.abiFilters.add(\"" << architecture << "\")" << newLine
<< indent << "}" << newLine;
flavours->addChildObject (getGradleProductFlavourForArch (arch));
}
result << "}" << newLine;
return result;
return flavours;
}
String createDependencies (const String& indent) const
GradleObject* getGradleProductFlavourForArch (const String& arch) const
{
String result;
auto flavour = new GradleObject ("create(\"" + arch + "\")");
flavour->add<GradleStatement> ("ndk.abiFilters.add(\"" + arch + "\")");
return flavour;
}
//==========================================================================
String getLocalPropertiesFileContent() const
{
String props;
result << "dependencies {" << newLine
<< indent << "compile \"com.android.support:support-v4:+\"" << newLine // needed for ContextCompat and ActivityCompat
<< "}" << newLine;
props << "ndk.dir=" << sanitisePath (getNDKPathString()) << newLine
<< "sdk.dir=" << sanitisePath (getSDKPathString()) << newLine;
return result;
return props;
}
void writeBuildDotGradleApp (const File& folder) const
String getGradleWrapperPropertiesFileContent() const
{
MemoryOutputStream memoryOutputStream;
String props;
const String indent = getIndentationString();
const String minimumSDKVersion = getMinimumSDKVersionString();
const String bundleIdentifier = project.getBundleIdentifier().toString();
props << "distributionUrl=https\\://services.gradle.org/distributions/gradle-"
<< getGradleVersionString() << "-all.zip";
String buildToolsVersion = getBuildToolsVersionString();
return props;
}
if (buildToolsVersion.isEmpty())
buildToolsVersion = "23.0.1";
//==========================================================================
void writeStringsXML (const File& folder) const
{
XmlElement strings ("resources");
XmlElement* resourceName = strings.createNewChildElement ("string");
memoryOutputStream << "apply plugin: 'com.android.model.application'" << newLine
<< newLine
<< "model {" << newLine
<< CodeHelpers::indent (createModelDotAndroid (indent,
minimumSDKVersion,
buildToolsVersion,
bundleIdentifier), indent.length(), true)
<< newLine
<< CodeHelpers::indent (createModelDotAndroidNDK (indent), indent.length(), true)
<< newLine
<< CodeHelpers::indent (createModelDotAndroidSources (indent), indent.length(), true)
<< newLine
<< CodeHelpers::indent (createModelDotAndroidDotBuildTypes (indent), indent.length(), true)
<< newLine
<< CodeHelpers::indent (createModelDotAndroidDotSigningConfigs (indent), indent.length(), true)
<< newLine
<< CodeHelpers::indent (createModelDotAndroidDotProductFlavors (indent), indent.length(), true)
<< "}" << newLine << newLine
<< createDependencies (indent);
resourceName->setAttribute ("name", "app_name");
resourceName->addTextElement (projectName);
overwriteFileIfDifferentOrThrow (folder.getChildFile ("app/build.gradle"), memoryOutputStream);
writeXmlOrThrow (strings, folder.getChildFile ("app/src/main/res/values/string.xml"), "utf-8", 100, true);
}
static const char* getIndentationString() noexcept
//==========================================================================
void writeAndroidManifest (const File& folder) const
{
return " ";
ScopedPointer<XmlElement> manifest (createManifestXML());
writeXmlOrThrow (*manifest, folder.getChildFile ("app/src/main/AndroidManifest.xml"), "utf-8", 100, true);
}
//==========================================================================
struct ShouldBeAddedToProjectPredicate
{
bool operator() (const Project::Item& projectItem) const { return projectItem.shouldBeAddedToTargetProject(); }
};
//==========================================================================
const File androidStudioExecutable;
JUCE_DECLARE_NON_COPYABLE (AndroidStudioProjectExporter)


+ 2
- 1
extras/Introjucer/Source/Project Saving/jucer_ProjectExporter.cpp View File

@@ -29,8 +29,9 @@
#include "jucer_ProjectExport_Make.h"
#include "jucer_ProjectExport_MSVC.h"
#include "jucer_ProjectExport_XCode.h"
#include "jucer_ProjectExport_Android.h"
#include "jucer_ProjectExport_AndroidBase.h"
#include "jucer_ProjectExport_AndroidStudio.h"
#include "jucer_ProjectExport_AndroidAnt.h"
#include "jucer_ProjectExport_CodeBlocks.h"
//==============================================================================


+ 4
- 1
extras/Introjucer/Source/Utility/jucer_PresetIDs.h View File

@@ -143,7 +143,6 @@ namespace Ids
DECLARE_ID (androidNDKPath);
DECLARE_ID (androidInternetNeeded);
DECLARE_ID (androidArchitectures);
DECLARE_ID (androidCpp11);
DECLARE_ID (androidMicNeeded);
DECLARE_ID (androidBluetoothNeeded);
DECLARE_ID (androidMinimumSDK);
@@ -158,6 +157,10 @@ namespace Ids
DECLARE_ID (androidNdkPlatformVersion);
DECLARE_ID (androidScreenOrientation);
DECLARE_ID (buildToolsVersion);
DECLARE_ID (gradleVersion);
DECLARE_ID (gradleWrapperVersion);
DECLARE_ID (gradleToolchain);
DECLARE_ID (gradleToolchainVersion);
DECLARE_ID (font);
DECLARE_ID (colour);
DECLARE_ID (userNotes);


Loading…
Cancel
Save