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 compile="0"/>
<Option link="0"/> <Option link="0"/>
</Unit> </Unit>
<Unit filename="../../Source/Project Saving/jucer_ProjectExport_Android.h">
<Unit filename="../../Source/Project Saving/jucer_ProjectExport_AndroidBase.h">
<Option compile="0"/> <Option compile="0"/>
<Option link="0"/> <Option link="0"/>
</Unit> </Unit>
@@ -437,6 +437,10 @@
<Option compile="0"/> <Option compile="0"/>
<Option link="0"/> <Option link="0"/>
</Unit> </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"> <Unit filename="../../Source/Project Saving/jucer_ProjectExport_CodeBlocks.h">
<Option compile="0"/> <Option compile="0"/>
<Option link="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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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"; }; 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, 66B49F08C5EC3E4974825FF8,
5432B7B9B2CF2EAEC8B66D5C, ); name = ComponentEditor; sourceTree = "<group>"; }; 5432B7B9B2CF2EAEC8B66D5C, ); name = ComponentEditor; sourceTree = "<group>"; };
E345840128627D533DF908AC = {isa = PBXGroup; children = ( E345840128627D533DF908AC = {isa = PBXGroup; children = (
6E7353DFEA8825B515049ABB,
049A726AFEC564314777C076,
16385D79A30C6E06EFB46B79, 16385D79A30C6E06EFB46B79,
4DB834787369EBFCFF560F46,
DBE0CDE1B017190ABBFF557C, DBE0CDE1B017190ABBFF557C,
05076CDF1511A5F8A8E18F1D, 05076CDF1511A5F8A8E18F1D,
C8A229ACD244F402C57286CD, 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_ObjectTypes.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/> <ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.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_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_CodeBlocks.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_MSVC.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"> <ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h">
<Filter>The Introjucer\ComponentEditor</Filter> <Filter>The Introjucer\ComponentEditor</Filter>
</ClInclude> </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> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h"> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h">
<Filter>The Introjucer\Project Saving</Filter> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </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"> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h">
<Filter>The Introjucer\Project Saving</Filter> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </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_ObjectTypes.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/> <ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.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_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_CodeBlocks.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_MSVC.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"> <ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h">
<Filter>The Introjucer\ComponentEditor</Filter> <Filter>The Introjucer\ComponentEditor</Filter>
</ClInclude> </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> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h"> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h">
<Filter>The Introjucer\Project Saving</Filter> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </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"> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h">
<Filter>The Introjucer\Project Saving</Filter> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </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_ObjectTypes.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/> <ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.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_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_CodeBlocks.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_MSVC.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"> <ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h">
<Filter>The Introjucer\ComponentEditor</Filter> <Filter>The Introjucer\ComponentEditor</Filter>
</ClInclude> </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> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h"> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h">
<Filter>The Introjucer\Project Saving</Filter> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </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"> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h">
<Filter>The Introjucer\Project Saving</Filter> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </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_ObjectTypes.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/> <ClInclude Include="..\..\Source\ComponentEditor\jucer_PaintRoutine.h"/>
<ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.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_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_CodeBlocks.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_Make.h"/>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_MSVC.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"> <ClInclude Include="..\..\Source\ComponentEditor\jucer_UtilityFunctions.h">
<Filter>The Introjucer\ComponentEditor</Filter> <Filter>The Introjucer\ComponentEditor</Filter>
</ClInclude> </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> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h"> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_AndroidStudio.h">
<Filter>The Introjucer\Project Saving</Filter> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </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"> <ClInclude Include="..\..\Source\Project Saving\jucer_ProjectExport_CodeBlocks.h">
<Filter>The Introjucer\Project Saving</Filter> <Filter>The Introjucer\Project Saving</Filter>
</ClInclude> </ClInclude>


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

@@ -364,10 +364,12 @@
file="Source/ComponentEditor/jucer_UtilityFunctions.h"/> file="Source/ComponentEditor/jucer_UtilityFunctions.h"/>
</GROUP> </GROUP>
<GROUP id="{579C9644-D5C2-8469-9439-F91C81337531}" name="Project Saving"> <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" <FILE id="AhU3qX" name="jucer_ProjectExport_AndroidStudio.h" compile="0"
resource="0" file="Source/Project Saving/jucer_ProjectExport_AndroidStudio.h"/> 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" <FILE id="EkBkj1" name="jucer_ProjectExport_CodeBlocks.h" compile="0"
resource="0" file="Source/Project Saving/jucer_ProjectExport_CodeBlocks.h"/> resource="0" file="Source/Project Saving/jucer_ProjectExport_CodeBlocks.h"/>
<FILE id="mVXrLi" name="jucer_ProjectExport_Make.h" compile="0" resource="0" <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 class AndroidProjectExporterBase : public ProjectExporter
{ {
public: public:
//==========================================================================
AndroidProjectExporterBase (Project& p, const ValueTree& t) AndroidProjectExporterBase (Project& p, const ValueTree& t)
: ProjectExporter (p, t) : ProjectExporter (p, t)
{
setEmptyPropertiesToDefaultValues();
}
//==========================================================================
virtual bool isAndroidStudio() = 0;
virtual bool isAndroidAnt() = 0;
//==========================================================================
void setEmptyPropertiesToDefaultValues()
{ {
if (getVersionCodeString().isEmpty()) if (getVersionCodeString().isEmpty())
getVersionCodeValue() = 1; getVersionCodeValue() = 1;
@@ -47,7 +58,6 @@ public:
if (getKeyStorePassValue().getValue().isVoid()) getKeyStorePassValue() = "android"; if (getKeyStorePassValue().getValue().isVoid()) getKeyStorePassValue() = "android";
if (getKeyAliasValue().getValue().isVoid()) getKeyAliasValue() = "androiddebugkey"; if (getKeyAliasValue().getValue().isVoid()) getKeyAliasValue() = "androiddebugkey";
if (getKeyAliasPassValue().getValue().isVoid()) getKeyAliasPassValue() = "android"; if (getKeyAliasPassValue().getValue().isVoid()) getKeyAliasPassValue() = "android";
if (getCPP11EnabledValue().getValue().isVoid()) getCPP11EnabledValue() = true;
initialiseDependencyPathValues(); initialiseDependencyPathValues();
@@ -55,12 +65,7 @@ public:
getScreenOrientationValue() = "unspecified"; 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 void create (const OwnedArray<LibraryModule>& modules) const override
{ {
const String package (getActivityClassPackage()); const String package (getActivityClassPackage());
@@ -70,9 +75,78 @@ public:
copyActivityJavaFiles (modules, target, package); 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 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), props.add (new TextPropertyComponent (getActivityClassPathValue(), "Android Activity class name", 256, false),
"The full java class name to use for the app's Activity class."); "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), props.add (new TextPropertyComponent (getMinimumSDKVersionValue(), "Minimum SDK version", 32, false),
"The number of the minimum version of the Android SDK that the app requires"); "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"), 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."); "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), props.add (new TextPropertyComponent (getOtherPermissionsValue(), "Custom permissions", 2048, false),
"A space-separated list of other permission flags that should be added to the manifest."); "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), props.add (new TextPropertyComponent (getKeyStoreValue(), "Key Signing: key.store", 2048, false),
"The key.store value, used when signing the package."); "The key.store value, used when signing the package.");
props.add (new TextPropertyComponent (getKeyStorePassValue(), "Key Signing: key.store.password", 2048, false), props.add (new TextPropertyComponent (getKeyStorePassValue(), "Key Signing: key.store.password", 2048, false),
"The key.store password, used when signing the package."); "The key.store password, used when signing the package.");
props.add (new TextPropertyComponent (getKeyAliasValue(), "Key Signing: key.alias", 2048, false), props.add (new TextPropertyComponent (getKeyAliasValue(), "Key Signing: key.alias", 2048, false),
"The key.alias value, used when signing the package."); "The key.alias value, used when signing the package.");
props.add (new TextPropertyComponent (getKeyAliasPassValue(), "Key Signing: key.alias.password", 2048, false), props.add (new TextPropertyComponent (getKeyAliasPassValue(), "Key Signing: key.alias.password", 2048, false),
"The key.alias password, used when signing the package."); "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 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 String getActivityName() const
{ {
return getActivityClassPath().fromLastOccurrenceOf (".", false, false); return getActivityClassPath().fromLastOccurrenceOf (".", false, false);
@@ -349,16 +349,6 @@ public:
return nullptr; return nullptr;
} }
String getCppFlags() const
{
String flags ("-fsigned-char -fexceptions -frtti");
if (! getNDKToolchainVersionString().startsWithIgnoreCase ("clang"))
flags << " -Wno-psabi";
return flags;
}
StringArray getPermissionsRequired() const StringArray getPermissionsRequired() const
{ {
StringArray s; StringArray s;
@@ -514,393 +504,3 @@ public:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidProjectExporterBase) 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 class AndroidStudioProjectExporter : public AndroidProjectExporterBase
{ {
public: 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* getName() { return "Android Studio"; }
static const char* getValueTreeTypeName() { return "ANDROIDSTUDIO"; } static const char* getValueTreeTypeName() { return "ANDROIDSTUDIO"; }
@@ -37,15 +43,69 @@ public:
return nullptr; 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) AndroidStudioProjectExporter (Project& p, const ValueTree& t)
: AndroidProjectExporterBase (p, t), : AndroidProjectExporterBase (p, t),
androidStudioExecutable (findAndroidStudioExecutable()) androidStudioExecutable (findAndroidStudioExecutable())
{ {
name = getName(); name = getName();
setEmptyPropertiesToDefaultValues();
}
//==============================================================================
void setEmptyPropertiesToDefaultValues()
{
if (getTargetLocationString().isEmpty()) if (getTargetLocationString().isEmpty())
getTargetLocationValue() = getDefaultBuildsRootFolder() + "AndroidStudio"; 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() + "\""); 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); } Value getNDKPlatformVersionValue() { return getSetting (Ids::androidNdkPlatformVersion); }
String getNDKPlatformVersionString() const { return settings [Ids::androidNdkPlatformVersion]; } String getNDKPlatformVersionString() const { return settings [Ids::androidNdkPlatformVersion]; }
Value getBuildToolsVersionValue() { return getSetting (Ids::buildToolsVersion); } Value getBuildToolsVersionValue() { return getSetting (Ids::buildToolsVersion); }
String getBuildToolsVersionString() const { return settings [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 void create (const OwnedArray<LibraryModule>& modules) const override
{ {
const File targetFolder (getTargetFolder()); const File targetFolder (getTargetFolder());
@@ -110,18 +150,36 @@ public:
copyActivityJavaFiles (modules, javaTarget, package); 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() static File findAndroidStudioExecutable()
{ {
#if JUCE_WINDOWS #if JUCE_WINDOWS
@@ -190,12 +248,12 @@ protected:
} }
private: private:
static void createSymboicLinkAndCreateParentFolders (const File& originalFile, const File& linkFile)
static void createSymlinkAndParentFolders (const File& originalFile, const File& linkFile)
{ {
{ {
const File linkFileParentDirectory (linkFile.getParentDirectory()); 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 // without this, the symlink would fail because it doesn't automatically create
// the folders if they don't exist // the folders if they don't exist
if (! linkFileParentDirectory.createDirectory()) if (! linkFileParentDirectory.createDirectory())
@@ -228,7 +286,7 @@ private:
const File originalFile (projectItem.getFile()); const File originalFile (projectItem.getFile());
const File targetFile (targetFolder.getChildFile (originalFile.getFileName())); 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/")); 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) static String sanitisePath (String path)
{ {
return expandHomeFolderToken (path).replace ("\\", "\\\\"); return expandHomeFolderToken (path).replace ("\\", "\\\\");
@@ -281,327 +330,449 @@ private:
.replace ("~", homeFolder); .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), " ", "")); StringArray architectures (StringArray::fromTokens (getABIs<AndroidStudioBuildConfiguration> (true), " ", ""));
architectures.mergeArray (StringArray::fromTokens (getABIs<AndroidStudioBuildConfiguration> (false), " ", "")); architectures.mergeArray (StringArray::fromTokens (getABIs<AndroidStudioBuildConfiguration> (false), " ", ""));
@@ -611,73 +782,71 @@ private:
for (int i = 0; i < architectures.size(); ++i) 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; 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; const File androidStudioExecutable;
JUCE_DECLARE_NON_COPYABLE (AndroidStudioProjectExporter) 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_Make.h"
#include "jucer_ProjectExport_MSVC.h" #include "jucer_ProjectExport_MSVC.h"
#include "jucer_ProjectExport_XCode.h" #include "jucer_ProjectExport_XCode.h"
#include "jucer_ProjectExport_Android.h"
#include "jucer_ProjectExport_AndroidBase.h"
#include "jucer_ProjectExport_AndroidStudio.h" #include "jucer_ProjectExport_AndroidStudio.h"
#include "jucer_ProjectExport_AndroidAnt.h"
#include "jucer_ProjectExport_CodeBlocks.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 (androidNDKPath);
DECLARE_ID (androidInternetNeeded); DECLARE_ID (androidInternetNeeded);
DECLARE_ID (androidArchitectures); DECLARE_ID (androidArchitectures);
DECLARE_ID (androidCpp11);
DECLARE_ID (androidMicNeeded); DECLARE_ID (androidMicNeeded);
DECLARE_ID (androidBluetoothNeeded); DECLARE_ID (androidBluetoothNeeded);
DECLARE_ID (androidMinimumSDK); DECLARE_ID (androidMinimumSDK);
@@ -158,6 +157,10 @@ namespace Ids
DECLARE_ID (androidNdkPlatformVersion); DECLARE_ID (androidNdkPlatformVersion);
DECLARE_ID (androidScreenOrientation); DECLARE_ID (androidScreenOrientation);
DECLARE_ID (buildToolsVersion); DECLARE_ID (buildToolsVersion);
DECLARE_ID (gradleVersion);
DECLARE_ID (gradleWrapperVersion);
DECLARE_ID (gradleToolchain);
DECLARE_ID (gradleToolchainVersion);
DECLARE_ID (font); DECLARE_ID (font);
DECLARE_ID (colour); DECLARE_ID (colour);
DECLARE_ID (userNotes); DECLARE_ID (userNotes);


Loading…
Cancel
Save