Resand
Resand (RESesource ANDroid) is a library for android resource reading and writing. It can read and
write AXML (ResXML) and ARSC (ResTable) files.
The purpose of this crate is that I wanted to be able to change the app name and package name of
an apk without including a large dependency such as apktool, or aapt, or any other similar external
tool.
At the moment it cannot change resource data into XML and XML into resource data, but I am working
on adding that, so at the moment all modifications to resource data have to be done directly in Rust.
There is not much documentation yet as this was mainly something I needed for one of my other
projects.
The data structures in the code are based off of the
Android Source Code
Usage
cargo add resand
The following examples use .unwrap(), but obviously you should handle errors properly.
Basic reading and writing of and xml tree:
use resand::xmltree::XMLTree;
use std::fs::File;
let mut file = File::open("./AndroidManifest.xml").unwrap();
let tree = XMLTree::read(&mut file).unwrap();
dbg!(&tree);
let mut output = File::create("./NewAndroidManifest.xml").unwrap();
tree.write(&mut output).unwrap();
Basic reading and writing of a resource table:
use resand::table::ResTable
use std::fs::File;
let mut file = File::open("./resources.arsc").unwrap();
let table = ResTable::read_all(&mut file).unwrap();
dbg!(&table);
let mut output = File::create("./new_resources.arsc").unwrap();
table.write_all(&mut output).unwrap();
Setting the app name:
let xml = XMLTree::read(...);
let mut table = ResTable::read_all(...)
let application = xml
.root
.get_elements(&["manifest", "application"], &xml.string_pool)
.pop()
.unwrap();
let attr = application
.get_attribute("label", &xml.string_pool).unwrap();
if let ResValueType::Reference(attr) = attr.typed_value.data {
let package = table.packages.first_mut().unwrap();
let entry = package
.resolve_ref_mut(attr).unwrap();
if let ResTableEntryValue::ResValue(value) = &mut entry.data {
value
.data
.write_string("New Name".to_string(), &mut table.string_pool);
}
}
table.write_all(...)
Setting the package name:
let mut xml = (...)
let mut table = (...)
let package = table.packages.first_mut().unwrap();
package.name = "new.package.name".to_string();
let root_element = xml
.root
.get_elements_mut(&["manifest"], &xml.string_pool)
.pop().unwrap();
let attr = root_element
.get_attribute_mut("package", &xml.string_pool).unwrap();
attr.write_string("new.package.name".to_string(), &mut xml.string_pool);
xml.write(...);
table.write_all(...);
Using the derive feature
cargo add resand --features derive
Setting the package name
use std::path::Path;
use resand::{
manifest::AndroidManifest,
traits::{FromNode, IntoNode},
xmltree::XMLTree,
};
fn main() {
let tree = XMLTree::from_path(Path::new(
"path/to/AndroidManifest.xml",
))
.unwrap();
let mut manifest = AndroidManifest::from_tree(tree).unwrap();
manifest.package = "com.foo.bar".to_string();
let mut output_buf = std::io::Cursor::new(Vec::new());
let tree = manifest.into_tree();
tree.write(&mut output_buf).unwrap();
}
Creating a new binary XML file
Target:
<network-security-config>
<debug-overrides>
<trust-anchors>
<certificates src="user" />
</trust-anchors>
</debug-overrides>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>
Code:
fn main() {
use resand::traits::IntoNode;
use resand_derive::{FromNode, IntoNode};
#[derive(Debug, IntoNode, FromNode)]
pub struct Certificate {
#[resand(attr)]
pub src: String,
}
#[derive(Debug, IntoNode, FromNode)]
pub struct TrustAnchor {
#[resand(child, many)]
pub certificates: Vec<Certificate>,
}
#[derive(Debug, IntoNode, FromNode)]
pub struct DebugOverride {
#[resand(child, name = "trust-anchors")] pub trust_anchors: TrustAnchor,
}
#[derive(Debug, IntoNode, FromNode)]
pub struct BaseConfig {
#[resand(attr)]
pub cleartext_traffic_permitted: bool,
#[resand(child)]
pub trust_anchors: TrustAnchor,
}
#[derive(Debug, IntoNode, FromNode)]
#[resand(name = "network-security-config")]
pub struct NetworkSecurityConfig {
#[resand(child)]
pub debug_overrides: DebugOverride,
#[resand(child)]
pub base_config: BaseConfig,
}
fn main() {
let tree = NetworkSecurityConfig {
debug_overrides: DebugOverride {
trust_anchors: TrustAnchor {
certificates: vec![Certificate {
src: "user".to_string(),
}],
},
},
base_config: BaseConfig {
cleartext_traffic_permitted: true,
trust_anchors: TrustAnchor {
certificates: vec![
Certificate {
src: "system".to_string(),
},
Certificate {
src: "user".to_string(),
},
],
},
},
}
.into_tree();
let mut file = std::fs::File::create("path/to/network_security_config.xml").unwrap();
tree.write(&mut file).unwrap();
}
License
Resand is licensed under the Apache-2.0 license which can be read here