When developing, testing, or auditing Android applications, understanding how the platform handles outbound network traffic is essential. Modern Android releases (Android 7.0 Nougat and higher) default to strict transport security policies, trusting only system-installed Certificate Authorities (CAs) by default. For engineers needing to route traffic through local testing proxies or inspect API communications in a controlled sandbox environment, configuring the application's Network Security Configuration is the standard approach.
In this tutorial, we examine how Android's networkSecurityConfig resource works under the hood, how to decompile an application package, inject a customized XML configuration, update the AndroidManifest.xml, and recompile the package using tools like APKTool Studio.
Understanding Android Network Security Configuration
The Network Security Configuration feature lets developers customize network security settings in a declarative XML file without modifying application source code directly. Introduced in API level 24, it controls cleartext traffic policies, custom certificate trust anchors, and domain-specific security constraints.
Default Behavior vs. Debugging Requirements
By default, apps targeting API 24 or higher only trust system certificates for HTTPS traffic:
- Production Default: Only pre-installed system CAs are trusted; user-installed CAs (such as those installed for diagnostic tools or local proxies) are ignored.
- Development Needs: During QA and security assessment in non-production environments, developers often need the application to recognize user-installed trust anchors or custom development CAs specifically for designated domains.
Step 1: Decompiling the APK
To inspect or modify XML resources within a compiled application, the binary XML files must first be decoded into readable, human-editable formats. Binary XML files in an APK are encoded in the Android Binary XML format, which cannot be directly modified with standard text editors.
You can perform this decompilation using a local CLI installation of Apktool or directly in the browser via APKTool Studio, which decodes resources and Smali bytecode without requiring local SDK installations.
# Local CLI syntax:
apktool d myapp.apk -o myapp_decompiled
Step 2: Defining the Custom Network Security Config
Once decompiled, navigate to the res/xml/ directory inside the decompiled package structure. If the directory does not exist, create it:
mkdir -p myapp_decompiled/res/xml
Create a new file named network_security_config.xml inside res/xml/. To permit user certificates for debugging traffic in an isolated test environment, define trust anchors as follows:
<?xml version='1.0' encoding='utf-8'?>
<network-security-config>
<base-config cleartextTrafficPermitted='false'>
<trust-anchors>
<certificates src='system' />
<certificates src='user' />
</trust-anchors>
</base-config>
</network-security-config>
For more targeted testing, you can scope custom trust anchors to specific non-production domains rather than the entire base configuration:
<?xml version='1.0' encoding='utf-8'?>
<network-security-config>
<domain-config cleartextTrafficPermitted='true'>
<domain includeSubdomains='true'>dev.example.local</domain>
<trust-anchors>
<certificates src='user' />
<certificates src='system' />
</trust-anchors>
</domain-config>
</network-security-config>
Step 3: Referencing the Config in AndroidManifest.xml
Next, locate AndroidManifest.xml in the root of the decompiled project folder. Open the file and locate the primary <application> tag.
Add the android:networkSecurityConfig attribute pointing to your newly created resource:
<manifest xmlns:android='http://schemas.android.com/apk/res/android'
package='com.example.myapp'>
<application
android:allowBackup='true'
android:icon='@mipmap/ic_launcher'
android:label='@string/app_name'
android:networkSecurityConfig='@xml/network_security_config'
android:theme='@style/AppTheme'>
<activity android:name='.MainActivity' android:exported='true'>
<intent-filter>
<action android:name='android.intent.action.MAIN' />
<category android:name='android.intent.category.LAUNCHER' />
</intent-filter>
</activity>
</application>
</manifest>
Ensure that the XML syntax remains valid and that no conflicting duplicate attributes are present on the <application> tag.
Step 4: Recompiling and Rebuilding the APK
With the resources and manifest updated, rebuild the APK package. This encodes modified XML back into the optimized binary format and packages the resources alongside existing DEX files.
apktool b myapp_decompiled -o myapp_modified.apk
If you are utilizing APKTool Studio, recompilation is handled automatically on the cloud build pipeline, reducing setup friction with Java and Android build dependencies.
Step 5: Aligning and Signing the Package
Android requires all installed packages to be digitally signed and aligned on 4-byte boundaries. Before deploying the modified package to a development device or emulator, execute zipalign and apksigner:
# 1. Align the APK on 4-byte boundaries
zipalign -v -p 4 myapp_modified.apk myapp_aligned.apk
# 2. Sign using a debug keystore (v2/v3 signatures)
apksigner sign --ks ~/.android/debug.keystore \n --ks-key-alias androiddebugkey \n --ks-pass pass:android \n --key-pass pass:android \n --out myapp_signed.apk \n myapp_aligned.apk
Verifying Deployment in Local Sandboxes
Once signed, install the package via ADB to your testing emulator or test device:
adb install -r myapp_signed.apk
By structuring diagnostic configurations explicitly through the standard networkSecurityConfig mechanism, developers can evaluate network transactions in QA workflows while preserving standard security baselines across release builds.