creator_tools/tools/aapt2/
compile.rs

1use std::path::{Path, PathBuf};
2use std::process::Command;
3
4/// # Compile
5/// AAPT2 supports compilation of all Android resource types, such as drawables and XML
6/// files. When you invoke AAPT2 for compilation, you should pass a single resource file
7/// as an input per invocation. AAPT2 then parses the file and generates an intermediate
8/// binary file with a .flat extension.
9///
10/// Although you can pass resource directories containing more than one resource files to
11/// AAPT2 using the --dir flag, you do not gain the benefits of incremental resource
12/// compilation when doing so. That is, when passing whole directories, AAPT2 recompiles
13/// all files in the directory even when only one resource has changed.
14///
15/// The output file types can differ based on the input you provide for compilation.
16/// The files AAPT2 outputs are not executables and you must later include these binary
17/// files as input in the link phase to generate an APK. However, the generated APK file
18/// is not an executable that you can deploy on an Android device right away, as it does
19/// not contain DEX files (compiled bytecode) and is not signed.
20///
21/// ## Compile syntax
22/// The general syntax for using compile is as follows:
23///
24/// ```sh
25/// aapt2 compile path-to-input-files [options] -o output-directory/
26/// ```
27/// ### Note
28/// For resource files, the path to input files must match the following structure:
29/// ```sh
30/// path/resource-type[-config]/file
31/// ```
32///
33/// In the following example, AAPT2 compiles resource files named values.xml and
34/// myImage.png individually:
35///
36/// ```sh
37/// aapt2 compile project_root/module_root/src/main/res/values-en/strings.xml -o compiled/
38/// aapt2 compile project_root/module_root/src/main/res/drawable/myImage.png -o compiled/
39/// ```
40///
41/// As shown in the table above, the name of the output file depends on the input file
42/// name and the name of its parent directory (the resource type and configuration).
43/// For the example above with strings.xml as input, aapt2 automatically names the output
44/// file as values-en_strings.arsc.flat. On the other hand, the file name for the compiled
45/// drawable file stored in the drawable directory will be drawable_img.png.flat.
46pub struct Aapt2Compile {
47    input: PathBuf,
48    /// Specifies the output path for the compiled resource(s).
49    ///
50    /// This is a required flag because you must specify a path to a directory where AAPT2
51    /// can output and store the compiled resources.
52    o: PathBuf,
53    /// Specifies the directory to scan for resources.
54    ///
55    /// Although you can use this flag to compile multiple resource files with one
56    /// command, it disables the benefits of incremental compilation and thus, should not
57    /// be used for large projects.
58    dir: Option<PathBuf>,
59    /// Generates pseudo-localized versions of default strings, such as en-XA and en-XB.
60    pseudo_localize: bool,
61    /// Disables PNG processing.
62    ///
63    /// Use this option if you have already processed the PNG files, or if you are
64    /// creating debug builds that do not require file size reduction. Enabling this
65    /// option results in a faster execution, but increases the output file size.
66    no_crunch: bool,
67    /// Treats errors that are permissible when using earlier versions of AAPT as
68    /// warnings.
69    ///
70    /// This flag should be used for unexpected compile time errors.
71    /// To resolve known behavior changes that you might get while using AAPT2, read
72    /// [Behavior changes in AAPT2.](https://developer.android.com/studio/command-line/aapt2#aapt2_changes)
73    legacy: bool,
74    /// Enable verbose logging.
75    v: bool,
76}
77
78impl Aapt2Compile {
79    pub fn new(input: &Path, o: &Path) -> Self {
80        Self {
81            input: input.to_owned(),
82            o: o.to_owned(),
83            dir: None,
84            pseudo_localize: false,
85            no_crunch: false,
86            legacy: false,
87            v: false,
88        }
89    }
90
91    pub fn dir(&mut self, dir: &Path) -> &mut Self {
92        self.dir = Some(dir.to_owned());
93        self
94    }
95
96    pub fn pseudo_localize(&mut self) -> &mut Self {
97        self.pseudo_localize = true;
98        self
99    }
100
101    pub fn no_crunch(&mut self) -> &mut Self {
102        self.no_crunch = true;
103        self
104    }
105
106    pub fn legacy(&mut self) -> &mut Self {
107        self.legacy = true;
108        self
109    }
110
111    pub fn v(&mut self) -> &mut Self {
112        self.v = true;
113        self
114    }
115
116    pub fn run(&self) {
117        let mut aapt2 = Command::new("aapt2");
118        aapt2.arg("compile");
119        aapt2.arg(&self.input);
120        aapt2.arg("-o").arg(&self.o);
121        if let Some(dir) = &self.dir {
122            aapt2.arg("--dir").arg(dir);
123        }
124        if self.pseudo_localize {
125            aapt2.arg("--pseudo-localize");
126        }
127        if self.no_crunch {
128            aapt2.arg("--no-crunch");
129        }
130        if self.legacy {
131            aapt2.arg("--legacy");
132        }
133        if self.v {
134            aapt2.arg("-v");
135        }
136        aapt2.output().expect("failed to execute process"); // TODO: Remove expect
137    }
138}