Browse Source

Write an AndroidManifest.xml file to be merged with app module's manifest.

Aman Jain 5 years ago
parent
commit
452af201b0

+ 35 - 7
platform/android/export/export.cpp

@@ -778,6 +778,30 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
 		}
 	}
 
+	void _write_tmp_manifest(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, bool p_debug) {
+		String manifest_text =
+				"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+				"<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+				"    xmlns:tools=\"http://schemas.android.com/tools\">\n";
+
+		manifest_text += _get_screen_sizes_tag(p_preset);
+		manifest_text += _get_gles_tag();
+
+		Vector<String> perms;
+		_get_permissions(p_preset, p_give_internet, perms);
+		for (int i = 0; i < perms.size(); i++) {
+			manifest_text += vformat("    <uses-permission android:name=\"%s\" />\n", perms.get(i));
+		}
+
+		manifest_text += _get_xr_features_tag(p_preset);
+		manifest_text += _get_instrumentation_tag(p_preset);
+		String plugins_names = get_plugins_names(get_enabled_plugins(p_preset));
+		manifest_text += _get_application_tag(p_preset, plugins_names);
+		manifest_text += "</manifest>\n";
+		String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release"));
+		store_string_at_path(manifest_path, manifest_text);
+	}
+
 	void _fix_manifest(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_manifest, bool p_give_internet) {
 		// Leaving the unused types commented because looking these constants up
 		// again later would be annoying
@@ -2423,6 +2447,7 @@ public:
 		EditorProgress ep("export", "Exporting for Android", 105, true);
 
 		bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build"));
+		bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG);
 
 		Ref<Image> main_image;
 		Ref<Image> foreground;
@@ -2452,9 +2477,10 @@ public:
 			if (err != OK) {
 				EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name");
 			}
-			// Copies the project icon files into the appropriate Gradle project directory
+			// Copies the project icon files into the appropriate Gradle project directory.
 			_copy_icons_to_gradle_project(p_preset, main_image, foreground, background);
-
+			// Write an AndroidManifest.xml file into the Gradle project directory.
+			_write_tmp_manifest(p_preset, p_give_internet, p_debug);
 			//build project if custom build is enabled
 			String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path");
 
@@ -2476,6 +2502,8 @@ public:
 			build_command = build_path.plus_file(build_command);
 
 			String package_name = get_package_name(p_preset->get("package/unique_name"));
+			String version_code = itos(p_preset->get("version/code"));
+			String version_name = p_preset->get("version/name");
 
 			Vector<PluginConfig> enabled_plugins = get_enabled_plugins(p_preset);
 			String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins);
@@ -2489,6 +2517,8 @@ public:
 			}
 			cmdline.push_back("build");
 			cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
+			cmdline.push_back("-Pexport_version_code=" + version_code); // argument to specify the version code.
+			cmdline.push_back("-Pexport_version_name=" + version_name); // argument to specify the version name.
 			cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies.
 			cmdline.push_back("-Pplugins_remote_binaries=" + remote_plugins_binaries); // argument to specify the list of plugins remote dependencies.
 			cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies.
@@ -2610,12 +2640,10 @@ public:
 			unzCloseCurrentFile(pkg);
 
 			//write
-
-			if (file == "AndroidManifest.xml") {
-				_fix_manifest(p_preset, data, p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG));
-			}
-
 			if (!use_custom_build) {
+				if (file == "AndroidManifest.xml") {
+					_fix_manifest(p_preset, data, p_give_internet);
+				}
 				if (file == "resources.arsc") {
 					_fix_resources(p_preset, data);
 				}

+ 100 - 0
platform/android/export/gradle_export_util.h

@@ -142,4 +142,104 @@ Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset
 	return OK;
 }
 
+String bool_to_string(bool v) {
+	return v ? "true" : "false";
+}
+
+String _get_gles_tag() {
+	bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name") == "GLES3" &&
+					 !ProjectSettings::get_singleton()->get("rendering/quality/driver/fallback_to_gles2");
+	return min_gles3 ? "    <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n" : "";
+}
+
+String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) {
+	String manifest_screen_sizes = "    <supports-screens \n        tools:node=\"replace\"";
+	String sizes[] = { "small", "normal", "large", "xlarge" };
+	size_t num_sizes = sizeof(sizes) / sizeof(sizes[0]);
+	for (size_t i = 0; i < num_sizes; i++) {
+		String feature_name = vformat("screen/support_%s", sizes[i]);
+		String feature_support = bool_to_string(p_preset->get(feature_name));
+		String xml_entry = vformat("\n        android:%sScreens=\"%s\"", sizes[i], feature_support);
+		manifest_screen_sizes += xml_entry;
+	}
+	manifest_screen_sizes += " />\n";
+	return manifest_screen_sizes;
+}
+
+String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) {
+	String manifest_xr_features;
+	bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
+	if (uses_xr) {
+		int dof_index = p_preset->get("xr_features/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof
+		if (dof_index == 1) {
+			manifest_xr_features += "    <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"false\" android:version=\"1\" />\n";
+		} else if (dof_index == 2) {
+			manifest_xr_features += "    <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"true\" android:version=\"1\" />\n";
+		}
+		int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
+		if (hand_tracking_index == 1) {
+			manifest_xr_features += "    <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n";
+		} else if (hand_tracking_index == 2) {
+			manifest_xr_features += "    <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"true\" />\n";
+		}
+	}
+	return manifest_xr_features;
+}
+
+String _get_instrumentation_tag(const Ref<EditorExportPreset> &p_preset) {
+	String package_name = p_preset->get("package/unique_name");
+	String manifest_instrumentation_text = vformat(
+			"    <instrumentation\n"
+			"        tools:node=\"replace\"\n"
+			"        android:name=\".GodotInstrumentation\"\n"
+			"        android:icon=\"@mipmap/icon\"\n"
+			"        android:label=\"@string/godot_project_name_string\"\n"
+			"        android:targetPackage=\"%s\" />\n",
+			package_name);
+	return manifest_instrumentation_text;
+}
+
+String _get_plugins_tag(const String &plugins_names) {
+	if (!plugins_names.empty()) {
+		return vformat("    <meta-data tools:node=\"replace\" android:name=\"plugins\" android:value=\"%s\" />\n", plugins_names);
+	} else {
+		return "    <meta-data tools:node=\"remove\" android:name=\"plugins\" />\n";
+	}
+}
+
+String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
+	bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
+	String orientation = (int)(p_preset->get("screen/orientation")) == 1 ? "portrait" : "landscape";
+	String manifest_activity_text = vformat(
+			"        <activity android:name=\"com.godot.game.GodotApp\" "
+			"tools:replace=\"android:screenOrientation\" "
+			"android:screenOrientation=\"%s\">\n",
+			orientation);
+	if (uses_xr) {
+		String focus_awareness = bool_to_string(p_preset->get("xr_features/focus_awareness"));
+		manifest_activity_text += vformat("            <meta-data tools:node=\"replace\" android:name=\"com.oculus.vr.focusaware\" android:value=\"%s\" />\n", focus_awareness);
+	} else {
+		manifest_activity_text += "            <meta-data tools:node=\"remove\" android:name=\"com.oculus.vr.focusaware\" />\n";
+	}
+	manifest_activity_text += "        </activity>\n";
+	return manifest_activity_text;
+}
+
+String _get_application_tag(const Ref<EditorExportPreset> &p_preset, const String &plugins_names) {
+	bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
+	String manifest_application_text =
+			"    <application android:label=\"@string/godot_project_name_string\"\n"
+			"        android:allowBackup=\"false\" tools:ignore=\"GoogleAppIndexingWarning\"\n"
+			"        android:icon=\"@mipmap/icon\">)\n\n"
+			"        <meta-data tools:node=\"remove\" android:name=\"xr_mode_metadata_name\" />\n";
+
+	manifest_application_text += _get_plugins_tag(plugins_names);
+	if (uses_xr) {
+		manifest_application_text += "        <meta-data tools:node=\"replace\" android:name=\"com.samsung.android.vr.application.mode\" android:value=\"vr_only\" />\n";
+	}
+	manifest_application_text += _get_activity_tag(p_preset);
+	manifest_application_text += "    </application>\n";
+	return manifest_application_text;
+}
+
 #endif //GODOT_GRADLE_EXPORT_UTIL_H

+ 2 - 0
platform/android/java/app/build.gradle

@@ -94,6 +94,8 @@ android {
 
         // Feel free to modify the application id to your own.
         applicationId getExportPackageName()
+        versionCode getExportVersionCode()
+        versionName getExportVersionName()
         minSdkVersion versions.minSdk
         targetSdkVersion versions.targetSdk
 //CHUNK_ANDROID_DEFAULTCONFIG_BEGIN

+ 16 - 0
platform/android/java/app/config.gradle

@@ -28,6 +28,22 @@ ext.getExportPackageName = { ->
     return appId
 }
 
+ext.getExportVersionCode = { ->
+    String versionCode = project.hasProperty("export_version_code") ? project.property("export_version_code") : ""
+    if (versionCode == null || versionCode.isEmpty()) {
+        versionCode = "1"
+    }
+    return Integer.parseInt(versionCode)
+}
+
+ext.getExportVersionName = { ->
+    String versionName = project.hasProperty("export_version_name") ? project.property("export_version_name") : ""
+    if (versionName == null || versionName.isEmpty()) {
+        versionName = "1.0"
+    }
+    return versionName
+}
+
 final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|"
 
 /**