# AndroidXML Pure Swift library for parsing binary XML files such as found in Android apk files. ## About Written from scratch and closely following the original C++ source code ([ResourceTypes.h], [ResourceTypes.cpp]). Names have been adapted to a more Swiftly syntax. Import of `Foundation` is optional which should makes the library cross-platform compatible (though I have not tested other than macOS). Since the AXML format is not documented anywhere – apart from the source code – you cannot rely on the structure to work forever. Especially, pay attention to other binary XML formats which have [been spotted](https://www.cclsolutionsgroup.com/post/android-abx-binary-xml) on Android. I do not think ABX is currently used for `.apk` files, only system files. However, If that should change I would need to make some adjustments to this library. ## Example Usage ### Automatic XML String Conversion ```swift let parser = try AndroidXML(path: "some/AndroidManifest.xml").parseXml() print(try parser.xmlString()) ``` ### Manual XML Parser ```swift let xml = try! AndroidXML(data: [...]).parseXml() try xml.iterElements({ startTag, attributes in print("<\(startTag)>") for (name, val) in try? attributes.asList() { print("\t", name, "=", val.resolve(xml.stringPool)) } }) { endTag in print("") } ``` ### Resource Table Lookup ```swift let lookupId = 0x7F100000 let xml = try! AndroidXML(path: "some/resources.arsc").parseTable() let res = try! xml.getResource(TblTableRef(lookupId))! let pkgPool = res.package.stringPool(for: .Keys)! for x in res.entries { let val = x.entry.value! print(pkgPool.getString(x.entry.key), val.resolve(xml.stringPool), x.config.screenType.density) } ``` ### Manual Table Parsing ```swift let xml = try AndroidXML(path: "some/resources.arsc").parseTable() for pkg in try xml.getPackages() { let pool = pkg.stringPool(for: .Keys)! try pkg.iterTypes { spec, types in //print("----- \(spec.id) ------") for type in types { try type.iterValues { idx, entry in if entry.isComplex { //print("::.::.complex", pool.getString(entry.key), entry.valueMap!.parent.asHex) for x in entry.valueMap!.entries { let _ = x.name.asHex let _ = x.value.resolve(xml.stringPool) } } else { let _ = pool.getString(entry.key) let _ = entry.value!.resolve(xml.stringPool) } } } } } ``` ## Developer Note There are a few places I could not properly test becaues none of my test files triggered the condition. For example, handling dynamic attributes and dynamic references. I've added some `assert` (ignored in release builds) to trigger as soon as a specific condition is met. If you encounter a file, which triggers such a condition, reach out so I can finalize the library. [ResourceTypes.h]: https://android.googlesource.com/platform/frameworks/base/+/master/libs/androidfw/include/androidfw/ResourceTypes.h [ResourceTypes.cpp]: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/libs/androidfw/ResourceTypes.cpp