mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-24 01:54:22 +00:00
Projucer: allow to specify custom content of AndroidManifest.xml
This commit is contained in:
parent
115354bef6
commit
df1b43b704
2 changed files with 151 additions and 35 deletions
|
|
@ -45,6 +45,58 @@ rather than using a dedicated scrollbar. The scrollbar is still available though
|
|||
needed.
|
||||
|
||||
|
||||
Change
|
||||
------
|
||||
The previous setting of Android exporter "Custom manifest xml elements" creating
|
||||
child nodes of <application> element has been replaced by "Custom manifest XML content"
|
||||
setting that allows to specify the content of the entire manifest instead.
|
||||
Any previously values of the old setting will be used in the new setting by default, and
|
||||
they will need changing as mentioned in Workaround. The custom content will be merged
|
||||
with the content auto-generated by Projucer. Any custom elements or custom attributes
|
||||
will override the ones set by Projucer. Projucer will also automatically add any
|
||||
missing and required elements and attributes.
|
||||
|
||||
|
||||
Possible Issues
|
||||
---------------
|
||||
If a Projucer project used "Custom manifest xml elements" field, the value will no
|
||||
longer be compatible with the project generated in the latest Projucer version. The solution
|
||||
is very simple and quick though, as mentioned in the Workaround section.
|
||||
|
||||
|
||||
Workaround
|
||||
----------
|
||||
For any elements previously used, simply embed them explicitly in <manifest><application>
|
||||
elements,for example instead of:
|
||||
|
||||
<meta-data android:name="paramId1" android:value="paramValue1"/>
|
||||
<meta-data android:name="paramId2" android:value="paramValue2"/>
|
||||
|
||||
simply write:
|
||||
|
||||
<manifest>
|
||||
<application>
|
||||
<meta-data android:name="paramId1" android:value="paramValue1"/>
|
||||
<meta-data android:name="paramId2" android:value="paramValue2"/>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
|
||||
Rationale
|
||||
---------
|
||||
To maintain the high level of flexibility of generated Android projects and to avoid
|
||||
creating fields in Projucer for every possible future parameter, it is simpler to allow to
|
||||
set up the required parameters manually. This way it is not only possible to add any custom
|
||||
elements but it is also possible to override the default attributes assigned by Projucer for
|
||||
the required elements. For instance, if the default value of <supports-screens> element is
|
||||
not satisfactory because you want a support for x-large screens only, simply set
|
||||
"Custom manifest XML content" to:
|
||||
|
||||
<manifest>
|
||||
<supports-screens android:xlargeScreens="true"/>
|
||||
</manifest>
|
||||
|
||||
|
||||
Version 5.1.2
|
||||
=============
|
||||
|
||||
|
|
|
|||
|
|
@ -841,8 +841,10 @@ private:
|
|||
props.add (new TextPropertyComponent (androidOtherPermissions.getPropertyAsValue(), "Custom permissions", 2048, false),
|
||||
"A space-separated list of other permission flags that should be added to the manifest.");
|
||||
|
||||
props.add (new TextPropertyComponent (androidManifestCustomXmlElements.getPropertyAsValue(), "Custom manifest xml elements", 8192, true),
|
||||
"You can specify custom XML elements that will be added to AndroidManifest.xml as children of <application> element.");
|
||||
props.add (new TextPropertyComponent (androidManifestCustomXmlElements.getPropertyAsValue(), "Custom manifest XML content", 8192, true),
|
||||
"You can specify custom AndroidManifest.xml content overriding the default one generated by Projucer. "
|
||||
"Projucer will automatically create any missing and required XML elements and attributes "
|
||||
"and merge them into your custom content.");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -1366,28 +1368,39 @@ private:
|
|||
//==============================================================================
|
||||
XmlElement* createManifestXML() const
|
||||
{
|
||||
XmlElement* manifest = new XmlElement ("manifest");
|
||||
XmlElement* manifest = XmlDocument::parse (androidManifestCustomXmlElements.get());
|
||||
|
||||
manifest->setAttribute ("xmlns:android", "http://schemas.android.com/apk/res/android");
|
||||
manifest->setAttribute ("android:versionCode", androidVersionCode.get());
|
||||
manifest->setAttribute ("android:versionName", project.getVersionString());
|
||||
manifest->setAttribute ("package", getActivityClassPackage());
|
||||
if (manifest == nullptr)
|
||||
manifest = new XmlElement ("manifest");
|
||||
|
||||
setAttributeIfNotPresent (*manifest, "xmlns:android", "http://schemas.android.com/apk/res/android");
|
||||
setAttributeIfNotPresent (*manifest, "android:versionCode", androidVersionCode.get());
|
||||
setAttributeIfNotPresent (*manifest, "android:versionName", project.getVersionString());
|
||||
setAttributeIfNotPresent (*manifest, "package", getActivityClassPackage());
|
||||
|
||||
if (! isLibrary())
|
||||
{
|
||||
XmlElement* screens = manifest->createNewChildElement ("supports-screens");
|
||||
screens->setAttribute ("android:smallScreens", "true");
|
||||
screens->setAttribute ("android:normalScreens", "true");
|
||||
screens->setAttribute ("android:largeScreens", "true");
|
||||
screens->setAttribute ("android:anyDensity", "true");
|
||||
if (manifest->getChildByName ("supports-screens") == nullptr)
|
||||
{
|
||||
XmlElement* screens = manifest->createNewChildElement ("supports-screens");
|
||||
screens->setAttribute ("android:smallScreens", "true");
|
||||
screens->setAttribute ("android:normalScreens", "true");
|
||||
screens->setAttribute ("android:largeScreens", "true");
|
||||
screens->setAttribute ("android:anyDensity", "true");
|
||||
}
|
||||
}
|
||||
|
||||
XmlElement* sdk = manifest->createNewChildElement ("uses-sdk");
|
||||
sdk->setAttribute ("android:minSdkVersion", androidMinimumSDK.get());
|
||||
sdk->setAttribute ("android:targetSdkVersion", androidMinimumSDK.get());
|
||||
auto* sdk = getOrCreateChildWithName (*manifest, "uses-sdk");
|
||||
setAttributeIfNotPresent (*sdk, "android:minSdkVersion", androidMinimumSDK.get());
|
||||
setAttributeIfNotPresent (*sdk, "android:targetSdkVersion", androidMinimumSDK.get());
|
||||
|
||||
{
|
||||
const StringArray permissions (getPermissionsRequired());
|
||||
StringArray permissions (getPermissionsRequired());
|
||||
|
||||
forEachXmlChildElementWithTagName (*manifest, child, "uses-permission")
|
||||
{
|
||||
permissions.removeString (child->getStringAttribute ("android:name"), false);
|
||||
}
|
||||
|
||||
for (int i = permissions.size(); --i >= 0;)
|
||||
manifest->createNewChildElement ("uses-permission")->setAttribute ("android:name", permissions[i]);
|
||||
|
|
@ -1395,19 +1408,33 @@ private:
|
|||
|
||||
if (project.getModules().isModuleEnabled ("juce_opengl"))
|
||||
{
|
||||
XmlElement* feature = manifest->createNewChildElement ("uses-feature");
|
||||
feature->setAttribute ("android:glEsVersion", (androidMinimumSDK.get().getIntValue() >= 18 ? "0x00030000" : "0x00020000"));
|
||||
feature->setAttribute ("android:required", "true");
|
||||
XmlElement* glVersion = nullptr;
|
||||
|
||||
forEachXmlChildElementWithTagName (*manifest, child, "uses-feature")
|
||||
{
|
||||
if (child->getStringAttribute ("android:glEsVersion").isNotEmpty())
|
||||
{
|
||||
glVersion = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (glVersion == nullptr)
|
||||
glVersion = manifest->createNewChildElement ("uses-feature");
|
||||
|
||||
setAttributeIfNotPresent (*glVersion, "android:glEsVersion", (androidMinimumSDK.get().getIntValue() >= 18 ? "0x00030000" : "0x00020000"));
|
||||
setAttributeIfNotPresent (*glVersion, "android:required", "true");
|
||||
}
|
||||
|
||||
if (! isLibrary())
|
||||
{
|
||||
XmlElement* app = manifest->createNewChildElement ("application");
|
||||
app->setAttribute ("android:label", "@string/app_name");
|
||||
auto* app = getOrCreateChildWithName (*manifest, "application");
|
||||
setAttributeIfNotPresent (*app, "android:label", "@string/app_name");
|
||||
|
||||
if (androidTheme.get().isNotEmpty())
|
||||
app->setAttribute ("android:theme", androidTheme.get());
|
||||
setAttributeIfNotPresent (*app, "android:theme", androidTheme.get());
|
||||
|
||||
if (! app->hasAttribute ("android:icon"))
|
||||
{
|
||||
ScopedPointer<Drawable> bigIcon (getBigIcon()), smallIcon (getSmallIcon());
|
||||
|
||||
|
|
@ -1417,29 +1444,66 @@ private:
|
|||
|
||||
if (androidMinimumSDK.get().getIntValue() >= 11)
|
||||
app->setAttribute ("android:hardwareAccelerated", "false"); // (using the 2D acceleration slows down openGL)
|
||||
else
|
||||
app->removeAttribute ("android:hardwareAccelerated");
|
||||
|
||||
XmlElement* act = app->createNewChildElement ("activity");
|
||||
act->setAttribute ("android:name", getActivitySubClassName());
|
||||
act->setAttribute ("android:label", "@string/app_name");
|
||||
auto* act = getOrCreateChildWithName (*app, "activity");
|
||||
|
||||
String configChanges ("keyboardHidden|orientation");
|
||||
if (androidMinimumSDK.get().getIntValue() >= 13)
|
||||
configChanges += "|screenSize";
|
||||
setAttributeIfNotPresent (*act, "android:name", getActivitySubClassName());
|
||||
setAttributeIfNotPresent (*act, "android:label", "@string/app_name");
|
||||
|
||||
act->setAttribute ("android:configChanges", configChanges);
|
||||
act->setAttribute ("android:screenOrientation", androidScreenOrientation.get());
|
||||
if (! act->hasAttribute ("android:configChanges"))
|
||||
{
|
||||
String configChanges ("keyboardHidden|orientation");
|
||||
if (androidMinimumSDK.get().getIntValue() >= 13)
|
||||
configChanges += "|screenSize";
|
||||
|
||||
XmlElement* intent = act->createNewChildElement ("intent-filter");
|
||||
intent->createNewChildElement ("action")->setAttribute ("android:name", "android.intent.action.MAIN");
|
||||
intent->createNewChildElement ("category")->setAttribute ("android:name", "android.intent.category.LAUNCHER");
|
||||
act->setAttribute ("android:configChanges", configChanges);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto configChanges = act->getStringAttribute ("android:configChanges");
|
||||
|
||||
for (XmlElement* e = XmlDocument::parse (androidManifestCustomXmlElements.get()); e != nullptr; e = e->getNextElement())
|
||||
app->addChildElement (e);
|
||||
if (androidMinimumSDK.get().getIntValue() < 13 && configChanges.contains ("screenSize"))
|
||||
{
|
||||
configChanges = configChanges.replace ("|screenSize", "")
|
||||
.replace ("screenSize|", "")
|
||||
.replace ("screenSize", "");
|
||||
|
||||
act->setAttribute ("android:configChanges", configChanges);
|
||||
}
|
||||
}
|
||||
|
||||
setAttributeIfNotPresent (*act, "android:screenOrientation", androidScreenOrientation.get());
|
||||
|
||||
auto* intent = getOrCreateChildWithName (*act, "intent-filter");
|
||||
|
||||
auto* action = getOrCreateChildWithName (*intent, "action");
|
||||
setAttributeIfNotPresent (*action, "android:name", "android.intent.action.MAIN");
|
||||
|
||||
auto* category = getOrCreateChildWithName (*intent, "category");
|
||||
setAttributeIfNotPresent (*category, "android:name", "android.intent.category.LAUNCHER");
|
||||
}
|
||||
|
||||
return manifest;
|
||||
}
|
||||
|
||||
static XmlElement* getOrCreateChildWithName (XmlElement& element, const String& name)
|
||||
{
|
||||
auto* child = element.getChildByName (name);
|
||||
|
||||
if (child == nullptr)
|
||||
child = element.createNewChildElement (name);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
static void setAttributeIfNotPresent (XmlElement& element, const Identifier& attribute, const String& value)
|
||||
{
|
||||
if (! element.hasAttribute (attribute.toString()))
|
||||
element.setAttribute (attribute, value);
|
||||
}
|
||||
|
||||
StringArray getPermissionsRequired() const
|
||||
{
|
||||
StringArray s;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue