diff options
Diffstat (limited to 'platform/macos/export')
-rw-r--r-- | platform/macos/export/export_plugin.cpp | 149 | ||||
-rw-r--r-- | platform/macos/export/export_plugin.h | 2 | ||||
-rw-r--r-- | platform/macos/export/plist.cpp | 2 |
3 files changed, 124 insertions, 29 deletions
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index de6016cb9b..49c8c7758d 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -34,6 +34,7 @@ #include "lipo.h" #include "macho.h" +#include "core/io/image_loader.h" #include "core/string/translation.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" @@ -90,11 +91,14 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP return false; } } break; - case 2: { // "altool" + case 2: { // "notarytool" + // All options are visible. + } break; + case 3: { // "altool" // All options are visible. } break; default: { // disabled - if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/apple_team_id" || p_option == "notarization/api_uuid" || p_option == "notarization/api_key") { + if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/apple_team_id" || p_option == "notarization/api_uuid" || p_option == "notarization/api_key" || p_option == "notarization/api_key_id") { return false; } } break; @@ -116,7 +120,8 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "debug/export_console_script", PROPERTY_HINT_ENUM, "No,Debug Only,Debug and Release"), 1)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.icns,*.png,*.webp,*.svg"), "")); + 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::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games")); @@ -127,9 +132,9 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false)); #ifdef MACOS_ENABLED - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),PyOxidizer rcodesign,Xcode codesign"), 3, true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),rcodesign,Xcode codesign"), 3, true)); #else - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),PyOxidizer rcodesign"), 1, true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),rcodesign"), 1, true)); #endif // "codesign" only options: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), "")); @@ -163,17 +168,18 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray())); #ifdef MACOS_ENABLED - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,PyOxidizer rcodesign,Xcode altool"), 0, true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,rcodesign,Xcode notarytool,Xcode altool (deprecated)"), 0, true)); #else - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,PyOxidizer rcodesign"), 0, true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,rcodesign"), 0, true)); #endif - // "altool" only options: + // "altool" and "notarytool" only options: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_team_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide team ID if your Apple ID belongs to multiple teams"), "")); - // "altool" and "rcodesign" only options: - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID"), "")); + // "altool", "notarytool" and "rcodesign" only options: + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID UUID"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_GLOBAL_FILE, "*.p8"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); @@ -268,7 +274,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, memcpy(&p_dest.write[ofs], result.ptr(), res_size); } -void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { +void EditorExportPlatformMacOS::_make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { Ref<ImageTexture> it = memnew(ImageTexture); Vector<uint8_t> data; @@ -302,7 +308,7 @@ void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy? copy->convert(Image::FORMAT_RGBA8); - copy->resize(icon_infos[i].size, icon_infos[i].size); + copy->resize(icon_infos[i].size, icon_infos[i].size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int())); if (icon_infos[i].is_png) { // Encode PNG icon. @@ -496,7 +502,12 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres args.push_back(p_preset->get("notarization/api_uuid")); args.push_back("--api-key"); - args.push_back(p_preset->get("notarization/api_key")); + args.push_back(p_preset->get("notarization/api_key_id")); + + if (!p_preset->get("notarization/api_key").operator String().is_empty()) { + args.push_back("--api-key-path"); + args.push_back(p_preset->get("notarization/api_key")); + } args.push_back(p_path); @@ -517,7 +528,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres } else { print_verbose("rcodesign (" + p_path + "):\n" + str); int next_nl = str.find("\n", rq_offset); - String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14); + String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 23, -1) : str.substr(rq_offset + 23, next_nl - rq_offset - 23); add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid)); add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour.")); add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:")); @@ -527,7 +538,91 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres } } break; #ifdef MACOS_ENABLED - case 2: { // "altool" + case 2: { // "notarytool" + print_verbose("using notarytool notarization..."); + + if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Xcode command line tools are not installed.")); + return Error::FAILED; + } + + List<String> args; + + args.push_back("notarytool"); + args.push_back("submit"); + + args.push_back(p_path); + + if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Neither Apple ID name nor App Store Connect issuer ID name not specified.")); + return Error::FAILED; + } + if (p_preset->get("notarization/apple_id_name") != "" && p_preset->get("notarization/api_uuid") != "") { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time.")); + return Error::FAILED; + } + + if (p_preset->get("notarization/apple_id_name") != "") { + if (p_preset->get("notarization/apple_id_password") == "") { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Apple ID password not specified.")); + return Error::FAILED; + } + args.push_back("--apple-id"); + args.push_back(p_preset->get("notarization/apple_id_name")); + + args.push_back("--password"); + args.push_back(p_preset->get("notarization/apple_id_password")); + } else { + if (p_preset->get("notarization/api_key_id") == "") { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified.")); + return Error::FAILED; + } + args.push_back("--issuer"); + args.push_back(p_preset->get("notarization/api_uuid")); + + if (!p_preset->get("notarization/api_key").operator String().is_empty()) { + args.push_back("--key"); + args.push_back(p_preset->get("notarization/api_key")); + } + + args.push_back("--key-id"); + args.push_back(p_preset->get("notarization/api_key_id")); + } + + args.push_back("--no-progress"); + + if (p_preset->get("notarization/apple_team_id")) { + args.push_back("--team-id"); + args.push_back(p_preset->get("notarization/apple_team_id")); + } + + String str; + int exitcode = 0; + Error err = OS::get_singleton()->execute("xcrun", args, &str, &exitcode, true); + if (err != OK) { + add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start xcrun executable.")); + return err; + } + + int rq_offset = str.find("id:"); + if (exitcode != 0 || rq_offset == -1) { + print_line("notarytool (" + p_path + "):\n" + str); + add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed, see editor log for details.")); + return Error::FAILED; + } else { + print_verbose("notarytool (" + p_path + "):\n" + str); + int next_nl = str.find("\n", rq_offset); + String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 4, -1) : str.substr(rq_offset + 4, next_nl - rq_offset - 4); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid)); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour.")); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:")); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun notarytool log <request uuid> --issuer <api uuid> --key-id <api key id> --key <api key path>\" or"); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun notarytool log <request uuid> --apple-id <your email> --password <app-specific pwd>>\""); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):")); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun stapler staple <app path>\""); + } + } break; + case 3: { // "altool" print_verbose("using altool notarization..."); if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) { @@ -571,7 +666,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres args.push_back(p_preset->get("notarization/api_uuid")); args.push_back("--apiKey"); - args.push_back(p_preset->get("notarization/api_key")); + args.push_back(p_preset->get("notarization/api_key_id")); } args.push_back("--type"); @@ -593,7 +688,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres return err; } - int rq_offset = str.find("RequestUUID"); + int rq_offset = str.find("RequestUUID:"); if (exitcode != 0 || rq_offset == -1) { print_line("xcrun altool (" + p_path + "):\n" + str); add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed, see editor log for details.")); @@ -601,7 +696,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres } else { print_verbose("xcrun altool (" + p_path + "):\n" + str); int next_nl = str.find("\n", rq_offset); - String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14); + String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 13, -1) : str.substr(rq_offset + 13, next_nl - rq_offset - 13); add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid)); add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour. When the process is completed, you'll receive an email.")); add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:")); @@ -726,7 +821,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre String str; int exitcode = 0; - Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true); + Error err = OS::get_singleton()->execute("codesign", args, &str, &exitcode, true); if (err != OK) { add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed.")); return err; @@ -1270,9 +1365,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p } else { Ref<Image> icon; icon.instantiate(); - icon->load(iconpath); - if (!icon->is_empty()) { - _make_icon(icon, data); + err = ImageLoader::load_image(iconpath, icon); + if (err == OK && !icon->is_empty()) { + _make_icon(p_preset, icon, data); } } } @@ -1817,7 +1912,7 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor err += TTR("Notarization: Code signing is required for notarization.") + "\n"; valid = false; } - if (notary_tool == 2) { + if (notary_tool == 2 || notary_tool == 3) { if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) { err += TTR("Notarization: Xcode command line tools are not installed.") + "\n"; valid = false; @@ -1832,11 +1927,11 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor if (p_preset->get("notarization/apple_id_name") != "") { if (p_preset->get("notarization/apple_id_password") == "") { err += TTR("Notarization: Apple ID password not specified.") + "\n"; + valid = false; } - valid = false; } if (p_preset->get("notarization/api_uuid") != "") { - if (p_preset->get("notarization/api_key") == "") { + if (p_preset->get("notarization/api_key_id") == "") { err += TTR("Notarization: App Store Connect API key ID not specified.") + "\n"; valid = false; } @@ -1847,7 +1942,7 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor err += TTR("Notarization: App Store Connect issuer ID name not specified.") + "\n"; valid = false; } - if (p_preset->get("notarization/api_key") == "") { + if (p_preset->get("notarization/api_key_id") == "") { err += TTR("Notarization: App Store Connect API key ID not specified.") + "\n"; valid = false; } diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h index b6ad587caa..af7570c394 100644 --- a/platform/macos/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -53,7 +53,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform { Ref<ImageTexture> logo; void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary); - void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data); + void _make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data); Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path); Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true); diff --git a/platform/macos/export/plist.cpp b/platform/macos/export/plist.cpp index cad014e65b..82ecd41d9c 100644 --- a/platform/macos/export/plist.cpp +++ b/platform/macos/export/plist.cpp @@ -353,7 +353,7 @@ bool PList::load_file(const String &p_filename) { } else { // Load text plist. Error err; - Vector<uint8_t> array = FileAccess::get_file_as_array(p_filename, &err); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(p_filename, &err); ERR_FAIL_COND_V(err != OK, false); String ret; |