android_tools/aapt2/
link.rs

1use super::aapt2_tool;
2use crate::error::{CommandExt, Error, Result};
3use std::path::{Path, PathBuf};
4
5/// ## Link
6/// In the link phase, `AAPT2` merges all the intermediate files generated from the
7/// compilation phase such as resource tables, binary XML files, and processed
8/// PNG files and packages them into a single APK. Additionally, other auxiliary
9/// files like `R.java` and ProGuard rules files can be generated during this phase.
10/// However, the generated APK does not contain DEX bytecode and is unsigned.
11/// That is, you can't deploy this APK to a device. If you're not using the Android
12/// Gradle Plugin to [`build your app from the command line`], you can use other command
13/// line tools, such as [`d8`] to compile Java bytecode into DEX bytecode and
14/// [`apksigner`] to sign your APK.
15///
16/// ## Link syntax
17/// The general syntax for using link is as follows:
18///
19/// ```sh
20/// `aapt2 link path-to-input-files [options] -o`
21/// `outputdirectory/outputfilename.apk --manifest AndroidManifest.xml`
22/// ```
23///
24/// In the following example, AAPT2 merges the two intermediate files -
25/// `drawable_Image.flat` and `values_values.arsc.flat`, and the `AndroidManifest.xml`
26/// file. `AAPT2` links the result against `android.jar` file which holds the resources
27/// defined in the android package:
28///
29/// ```sh
30///  `aapt2 link -o output.apk
31///  -I android_sdk/platforms/android_version/android.jar
32///     compiled/res/values_values.arsc.flat
33///     compiled/res/drawable_Image.flat --manifest /path/to/AndroidManifest.xml -v`
34/// ```
35///
36/// [d8]: https://developer.android.com/studio/command-line/d8
37/// [apksigner]: https://developer.android.com/studio/command-line/apksigner
38/// [build your app from the command line]: https://developer.android.com/studio/build/building-cmdline
39#[derive(Debug, Default)]
40pub struct Aapt2Link {
41    inputs: Vec<PathBuf>,
42    compiled_res: Option<PathBuf>,
43    output_apk: PathBuf,
44    manifest: PathBuf,
45    android_jar: Option<PathBuf>,
46    assets: Option<PathBuf>,
47    individual_flat: Option<PathBuf>,
48    package_id: Option<String>,
49    allow_reserved_package_id: bool,
50    java: Option<PathBuf>,
51    proguard_options: Option<PathBuf>,
52    proguard_main_dex: Option<PathBuf>,
53    proguard_conditional_keep_rules: bool,
54    proguard_minimal_keep_rules: bool,
55    no_auto_version: bool,
56    no_version_vectors: bool,
57    no_version_transitions: bool,
58    no_resource_deduping: bool,
59    no_resource_removal: bool,
60    enable_sparse_encoding: bool,
61    package_identifier: bool,
62    suggested_strings: bool,
63    config: Vec<String>,
64    preferred_density: Option<i32>,
65    product: Option<PathBuf>,
66    output_to_dir: Option<PathBuf>,
67    no_xml_namespaces: bool,
68    min_sdk_version: Option<u32>,
69    target_sdk_version: Option<u32>,
70    version_code: Option<u32>,
71    version_code_major: Option<u32>,
72    version_name: Option<String>,
73    replace_version: bool,
74    compile_sdk_version_code: Option<u32>,
75    compile_sdk_version_name: Option<String>,
76    shared_lib: bool,
77    static_lib: bool,
78    proto_format: bool,
79    no_static_lib_packages: bool,
80    non_final_ids: bool,
81    no_proguard_location_reference: bool,
82    emit_ids: Option<PathBuf>,
83    stable_ids: Option<PathBuf>,
84    private_symbols: Option<String>,
85    custom_package: Option<PathBuf>,
86    extra_packages: Option<PathBuf>,
87    add_javadoc_annotation: Option<String>,
88    output_text_symbols: Option<PathBuf>,
89    auto_add_overlay: bool,
90    override_styles_instead_of_overlaying: bool,
91    rename_manifest_package: Option<String>,
92    rename_resources_package: Option<String>,
93    rename_instrumentation_target_package: Option<String>,
94    extensions: Vec<String>,
95    no_compress: bool,
96    keep_raw_values: bool,
97    no_compress_regex: Option<String>,
98    warn_manifest_validation: bool,
99    split: Option<PathBuf>,
100    strict_visibility: bool,
101    exclude_sources: bool,
102    trace_folder: Option<String>,
103    merge_only: bool,
104    verbose: bool,
105    help: bool,
106}
107
108impl Aapt2Link {
109    /// Specifies the output path for the linked resource APK.
110    ///
111    /// This is a required flag because you must specify the path for the output APK that
112    /// can hold the linked resources.
113    ///
114    /// Specifies the path to the Android manifest file to build.
115    ///
116    /// This is a required flag because the manifest file encloses essential information
117    /// about your app like package name and application ID
118    pub fn new(inputs: &[PathBuf], output_apk: &Path, manifest: &Path) -> Self {
119        Self {
120            inputs: inputs.to_vec(),
121            compiled_res: None,
122            output_apk: output_apk.to_owned(),
123            manifest: manifest.to_owned(),
124            ..Default::default()
125        }
126    }
127
128    /// Specifies the output path for the linked resource APK.
129    ///
130    /// This is a required flag because you must specify the path for the output APK that
131    /// can hold the linked resources.
132    ///
133    /// Specifies the path to the Android manifest file to build.
134    ///
135    /// This is a required flag because the manifest file encloses essential information
136    /// about your app like package name and application ID
137    pub fn new_from_compiled_res(
138        compiled_res: Option<PathBuf>,
139        output_apk: &Path,
140        manifest: &Path,
141    ) -> Self {
142        Self {
143            inputs: Vec::new(),
144            compiled_res,
145            output_apk: output_apk.to_owned(),
146            manifest: manifest.to_owned(),
147            ..Default::default()
148        }
149    }
150
151    /// Generates output file for ProGuard rules for the main dex
152    pub fn proguard_main_dex(&mut self, proguard_main_dex: PathBuf) -> &mut Self {
153        self.proguard_main_dex = Some(proguard_main_dex);
154        self
155    }
156
157    /// Generate a minimal set of Proguard keep rules
158    pub fn proguard_minimal_keep_rules(&mut self, proguard_minimal_keep_rules: bool) -> &mut Self {
159        self.proguard_minimal_keep_rules = proguard_minimal_keep_rules;
160        self
161    }
162
163    /// Disables automatic removal of resources without
164    pub fn no_resource_removal(&mut self, no_resource_removal: bool) -> &mut Self {
165        self.no_resource_removal = no_resource_removal;
166        self
167    }
168    /// Legacy flag that specifies to use the package identifier 0x01
169    pub fn package_identifier(&mut self, package_identifier: bool) -> &mut Self {
170        self.package_identifier = package_identifier;
171        self
172    }
173
174    /// Comma separated list of product names to keep
175    pub fn product(&mut self, product: PathBuf) -> &mut Self {
176        self.product = Some(product);
177        self
178    }
179
180    /// Removes XML namespace prefix and URI information
181    pub fn no_xml_namespaces(&mut self, no_xml_namespaces: bool) -> &mut Self {
182        self.no_xml_namespaces = no_xml_namespaces;
183        self
184    }
185
186    /// Version code major (integer) to inject into the `AndroidManifest.xml` if none is
187    /// present
188    pub fn version_code_major(&mut self, version_code_major: u32) -> &mut Self {
189        self.version_code_major = Some(version_code_major);
190        self
191    }
192
193    /// Version name to inject into the `AndroidManifest.xml` if none is present
194    pub fn version_name(&mut self, version_name: String) -> &mut Self {
195        self.version_name = Some(version_name);
196        self
197    }
198
199    /// If `--version-code` and/or `--version-name` are specified, these values will
200    /// replace any value already in the manifest. By default, nothing is changed if
201    /// the manifest already defines these attributes
202    pub fn replace_version(&mut self, replace_version: bool) -> &mut Self {
203        self.replace_version = replace_version;
204        self
205    }
206
207    /// Version code (integer) to inject into the `AndroidManifest.xml` if none is present
208    pub fn compile_sdk_version_code(&mut self, compile_sdk_version_code: u32) -> &mut Self {
209        self.compile_sdk_version_code = Some(compile_sdk_version_code);
210        self
211    }
212
213    /// Generates a shared Android runtime library
214    pub fn shared_lib(&mut self, shared_lib: bool) -> &mut Self {
215        self.shared_lib = shared_lib;
216        self
217    }
218
219    /// Generate a static Android library
220    pub fn static_lib(&mut self, static_lib: bool) -> &mut Self {
221        self.static_lib = static_lib;
222        self
223    }
224
225    /// Merge all library resources under the app's package
226    pub fn no_static_lib_packages(&mut self, no_static_lib_packages: bool) -> &mut Self {
227        self.no_static_lib_packages = no_static_lib_packages;
228        self
229    }
230
231    /// Keep proguard rules files from having a reference to the source file
232    pub fn no_proguard_location_reference(
233        &mut self,
234        no_proguard_location_reference: bool,
235    ) -> &mut Self {
236        self.no_proguard_location_reference = no_proguard_location_reference;
237        self
238    }
239
240    /// Package name to use when generating `R.java` for private symbols. If not
241    /// specified, public and private symbols will use the application's package name
242    pub fn private_symbols(&mut self, private_symbols: String) -> &mut Self {
243        self.private_symbols = Some(private_symbols);
244        self
245    }
246
247    /// Causes styles defined in `-R` resources to replace previous definitions instead of
248    /// merging into them
249    pub fn override_styles_instead_of_overlaying(
250        &mut self,
251        override_styles_instead_of_overlaying: bool,
252    ) -> &mut Self {
253        self.override_styles_instead_of_overlaying = override_styles_instead_of_overlaying;
254        self
255    }
256
257    /// Renames the package in resources table
258    pub fn rename_resources_package(&mut self, rename_resources_package: String) -> &mut Self {
259        self.rename_resources_package = Some(rename_resources_package);
260        self
261    }
262
263    /// Provides the path to the platform's `android.jar` or other APKs like
264    /// `framework-res.apk`  which might be useful while building features. This flag is
265    /// required if you are using attributes with android namespace (for example,
266    /// android:id) in your resource files
267    pub fn android_jar(&mut self, android_jar: PathBuf) -> &mut Self {
268        self.android_jar = Some(android_jar);
269        self
270    }
271
272    /// Specifies an assets directory to be included in the APK.
273    ///
274    /// You can use this directory to store original unprocessed files. To learn more,
275    /// read [`Accessing original`] files.
276    ///
277    /// [`Accessing original`]: https://developer.android.com/guide/topics/resources/providing-resources#OriginalFiles
278    pub fn assets(&mut self, assets: PathBuf) -> &mut Self {
279        self.assets = Some(assets);
280        self
281    }
282
283    /// Pass individual `.flat` file to link, using `overlay` semantics without using the
284    /// `<add-resource>` tag.
285    ///
286    /// When you a provide a resource file that overlays (extends or modifies) an existing
287    /// file, the last conflicting resource given is used
288    pub fn individual_flat(&mut self, individual_flat: PathBuf) -> &mut Self {
289        self.individual_flat = Some(individual_flat);
290        self
291    }
292
293    /// Specifies the package ID to use for your app.
294    ///
295    /// The package ID that you specify must be greater than or equal to 0x7f unless used
296    /// in combination with `--allow-reserved-package-id`
297    pub fn package_id(&mut self, package_id: String) -> &mut Self {
298        self.package_id = Some(package_id);
299        self
300    }
301
302    /// Allows the use of a reserved package ID.
303    ///
304    /// Reserved package IDs are IDs that are normally assigned to shared libraries and
305    /// are in the range from 0x02 to 0x7e inclusive. By using
306    /// `--allow-reserved-package-id`, you can assign IDs that fall in the range of
307    /// reserved package IDs.
308    ///
309    /// This should only be used for packages with a min-sdk version of 26 or lower
310    pub fn allow_reserved_package_id(&mut self, allow_reserved_package_id: bool) -> &mut Self {
311        self.allow_reserved_package_id = allow_reserved_package_id;
312        self
313    }
314
315    /// Specifies the directory in which to generate `R.java`
316    pub fn java(&mut self, java: PathBuf) -> &mut Self {
317        self.java = Some(java);
318        self
319    }
320
321    /// Generates output file for ProGuard rules
322    pub fn proguard_options(&mut self, proguard_options: PathBuf) -> &mut Self {
323        self.proguard_options = Some(proguard_options);
324        self
325    }
326
327    /// Output file for generated Proguard rules for the main dex
328    pub fn proguard_conditional_keep_rules(
329        &mut self,
330        proguard_conditional_keep_rules: bool,
331    ) -> &mut Self {
332        self.proguard_conditional_keep_rules = proguard_conditional_keep_rules;
333        self
334    }
335
336    /// Disables automatic style and layout SDK versioning
337    pub fn no_auto_version(&mut self, no_auto_version: bool) -> &mut Self {
338        self.no_auto_version = no_auto_version;
339        self
340    }
341
342    /// Disables automatic versioning of vector drawables. Use this only when building
343    /// your APK with the Vector Drawable Library
344    pub fn no_version_vectors(&mut self, no_version_vectors: bool) -> &mut Self {
345        self.no_version_vectors = no_version_vectors;
346        self
347    }
348
349    /// Disables automatic versioning of transition resources. Use this only when building
350    /// your APK with Transition Support library
351    pub fn no_version_transitions(&mut self, no_version_transitions: bool) -> &mut Self {
352        self.no_version_transitions = no_version_transitions;
353        self
354    }
355
356    /// Disables automatic de-duplication of resources with identical values across
357    /// compatible configurations
358    pub fn no_resource_deduping(&mut self, no_resource_deduping: bool) -> &mut Self {
359        self.no_resource_deduping = no_resource_deduping;
360        self
361    }
362
363    /// Enables encoding of sparse entries using a binary search tree. This is useful for
364    /// optimization of APK size, but at the cost of resource retrieval performance
365    pub fn enable_sparse_encoding(&mut self, enable_sparse_encoding: bool) -> &mut Self {
366        self.enable_sparse_encoding = enable_sparse_encoding;
367        self
368    }
369
370    /// Requires localization of strings marked 'suggested'
371    pub fn suggested_strings(&mut self, suggested_strings: bool) -> &mut Self {
372        self.suggested_strings = suggested_strings;
373        self
374    }
375
376    /// Provides a list of configurations separated by commas.
377    ///
378    /// For example, if you have dependencies on the support library (which contains
379    /// translations for multiple languages), you can filter resources just for the given
380    /// language configuration, like English or Spanish.
381    ///
382    /// You must define the language configuration by a two-letter ISO 639-1 language
383    /// code, optionally followed by a two letter ISO 3166-1-alpha-2 region code preceded
384    /// by lowercase 'r' (for example, en-rUS).
385    pub fn config(&mut self, config: String) -> &mut Self {
386        self.config.push(config);
387        self
388    }
389
390    /// Allows `AAPT2` to select the closest matching density and strip out all others.
391    ///
392    /// There are several pixel density qualifiers available to use in your app, such as
393    /// ldpi, hdpi, and xhdpi. When you specify a preferred density, `AAPT2` selects and
394    /// stores the closest matching density in the resource table and removes all others.
395    pub fn preferred_density(&mut self, preferred_density: i32) -> &mut Self {
396        self.preferred_density = Some(preferred_density);
397        self
398    }
399
400    /// Outputs the APK contents to a directory specified by `-o`.
401    ///
402    /// If you get any errors using this flag, you can resolve them by upgrading to
403    /// [`Android SDK Build Tools 28.0.0 or higher`].
404    ///
405    /// [`Android SDK Build Tools 28.0.0 or higher`]: https://developer.android.com/studio/releases/build-tools
406    pub fn output_to_dir(&mut self, output_to_dir: &Path) -> &mut Self {
407        self.output_to_dir = Some(output_to_dir.to_path_buf());
408        self
409    }
410
411    /// Sets the default minimum SDK version to use for `AndroidManifest.xml`
412    pub fn min_sdk_version(&mut self, min_sdk_version: u32) -> &mut Self {
413        self.min_sdk_version = Some(min_sdk_version);
414        self
415    }
416
417    /// Sets the default target SDK version to use for `AndroidManifest.xml`
418    pub fn target_sdk_version(&mut self, target_sdk_version: u32) -> &mut Self {
419        self.target_sdk_version = Some(target_sdk_version);
420        self
421    }
422
423    /// Specifies the version code (integer) to inject into the `AndroidManifest.xml` if
424    /// none is present
425    pub fn version_code(&mut self, version_code: u32) -> &mut Self {
426        self.version_code = Some(version_code);
427        self
428    }
429
430    /// Specifies the version name to inject into the AndroidManifest.xml if none is
431    /// present
432    pub fn compile_sdk_version_name(&mut self, compile_sdk_version_name: String) -> &mut Self {
433        self.compile_sdk_version_name = Some(compile_sdk_version_name);
434        self
435    }
436
437    /// Generates compiled resources in Protobuf format.
438    /// Suitable as input to the [`bundle tool`] for generating an Android App Bundle.
439    ///
440    /// [`bundle tool`]: https://developer.android.com/studio/build/building-cmdline#bundletool-build
441    pub fn proto_format(&mut self, proto_format: bool) -> &mut Self {
442        self.proto_format = proto_format;
443        self
444    }
445
446    /// Generates `R.java` with non-final resource IDs (references to the IDs from app's
447    /// code will not get inlined during kotlinc/javac compilation)
448    pub fn non_final_ids(&mut self, non_final_ids: bool) -> &mut Self {
449        self.non_final_ids = non_final_ids;
450        self
451    }
452
453    /// Emits a file at the given path with a list of names of resource types and their ID
454    /// mappings. It is suitable to use with `--stable-ids`
455    pub fn emit_ids(&mut self, emit_ids: PathBuf) -> &mut Self {
456        self.emit_ids = Some(emit_ids);
457        self
458    }
459
460    /// Consumes the file generated with `--emit-ids` containing the list of names of
461    /// resource types and their assigned IDs.
462    ///
463    /// This option allows assigned IDs to remain stable even when you delete or add new
464    /// resources while linking
465    pub fn stable_ids(&mut self, stable_ids: PathBuf) -> &mut Self {
466        self.stable_ids = Some(stable_ids);
467        self
468    }
469
470    /// Specifies custom Java package under which to generate `R.java`
471    pub fn custom_package(&mut self, custom_package: PathBuf) -> &mut Self {
472        self.custom_package = Some(custom_package);
473        self
474    }
475
476    /// Generates the same `R.java` file but with different package names
477    pub fn extra_packages(&mut self, extra_packages: PathBuf) -> &mut Self {
478        self.extra_packages = Some(extra_packages);
479        self
480    }
481
482    /// Adds a JavaDoc annotation to all generated Java classes
483    pub fn add_javadoc_annotation(&mut self, add_javadoc_annotation: String) -> &mut Self {
484        self.add_javadoc_annotation = Some(add_javadoc_annotation);
485        self
486    }
487
488    /// Generates a text file containing the resource symbols of the R class in the
489    /// specified file.
490    ///
491    /// You must specify the path to the output file
492    pub fn output_text_symbols(&mut self, output_text_symbols: PathBuf) -> &mut Self {
493        self.output_text_symbols = Some(output_text_symbols);
494        self
495    }
496
497    /// Allows the addition of new resources in overlays without using the <add-resource>
498    /// tag
499    pub fn auto_add_overlay(&mut self, auto_add_overlay: bool) -> &mut Self {
500        self.auto_add_overlay = auto_add_overlay;
501        self
502    }
503
504    /// Renames the package in `AndroidManifest.xml`
505    pub fn rename_manifest_package(&mut self, rename_manifest_package: String) -> &mut Self {
506        self.rename_manifest_package = Some(rename_manifest_package);
507        self
508    }
509
510    /// Changes the name of the target package for [`instrumentation`].
511    ///
512    /// It should be used in conjunction with `--rename-manifest-package`.
513    ///
514    /// [`instrumentation`]: https://developer.android.com/reference/android/app/Instrumentation
515    pub fn rename_instrumentation_target_package(
516        &mut self,
517        rename_instrumentation_target_package: String,
518    ) -> &mut Self {
519        self.rename_instrumentation_target_package = Some(rename_instrumentation_target_package);
520        self
521    }
522
523    /// Do not compress any resources
524    pub fn no_compress(&mut self, no_compress: bool) -> &mut Self {
525        self.no_compress = no_compress;
526        self
527    }
528
529    /// Preserve raw attribute values in xml files
530    pub fn keep_raw_values(&mut self, keep_raw_values: bool) -> &mut Self {
531        self.keep_raw_values = keep_raw_values;
532        self
533    }
534
535    /// Specifies the extensions of files that you do not want to compress
536    pub fn extension(&mut self, extension: String) -> &mut Self {
537        self.extensions.push(extension);
538        self
539    }
540
541    /// Do not compress extensions matching the regular expression. Remember to use the
542    /// '$' symbol for end of line. Uses a case-sensitive ECMAScriptregular expression
543    /// grammar
544    pub fn no_compress_regex(&mut self, no_compress_regex: String) -> &mut Self {
545        self.no_compress_regex = Some(no_compress_regex);
546        self
547    }
548
549    /// Treat manifest validation errors as warnings
550    pub fn warn_manifest_validation(&mut self, warn_manifest_validation: bool) -> &mut Self {
551        self.warn_manifest_validation = warn_manifest_validation;
552        self
553    }
554
555    /// Splits resources based on a set of configurations to generate a different version
556    /// of the APK.
557    ///
558    /// You must specify the path to the output APK along with the set of configurations
559    pub fn split(&mut self, split: PathBuf) -> &mut Self {
560        self.split = Some(split);
561        self
562    }
563
564    /// Do not allow overlays with different visibility levels
565    pub fn strict_visibility(&mut self, strict_visibility: bool) -> &mut Self {
566        self.strict_visibility = strict_visibility;
567        self
568    }
569
570    /// Generate systrace json trace fragment to specified folder
571    pub fn trace_folder(&mut self, trace_folder: String) -> &mut Self {
572        self.trace_folder = Some(trace_folder);
573        self
574    }
575
576    /// Do not serialize source file information when generating resources in Protobuf
577    /// format
578    pub fn exclude_sources(&mut self, exclude_sources: bool) -> &mut Self {
579        self.exclude_sources = exclude_sources;
580        self
581    }
582
583    /// Only merge the resources, without verifying resource references. This flag should
584    /// only be used together with the `--static-lib` flag
585    pub fn merge_only(&mut self, merge_only: bool) -> &mut Self {
586        self.merge_only = merge_only;
587        self
588    }
589
590    /// Enables increased verbosity of the output
591    pub fn verbose(&mut self, verbose: bool) -> &mut Self {
592        self.verbose = verbose;
593        self
594    }
595
596    /// Displays this help menu
597    pub fn help(&mut self, help: bool) -> &mut Self {
598        self.help = help;
599        self
600    }
601
602    /// Executes aapt2 link with arguments
603    pub fn run(&self) -> Result<PathBuf> {
604        let mut aapt2 = aapt2_tool()?;
605        aapt2.arg("link");
606        if !self.inputs.is_empty() {
607            self.inputs.iter().for_each(|input| {
608                aapt2.arg(input);
609            });
610        } else if let Some(compiled_res) = &self.compiled_res {
611            let paths = std::fs::read_dir(compiled_res)
612                .map_err(|_| Error::CompiledResourcesNotFound)?
613                .flat_map(|e| e.map(|x| x.path()))
614                .collect::<Vec<_>>();
615            paths.iter().for_each(|input| {
616                if !input.ends_with("AndroidManifest.xml") {
617                    aapt2.arg(input);
618                }
619            });
620        }
621        aapt2.arg("-o").arg(&self.output_apk);
622        aapt2.arg("--manifest").arg(&self.manifest);
623        if let Some(android_jar) = &self.android_jar {
624            aapt2.arg("-I").arg(android_jar);
625        }
626        if let Some(assets) = &self.assets {
627            aapt2.arg("-A").arg(assets);
628        }
629        if let Some(individual_flat) = &self.individual_flat {
630            aapt2.arg("-R").arg(individual_flat);
631        }
632        if let Some(package_id) = &self.package_id {
633            aapt2.arg("--package-id").arg(package_id);
634        }
635        if self.allow_reserved_package_id {
636            aapt2.arg("--allow-reserved-package-id");
637        }
638        if let Some(java) = &self.java {
639            aapt2.arg("--java").arg(java);
640        }
641        if let Some(proguard_options) = &self.proguard_options {
642            aapt2.arg("--proguard").arg(proguard_options);
643        }
644        if self.proguard_conditional_keep_rules {
645            aapt2.arg("--proguard-conditional-keep-rules");
646        }
647        if self.no_auto_version {
648            aapt2.arg("--no-auto-version");
649        }
650        if self.no_version_vectors {
651            aapt2.arg("--no-version-vectors");
652        }
653        if self.no_version_transitions {
654            aapt2.arg("--no-version-transitions");
655        }
656        if self.no_resource_deduping {
657            aapt2.arg("--no-resource-deduping");
658        }
659        if self.enable_sparse_encoding {
660            aapt2.arg("--enable-sparse-encoding");
661        }
662        if self.suggested_strings {
663            aapt2.arg("-z");
664        }
665        if !self.config.is_empty() {
666            aapt2.arg("-c").arg(self.config.join(","));
667        }
668        if let Some(preferred_density) = self.preferred_density {
669            aapt2
670                .arg("--preferred-density")
671                .arg(preferred_density.to_string());
672        }
673        if let Some(output_to_dir) = &self.output_to_dir {
674            aapt2.arg("--output-to-dir").arg("-o").arg(output_to_dir);
675        }
676        if let Some(min_sdk_version) = self.min_sdk_version {
677            aapt2
678                .arg("--min-sdk-version")
679                .arg(min_sdk_version.to_string());
680        }
681        if let Some(target_sdk_version) = self.target_sdk_version {
682            aapt2
683                .arg("--target-sdk-version")
684                .arg(target_sdk_version.to_string());
685        }
686        if let Some(version_code) = &self.version_code {
687            aapt2.arg("--version-code").arg(version_code.to_string());
688        }
689        if let Some(compile_sdk_version_name) = &self.compile_sdk_version_name {
690            aapt2
691                .arg("--compile-sdk-version-name")
692                .arg(compile_sdk_version_name);
693        }
694        if self.proto_format {
695            aapt2.arg("--proto-format");
696        }
697        if self.non_final_ids {
698            aapt2.arg("--non-final-ids");
699        }
700        if let Some(emit_ids) = &self.emit_ids {
701            aapt2.arg("--emit-ids").arg(emit_ids);
702        }
703        if let Some(stable_ids) = &self.stable_ids {
704            aapt2.arg("--stable-ids").arg(stable_ids);
705        }
706        if let Some(custom_package) = &self.custom_package {
707            aapt2.arg("--custom-package").arg(custom_package);
708        }
709        if let Some(extra_packages) = &self.extra_packages {
710            aapt2.arg("--extra-packages").arg(extra_packages);
711        }
712        if let Some(add_javadoc_annotation) = &self.add_javadoc_annotation {
713            aapt2
714                .arg("--add-javadoc-annotation")
715                .arg(add_javadoc_annotation);
716        }
717        if let Some(output_text_symbols) = &self.output_text_symbols {
718            aapt2.arg("--output-text-symbols").arg(output_text_symbols);
719        }
720        if self.auto_add_overlay {
721            aapt2.arg("--auto-add-overlay");
722        }
723        if let Some(rename_manifest_package) = &self.rename_manifest_package {
724            aapt2
725                .arg("--rename-manifest-package")
726                .arg(rename_manifest_package);
727        }
728        if let Some(rename_instrumentation_target_package) =
729            &self.rename_instrumentation_target_package
730        {
731            aapt2
732                .arg("--rename-instrumentation-target-package")
733                .arg(rename_instrumentation_target_package);
734        }
735        self.extensions.iter().for_each(|extension| {
736            aapt2.arg("-0").arg(extension);
737        });
738        if let Some(split) = &self.split {
739            aapt2.arg("--split").arg(split);
740        }
741        if self.verbose {
742            aapt2.arg("-v");
743        }
744        if self.help {
745            aapt2.arg("-h");
746        }
747        if let Some(proguard_main_dex) = &self.proguard_main_dex {
748            aapt2.arg("--proguard-main-dex").arg(proguard_main_dex);
749        }
750        if self.proguard_minimal_keep_rules {
751            aapt2.arg("--proguard-minimal-keep-rules");
752        }
753        if self.no_resource_removal {
754            aapt2.arg("--no-resource-removal");
755        }
756        if self.package_identifier {
757            aapt2.arg("-x");
758        }
759        if let Some(product) = &self.product {
760            aapt2.arg("--product").arg(product);
761        }
762        if self.no_xml_namespaces {
763            aapt2.arg("--no-xml-namespaces");
764        }
765        if let Some(version_code_major) = &self.version_code_major {
766            aapt2
767                .arg("--version-code-major")
768                .arg(version_code_major.to_string());
769        }
770        if let Some(version_name) = &self.version_name {
771            aapt2.arg("--version-name").arg(version_name);
772        }
773        if self.replace_version {
774            aapt2.arg("--replace-version");
775        }
776        if let Some(compile_sdk_version_code) = &self.compile_sdk_version_code {
777            aapt2
778                .arg("--compile-sdk-version-code")
779                .arg(compile_sdk_version_code.to_string());
780        }
781        if self.shared_lib {
782            aapt2.arg("--shared-lib");
783        }
784        if self.static_lib {
785            aapt2.arg("--static-lib");
786        }
787        if self.no_static_lib_packages {
788            aapt2.arg("--no-static-lib-packages");
789        }
790        if self.no_proguard_location_reference {
791            aapt2.arg("--no-proguard-location-reference");
792        }
793        if let Some(private_symbols) = &self.private_symbols {
794            aapt2.arg("--private-symbols").arg(private_symbols);
795        }
796        if self.override_styles_instead_of_overlaying {
797            aapt2.arg("--override-styles-instead-of-overlaying");
798        }
799        if let Some(rename_resources_package) = &self.rename_resources_package {
800            aapt2
801                .arg("--rename-resources-package")
802                .arg(rename_resources_package);
803        }
804        if self.no_compress {
805            aapt2.arg("--no-compress");
806        }
807        if self.keep_raw_values {
808            aapt2.arg("--keep-raw-values");
809        }
810        if let Some(no_compress_regex) = &self.no_compress_regex {
811            aapt2.arg("--no-compress-regex").arg(no_compress_regex);
812        }
813        if self.warn_manifest_validation {
814            aapt2.arg("--warn-manifest-validation");
815        }
816        if self.strict_visibility {
817            aapt2.arg("--strict-visibility");
818        }
819        if self.exclude_sources {
820            aapt2.arg("--exclude-sources");
821        }
822        if let Some(trace_folder) = &self.trace_folder {
823            aapt2.arg("--trace-folder").arg(trace_folder);
824        }
825        if self.merge_only {
826            aapt2.arg("--merge-only");
827        }
828        aapt2.output_err(true)?;
829        Ok(self.output_apk.clone())
830    }
831}