Merge pull request #87029 from bruvzg/info_plist_keys

[macOS/iOS export] Add option to set custom Info.plist data.
This commit is contained in:
Rémi Verschelde 2024-01-11 20:46:02 +01:00
commit 26b1fd0d84
No known key found for this signature in database
GPG Key ID: C3336907360768E1
9 changed files with 108 additions and 24 deletions

View File

@ -448,7 +448,9 @@ PList::PList() {
}
PList::PList(const String &p_string) {
load_string(p_string);
String err_str;
bool ok = load_string(p_string, err_str);
ERR_FAIL_COND_MSG(!ok, "PList: " + err_str);
}
uint64_t PList::read_bplist_var_size_int(Ref<FileAccess> p_file, uint8_t p_size) {
@ -642,11 +644,15 @@ bool PList::load_file(const String &p_filename) {
String ret;
ret.parse_utf8((const char *)array.ptr(), array.size());
return load_string(ret);
String err_str;
bool ok = load_string(ret, err_str);
ERR_FAIL_COND_V_MSG(!ok, false, "PList: " + err_str);
return true;
}
}
bool PList::load_string(const String &p_string) {
bool PList::load_string(const String &p_string, String &r_err_out) {
root = Ref<PListNode>();
int pos = 0;
@ -657,14 +663,16 @@ bool PList::load_string(const String &p_string) {
while (pos >= 0) {
int open_token_s = p_string.find("<", pos);
if (open_token_s == -1) {
ERR_FAIL_V_MSG(false, "PList: Unexpected end of data. No tags found.");
r_err_out = "Unexpected end of data. No tags found.";
return false;
}
int open_token_e = p_string.find(">", open_token_s);
pos = open_token_e;
String token = p_string.substr(open_token_s + 1, open_token_e - open_token_s - 1);
if (token.is_empty()) {
ERR_FAIL_V_MSG(false, "PList: Invalid token name.");
r_err_out = "Invalid token name.";
return false;
}
String value;
if (token[0] == '?' || token[0] == '!') { // Skip <?xml ... ?> and <!DOCTYPE ... >
@ -684,7 +692,8 @@ bool PList::load_string(const String &p_string) {
}
if (!in_plist) {
ERR_FAIL_V_MSG(false, "PList: Node outside of <plist> tag.");
r_err_out = "Node outside of <plist> tag.";
return false;
}
if (token == "dict") {
@ -693,13 +702,15 @@ bool PList::load_string(const String &p_string) {
Ref<PListNode> dict = PListNode::new_dict();
dict->data_type = PList::PLNodeType::PL_NODE_TYPE_DICT;
if (!stack.back()->get()->push_subnode(dict, key)) {
ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type.");
r_err_out = "Can't push subnode, invalid parent type.";
return false;
}
stack.push_back(dict);
} else {
// Add root node.
if (!root.is_null()) {
ERR_FAIL_V_MSG(false, "PList: Root node already set.");
r_err_out = "Root node already set.";
return false;
}
Ref<PListNode> dict = PListNode::new_dict();
stack.push_back(dict);
@ -711,7 +722,8 @@ bool PList::load_string(const String &p_string) {
if (token == "/dict") {
// Exit current dict.
if (stack.is_empty() || stack.back()->get()->data_type != PList::PLNodeType::PL_NODE_TYPE_DICT) {
ERR_FAIL_V_MSG(false, "PList: Mismatched </dict> tag.");
r_err_out = "Mismatched </dict> tag.";
return false;
}
stack.pop_back();
continue;
@ -722,13 +734,15 @@ bool PList::load_string(const String &p_string) {
// Add subnode end enter it.
Ref<PListNode> arr = PListNode::new_array();
if (!stack.back()->get()->push_subnode(arr, key)) {
ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type.");
r_err_out = "Can't push subnode, invalid parent type.";
return false;
}
stack.push_back(arr);
} else {
// Add root node.
if (!root.is_null()) {
ERR_FAIL_V_MSG(false, "PList: Root node already set.");
r_err_out = "Root node already set.";
return false;
}
Ref<PListNode> arr = PListNode::new_array();
stack.push_back(arr);
@ -740,7 +754,8 @@ bool PList::load_string(const String &p_string) {
if (token == "/array") {
// Exit current array.
if (stack.is_empty() || stack.back()->get()->data_type != PList::PLNodeType::PL_NODE_TYPE_ARRAY) {
ERR_FAIL_V_MSG(false, "PList: Mismatched </array> tag.");
r_err_out = "Mismatched </array> tag.";
return false;
}
stack.pop_back();
continue;
@ -751,13 +766,15 @@ bool PList::load_string(const String &p_string) {
} else {
int end_token_s = p_string.find("</", pos);
if (end_token_s == -1) {
ERR_FAIL_V_MSG(false, vformat("PList: Mismatched <%s> tag.", token));
r_err_out = vformat("Mismatched <%s> tag.", token);
return false;
}
int end_token_e = p_string.find(">", end_token_s);
pos = end_token_e;
String end_token = p_string.substr(end_token_s + 2, end_token_e - end_token_s - 2);
if (end_token != token) {
ERR_FAIL_V_MSG(false, vformat("PList: Mismatched <%s> and <%s> token pair.", token, end_token));
r_err_out = vformat("Mismatched <%s> and <%s> token pair.", token, end_token);
return false;
}
value = p_string.substr(open_token_e + 1, end_token_s - open_token_e - 1);
}
@ -780,15 +797,18 @@ bool PList::load_string(const String &p_string) {
} else if (token == "date") {
var = PListNode::new_date(value);
} else {
ERR_FAIL_V_MSG(false, "PList: Invalid value type.");
r_err_out = vformat("Invalid value type: %s.", token);
return false;
}
if (stack.is_empty() || !stack.back()->get()->push_subnode(var, key)) {
ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type.");
r_err_out = "Can't push subnode, invalid parent type.";
return false;
}
}
}
if (!stack.is_empty() || !done_plist) {
ERR_FAIL_V_MSG(false, "PList: Unexpected end of data. Root node is not closed.");
r_err_out = "Unexpected end of data. Root node is not closed.";
return false;
}
return true;
}

View File

@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef MACOS_PLIST_H
#define MACOS_PLIST_H
#ifndef PLIST_H
#define PLIST_H
// Property list file format (application/x-plist) parser, property list ASN-1 serialization.
@ -75,7 +75,7 @@ public:
PList(const String &p_string);
bool load_file(const String &p_filename);
bool load_string(const String &p_string);
bool load_string(const String &p_string, String &r_err_out);
PackedByteArray save_asn1() const;
String save_text() const;
@ -125,4 +125,4 @@ public:
~PListNode() {}
};
#endif // MACOS_PLIST_H
#endif // PLIST_H

View File

@ -58,5 +58,6 @@ $usage_descriptions
</dict>
<key>NSHighResolutionCapable</key>
$highres
$additional_plist_content
</dict>
</plist>

View File

@ -10,6 +10,13 @@
<link title="iOS plugins documentation index">$DOCS_URL/tutorials/platform/ios/index.html</link>
</tutorials>
<members>
<member name="application/additional_plist_content" type="String" setter="" getter="">
Additional data added to the root [code]&lt;dict&gt;[/code] section of the [url=https://developer.apple.com/documentation/bundleresources/information_property_list]Info.plist[/url] file. The value should be an XML section with pairs of key-value elements, e.g.:
[codeblock]
&lt;key&gt;key_name&lt;/key&gt;
&lt;string&gt;value&lt;/string&gt;
[/codeblock]
</member>
<member name="application/app_store_team_id" type="String" setter="" getter="">
Apple Team ID, unique 10-character string. To locate your Team ID check "Membership details" section in your Apple developer account dashboard, or "Organizational Unit" of your code signing certificate. See [url=https://developer.apple.com/help/account/manage-your-team/locate-your-team-id]Locate your Team ID[/url].
</member>

View File

@ -34,6 +34,7 @@
#include "run_icon_svg.gen.h"
#include "core/io/json.h"
#include "core/io/plist.h"
#include "core/string/translation.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
@ -154,6 +155,8 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/min_ios_version"), "12.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/additional_plist_content", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/export_project_only"), false));
@ -1498,6 +1501,8 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
false
};
config_data.plist_content += p_preset->get("application/additional_plist_content").operator String() + "\n";
Vector<IOSExportAsset> assets;
Ref<DirAccess> tmp_app_path = DirAccess::create_for_path(dest_dir);
@ -1867,6 +1872,26 @@ bool EditorExportPlatformIOS::has_valid_export_configuration(const Ref<EditorExp
valid = dvalid || rvalid;
r_missing_templates = !valid;
const String &additional_plist_content = p_preset->get("application/additional_plist_content");
if (!additional_plist_content.is_empty()) {
const String &plist = vformat("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
"<plist version=\"1.0\">"
"<dict>\n"
"%s\n"
"</dict>\n"
"</plist>\n",
additional_plist_content);
String plist_err;
Ref<PList> plist_parser;
plist_parser.instantiate();
if (!plist_parser->load_string(plist, plist_err)) {
err += TTR("Invalid additional PList content: ") + plist_err + "\n";
valid = false;
}
}
if (!err.is_empty()) {
r_error = err;
}

View File

@ -10,6 +10,13 @@
<link title="Running Godot apps on macOS">$DOCS_URL/tutorials//export/running_on_macos.html</link>
</tutorials>
<members>
<member name="application/additional_plist_content" type="String" setter="" getter="">
Additional data added to the root [code]&lt;dict&gt;[/code] section of the [url=https://developer.apple.com/documentation/bundleresources/information_property_list]Info.plist[/url] file. The value should be an XML section with pairs of key-value elements, e.g.:
[codeblock]
&lt;key&gt;key_name&lt;/key&gt;
&lt;string&gt;value&lt;/string&gt;
[/codeblock]
</member>
<member name="application/app_category" type="String" setter="" getter="">
Application category for the App Store.
</member>

View File

@ -32,8 +32,8 @@
#include "lipo.h"
#include "macho.h"
#include "plist.h"
#include "core/io/plist.h"
#include "core/os/os.h"
#include "editor/editor_paths.h"
#include "editor/editor_settings.h"

View File

@ -41,11 +41,10 @@
// - Requirements code generator is not implemented (only hard-coded requirements for the ad-hoc signing is supported).
// - RFC5652/CMS blob generation is not implemented, supports ad-hoc signing only.
#include "plist.h"
#include "core/crypto/crypto_core.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/plist.h"
#include "core/object/ref_counted.h"
#include "modules/modules_enabled.gen.h" // For regex.

View File

@ -37,6 +37,7 @@
#include "run_icon_svg.gen.h"
#include "core/io/image_loader.h"
#include "core/io/plist.h"
#include "core/string/translation.h"
#include "drivers/png/png_driver_common.h"
#include "editor/editor_node.h"
@ -388,6 +389,8 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_angle", PROPERTY_HINT_ENUM, "Auto,Yes,No"), 0, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/additional_plist_content", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/platform_build"), "14C18"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/sdk_version"), "13.1"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/sdk_build"), "22C55"));
@ -672,6 +675,8 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_pres
strnew += lines[i].replace("$min_version", p_preset->get("application/min_macos_version")) + "\n";
} else if (lines[i].find("$highres") != -1) {
strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "\t<true/>" : "\t<false/>") + "\n";
} else if (lines[i].find("$additional_plist_content") != -1) {
strnew += lines[i].replace("$additional_plist_content", p_preset->get("application/additional_plist_content")) + "\n";
} else if (lines[i].find("$platfbuild") != -1) {
strnew += lines[i].replace("$platfbuild", p_preset->get("xcode/platform_build")) + "\n";
} else if (lines[i].find("$sdkver") != -1) {
@ -2095,6 +2100,26 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
};
}
const String &additional_plist_content = p_preset->get("application/additional_plist_content");
if (!additional_plist_content.is_empty()) {
const String &plist = vformat("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
"<plist version=\"1.0\">"
"<dict>\n"
"%s\n"
"</dict>\n"
"</plist>\n",
additional_plist_content);
String plist_err;
Ref<PList> plist_parser;
plist_parser.instantiate();
if (!plist_parser->load_string(plist, plist_err)) {
err += TTR("Invalid additional PList content: ") + plist_err + "\n";
valid = false;
}
}
List<ExportOption> options;
get_export_options(&options);
for (const EditorExportPlatform::ExportOption &E : options) {