.. Pyaxml documentation master file, created by
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

Welcome to Pyaxml's documentation |version| |release|!
==========================================================

PyAxml is a full python tool to play with AXML (Android XML) files.
This tool is useful to decode and encode AXML files and manipulate AXML files
over a `Protocol Buffers <https://protobuf.dev/>`_ object.
It is designed to work with Python 3 and Rust only.

Some examples of the use of the tool is provided with the project:

- copymanifest.py that allow to decode and reencode the original file
- replace_activity_name.py to change the name an activity and replace by an other

If you want to see more example you can dig more on the project
`apkpatcher <https://gitlab.com/MadSquirrels/mobile/apkpatcher>`_ that use this
library to add some useful permission and inject a library inside the target
application.
To have a better understanding about how is composed the AXML format a
graphic is associated in drawio and svg format: format.drawio, format.drawio.svg

The link of the project https://gitlab.com/MadSquirrels/mobile/pyaxml

QuickStart
==========

To get you started, here is a detailed example of how to replace an activity 
in an Android AXML file using Python. This script utilizes the pyaxml library 
to handle the AXML format.

.. code-block:: python

   import pyaxml
   import click

   @click.command()
   @click.argument('input_file')
   @click.argument('output_file')
   @click.argument('activity_name')
   @click.argument('new_activity_name')
   def replace_activity(input_file, output_file, activity_name, new_activity_name):
      filename = input_file
      with open(filename, "rb") as f:
         axml = pyaxml.AXML.from_axml(f.read())
         xml = axml.to_xml()
         android_name = "{http://schemas.android.com/apk/res/android}name"
         for activity in xml.findall(f"./application/activity/[@{android_name}='{activity_name}']"):
               activity.attrib[android_name] = new_activity_name
         axml_object = pyaxml.AXML()
         axml_object.from_xml(xml)
      # Rewrite the file
      with open(output_file, "wb") as f:
         f.write(axml_object.pack())

   if __name__ == "__main__":
      replace_activity()


To begin with a more simple example you can use the tool to only encode and
decode AXML thanks to 3 available commands:

- axml2xml: to decode AXML and print it in XML;
- arsc2xml: to decode ARSC and print it in XML;
- xml2axml: to encode XML in AXML.


.. code-block:: bash

  # Python CLI
  pyaxml axml2xml -i AndroidManifest.xml
  pyaxml arsc2xml -i resources.arsc
  pyaxml xml2axml -i AndroidManifest.xml -o AndroidManifest.axml

  # Rust CLI (same commands, no Python required)
  pyaxml-rs axml2xml -i AndroidManifest.xml
  pyaxml-rs arsc2xml -i resources.arsc
  pyaxml-rs xml2axml -i AndroidManifest.xml -o AndroidManifest.axml

AXML or ARSC
------------

In Android application development, AXML and ARSC files are key components:

- AXML (Android XML): Typically used for AndroidManifest.xml, which contains essential information about the application such as its components and permissions.
- ARSC (Android Resource Synchronized Container): Contains compiled resources like strings, styles, and layouts.

To handle these file types, pyaxml provides distinct classes for each:

- AXML: Manages AXML files, allowing for parsing and modification of XML data.
- ARSC: Handles ARSC files, enabling the manipulation of compiled resource data.


When dealing with files whose type you might not be certain of, pyaxml offers a convenient solution:

- AXML_guess: This class includes the from_axml method, which can automatically determine whether a file is an AXML or an ARSC file. Based on this determination, it returns an instance of either the AXML class or the ARSC class.

**Example Usage**

Here's how you might use AXML_guess to handle files without knowing their exact type:

.. code-block:: python

   import pyaxml
   import click

   @click.command()
   @click.argument('input_file')
   def process_file(input_file):
      filename = input_file
      with open(filename, "rb") as f:
         guessed_object = pyaxml.AXML_guess.from_axml(data)
         
         if isinstance(guessed_object, pyaxml.AXML):
               print("Processing AXML file")
               # Handle AXML file
               xml = guessed_object.to_xml()
               # Perform operations on XML data
               # ...
         elif isinstance(guessed_object, pyaxml.ARSC):
               print("Processing ARSC file")
               # Handle ARSC file
               # Perform operations on ARSC data
               # ...
         else:
               print("Unknown file type")
      
      # Write the modified AXML to the output file
      with open(output_file, "wb") as f:
         f.write(guessed_object.pack())

   if __name__ == "__main__":
      process_file()



Details
=======

.. toctree::
  :maxdepth: 2
  :titlesonly:
  :glob:

  user_guide
  developer_guide
  modules
  rust_api

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
