diff options
author | RĂ©mi Verschelde <rverschelde@gmail.com> | 2019-04-23 17:39:23 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-23 17:39:23 +0200 |
commit | 6098a7f1914f64c77d689f54d5432095911b744f (patch) | |
tree | bf07da3b3177f3d104ecb5a66a7dc24b207fb08a /platform | |
parent | b0da7b66ce278179eedd0e21dae1d84ed3f4459d (diff) | |
parent | dd03dcbd5a1d4a23d4fb3aa41da0c91fe2c5eda5 (diff) |
Merge pull request #27781 from reduz/new_android_export
Android now (optionally) builds the template when exporting
Diffstat (limited to 'platform')
-rw-r--r-- | platform/android/SCsub | 108 | ||||
-rw-r--r-- | platform/android/build.gradle.template | 88 | ||||
-rw-r--r-- | platform/android/export/export.cpp | 399 | ||||
-rw-r--r-- | platform/android/file_access_android.h | 2 | ||||
-rw-r--r-- | platform/android/file_access_jandroid.h | 2 | ||||
-rw-r--r-- | platform/android/java/AndroidManifest.xml (renamed from platform/android/AndroidManifest.xml.template) | 26 | ||||
-rw-r--r-- | platform/android/java/build.gradle | 115 | ||||
-rw-r--r-- | platform/osx/export/export.cpp | 2 | ||||
-rw-r--r-- | platform/windows/os_windows.cpp | 8 | ||||
-rw-r--r-- | platform/windows/os_windows.h | 2 |
10 files changed, 525 insertions, 227 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub index d494372bcd..22ed476c6f 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -34,114 +34,6 @@ env_thirdparty = env_android.Clone() env_thirdparty.disable_warnings() android_objects.append(env_thirdparty.SharedObject('#thirdparty/misc/ifaddrs-android.cc')) -abspath = env.Dir(".").abspath - -with open_utf8(abspath + "/build.gradle.template", "r") as gradle_basein: - gradle_text = gradle_basein.read() - -gradle_maven_flat_text = "" -if len(env.android_flat_dirs) > 0: - gradle_maven_flat_text += "flatDir {\n" - gradle_maven_flat_text += "\tdirs " - for x in env.android_flat_dirs: - gradle_maven_flat_text += "'" + x + "'," - - gradle_maven_flat_text = gradle_maven_flat_text[:-1] - gradle_maven_flat_text += "\n\t}\n" - -gradle_maven_repos_text = "" -gradle_maven_repos_text += gradle_maven_flat_text - -if len(env.android_maven_repos) > 0: - gradle_maven_repos_text += "" - for x in env.android_maven_repos: - gradle_maven_repos_text += "\tmaven {\n" - gradle_maven_repos_text += "\t" + x + "\n" - gradle_maven_repos_text += "\t}\n" - -gradle_maven_dependencies_text = "" - -for x in env.android_dependencies: - gradle_maven_dependencies_text += x + "\n\t" - -gradle_java_dirs_text = "" - -for x in env.android_java_dirs: - gradle_java_dirs_text += ",'" + x.replace("\\", "/") + "'" - -gradle_plugins = "" -for x in env.android_gradle_plugins: - gradle_plugins += "apply plugin: \"" + x + "\"\n" - -gradle_classpath = "" -for x in env.android_gradle_classpath: - gradle_classpath += "\t\tclasspath \"" + x + "\"\n" - -gradle_res_dirs_text = "" - -for x in env.android_res_dirs: - gradle_res_dirs_text += ",'" + x.replace("\\", "/") + "'" - -gradle_aidl_dirs_text = "" - -for x in env.android_aidl_dirs: - gradle_aidl_dirs_text += ",'" + x.replace("\\", "/") + "'" - -gradle_jni_dirs_text = "" - -for x in env.android_jni_dirs: - gradle_jni_dirs_text += ",'" + x.replace("\\", "/") + "'" - -gradle_asset_dirs_text = "" - -for x in env.android_asset_dirs: - gradle_asset_dirs_text += ",'" + x.replace("\\", "/") + "'" - -gradle_default_config_text = "" - -minSdk = 18 -targetSdk = 28 - -for x in env.android_default_config: - if x.startswith("minSdkVersion") and int(x.split(" ")[-1]) < minSdk: - x = "minSdkVersion " + str(minSdk) - if x.startswith("targetSdkVersion") and int(x.split(" ")[-1]) > targetSdk: - x = "targetSdkVersion " + str(targetSdk) - - gradle_default_config_text += x + "\n\t\t" - -if "minSdkVersion" not in gradle_default_config_text: - gradle_default_config_text += ("minSdkVersion " + str(minSdk) + "\n\t\t") - -if "targetSdkVersion" not in gradle_default_config_text: - gradle_default_config_text += ("targetSdkVersion " + str(targetSdk) + "\n\t\t") - -gradle_text = gradle_text.replace("$$GRADLE_REPOSITORY_URLS$$", gradle_maven_repos_text) -gradle_text = gradle_text.replace("$$GRADLE_DEPENDENCIES$$", gradle_maven_dependencies_text) -gradle_text = gradle_text.replace("$$GRADLE_JAVA_DIRS$$", gradle_java_dirs_text) -gradle_text = gradle_text.replace("$$GRADLE_RES_DIRS$$", gradle_res_dirs_text) -gradle_text = gradle_text.replace("$$GRADLE_ASSET_DIRS$$", gradle_asset_dirs_text) -gradle_text = gradle_text.replace("$$GRADLE_AIDL_DIRS$$", gradle_aidl_dirs_text) -gradle_text = gradle_text.replace("$$GRADLE_JNI_DIRS$$", gradle_jni_dirs_text) -gradle_text = gradle_text.replace("$$GRADLE_DEFAULT_CONFIG$$", gradle_default_config_text) -gradle_text = gradle_text.replace("$$GRADLE_PLUGINS$$", gradle_plugins) -gradle_text = gradle_text.replace("$$GRADLE_CLASSPATH$$", gradle_classpath) - -with open_utf8(abspath + "/java/build.gradle", "w") as gradle_baseout: - gradle_baseout.write(gradle_text) - - -with open_utf8(abspath + "/AndroidManifest.xml.template", "r") as pp_basein: - manifest = pp_basein.read() - -manifest = manifest.replace("$$ADD_APPLICATION_CHUNKS$$", env.android_manifest_chunk) -manifest = manifest.replace("$$ADD_PERMISSION_CHUNKS$$", env.android_permission_chunk) -manifest = manifest.replace("$$ADD_APPATTRIBUTE_CHUNKS$$", env.android_appattributes_chunk) - -with open_utf8(abspath + "/java/AndroidManifest.xml", "w") as pp_baseout: - pp_baseout.write(manifest) - - lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"]) lib_arch_dir = '' diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template deleted file mode 100644 index 2fea250061..0000000000 --- a/platform/android/build.gradle.template +++ /dev/null @@ -1,88 +0,0 @@ -buildscript { - repositories { - google() - jcenter() - $$GRADLE_REPOSITORY_URLS$$ - } - dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' - $$GRADLE_CLASSPATH$$ - } -} - -apply plugin: 'com.android.application' - -allprojects { - repositories { - mavenCentral() - google() - jcenter() - $$GRADLE_REPOSITORY_URLS$$ - } -} - -dependencies { - implementation "com.android.support:support-core-utils:28.0.0" - $$GRADLE_DEPENDENCIES$$ -} - -android { - - lintOptions { - abortOnError false - disable 'MissingTranslation','UnusedResources' - } - - compileSdkVersion 28 - buildToolsVersion "28.0.3" - useLibrary 'org.apache.http.legacy' - - packagingOptions { - exclude 'META-INF/LICENSE' - exclude 'META-INF/NOTICE' - } - defaultConfig { - $$GRADLE_DEFAULT_CONFIG$$ - } - // Both signing and zip-aligning will be done at export time - buildTypes.all { buildType -> - buildType.zipAlignEnabled false - buildType.signingConfig null - } - sourceSets { - main { - manifest.srcFile 'AndroidManifest.xml' - java.srcDirs = ['src' - $$GRADLE_JAVA_DIRS$$ - ] - res.srcDirs = [ - 'res' - $$GRADLE_RES_DIRS$$ - ] - aidl.srcDirs = [ - 'aidl' - $$GRADLE_AIDL_DIRS$$ - ] - assets.srcDirs = [ - 'assets' - $$GRADLE_ASSET_DIRS$$ - ] - } - debug.jniLibs.srcDirs = [ - 'libs/debug' - $$GRADLE_JNI_DIRS$$ - ] - release.jniLibs.srcDirs = [ - 'libs/release' - $$GRADLE_JNI_DIRS$$ - ] - } - - applicationVariants.all { variant -> - variant.outputs.all { output -> - output.outputFileName = "../../../../../../../bin/android_${variant.name}.apk" - } - } -} - -$$GRADLE_PLUGINS$$ diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index afccbd113e..f70cee2964 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -417,6 +417,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { name = "noname"; pname = pname.replace("$genname", name); + return pname; } @@ -1143,11 +1144,12 @@ public: r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_package/use_custom_build"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.$genname"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "screen/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait"), 0)); @@ -1388,21 +1390,25 @@ public: virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err; - r_missing_templates = find_export_template("android_debug.apk") == String() || find_export_template("android_release.apk") == String(); - if (p_preset->get("custom_package/debug") != "") { - if (FileAccess::exists(p_preset->get("custom_package/debug"))) { - r_missing_templates = false; - } else { - err += TTR("Custom debug template not found.") + "\n"; + if (!bool(p_preset->get("custom_package/use_custom_build"))) { + + r_missing_templates = find_export_template("android_debug.apk") == String() || find_export_template("android_release.apk") == String(); + + if (p_preset->get("custom_package/debug") != "") { + if (FileAccess::exists(p_preset->get("custom_package/debug"))) { + r_missing_templates = false; + } else { + err += TTR("Custom debug template not found.") + "\n"; + } } - } - if (p_preset->get("custom_package/release") != "") { - if (FileAccess::exists(p_preset->get("custom_package/release"))) { - r_missing_templates = false; - } else { - err += TTR("Custom release template not found.") + "\n"; + if (p_preset->get("custom_package/release") != "") { + if (FileAccess::exists(p_preset->get("custom_package/release"))) { + r_missing_templates = false; + } else { + err += TTR("Custom release template not found.") + "\n"; + } } } @@ -1435,6 +1441,30 @@ public: } } + if (bool(p_preset->get("custom_package/use_custom_build"))) { + String sdk_path = EditorSettings::get_singleton()->get("export/android/custom_build_sdk_path"); + if (sdk_path == "") { + err += TTR("Custom build requires a valid Android SDK path in Editor Settings.") + "\n"; + valid = false; + } else { + Error errn; + DirAccess *da = DirAccess::open(sdk_path.plus_file("tools"), &errn); + if (errn != OK) { + err += TTR("Invalid Android SDK path for custom build in Editor Settings.") + "\n"; + valid = false; + } + if (da) { + memdelete(da); + } + } + + if (!FileAccess::exists("res://android/build/build.gradle")) { + + err += TTR("Android project is not installed for compiling. Install from Editor menu.") + "\n"; + valid = false; + } + } + bool apk_expansion = p_preset->get("apk_expansion/enable"); if (apk_expansion) { @@ -1473,6 +1503,260 @@ public: return list; } + void _update_custom_build_project() { + + DirAccessRef da = DirAccess::open("res://android"); + + ERR_FAIL_COND(!da); + Map<String, List<String> > directory_paths; + Map<String, List<String> > manifest_sections; + Map<String, List<String> > gradle_sections; + da->list_dir_begin(); + String d = da->get_next(); + while (d != String()) { + + if (!d.begins_with(".") && d != "build" && da->current_is_dir()) { //a dir and not the build dir + //add directories found + DirAccessRef ds = DirAccess::open(String("res://android").plus_file(d)); + if (ds) { + ds->list_dir_begin(); + String sd = ds->get_next(); + while (sd != String()) { + + if (!sd.begins_with(".") && ds->current_is_dir()) { + String key = sd.to_upper(); + if (!directory_paths.has(key)) { + directory_paths[key] = List<String>(); + } + String path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android").plus_file(d).plus_file(sd); + directory_paths[key].push_back(path); + print_line("Add: " + sd + ":" + path); + } + + sd = ds->get_next(); + } + ds->list_dir_end(); + } + //parse manifest + { + FileAccessRef f = FileAccess::open(String("res://android").plus_file(d).plus_file("AndroidManifest.conf"), FileAccess::READ); + if (f) { + + String section; + while (!f->eof_reached()) { + String l = f->get_line(); + String k = l.strip_edges(); + if (k.begins_with("[")) { + section = k.substr(1, k.length() - 2).strip_edges().to_upper(); + print_line("Section: " + section); + } else if (k != String()) { + if (!manifest_sections.has(section)) { + manifest_sections[section] = List<String>(); + } + manifest_sections[section].push_back(l); + } + } + + f->close(); + } + } + //parse gradle + { + FileAccessRef f = FileAccess::open(String("res://android").plus_file(d).plus_file("gradle.conf"), FileAccess::READ); + if (f) { + + String section; + while (!f->eof_reached()) { + String l = f->get_line().strip_edges(); + String k = l.strip_edges(); + if (k.begins_with("[")) { + section = k.substr(1, k.length() - 2).strip_edges().to_upper(); + print_line("Section: " + section); + } else if (k != String()) { + if (!gradle_sections.has(section)) { + gradle_sections[section] = List<String>(); + } + gradle_sections[section].push_back(l); + } + } + } + } + } + d = da->get_next(); + } + da->list_dir_end(); + + { //fix gradle build + + String new_file; + { + FileAccessRef f = FileAccess::open("res://android/build/build.gradle", FileAccess::READ); + if (f) { + + while (!f->eof_reached()) { + String l = f->get_line(); + + if (l.begins_with("//CHUNK_")) { + String text = l.replace_first("//CHUNK_", ""); + int begin_pos = text.find("_BEGIN"); + if (begin_pos != -1) { + text = text.substr(0, begin_pos); + text = text.to_upper(); //just in case + + String end_marker = "//CHUNK_" + text + "_END"; + size_t pos = f->get_position(); + bool found = false; + while (!f->eof_reached()) { + l = f->get_line(); + if (l.begins_with(end_marker)) { + found = true; + break; + } + } + + new_file += "//CHUNK_" + text + "_BEGIN\n"; + + if (!found) { + ERR_PRINTS("No end marker found in build.gradle for chunk: " + text); + f->seek(pos); + } else { + + //add chunk lines + if (gradle_sections.has(text)) { + for (List<String>::Element *E = gradle_sections[text].front(); E; E = E->next()) { + new_file += E->get() + "\n"; + } + } + new_file += end_marker + "\n"; + } + } else { + new_file += l + "\n"; //pass line by + } + } else if (l.begins_with("//DIR_")) { + String text = l.replace_first("//DIR_", ""); + int begin_pos = text.find("_BEGIN"); + if (begin_pos != -1) { + text = text.substr(0, begin_pos); + text = text.to_upper(); //just in case + + String end_marker = "//DIR_" + text + "_END"; + size_t pos = f->get_position(); + bool found = false; + while (!f->eof_reached()) { + l = f->get_line(); + if (l.begins_with(end_marker)) { + found = true; + break; + } + } + + new_file += "//DIR_" + text + "_BEGIN\n"; + + if (!found) { + ERR_PRINTS("No end marker found in build.gradle for dir: " + text); + f->seek(pos); + } else { + //add chunk lines + if (directory_paths.has(text)) { + for (List<String>::Element *E = directory_paths[text].front(); E; E = E->next()) { + new_file += ",'" + E->get().replace("'", "\'") + "'"; + new_file += "\n"; + } + } + new_file += end_marker + "\n"; + } + } else { + new_file += l + "\n"; //pass line by + } + + } else { + new_file += l + "\n"; + } + } + } + } + + FileAccessRef f = FileAccess::open("res://android/build/build.gradle", FileAccess::WRITE); + f->store_string(new_file); + f->close(); + } + + { //fix manifest + + String new_file; + { + FileAccessRef f = FileAccess::open("res://android/build/AndroidManifest.xml", FileAccess::READ); + if (f) { + + while (!f->eof_reached()) { + String l = f->get_line(); + + if (l.begins_with("<!--CHUNK_")) { + String text = l.replace_first("<!--CHUNK_", ""); + int begin_pos = text.find("_BEGIN-->"); + if (begin_pos != -1) { + text = text.substr(0, begin_pos); + text = text.to_upper(); //just in case + + String end_marker = "<!--CHUNK_" + text + "_END-->"; + size_t pos = f->get_position(); + bool found = false; + while (!f->eof_reached()) { + l = f->get_line(); + if (l.begins_with(end_marker)) { + found = true; + break; + } + } + + new_file += "<!--CHUNK_" + text + "_BEGIN-->\n"; + + if (!found) { + ERR_PRINTS("No end marker found in AndroidManifest.conf for chunk: " + text); + f->seek(pos); + } else { + //add chunk lines + if (manifest_sections.has(text)) { + for (List<String>::Element *E = manifest_sections[text].front(); E; E = E->next()) { + new_file += E->get() + "\n"; + } + } + new_file += end_marker + "\n"; + } + } else { + new_file += l + "\n"; //pass line by + } + + } else if (l.strip_edges().begins_with("<application")) { + String last_tag = "android:icon=\"@drawable/icon\""; + int last_tag_pos = l.find(last_tag); + if (last_tag_pos == -1) { + WARN_PRINTS("No adding of application tags because could not find last tag for <application: " + last_tag); + new_file += l + "\n"; + } else { + String base = l.substr(0, last_tag_pos + last_tag.length()); + if (manifest_sections.has("application_tags")) { + for (List<String>::Element *E = manifest_sections["application_tags"].front(); E; E = E->next()) { + String to_add = E->get().strip_edges(); + base += " " + to_add + " "; + } + } + base += ">\n"; + new_file += base; + } + } else { + new_file += l + "\n"; + } + } + } + } + + FileAccessRef f = FileAccess::open("res://android/build/AndroidManifest.xml", FileAccess::WRITE); + f->store_string(new_file); + f->close(); + } + } + virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) { ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); @@ -1481,21 +1765,86 @@ public: EditorProgress ep("export", "Exporting for Android", 105); - if (p_debug) - src_apk = p_preset->get("custom_package/debug"); - else - src_apk = p_preset->get("custom_package/release"); + if (bool(p_preset->get("custom_package/use_custom_build"))) { //custom build + //re-generate build.gradle and AndroidManifest.xml - src_apk = src_apk.strip_edges(); - if (src_apk == "") { + { //test that installed build version is alright + FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ); + if (!f) { + EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu.")); + return ERR_UNCONFIGURED; + } + String version = f->get_line().strip_edges(); + if (version != VERSION_FULL_CONFIG) { + EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG)); + return ERR_UNCONFIGURED; + } + } + //build project if custom build is enabled + String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path"); + + ERR_FAIL_COND_V(sdk_path == "", ERR_UNCONFIGURED); + + _update_custom_build_project(); + + OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required + + String build_command; +#ifdef WINDOWS_ENABLED + build_command = "gradlew.bat"; +#else + build_command = "gradlew"; +#endif + + String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build"); + + build_command = build_path.plus_file(build_command); + + List<String> cmdline; + cmdline.push_back("build"); + cmdline.push_back("-p"); + cmdline.push_back(build_path); + /*{ used for debug + int ec; + String pipe; + OS::get_singleton()->execute(build_command, cmdline, true, NULL, NULL, &ec); + print_line("exit code: " + itos(ec)); + } + */ + int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline); + if (result != 0) { + EditorNode::get_singleton()->show_warning(TTR("Building of Android project failed, check output for the error.\nAlternatively visit docs.godotengine.org for Android build documentation.")); + return ERR_CANT_CREATE; + } if (p_debug) { - src_apk = find_export_template("android_debug.apk"); + src_apk = build_path.plus_file("build/outputs/apk/debug/build-debug-unsigned.apk"); } else { - src_apk = find_export_template("android_release.apk"); + src_apk = build_path.plus_file("build/outputs/apk/release/build-release-unsigned.apk"); + } + + if (!FileAccess::exists(src_apk)) { + EditorNode::get_singleton()->show_warning(TTR("No build apk generated at: ") + "\n" + src_apk); + return ERR_CANT_CREATE; } + + } else { + + if (p_debug) + src_apk = p_preset->get("custom_package/debug"); + else + src_apk = p_preset->get("custom_package/release"); + + src_apk = src_apk.strip_edges(); if (src_apk == "") { - EditorNode::add_io_error("Package not found: " + src_apk); - return ERR_FILE_NOT_FOUND; + if (p_debug) { + src_apk = find_export_template("android_debug.apk"); + } else { + src_apk = find_export_template("android_release.apk"); + } + if (src_apk == "") { + EditorNode::add_io_error("Package not found: " + src_apk); + return ERR_FILE_NOT_FOUND; + } } } @@ -1975,6 +2324,8 @@ void register_android_exporter() { EDITOR_DEF("export/android/debug_keystore_user", "androiddebugkey"); EDITOR_DEF("export/android/debug_keystore_pass", "android"); EDITOR_DEF("export/android/force_system_user", false); + EDITOR_DEF("export/android/custom_build_sdk_path", ""); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/custom_build_sdk_path", PROPERTY_HINT_GLOBAL_DIR, "*.keystore")); EDITOR_DEF("export/android/timestamping_authority_url", ""); EDITOR_DEF("export/android/shutdown_adb_on_exit", true); diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index f8d46ea5d2..b8e78627ec 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -70,6 +70,8 @@ public: virtual bool file_exists(const String &p_path); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file) { return 0; } + virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } //static void make_default(); diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h index 4f02fea81d..9429100d65 100644 --- a/platform/android/file_access_jandroid.h +++ b/platform/android/file_access_jandroid.h @@ -74,6 +74,8 @@ public: static void setup(jobject p_io); virtual uint64_t _get_modified_time(const String &p_file) { return 0; } + virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } FileAccessJAndroid(); ~FileAccessJAndroid(); diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/java/AndroidManifest.xml index daaf847f11..29ddd844ba 100644 --- a/platform/android/AndroidManifest.xml.template +++ b/platform/android/java/AndroidManifest.xml @@ -11,11 +11,20 @@ android:largeScreens="true" android:xlargeScreens="true"/> +<!--glEsVersion is modified by the exporter, changing this value here has no effect--> <uses-feature android:glEsVersion="0x00020000" android:required="true" /> +<!--Adding custom text to manifest is fine, but do it outside the custom user and application BEGIN/ENDregions, as that gets rewritten--> -$$ADD_PERMISSION_CHUNKS$$ +<!--Custom permissions XML added by add-ons. It's recommended to add them from the export preset, though--> +<!--CHUNK_USER_PERMISSIONS_BEGIN--> +<!--CHUNK_USER_PERMISSIONS_END--> + +<!--Anything in this line after the icon will be erased when doing custom build. If you want to add tags manually, do before it.--> + <application android:label="@string/godot_project_name_string" android:allowBackup="false" tools:ignore="GoogleAppIndexingWarning" android:icon="@drawable/icon"> + +<!--The following values are replaced when Godot exports, modifying them here has no effect. Do theses changes in the--> +<!--export preset. Adding new ones is fine.--> - <application android:label="@string/godot_project_name_string" android:icon="@drawable/icon" android:allowBackup="false" tools:ignore="GoogleAppIndexingWarning" $$ADD_APPATTRIBUTE_CHUNKS$$ > <activity android:name="org.godotengine.godot.Godot" android:label="@string/godot_project_name_string" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" @@ -32,13 +41,22 @@ $$ADD_PERMISSION_CHUNKS$$ </activity> <service android:name="org.godotengine.godot.GodotDownloaderService" /> -$$ADD_APPLICATION_CHUNKS$$ +<!--Custom application XML added by add-ons--> +<!--CHUNK_APPLICATION_BEGIN--> +<activity android:name="com.google.android.gms.ads.AdActivity" + android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/> +<meta-data android:name="com.google.android.gms.version" + android:value="@integer/google_play_services_version" /> +<meta-data + android:name="com.google.android.gms.ads.AD_MANAGER_APP" + android:value="true"/> +<!--CHUNK_APPLICATION_END--> </application> <instrumentation android:icon="@drawable/icon" android:label="@string/godot_project_name_string" android:name="org.godotengine.godot.GodotInstrumentation" - android:targetPackage="com.godot.game" /> + android:targetPackage="org.godotengine.game" /> </manifest> diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle new file mode 100644 index 0000000000..868bbee831 --- /dev/null +++ b/platform/android/java/build.gradle @@ -0,0 +1,115 @@ +//Gradle project for Godot Engine Android port. +//Do not modify code between the BEGIN/END sections, as it's autogenerated by add-ons + +buildscript { + repositories { + google() + jcenter() +//CHUNK_BUILDSCRIPT_REPOSITORIES_BEGIN +//CHUNK_BUILDSCRIPT_REPOSITORIES_END + } + dependencies { + classpath 'com.android.tools.build:gradle:3.2.1' +//CHUNK_BUILD_DEPENDENCIES_BEGIN +//CHUNK_BUILD_DEPENDENCIES_END + } +} + +apply plugin: 'com.android.application' + +allprojects { + repositories { + mavenCentral() + google() + jcenter() +//CHUNK_ALLPROJECTS_REPOSITORIES_BEGIN +//CHUNK_ALLPROJECTS_REPOSITORIES_END + + } +} + +dependencies { + implementation "com.android.support:support-core-utils:28.0.0" +//CHUNK_DEPENDENCIES_BEGIN +compile ('com.google.android.gms:play-services-ads:16.0.0') { exclude group: 'com.android.support' } +//CHUNK_DEPENDENCIES_END +} + +android { + + lintOptions { + abortOnError false + disable 'MissingTranslation','UnusedResources' + } + + compileSdkVersion 28 + buildToolsVersion "28.0.3" + useLibrary 'org.apache.http.legacy' + + packagingOptions { + exclude 'META-INF/LICENSE' + exclude 'META-INF/NOTICE' + } + defaultConfig { + minSdkVersion 18 + targetSdkVersion 28 +//CHUNK_ANDROID_DEFAULTCONFIG_BEGIN +//CHUNK_ANDROID_DEFAULTCONFIG_END + } + // Both signing and zip-aligning will be done at export time + buildTypes.all { buildType -> + buildType.zipAlignEnabled false + buildType.signingConfig null + } + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src' +//DIR_SRC_BEGIN +,'/home/red/coding/godot-demos/2d/platformer/android/admob/src' +//DIR_SRC_END + ] + res.srcDirs = [ + 'res' +//DIR_RES_BEGIN +//DIR_RES_END + ] + aidl.srcDirs = [ + 'aidl' +//DIR_AIDL_BEGIN +//DIR_AIDL_END + ] + assets.srcDirs = [ + 'assets' +//DIR_ASSETS_BEGIN +//DIR_ASSETS_END + + ] + } + debug.jniLibs.srcDirs = [ + 'libs/debug' +//DIR_JNI_DEBUG_BEGIN +//DIR_JNI_DEBUG_END + ] + release.jniLibs.srcDirs = [ + 'libs/release' +//DIR_JNI_RELEASE_BEGIN +//DIR_JNI_RELEASE_END + ] + } +// No longer used, as it's not useful for build source template +// applicationVariants.all { variant -> +// variant.outputs.all { output -> +// output.outputFileName = "../../../../../../../bin/android_${variant.name}.apk" +// } +// } + +} + +//CHUNK_GLOBAL_BEGIN +//CHUNK_GLOBAL_END + + + + + diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 5e94bc457b..1a63d6ff75 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -568,7 +568,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p f->close(); if (is_execute) { // Chmod with 0755 if the file is executable - f->_chmod(file, 0755); + FileAccess::set_unix_permissions(file, 0755); } memdelete(f); } else { diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 5e12106639..0c3d8af220 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -2460,7 +2460,7 @@ void OS_Windows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, DeleteDC(hMainDC); } -Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) { +Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) { if (p_blocking && r_pipe) { @@ -2479,7 +2479,13 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, char buf[65535]; while (fgets(buf, 65535, f)) { + if (p_pipe_mutex) { + p_pipe_mutex->lock(); + } (*r_pipe) += buf; + if (p_pipe_mutex) { + p_pipe_mutex->lock(); + } } int rv = _pclose(f); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index c15e1cabc3..0e0b9bf3f6 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -261,7 +261,7 @@ public: virtual void delay_usec(uint32_t p_usec) const; virtual uint64_t get_ticks_usec() const; - virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false); + virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL); virtual Error kill(const ProcessID &p_pid); virtual int get_process_id() const; |