Zip-align exported APK
This commit is contained in:
@ -1031,10 +1031,19 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file,
|
|||||||
|
|
||||||
if (lSeek!=0)
|
if (lSeek!=0)
|
||||||
{
|
{
|
||||||
if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
|
if (lSeek<0) {
|
||||||
lSeek=0;
|
// WORKAROUND for backwards seeking
|
||||||
else
|
z_off_t pos = ZTELL64(s->z_filefunc, s->filestream);
|
||||||
err=UNZ_ERRNO;
|
if (ZSEEK64(s->z_filefunc, s->filestream,pos+lSeek,ZLIB_FILEFUNC_SEEK_SET)==0)
|
||||||
|
lSeek=0;
|
||||||
|
else
|
||||||
|
err=UNZ_ERRNO;
|
||||||
|
} else {
|
||||||
|
if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
|
||||||
|
lSeek=0;
|
||||||
|
else
|
||||||
|
err=UNZ_ERRNO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while(acc < file_info.size_file_extra)
|
while(acc < file_info.size_file_extra)
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "os/file_access.h"
|
#include "os/file_access.h"
|
||||||
#include "os/os.h"
|
#include "os/os.h"
|
||||||
#include "platform/android/logo.h"
|
#include "platform/android/logo.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
static const char* android_perms[]={
|
static const char* android_perms[]={
|
||||||
@ -1069,7 +1070,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
|
|||||||
|
|
||||||
String src_apk;
|
String src_apk;
|
||||||
|
|
||||||
EditorProgress ep("export","Exporting for Android",104);
|
EditorProgress ep("export","Exporting for Android",105);
|
||||||
|
|
||||||
if (p_debug)
|
if (p_debug)
|
||||||
src_apk=custom_debug_package;
|
src_apk=custom_debug_package;
|
||||||
@ -1109,7 +1110,8 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
|
|||||||
zlib_filefunc_def io2=io;
|
zlib_filefunc_def io2=io;
|
||||||
FileAccess *dst_f=NULL;
|
FileAccess *dst_f=NULL;
|
||||||
io2.opaque=&dst_f;
|
io2.opaque=&dst_f;
|
||||||
zipFile apk=zipOpen2(p_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io2);
|
String unaligned_path=EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmpexport-unaligned.apk";
|
||||||
|
zipFile unaligned_apk=zipOpen2(unaligned_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io2);
|
||||||
|
|
||||||
|
|
||||||
while(ret==UNZ_OK) {
|
while(ret==UNZ_OK) {
|
||||||
@ -1192,7 +1194,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
|
|||||||
// Respect decision on compression made by AAPT for the export template
|
// Respect decision on compression made by AAPT for the export template
|
||||||
const bool uncompressed = info.compression_method == 0;
|
const bool uncompressed = info.compression_method == 0;
|
||||||
|
|
||||||
zipOpenNewFileInZip(apk,
|
zipOpenNewFileInZip(unaligned_apk,
|
||||||
file.utf8().get_data(),
|
file.utf8().get_data(),
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -1203,8 +1205,8 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
|
|||||||
uncompressed ? 0 : Z_DEFLATED,
|
uncompressed ? 0 : Z_DEFLATED,
|
||||||
Z_DEFAULT_COMPRESSION);
|
Z_DEFAULT_COMPRESSION);
|
||||||
|
|
||||||
zipWriteInFileInZip(apk,data.ptr(),data.size());
|
zipWriteInFileInZip(unaligned_apk,data.ptr(),data.size());
|
||||||
zipCloseFileInZip(apk);
|
zipCloseFileInZip(unaligned_apk);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = unzGoToNextFile(pkg);
|
ret = unzGoToNextFile(pkg);
|
||||||
@ -1261,7 +1263,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
|
|||||||
|
|
||||||
APKExportData ed;
|
APKExportData ed;
|
||||||
ed.ep=&ep;
|
ed.ep=&ep;
|
||||||
ed.apk=apk;
|
ed.apk=unaligned_apk;
|
||||||
|
|
||||||
err = export_project_files(save_apk_file,&ed,false);
|
err = export_project_files(save_apk_file,&ed,false);
|
||||||
}
|
}
|
||||||
@ -1290,7 +1292,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
|
|||||||
print_line(itos(i)+" param: "+cl[i]);
|
print_line(itos(i)+" param: "+cl[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
zipOpenNewFileInZip(apk,
|
zipOpenNewFileInZip(unaligned_apk,
|
||||||
"assets/_cl_",
|
"assets/_cl_",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -1301,12 +1303,12 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
|
|||||||
0, // No compress (little size gain and potentially slower startup)
|
0, // No compress (little size gain and potentially slower startup)
|
||||||
Z_DEFAULT_COMPRESSION);
|
Z_DEFAULT_COMPRESSION);
|
||||||
|
|
||||||
zipWriteInFileInZip(apk,clf.ptr(),clf.size());
|
zipWriteInFileInZip(unaligned_apk,clf.ptr(),clf.size());
|
||||||
zipCloseFileInZip(apk);
|
zipCloseFileInZip(unaligned_apk);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
zipClose(apk,NULL);
|
zipClose(unaligned_apk,NULL);
|
||||||
unzClose(pkg);
|
unzClose(pkg);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -1363,7 +1365,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
|
|||||||
args.push_back(keystore);
|
args.push_back(keystore);
|
||||||
args.push_back("-storepass");
|
args.push_back("-storepass");
|
||||||
args.push_back(password);
|
args.push_back(password);
|
||||||
args.push_back(p_path);
|
args.push_back(unaligned_path);
|
||||||
args.push_back(user);
|
args.push_back(user);
|
||||||
int retval;
|
int retval;
|
||||||
int err = OS::get_singleton()->execute(jarsigner,args,true,NULL,NULL,&retval);
|
int err = OS::get_singleton()->execute(jarsigner,args,true,NULL,NULL,&retval);
|
||||||
@ -1376,7 +1378,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
|
|||||||
|
|
||||||
args.clear();
|
args.clear();
|
||||||
args.push_back("-verify");
|
args.push_back("-verify");
|
||||||
args.push_back(p_path);
|
args.push_back(unaligned_path);
|
||||||
args.push_back("-verbose");
|
args.push_back("-verbose");
|
||||||
|
|
||||||
err = OS::get_singleton()->execute(jarsigner,args,true,NULL,NULL,&retval);
|
err = OS::get_singleton()->execute(jarsigner,args,true,NULL,NULL,&retval);
|
||||||
@ -1386,6 +1388,92 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Let's zip-align (must be done after signing)
|
||||||
|
|
||||||
|
static const int ZIP_ALIGNMENT = 4;
|
||||||
|
|
||||||
|
ep.step("Aligning APK..",105);
|
||||||
|
|
||||||
|
unzFile tmp_unaligned = unzOpen2(unaligned_path.utf8().get_data(), &io);
|
||||||
|
if (!tmp_unaligned) {
|
||||||
|
|
||||||
|
EditorNode::add_io_error("Could not find temp unaligned APK.");
|
||||||
|
return ERR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(!tmp_unaligned, ERR_CANT_OPEN);
|
||||||
|
ret = unzGoToFirstFile(tmp_unaligned);
|
||||||
|
|
||||||
|
io2=io;
|
||||||
|
dst_f=NULL;
|
||||||
|
io2.opaque=&dst_f;
|
||||||
|
zipFile final_apk=zipOpen2(p_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io2);
|
||||||
|
|
||||||
|
// Take files from the unaligned APK and write them out to the aligned one
|
||||||
|
// in raw mode, i.e. not uncompressing and recompressing, aligning them as needed,
|
||||||
|
// following what is done in https://github.com/android/platform_build/blob/master/tools/zipalign/ZipAlign.cpp
|
||||||
|
int bias = 0;
|
||||||
|
while(ret==UNZ_OK) {
|
||||||
|
|
||||||
|
unz_file_info info;
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
|
||||||
|
char fname[16384];
|
||||||
|
char extra[16384];
|
||||||
|
ret = unzGetCurrentFileInfo(tmp_unaligned,&info,fname,16384,extra,16384-ZIP_ALIGNMENT,NULL,0);
|
||||||
|
|
||||||
|
String file=fname;
|
||||||
|
|
||||||
|
Vector<uint8_t> data;
|
||||||
|
data.resize(info.compressed_size);
|
||||||
|
|
||||||
|
// read
|
||||||
|
int method, level;
|
||||||
|
unzOpenCurrentFile2(tmp_unaligned, &method, &level, 1); // raw read
|
||||||
|
long file_offset = unzGetCurrentFileZStreamPos64(tmp_unaligned);
|
||||||
|
unzReadCurrentFile(tmp_unaligned,data.ptr(),data.size());
|
||||||
|
unzCloseCurrentFile(tmp_unaligned);
|
||||||
|
|
||||||
|
// align
|
||||||
|
int padding = 0;
|
||||||
|
if (!info.compression_method) {
|
||||||
|
// Uncompressed file => Align
|
||||||
|
long new_offset = file_offset + bias;
|
||||||
|
padding = (ZIP_ALIGNMENT - (new_offset % ZIP_ALIGNMENT)) % ZIP_ALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(extra + info.size_file_extra, 0, padding);
|
||||||
|
|
||||||
|
// write
|
||||||
|
zipOpenNewFileInZip2(final_apk,
|
||||||
|
file.utf8().get_data(),
|
||||||
|
NULL,
|
||||||
|
extra,
|
||||||
|
info.size_file_extra + padding,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
method,
|
||||||
|
level,
|
||||||
|
1); // raw write
|
||||||
|
zipWriteInFileInZip(final_apk,data.ptr(),data.size());
|
||||||
|
zipCloseFileInZipRaw(final_apk,info.uncompressed_size,info.crc);
|
||||||
|
|
||||||
|
bias += padding;
|
||||||
|
|
||||||
|
ret = unzGoToNextFile(tmp_unaligned);
|
||||||
|
}
|
||||||
|
|
||||||
|
zipClose(final_apk,NULL);
|
||||||
|
unzClose(tmp_unaligned);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user