@@ -362,6 +362,10 @@ fn doInstallApk(apk: *Apk) std.mem.Allocator.Error!*Step.InstallFile {
362362 // - classes.dex
363363 const apk_files = b .addWriteFiles ();
364364
365+ // These files belong in root and *must not* be compressed
366+ // - resources.arsc
367+ const apk_files_not_compressed = b .addWriteFiles ();
368+
365369 // Add build artifacts, usually a shared library targetting:
366370 // - aarch64-linux-android
367371 // - arm-linux-androideabi
@@ -491,10 +495,24 @@ fn doInstallApk(apk: *Apk) std.mem.Allocator.Error!*Step.InstallFile {
491495 const extracted_apk_dir = resources_apk .dirname ();
492496 jar .setCwd (extracted_apk_dir );
493497 _ = apk_files .addCopyDirectory (extracted_apk_dir , "" , .{
494- // Ignore the *.apk that exists in this directory
495- .exclude_extensions = &.{".apk" },
498+ .exclude_extensions = &.{
499+ // ignore the *.apk that exists in this directory
500+ ".apk" ,
501+ // ignore resources.arsc as Android 30+ APIs does not supporting
502+ // compressing this in the zip file
503+ ".arsc" ,
504+ },
496505 });
497506 apk_files .step .dependOn (& jar .step );
507+
508+ // Setup directory of additional files that should not be compressed
509+
510+ // NOTE(jae): 2025-03-23 - https://github.com/silbinarywolf/zig-android-sdk/issues/23
511+ // We apply resources.arsc seperately to the zip file to avoid compressing it, otherwise we get the following
512+ // error when we "adb install"
513+ // - "Targeting R+ (version 30 and above) requires the resources.arsc of installed APKs to be stored uncompressed and aligned on a 4-byte boundary"
514+ _ = apk_files_not_compressed .addCopyFile (extracted_apk_dir .path (b , "resources.arsc" ), "resources.arsc" );
515+ apk_files_not_compressed .step .dependOn (& jar .step );
498516 }
499517
500518 // Create zip via "jar" as it's cross-platform and aapt2 can't zip *.so or *.dex files.
@@ -513,9 +531,12 @@ fn doInstallApk(apk: *Apk) std.mem.Allocator.Error!*Step.InstallFile {
513531 // Hack to ensure this side-effect re-triggers zipping this up
514532 jar .addFileInput (directory_to_zip .path (b , "AndroidManifest.xml" ));
515533
516- // -c = compress
517- // -f specify filename
518- // -M do not include a MANIFEST file
534+ // Written as-is from running "jar --help"
535+ // -c, --create = Create the archive. When the archive file name specified
536+ // -u, --update = Update an existing jar archive
537+ // -f, --file=FILE = The archive file name. When omitted, either stdin or
538+ // -M, --no-manifest = Do not create a manifest file for the entries
539+ // -0, --no-compress = Store only; use no ZIP compression
519540 const compress_zip_arg = "-cfM" ;
520541 if (b .verbose ) jar .addArg (compress_zip_arg ++ "v" ) else jar .addArg (compress_zip_arg );
521542 const output_zip_file = jar .addOutputFileArg ("compiled_code.zip" );
@@ -524,6 +545,32 @@ fn doInstallApk(apk: *Apk) std.mem.Allocator.Error!*Step.InstallFile {
524545 break :blk output_zip_file ;
525546 };
526547
548+ // Update zip with files that are not compressed (ie. resources.arsc)
549+ const update_zip : * Step = blk : {
550+ const jar = b .addSystemCommand (&[_ ][]const u8 {
551+ apk .tools .java_tools .jar ,
552+ });
553+ jar .setName (runNameContext ("jar (update zip with uncompressed files)" ));
554+
555+ const directory_to_zip = apk_files_not_compressed .getDirectory ();
556+ jar .setCwd (directory_to_zip );
557+ // NOTE(jae): 2025-03-23
558+ // Hack to ensure this side-effect re-triggers zipping this up
559+ jar .addFileInput (apk_files_not_compressed .getDirectory ().path (b , "resources.arsc" ));
560+
561+ // Written as-is from running "jar --help"
562+ // -c, --create = Create the archive. When the archive file name specified
563+ // -u, --update = Update an existing jar archive
564+ // -f, --file=FILE = The archive file name. When omitted, either stdin or
565+ // -M, --no-manifest = Do not create a manifest file for the entries
566+ // -0, --no-compress = Store only; use no ZIP compression
567+ const update_zip_arg = "-ufM0" ;
568+ if (b .verbose ) jar .addArg (update_zip_arg ++ "v" ) else jar .addArg (update_zip_arg );
569+ jar .addFileArg (zip_file );
570+ jar .addArg ("." );
571+ break :blk & jar .step ;
572+ };
573+
527574 // NOTE(jae): 2024-09-28 - https://github.com/silbinarywolf/zig-android-sdk/issues/8
528575 // Experimented with using "lint" but it didn't actually catch the issue described
529576 // in the above Github, ie. having "<category android:name="org.khronos.openxr.intent.category.IMMERSIVE_HMD" />"
@@ -561,7 +608,10 @@ fn doInstallApk(apk: *Apk) std.mem.Allocator.Error!*Step.InstallFile {
561608 "4" ,
562609 });
563610
611+ // Depend on zip file and the additional update to it
564612 zipalign .addFileArg (zip_file );
613+ zipalign .step .dependOn (update_zip );
614+
565615 const apk_file = zipalign .addOutputFileArg (b .fmt ("aligned-{s}.apk" , .{apk_name }));
566616 break :blk apk_file ;
567617 };
0 commit comments