|
@@ -1554,6 +1554,7 @@ public:
|
|
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
|
|
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
|
|
|
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_template/use_custom_build"), false));
|
|
|
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "custom_template/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), 0));
|
|
|
|
|
|
Vector<PluginConfig> plugins_configs = get_plugins();
|
|
|
for (int i = 0; i < plugins_configs.size(); i++) {
|
|
@@ -1974,6 +1975,13 @@ public:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (int(p_preset->get("custom_template/export_format")) == 1 && /*AAB*/
|
|
|
+ !bool(p_preset->get("custom_template/use_custom_build"))) {
|
|
|
+ valid = false;
|
|
|
+ err += TTR("\"Export AAB\" is only valid when \"Use Custom Build\" is enabled.");
|
|
|
+ err += "\n";
|
|
|
+ }
|
|
|
+
|
|
|
r_error = err;
|
|
|
return valid;
|
|
|
}
|
|
@@ -1981,6 +1989,7 @@ public:
|
|
|
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
|
|
|
List<String> list;
|
|
|
list.push_back("apk");
|
|
|
+ list.push_back("aab");
|
|
|
return list;
|
|
|
}
|
|
|
|
|
@@ -2007,7 +2016,21 @@ public:
|
|
|
return have_plugins_changed || first_build;
|
|
|
}
|
|
|
|
|
|
- Error get_command_line_flags(const Ref<EditorExportPreset> &p_preset, const String &p_path, int p_flags, Vector<uint8_t> &r_command_line_flags) {
|
|
|
+ String get_apk_expansion_fullpath(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
|
|
|
+ int version_code = p_preset->get("version/code");
|
|
|
+ String package_name = p_preset->get("package/unique_name");
|
|
|
+ String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb";
|
|
|
+ String fullpath = p_path.get_base_dir().plus_file(apk_file_name);
|
|
|
+ return fullpath;
|
|
|
+ }
|
|
|
+
|
|
|
+ Error save_apk_expansion_file(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
|
|
|
+ String fullpath = get_apk_expansion_fullpath(p_preset, p_path);
|
|
|
+ Error err = save_pack(p_preset, fullpath);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ void get_command_line_flags(const Ref<EditorExportPreset> &p_preset, const String &p_path, int p_flags, Vector<uint8_t> &r_command_line_flags) {
|
|
|
String cmdline = p_preset->get("command_line/extra_args");
|
|
|
Vector<String> command_line_strings = cmdline.strip_edges().split(" ");
|
|
|
for (int i = 0; i < command_line_strings.size(); i++) {
|
|
@@ -2021,17 +2044,8 @@ public:
|
|
|
|
|
|
bool apk_expansion = p_preset->get("apk_expansion/enable");
|
|
|
if (apk_expansion) {
|
|
|
- int version_code = p_preset->get("version/code");
|
|
|
- String package_name = p_preset->get("package/unique_name");
|
|
|
- String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb";
|
|
|
- String fullpath = p_path.get_base_dir().plus_file(apk_file_name);
|
|
|
+ String fullpath = get_apk_expansion_fullpath(p_preset, p_path);
|
|
|
String apk_expansion_public_key = p_preset->get("apk_expansion/public_key");
|
|
|
- Error err = save_pack(p_preset, fullpath);
|
|
|
-
|
|
|
- if (err != OK) {
|
|
|
- EditorNode::add_io_error("Could not write expansion package file: " + apk_file_name);
|
|
|
- return err;
|
|
|
- }
|
|
|
|
|
|
command_line_strings.push_back("--use_apk_expansion");
|
|
|
command_line_strings.push_back("--apk_expansion_md5");
|
|
@@ -2077,7 +2091,6 @@ public:
|
|
|
copymem(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length);
|
|
|
}
|
|
|
}
|
|
|
- return OK;
|
|
|
}
|
|
|
|
|
|
Error sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, String apk_path, EditorProgress ep) {
|
|
@@ -2171,11 +2184,16 @@ public:
|
|
|
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
|
|
|
|
|
String src_apk;
|
|
|
+ Error err;
|
|
|
|
|
|
EditorProgress ep("export", "Exporting for Android", 105, true);
|
|
|
|
|
|
bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build"));
|
|
|
+ int export_format = int(p_preset->get("custom_template/export_format"));
|
|
|
bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG);
|
|
|
+ bool _signed = p_preset->get("package/signed");
|
|
|
+ bool apk_expansion = p_preset->get("apk_expansion/enable");
|
|
|
+ Vector<String> enabled_abis = get_enabled_abis(p_preset);
|
|
|
|
|
|
Ref<Image> main_image;
|
|
|
Ref<Image> foreground;
|
|
@@ -2183,25 +2201,48 @@ public:
|
|
|
|
|
|
load_icon_refs(p_preset, main_image, foreground, background);
|
|
|
|
|
|
+ Vector<uint8_t> command_line_flags;
|
|
|
+ // Write command line flags into the command_line_flags variable.
|
|
|
+ get_command_line_flags(p_preset, p_path, p_flags, command_line_flags);
|
|
|
+
|
|
|
+ if (export_format == 1) {
|
|
|
+ if (!p_path.ends_with(".aab")) {
|
|
|
+ EditorNode::get_singleton()->show_warning(TTR("Invalid filename! Android App Bundle requires the *.aab extension."));
|
|
|
+ return ERR_UNCONFIGURED;
|
|
|
+ }
|
|
|
+ if (apk_expansion) {
|
|
|
+ EditorNode::get_singleton()->show_warning(TTR("APK Expansion not compatible with Android App Bundle."));
|
|
|
+ return ERR_UNCONFIGURED;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (export_format == 0 && !p_path.ends_with(".apk")) {
|
|
|
+ EditorNode::get_singleton()->show_warning(
|
|
|
+ TTR("Invalid filename! Android APK requires the *.apk extension."));
|
|
|
+ return ERR_UNCONFIGURED;
|
|
|
+ }
|
|
|
+ if (export_format > 1 || export_format < 0) {
|
|
|
+ EditorNode::add_io_error("Unsupported export format!\n");
|
|
|
+ return ERR_UNCONFIGURED; //TODO: is this the right error?
|
|
|
+ }
|
|
|
+
|
|
|
if (use_custom_build) {
|
|
|
- //re-generate build.gradle and AndroidManifest.xml
|
|
|
- { //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;
|
|
|
- }
|
|
|
+ //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;
|
|
|
}
|
|
|
+ String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path");
|
|
|
+ ERR_FAIL_COND_V_MSG(sdk_path == "", ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/custom_build_sdk_path'.");
|
|
|
|
|
|
// TODO: should we use "package/name" or "application/config/name"?
|
|
|
String project_name = get_project_name(p_preset->get("package/name"));
|
|
|
- // instead of calling _fix_resources
|
|
|
- Error err = _create_project_name_strings_files(p_preset, project_name);
|
|
|
+ err = _create_project_name_strings_files(p_preset, project_name); //project name localization.
|
|
|
if (err != OK) {
|
|
|
EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name");
|
|
|
}
|
|
@@ -2209,14 +2250,32 @@ public:
|
|
|
_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");
|
|
|
|
|
|
- ERR_FAIL_COND_V_MSG(sdk_path == "", ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/custom_build_sdk_path'.");
|
|
|
+ //stores all the project files inside the Gradle project directory. Also includes all ABIs
|
|
|
+ if (!apk_expansion) {
|
|
|
+ DirAccess *da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
|
|
+ if (da_res->dir_exists("res://android/build/assets")) {
|
|
|
+ DirAccess *da_assets = DirAccess::open("res://android/build/assets");
|
|
|
+ da_assets->erase_contents_recursive();
|
|
|
+ da_res->remove("res://android/build/assets");
|
|
|
+ }
|
|
|
+ err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, NULL, ignore_so_file);
|
|
|
+ if (err != OK) {
|
|
|
+ EditorNode::add_io_error("Could not export project files to gradle project\n");
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ err = save_apk_expansion_file(p_preset, p_path);
|
|
|
+ if (err != OK) {
|
|
|
+ EditorNode::add_io_error("Could not write expansion package file!");
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ store_file_at_path("res://android/build/assets/_cl_", command_line_flags);
|
|
|
|
|
|
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
|
|
@@ -2224,12 +2283,12 @@ public:
|
|
|
#endif
|
|
|
|
|
|
String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build");
|
|
|
-
|
|
|
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");
|
|
|
+ String enabled_abi_string = String("|").join(enabled_abis);
|
|
|
|
|
|
Vector<PluginConfig> enabled_plugins = get_enabled_plugins(p_preset);
|
|
|
String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins);
|
|
@@ -2241,10 +2300,20 @@ public:
|
|
|
if (clean_build_required) {
|
|
|
cmdline.push_back("clean");
|
|
|
}
|
|
|
- cmdline.push_back("build");
|
|
|
+
|
|
|
+ String build_type = p_debug ? "Debug" : "Release";
|
|
|
+ if (export_format == 1) {
|
|
|
+ String bundle_build_command = vformat("bundle%s", build_type);
|
|
|
+ cmdline.push_back(bundle_build_command);
|
|
|
+ } else if (export_format == 0) {
|
|
|
+ String apk_build_command = vformat("assemble%s", build_type);
|
|
|
+ cmdline.push_back(apk_build_command);
|
|
|
+ }
|
|
|
+
|
|
|
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("-Pexport_enabled_abis=" + enabled_abi_string); // argument to specify enabled ABIs.
|
|
|
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.
|
|
@@ -2262,35 +2331,54 @@ public:
|
|
|
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 = build_path.plus_file("build/outputs/apk/debug/android_debug.apk");
|
|
|
- } else {
|
|
|
- src_apk = build_path.plus_file("build/outputs/apk/release/android_release.apk");
|
|
|
+
|
|
|
+ List<String> copy_args;
|
|
|
+ String copy_command;
|
|
|
+ if (export_format == 1) {
|
|
|
+ copy_command = vformat("copyAndRename%sAab", build_type);
|
|
|
+ } else if (export_format == 0) {
|
|
|
+ copy_command = vformat("copyAndRename%sApk", build_type);
|
|
|
}
|
|
|
|
|
|
- if (!FileAccess::exists(src_apk)) {
|
|
|
- EditorNode::get_singleton()->show_warning(TTR("No build apk generated at: ") + "\n" + src_apk);
|
|
|
+ copy_args.push_back(copy_command);
|
|
|
+
|
|
|
+ copy_args.push_back("-p"); // argument to specify the start directory.
|
|
|
+ copy_args.push_back(build_path); // start directory.
|
|
|
+
|
|
|
+ String export_filename = p_path.get_file();
|
|
|
+ String export_path = p_path.get_base_dir();
|
|
|
+
|
|
|
+ copy_args.push_back("-Pexport_path=file:" + export_path);
|
|
|
+ copy_args.push_back("-Pexport_filename=" + export_filename);
|
|
|
+
|
|
|
+ int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args);
|
|
|
+ if (copy_result != 0) {
|
|
|
+ EditorNode::get_singleton()->show_warning(TTR("Unable to copy and rename export file, check gradle project directory for outputs."));
|
|
|
return ERR_CANT_CREATE;
|
|
|
}
|
|
|
-
|
|
|
- } else {
|
|
|
+ if (_signed) {
|
|
|
+ err = sign_apk(p_preset, p_debug, p_path, ep);
|
|
|
+ if (err != OK) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return OK;
|
|
|
+ }
|
|
|
+ // This is the start of the Legacy build system
|
|
|
+ if (p_debug)
|
|
|
+ src_apk = p_preset->get("custom_template/debug");
|
|
|
+ else
|
|
|
+ src_apk = p_preset->get("custom_template/release");
|
|
|
+ src_apk = src_apk.strip_edges();
|
|
|
+ if (src_apk == "") {
|
|
|
if (p_debug) {
|
|
|
- src_apk = p_preset->get("custom_template/debug");
|
|
|
+ src_apk = find_export_template("android_debug.apk");
|
|
|
} else {
|
|
|
- src_apk = p_preset->get("custom_template/release");
|
|
|
+ src_apk = find_export_template("android_release.apk");
|
|
|
}
|
|
|
-
|
|
|
- src_apk = src_apk.strip_edges();
|
|
|
if (src_apk == "") {
|
|
|
- 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;
|
|
|
- }
|
|
|
+ EditorNode::add_io_error("Package not found: " + src_apk);
|
|
|
+ return ERR_FILE_NOT_FOUND;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2327,19 +2415,13 @@ public:
|
|
|
|
|
|
zipFile unaligned_apk = zipOpen2(tmp_unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2);
|
|
|
|
|
|
- bool _signed = p_preset->get("package/signed");
|
|
|
String cmdline = p_preset->get("command_line/extra_args");
|
|
|
|
|
|
String version_name = p_preset->get("version/name");
|
|
|
String package_name = p_preset->get("package/unique_name");
|
|
|
|
|
|
- bool apk_expansion = p_preset->get("apk_expansion/enable");
|
|
|
String apk_expansion_pkey = p_preset->get("apk_expansion/public_key");
|
|
|
|
|
|
- Vector<String> enabled_abis = get_enabled_abis(p_preset);
|
|
|
-
|
|
|
- // Prepare images to be resized for the icons. If some image ends up being uninitialized, the default image from the export template will be used.
|
|
|
-
|
|
|
Vector<String> invalid_abis(enabled_abis);
|
|
|
while (ret == UNZ_OK) {
|
|
|
//get filename
|
|
@@ -2360,30 +2442,26 @@ public:
|
|
|
unzCloseCurrentFile(pkg);
|
|
|
|
|
|
//write
|
|
|
-
|
|
|
- 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);
|
|
|
- }
|
|
|
-
|
|
|
- for (int i = 0; i < icon_densities_count; ++i) {
|
|
|
- if (main_image.is_valid() && !main_image->empty()) {
|
|
|
- if (file == launcher_icons[i].export_path) {
|
|
|
- _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
|
|
|
- }
|
|
|
+ if (file == "AndroidManifest.xml") {
|
|
|
+ _fix_manifest(p_preset, data, p_give_internet);
|
|
|
+ }
|
|
|
+ if (file == "resources.arsc") {
|
|
|
+ _fix_resources(p_preset, data);
|
|
|
+ }
|
|
|
+ for (int i = 0; i < icon_densities_count; ++i) {
|
|
|
+ if (main_image.is_valid() && !main_image->empty()) {
|
|
|
+ if (file == launcher_icons[i].export_path) {
|
|
|
+ _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
|
|
|
}
|
|
|
- if (foreground.is_valid() && !foreground->empty()) {
|
|
|
- if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
|
|
|
- _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
|
|
|
- }
|
|
|
+ }
|
|
|
+ if (foreground.is_valid() && !foreground->empty()) {
|
|
|
+ if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
|
|
|
+ _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
|
|
|
}
|
|
|
- if (background.is_valid() && !background->empty()) {
|
|
|
- if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
|
|
|
- _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
|
|
|
- }
|
|
|
+ }
|
|
|
+ if (background.is_valid() && !background->empty()) {
|
|
|
+ if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
|
|
|
+ _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -2442,18 +2520,26 @@ public:
|
|
|
if (ep.step("Adding files...", 1)) {
|
|
|
CLEANUP_AND_RETURN(ERR_SKIP);
|
|
|
}
|
|
|
- Error err = OK;
|
|
|
+ err = OK;
|
|
|
|
|
|
if (p_flags & DEBUG_FLAG_DUMB_CLIENT) {
|
|
|
APKExportData ed;
|
|
|
ed.ep = &ep;
|
|
|
ed.apk = unaligned_apk;
|
|
|
err = export_project_files(p_preset, ignore_apk_file, &ed, save_apk_so);
|
|
|
- } else if (!apk_expansion) {
|
|
|
- APKExportData ed;
|
|
|
- ed.ep = &ep;
|
|
|
- ed.apk = unaligned_apk;
|
|
|
- err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so);
|
|
|
+ } else {
|
|
|
+ if (apk_expansion) {
|
|
|
+ err = save_apk_expansion_file(p_preset, p_path);
|
|
|
+ if (err != OK) {
|
|
|
+ EditorNode::add_io_error("Could not write expansion package file!");
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ APKExportData ed;
|
|
|
+ ed.ep = &ep;
|
|
|
+ ed.apk = unaligned_apk;
|
|
|
+ err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (err != OK) {
|
|
@@ -2462,10 +2548,6 @@ public:
|
|
|
CLEANUP_AND_RETURN(ERR_SKIP);
|
|
|
}
|
|
|
|
|
|
- Vector<uint8_t> command_line_flags;
|
|
|
- // Write command line flags into the command_line_flags variable.
|
|
|
- err = get_command_line_flags(p_preset, p_path, p_flags, command_line_flags);
|
|
|
-
|
|
|
zip_fileinfo zipfi = get_zip_fileinfo();
|
|
|
zipOpenNewFileInZip(unaligned_apk,
|
|
|
"assets/_cl_",
|