Skip to content

Latest commit

 

History

History
1555 lines (1186 loc) · 55.3 KB

File metadata and controls

1555 lines (1186 loc) · 55.3 KB
name android-apk-patch
description A complete, self-contained reference for modifying Android APKs — from decompilation to adding features, signing, testing, and local delivery. Covers split APKs, GApps, signing schemes, and dynamic analysis. No Xposed/LSPatch dependency.
metadata
author version tags
mte90
1.0.0
android
apk
gapps
reveng
patch

Table of Contents

  1. Toolchain Setup & Version Requirements
  2. Decompilation & Recompilation Workflow
  3. Split APK Handling (.apks / .apkm / .xapk)
  4. Signing: Schemes, Pitfalls, and Fix Procedures
  5. Dependency Hell: Frameworks, AndroidX, OEM Resources
  6. GApps-Dependent APKs: Patching & Workarounds
  7. Testing Without a Physical Device
  8. Local Testing: Redroid & Waydroid
  9. Advanced Patching Techniquesreferences/advanced-patching.md
  10. Adding Features to an APKreferences/adding-features.md
  11. Delivering the APK to an End Userreferences/delivery.md
  12. End-to-End Workflow: Zero to Deliveryreferences/end-to-end-workflow.md
  13. Troubleshooting: Common Failures & Resolutionsreferences/troubleshooting.md
  14. Quick Reference Cheat Sheetreferences/quick-reference.md

1. Toolchain Setup & Version Requirements

1.1 Mandatory Tools (Current Stable Versions)

Tool Version Purpose URL
Apktool v2.11.0 (Jan 2025) Decompile/recompile APKs https://github.com/iBotPeaches/Apktool
jadx v1.5.1 Read-only Java decompiler https://github.com/skylot/jadx
smali/baksmali v3.0.9 (bundled in Apktool 2.11.0) DEX bytecode assembly/disassembly https://github.com/baksmali/smali
APKEditor Latest Merge/split APK handling https://github.com/pxb1988/APKEditor
apksigner SDK Build Tools 35.0.x APK signing (v1/v2/v3/v4) Part of Android SDK
zipalign SDK Build Tools 35.0.x APK alignment before signing Part of Android SDK
Frida v17.9.0 Dynamic instrumentation https://frida.re
ADB Platform Tools 35.0.x Device/emulator communication Part of Android SDK

1.2 Why Old Tool Versions Will Fail You

  • Apktool < 2.9.0 — Cannot handle API 34+ resources. Decompilation of Android 14+ APKs will crash with obscure AAPT errors or produce corrupted resources.arsc output.
  • Apktool < 2.6.0 — Uses legacy AAPT (v1) instead of AAPT2. Causes massive resource recompilation failures with any app using AndroidX, Material Components, or modern resource features.
  • smali < 3.0.5 — Cannot disassemble DEX format 038+ (Android 13+). baksmali will fail with "Unsupported DEX format" on any app compiled with minSdkVersion 33+.
  • jarsigner (any version) — Only produces v1 (JAR) signatures. Modern Android (7.0+) requires at minimum v2 signatures. Using jarsigner will result in INSTALL_PARSE_FAILED_NO_CERTIFICATES or silent signature rejection.

1.3 Environment Setup

# Java 11+ required (Java 17 recommended)
java -version  # verify
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk

# Install Apktool
# Download latest from https://github.com/iBotPeaches/Apktool/releases
# Move apktool.jar to PATH
chmod +x apktool
sudo mv apktool /usr/local/bin/

# Install Android SDK Build Tools (for apksigner + zipalign)
sdkmanager "build-tools;35.0.0"
sdkmanager "platform-tools"

# Install jadx
# Download from https://github.com/skylot/jadx/releases
# Extract and add bin/ to PATH

# Install Frida
pip install frida-tools

# Install APKEditor
# Download APKEditor.jar from https://github.com/pxb1988/APKEditor/releases

2. Decompilation & Recompilation Workflow

2.1 Standard Single APK Workflow

# Step 1: Analyze with jadx first (understand what you're modifying)
jadx-gui target.apk  # GUI for exploration
# or
jadx -d analysis_output/ target.apk  # CLI

# Step 2: Decompile with apktool
apktool d target.apk -o decompiled/ -f
# -f = force overwrite existing output directory
# --api 35 = force target API level (use if resource errors occur)

# Step 3: Make modifications
# - Edit smali files in decompiled/smali*/  (Java bytecode)
# - Edit resources in decompiled/res/       (layouts, strings, drawables)
# - Edit AndroidManifest.xml               (permissions, components)
# - Edit assets/                           (bundled files, web content)

# Step 4: Recompile
apktool b decompiled/ -o rebuilt.apk
# Use --use-aapt2 flag if not on 2.11.0 (now default)

# Step 5: Align (CRITICAL - must be BEFORE signing)
zipalign -v -p 4 rebuilt.apk rebuilt_aligned.apk

# Step 6: Sign
apksigner sign --ks ~/.android/debug.keystore \
    --ks-pass pass:android \
    --key-pass pass:android \
    rebuilt_aligned.apk

# Step 7: Verify
apksigner verify --verbose --print-certs rebuilt_aligned.apk

# Step 8: Install
adb install -r rebuilt_aligned.apk

2.2 Important Decompilation Flags

# Force specific API level (fixes many resource resolution issues)
apktool d target.apk -o out/ -f --api 35

# Ignore missing resources (new in 2.11.x, for XAPK/base APK decompilation)
apktool d target.apk -o out/ -f --ignore-missing-resources

# Keep original sources only (skip resources, faster)
apktool d target.apk -o out/ -f -s

# Decode only resources (skip smali, for resource-only mods)
apktool d target.apk -o out/ -f -r

# For Samsung/Android 15 framework JARs with DEX format 039
apktool d framework.jar -api 29 -o out/

# Use a custom framework file (for OEM system APKs)
apktool if /path/to/oem-framework.apk
apktool d system_app.apk -o out/ -f

2.3 Understanding the Decompiled Structure

decompiled/
├── AndroidManifest.xml        # App manifest (XML format, editable)
├── apktool.yml                # Apktool metadata (DO NOT manually edit version fields)
├── assets/                    # Raw asset files
├── lib/                       # Native libraries (.so files) by architecture
│   ├── arm64-v8a/
│   ├── armeabi-v7a/
│   └── x86_64/
├── original/                  # Original files (META-INF, etc.)
├── res/                       # Compiled resources (XML format, editable)
│   ├── values/                # String values, styles, colors, dimensions
│   ├── layout/                # Layout XML files
│   ├── drawable/              # Vector drawables, layer lists
│   ├── xml/                   # Preferences, searchable config, etc.
│   └── mipmap-*/              # App icons by density
├── smali/                     # Disassembled DEX bytecode (MAIN CODE)
│   ├── com/
│   │   └── example/
│   │       └── app/
│   │           ├── MainActivity.smali
│   │           └── ...
│   └── android/
│       └── ...
└── smali_classes2/            # Additional DEX files (multi-dex apps)
    └── ...

2.4 Smali Editing Basics

Smali is a human-readable representation of DEX bytecode. Key patterns you'll encounter:

# Class declaration
.class public Lcom/example/app/MainActivity;
.super Landroidx/appcompat/app/AppCompatActivity;

# Method declaration
.method public onCreate(Landroid/os/Bundle;)V
    .registers 4
    
    # Calling super
    invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
    
    # Setting a field
    const-string v0, "patched_value"
    iput-object v0, p0, Lcom/example/app/MainActivity;->mStatus:Ljava/lang/String;
    
    # Conditional check
    if-eqz v0, :cond_skip
    # ... code ...
    :cond_skip
    return-void
.end method

# Common patches:

# 1. Force a boolean method to always return true
.method public isPremium()Z
    .registers 2
    const/4 v0, 0x1        # true
    return v0
.end method

# 2. NOP out a method call (comment effect by replacing with nop)
# Replace: invoke-virtual {v0}, Lcom/example/Payroll;->show()V
# With:    nop

# 3. Remove a permission check
# Replace: if-eqz v0, :cond_deny
# With:    nop              # always falls through

2.5 Resource Editing

Resources are stored as compiled XML (AXML) that apktool decodes. Common modifications:

<!-- res/values/strings.xml - Change app name -->
<string name="app_name">My Patched App</string>

<!-- res/values/colors.xml - Change theme colors -->
<color name="primary">#FF6200EE</color>

<!-- AndroidManifest.xml - Add permissions -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />

<!-- AndroidManifest.xml - Export an activity (make it launchable) -->
<activity android:name=".HiddenActivity" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<!-- res/layout/activity_main.xml - Modify UI -->
<TextView
    android:id="@+id/status_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="PATCHED" />

3. Split APK Handling

3.1 Understanding Split APK Formats

Modern Play Store apps use Android App Bundles (AAB), which are split into multiple APKs:

Format Source Extension Contents
Bundletool Google Play / developer tools .apks ZIP with base + splits + toc.pb (protobuf metadata)
APKMirror APKMirror downloads .apkm Same as .apks, renamed
APKPure APKPure downloads .xapk Similar concept, slightly different metadata
Individual Manual extraction .apk each Each split as separate APK file

Split types you'll encounter:

  • base.apk — Core app code, shared resources, manifest
  • split_config.arm64_v8a.apk — ARM64 native libraries
  • split_config.armeabi_v7a.apk — ARMv7 native libraries
  • split_config.x86_64.apk — x86_64 native libraries
  • split_config.xxhdpi.apk — Screen density-specific resources
  • split_config.en.apk — Language-specific resources
  • split_config.google_apis.apk — Google APIs integration code
  • split_config.firebase.apk — Firebase integration code

3.2 Extraction & Merging Workflow

# Step 1: Extract splits from bundle format
# .apks and .apkm are just ZIP files
mkdir splits/ && cd splits/
unzip ../input.apks          # or .apkm
# This produces: base.apk, split_config.*.apk, toc.pb, etc.

# For .xapk, same approach:
unzip ../input.xapk

# Step 2: Merge into a single "fat APK" using APKEditor
java -jar APKEditor.jar m -i base.apk split_config.arm64_v8a.apk \
    split_config.xxhdpi.apk split_config.en.apk -o merged.apk

# APKEditor intelligently merges resource tables from all splits.
# The resulting merged.apk is self-contained for decompilation.

# Step 3: Decompile the merged APK
apktool d merged.apk -o decompiled/ -f

# Step 4: Make your modifications (smali, resources, manifest)

# Step 5: Recompile
apktool b decompiled/ -o modified_base.apk

# Step 6: Align and sign (see Section 4)
zipalign -v -p 4 modified_base.apk modified_base_aligned.apk
apksigner sign --ks ~/.android/debug.keystore \
    --ks-pass pass:android --key-pass pass:android \
    modified_base_aligned.apk

3.3 Re-installing Modified Split APKs

Option A: Replace base APK only (recommended when possible)

If you only modified the base APK (most common scenario), you can keep the original split APKs:

# Uninstall the app first (signature mismatch will block update)
adb uninstall com.example.app

# Install base + original splits together
adb install-multiple modified_base_aligned.apk \
    splits/split_config.arm64_v8a.apk \
    splits/split_config.xxhdpi.apk \
    splits/split_config.en.apk

Option B: Re-sign ALL APKs with the same key

If splits fail because of signature mismatch (some splits embed signature checks):

# Sign every APK with the same keystore
for apk in modified_base_aligned.apk splits/split_config.*.apk; do
    apksigner sign --ks ~/.android/debug.keystore \
        --ks-pass pass:android --key-pass pass:android \
        "$apk"
done

# Install all at once
adb install-multiple modified_base_aligned.apk splits/split_config.*.apk

Option C: Create a new bundle for distribution

# Create .apks bundle using bundletool
java -jar bundletool.jar build-bundle \
    --modules=modified_base_aligned.apk,splits/split_config.arm64_v8a_apk \
    --output=patched.apks

3.4 Split APK Pitfalls

Pitfall Description Fix
Missing native libs after merge APKEditor may not merge all lib/ directories from arch splits Manually copy missing .so files into merged APK's lib/ before decompiling
Resource conflicts during merge Two splits define same resource ID with different values Merge only base + arch split first, then add density/language splits one at a time
toc.pb metadata mismatch Modified APK doesn't match original bundle metadata Don't use bundletool for installation — use adb install-multiple directly
Feature module splits Some splits contain code (not just resources) Decompile the feature split separately, understand its code, and merge smali directories
Base APK decompilation produces null resources Known apktool issue with some split APK bases Merge with APKEditor first, or use --ignore-missing-resources flag

4. Signing: Schemes, Pitfalls, and Fix Procedures

4.1 APK Signature Schemes Explained

Scheme Since Mechanism Tamper Resistance
v1 (JAR signing) API 1 (all Android) Signs individual file entries inside META-INF/ Weak — can strip and re-sign without app knowing
v2 (APK Signature Scheme v2) API 24 (Android 7.0) Binary signature block before ZIP central directory; verifies entire APK Strong — any byte modification (even metadata) invalidates it
v3 (APK Signature Scheme v3) API 28 (Android 9.0) Same as v2 + supports key rotation via proof-of-rotation lineage Same integrity + allows changing signing keys
v4 (APK Signature Scheme v4) API 30 (Android 11) Merkle hash tree stored separately; enables streaming verification during incremental installs Same integrity + incremental install support

Critical rule: v2/v3 are whole-APK signatures. Modifying even a single byte of smali code, a single resource string, or even the ZIP comment field invalidates them. This is why every recompilation requires a full re-sign.

Android verification order: v4 → v3 → v2 → v1 (falls back through each level).

4.2 apksigner vs jarsigner — Why jarsigner Is Dead

Feature apksigner jarsigner
Signature schemes v1, v2, v3, v4 v1 only
Whole-APK verification Yes No
Key rotation support Yes (v3) No
Required for API 24+ Yes No — will be rejected
Alignment awareness Yes No
Source Android SDK Build Tools JDK

NEVER use jarsigner for APK signing. Period. It produces v1-only signatures that modern Android (7.0+) silently rejects or explicitly denies installation.

4.3 Proper Signing Procedure

# === Creating a Custom Keystore (one-time) ===
keytool -genkey -v -keystore ~/release.keystore \
    -alias myapp \
    -keyalg RSA \
    -keysize 2048 \
    -validity 10000
# You'll be prompted for:
# - Keystore password (use something STRONG and memorable)
# - Key password (same or different)
# - Your name, organization, city, state, country code
# Store the keystore and passwords securely — you CANNOT change the key later

# === Using the Android Debug Keystore (for testing only) ===
# Location: ~/.android/debug.keystore
# Password: android
# Alias: androiddebugkey
# This keystore is identical on ALL Android SDK installations.
# DO NOT use for production — apps signed with it cannot be published or updated.

# === Full Signing Workflow ===

# Step 1: Align the APK (MUST be before signing)
zipalign -v -p 4 rebuilt.apk rebuilt_aligned.apk

# Step 2: Sign with apksigner (all three schemes for maximum compatibility)
apksigner sign \
    --ks ~/release.keystore \
    --ks-key-alias myapp \
    --ks-pass pass:your_keystore_password \
    --key-pass pass:your_key_password \
    --v1-signing-enabled true \
    --v2-signing-enabled true \
    --v3-signing-enabled true \
    rebuilt_aligned.apk
# Note: v4 is NOT signed here — it's computed on-demand during installation

# Step 3: Verify the signature
apksigner verify --verbose --print-certs rebuilt_aligned.apk
# Expected output:
# Verifies
# Verified using v1 scheme (JAR signing): true
# Verified using v2 scheme (APK Signature Scheme v2): true
# Verified using v3 scheme (APK Signature Scheme v3): true
# Number of signers: 1

# Step 4: Optional — Check what schemes are present
apksigner verify --print-certs -v rebuilt_aligned.apk

4.4 Signature-Related Failures and Fixes

Error Message Root Cause Fix
INSTALL_FAILED_UPDATE_INCOMPATIBLE App already installed with different signing key adb uninstall com.example.app then reinstall
INSTALL_PARSE_FAILED_NO_CERTIFICATES APK not signed at all Sign with apksigner
INSTALL_FAILED_VERIFICATION_FAILURE Device requires verified installs (MIUI, Samsung Knox) Disable MIUI optimization, or enable "Install via USB" in Developer Options
App installs but immediately crashes Runtime signature self-check (PackageManager.getPackageInfo() with GET_SIGNATURES) See Section 9.3 (Frida signature bypass) or patch smali signature check
SecurityException: Signature not valid App explicitly checks caller signature Patch the smali signature check, or use signature spoofing (see 6.4)
INSTALL_FAILED_INVALID_APK APK corrupted or malformed after recompilation Check for AAPT2 errors during build, verify zip integrity
Play Store says "App not installed" Custom signature not recognized by Play Store Expected — Play Store only accepts Google-signed updates for apps it manages
Splits fail with INSTALL_FAILED_SESSION_INVALID Splits signed with different keys Sign ALL splits with the same keystore before install-multiple

4.5 Key Rotation with v3 Signing

If you need to change signing keys (e.g., you lost your keystore):

# Sign with the NEW key, providing the OLD key's lineage
apksigner sign \
    --ks new-release.keystore \
    --ks-key-alias newkey \
    --ks-pass pass:new_password \
    --v1-signing-enabled true \
    --v2-signing-enabled true \
    --v3-signing-enabled true \
    --lineage /path/to/lineage-file \
    rebuilt_aligned.apk

# To extract lineage from the OLD keystore:
apksigner sign \
    --ks old-release.keystore \
    --ks-key-alias oldkey \
    --ks-pass pass:old_password \
    --v3-signing-enabled true \
    --lineage /path/to/lineage-file \
    --next-signer new-release.keystore newkey pass:new_password \
    dummy.apk

Caveat: Key rotation only works if the app was PREVIOUSLY signed with v3. If the original app only has v1/v2, you're out of luck — you must uninstall and reinstall.


5. Dependency Hell: Frameworks, AndroidX, OEM Resources

5.1 Common Resource Dependency Errors

# Error 1: Missing AndroidX resources
error: resource 'com.example:id/material_textinput' not found

# Error 2: Styleable attribute not found
error: style attribute 'attr/layout_constraintBaseline_toBaselineOf' not found

# Error 3: AAPT2 crash
ERROR: AAPT2 aapt2(...) exited with code 1
brut.androlib.AndrolibException

# Error 4: Duplicate resource
error: resource 'style/Theme.MaterialComponents' has already been defined

# Error 5: Missing framework resource
error: resource '@android:configui_configFlags' not found

5.2 Systematic Dependency Resolution

Step 1: Install ROM-specific frameworks

For most third-party apps, Apktool's bundled framework (since 2.5.0) is sufficient. But for system apps, OEM apps, or apps that reference framework resources not in AOSP, you need:

# Install the standard Android framework (usually automatic)
apktool if framework-res.apk

# Pull framework files from a rooted device
adb pull /system/framework/ ./device_frameworks/

# Install OEM-specific frameworks
# Samsung:
apktool if device_frameworks/sec_platform_library.jar
apktool if device_frameworks/com.samsung.device.jar
apktool if device_frameworks/frameworksSamsungSDK.jar

# Xiaomi/MIUI:
apktool if device_frameworks/framework-miui-res.apk
apktool if device_frameworks/MiuiSdk.jar
apktool if device_frameworks/framework-mi.jar

# Huawei:
apktool if device_frameworks/HWExtension.jar
apktool if device_frameworks/hwsdk.jar

# OnePlus/Oplus:
apktool if device_frameworks/oplus-framework.jar
apktool if device_frameworks/oplus-res.apk

# Check what frameworks are currently installed
ls ~/.local/share/apktool/framework/

Step 2: Install shared library APKs

Some apps depend on vendor-shared library APKs:

# Find shared library APKs on device
adb shell pm list packages -f | grep shared
adb shell pm list packages -f | grep library

# Pull and install as framework
adb pull /system/app/SomeSharedLib/SomeSharedLib.apk
apktool if SomeSharedLib.apk

Step 3: Force API level to resolve resource conflicts

# If resources from newer APIs aren't found
apktool d target.apk -o out/ -f --api 35

# If dealing with legacy frameworks
apktool d target.apk -o out/ -f --api 29

Step 4: Use the ignore flag for known non-critical missing resources

# New in Apktool 2.11.x
apktool d target.apk -o out/ -f --ignore-missing-resources

5.3 AndroidX-Specific Issues

Issue A: Cross-library resource references

AndroidX migrated all android.support.* classes to androidx.* namespaces. This causes two major categories of issues:

  • Cross-library resource references: AndroidX libraries reference resources across package boundaries. When decompiled, these may resolve incorrectly.
  • R8-obfuscated resource names: When R8 shrinks an app, it may remove unused AndroidX resources. On recompilation, the remaining code may reference resources that were stripped.

Fix: Ensure Apktool 2.11.0+ is used (correctly handles AndroidX cross-references). For R8-obfuscated apps, manually add the required library .aar files as frameworks.

Issue B: Obfuscation

R8/ProGuard/DexGuard can strip resources. This is extremely hard to resolve automatically—your best options are:

  1. Decompile the original APK without modification and immediately recompile (if that fails too, it's a tool limitation)
  2. Manually add the missing resource definition to res/values/ files
  3. Use --ignore-missing-resources and accept that some features may break

5.4 AAPT2 Error Catalog

Error Cause Fix
resource has already been defined Duplicate resource entry in AAPT2 Apktool 2.11.0+ handles most cases. If persists, search for duplicate definitions in res/values/*.xml
failed to compile values files Style/attr references to undefined resources Check attrs.xml, styles.xml, themes.xml for references to removed resources
malformed compiled jar Samsung DEX format 039 in framework apktool d -api 29
no resource identifier found for attribute Missing library dependency Install the required library APK as framework
invalid file path Windows path length limit or special characters in resources Move project to short path, rename files
unmarshalling resource table Corrupted resources.arsc in original APK Try --ignore-missing-resources, or use APKEditor to decompile instead
Error: java.nio.BufferOverflowException Very large resource table (>2GB) Use 64-bit Java and increase heap: JAVA_OPTS="-Xmx4g" apktool b ...

6. GApps-Dependent APKs: Patching & Workarounds

6.1 The GApps Dependency Problem

Apps that depend on Google Play Services are the hardest to patch because:

  1. Split APK hell: Play Services is distributed as ~100+ dynamic feature modules via split APKs
  2. Runtime signature verification: Both the OS and other GApps verify Play Services' signature at runtime
  3. DroidGuard attestation: Google's attestation service is deeply integrated into Play Services core
  4. Automatic updates: The Play Store auto-updates Play Services, overwriting any patches
  5. Play Integrity API: Modern apps use Play Integrity to verify device and app integrity — impossible to fully bypass on emulators

Bottom line: Do NOT try to directly patch com.google.android.gms. It's a losing battle. Instead, use the approaches in the following sections.

6.2 Strategy 1: MicroG (Recommended for GApps-Free Patching)

MicroG is a lightweight, open-source replacement for Google Play Services.

# MicroG provides:
# - Location services (via UnifiedNlp / OpenStreetMap backends)
# - Push notifications (via ntfy or custom push servers)
# - Device registration
# - Maps API (via OpenStreetMap)
# - Limited Google account support

# MicroG does NOT provide:
# - Play Integrity passing
# - Full DroidGuard attestation
# - SafetyNet compatibility
# - All Google API parity
# - Some Play Games features

# Setup MicroG:
# 1. Download GmsCore.apk from https://github.com/microg/GmsCore/releases
#    Or use "MicroG RE" (Redesign for ReVanced) for better compatibility
# 2. Install on your device/emulator
# 3. Install a push notification provider (e.g., ntfy)
# 4. Configure signature spoofing (see 6.4)

6.3 Strategy 2: Patching Individual GApps (YouTube, Maps, etc.)

ReVanced (the successor to Vanced) provides pre-made patches:

Manual patching of GApps:

The key challenge: GApps perform runtime signature verification. They check their own signature against a known Google certificate fingerprint and refuse to function if the signature doesn't match.

# The patching approach:

# 1. Decompile the app
apktool d google_app.apk -o decompiled/

# 2. Find the signature verification code
# Search smali for these patterns:
#   getPackageInfo
#   GET_SIGNATURES
#   PackageManager
#   MessageDigest
#   equals      (for signature comparison)
#   toByteArray (for signature byte extraction)

# 3. Patch or NOP the signature check
# Common pattern in smali:
#   const-string v0, "308203e3..."
#   invoke-virtual {v0}, Ljava/lang/String;->getBytes()[B
#   invoke-static {...}, Ljava/security/MessageDigest;->getInstance(...)L...
#   # Replace with: const/4 v_result, 0x1  (return true/valid)

6.4 Strategy 3: Signature Spoofing

What it does: Makes MicroG's signature appear as the real Google Play Services signature to other apps.

ROM-level support (cleanest approach):

  • LineageOS: Settings → System → Developer options → "Allow signature spoofing"
  • AXP.OS, /e/OS, CalyxOS: Built-in with per-app control

Magisk module approach (for stock ROMs):

  • Patches framework.jar at runtime to allow apps to declare spoofing support
  • MicroG declares spoofing support in its manifest
  • Other apps query MicroG's signature and receive Google's signature bytes
# Install signature spoofing Magisk module:
# Search for "FakeGApps" or "sigspoof" in Magisk Modules repository
# Or use: https://github.com/microg/android_packages_apps_GmsCore/wiki/Installation

6.5 Strategy 4: Play Integrity Bypass (2025 State)

Tool Type Works On Status
TrickyStore Magisk module Android 8+ (with Zygisk) Active — spoofs device attestation key
Play Integrity Fix NEXT Magisk module Android 8+ (with Zygisk) Active — aims for valid attestation
PIFork Magisk module Pre-Android 13 Active fork by osm0sis

Stack for passing Play Integrity (2025):

  1. Root via Magisk / KernelSU / APatch
  2. Install ZygiskNext
  3. Install Play Integrity Fix (or NEXT/fork)
  4. Install TrickyStore + TrickyStore Addon
  5. Do NOT put com.google.android.gms on Magisk DenyList

CRITICAL LIMITATION: Play Integrity does NOT pass on any emulator. Emulators are detected via hardware attestation checks that cannot be spoofed in software. For Play Integrity testing, you MUST use a physical device.


7. Testing Without a Physical Device

7.1 Emulator Selection Matrix

Emulator Root Support ARM Translation GApps Support Best For Verdict
Android Studio AVD Magisk via rootAVD Native (ARM images) / Translated (x86) Google APIs / Google Play images Dev, security testing, patch verification Best choice
Genymotion Built-in basic root libhoudini (not included by default since 3.x) Requires manual GApps flash Professional CI/CD testing Good for automated testing
Waydroid Magisk via script libndk_translation (SSE 4.2 required) Manual via waydroid_script Linux desktop Android apps Good for Linux users
BlueStacks Difficult, no Magisk Built-in Pre-installed Gaming only Not recommended for dev work
Nox Clunky, unreliable Built-in Partial Gaming/automation Not recommended for dev work

7.2 Setting Up Android Studio AVD for APK Testing

# Step 1: Install Android Studio
# Download from https://developer.android.com/studio

# Step 2: Create an AVD (Virtual Device)
# Android Studio → Tools → Device Manager → Create Device
# Recommended configuration:
# - Device: Pixel 7 (or any recent phone profile)
# - System Image: API 35 (Android 15), x86_64 (for speed)
#   OR ARM64 if testing ARM-specific native libs
# - RAM: 4096 MB minimum (8192 MB preferred)
# - AVD Name: "test_device_api35"

# Step 3: Root the AVD with rootAVD
pip3 install rootAVD
rootAVD -s test_device_api35  # Root by AVD name

# Step 4: Verify root
emulator -avd test_device_api35 -no-snapshot-load
adb shell su -c "id"
# Expected: uid=0(root) gid=0(root)

# Step 5: Install Magisk modules (if needed)
# Push module zip to device and flash via Magisk app
adb push module.zip /sdcard/Download/
# Then flash in Magisk Manager app on the emulator

# Step 6: Install your patched APK
adb install -r patched.apk

# For split APKs:
adb install-multiple base.apk split_config.arm64_v8a.apk split_config.en.apk

# Force downgrade if version conflict:
adb install -r -d -t patched.apk

# Clean install if signature mismatch:
adb uninstall com.example.app
adb install patched.apk

7.3 GApps Testing on Emulator

Option A: AVD with Google APIs image

# Create AVD with "Google APIs" system image
# Android Studio → Device Manager → Create Device
# Choose system image: "Google APIs" (not "Google Play")
# This includes Play Services but allows more flexibility

# Caveat: Pre-installed Google Play Services CANNOT be replaced
# with patched versions because the system expects Google's signature

Option B: AVD without Google APIs + MicroG (recommended for GApps-free testing)

# Create AVD with "No Google APIs" / AOSP system image
# This gives you a clean slate

# Install MicroG:
adb install GmsCore.apk
adb install ntfy.apk  # Push notification provider

# Install your patched app:
adb install patched.apk

# Verify MicroG self-check:
# Open MicroG app → Self-check → All should be green (except Play Integrity)

7.4 x86 vs ARM Translation Issues

Android Studio AVD:

  • x86_64 images: ~10x faster than ARM emulation. Uses native x86 execution.
  • ARM64 images: Slower but runs ARM native libraries directly.
  • ARM translation: When running x86_64 image with ARM APKs, the emulator translates ARM instructions to x86 transparently.
  • Problem: Some native libraries (anti-tamper, anti-debug, DRM) detect the translation layer and refuse to run.
  • Fix: Use ARM64 system images when testing apps with ARM-specific native code that performs translation detection.

Genymotion:

  • Runs x86 images by default
  • libhoudini for ARM translation (not included since Genymotion 3.x)
  • Install via: https://github.com/vnsh01/Nyx (for Android 11)
  • macOS Apple Silicon devices don't need translation (native ARM64)

Waydroid:

7.5 Frida Setup on Emulator

# Install Frida tools
pip install frida-tools

# Download frida-server for the emulator's architecture
# Check architecture: adb shell getprop ro.product.cpu.abi
# For x86_64 emulator: download frida-server-x86_64.xz
# For arm64 emulator: download frida-server-arm64.xz

# Push and run frida-server
adb push frida-server /data/local/tmp/
adb shell "chmod 755 /data/local/tmp/frida-server"
adb shell "/data/local/tmp/frida-server -D &"

# Verify connection
frida-ps -U  # Should list running processes

# Run Frida REPL against a running app
frida -U -n com.example.app

# Spawn app with Frida injected
frida -U -f com.example.app -l hook.js --no-pause

# Run a JavaScript hook script
frida -U -l bypass_signature.js -n com.example.app

7.6 ADB Commands Reference for Testing

# === Installation ===
adb install -r app.apk              # Replace existing app
adb install -d app.apk              # Allow version downgrade
adb install -t app.apk              # Allow test APKs
adb install-multiple base.apk s1.apk s2.apk  # Split APKs
adb uninstall com.example.app       # Remove app + data

# === Debugging ===
adb logcat                          # View logs
adb logcat -s "ActivityManager"     # Filter by tag
adb logcat | grep -i "FATAL"        # Filter crash logs
adb shell dumpsys package com.example.app  # Package info

# === File operations ===
adb push file.txt /sdcard/          # Upload file
adb pull /sdcard/file.txt ./        # Download file

# === Root operations ===
adb shell su -c "command"           # Run as root
adb shell su -c "mount -o rw,remount /system"
adb push patched.apk /system/app/TargetApp/target.apk
adb shell su -c "chmod 644 /system/app/TargetApp/target.apk"

# === Emulator-specific ===
emulator -avd NAME -no-snapshot-load  # Start emulator fresh
adb reboot                          # Reboot emulator

7.7 ADB Install Flags Reference

Flag Meaning Use Case
-r Replace/reinstall existing app Updating a patched APK
-d Allow version downgrade Installing older patched version
-t Allow test APKs (android:testOnly="true") Debug/test builds
-g Grant all runtime permissions Testing with all permissions
--force-install Force install (Android 13+) Bypass signature/version checks
-p Partial install (split APK mode) Internal use for install-multiple

8. Local Testing: Redroid & Waydroid

8.1 Signing for Local Testing: Everything You Need to Know

8.1.1 The Debug Keystore (Quick & Dirty)

Location:  ~/.android/debug.keystore
Password:  android
Alias:     androiddebugkey
Key pass:  android

When to use: Local-only testing on redroid, Waydroid, your own devices, emulators.

When NOT to use: Distributing APKs to others, publishing to Play Store.

8.1.2 Custom Keystore for Reproducible Signing

# One-time creation
keytool -genkey -v \
    -keystore ~/apk-testing.keystore \
    -alias testing \
    -keyalg RSA \
    -keysize 2048 \
    -validity 10000

# You'll be prompted for:
# - Keystore password (use something STRONG and memorable)
# - Key password (same or different)
# - Your name, organization, city, state, country code
# 
# BACKUP THIS FILE. If you lose it, you'll have to uninstall and reinstall every app you ever signed.

8.1.3 The Critical Order: zipalign THEN sign

# CORRECT ORDER:
zipalign -v -p 4 rebuilt.apk rebuilt_aligned.apk    # Step 1: ALIGN first
apksigner sign --ks key.keystore aligned.apk        # Step 2: SIGN second

# WRONG ORDER (will break v2/v3 signatures):
apksigner sign --ks key.keystore rebuilt.apk          # Signing first
zipalign -v -p 4 rebuilt.apk aligned.apk              # Then aligning BREAKS the signature!

Why: v2/v3 signatures are computed over the entire APK binary, including the position of entries within the ZIP. zipalign moves entries around to 4-byte boundaries, which invalidates any signature computed before alignment.

8.1.4 Signing Split APKs with the Same Key

When testing split APKs on redroid/Waydroid, ALL splits in a bundle must share the same signing key:

# Extract splits from .apks/.apkm
unzip input.apks -d splits/

# Align all APKs
for apk in splits/*.apk; do
    zipalign -v -p 4 "$apk" "${apk%.apk}_aligned.apk"
done

# Sign ALL splits with THE SAME key
for apk in splits/*_aligned.apk; do
    apksigner sign \
        --ks ~/apk-testing.keystore \
        --ks-key-alias testing \
        --ks-pass pass:your_password \
        --key-pass pass:your_password \
        "$apk"
done

# Install all at once via ADB
adb install-multiple splits/base_aligned.apk \
    splits/split_config.arm64_v8a_aligned.apk \
    splits/split_config.en_aligned.apk

8.1.5 uber-apk-signer: All-in-One Alternative

If you want to skip the manual zipalign + apksigner dance:

# Download from https://github.com/patrickfav/uber-apk-signer/releases
java -jar uber-apk-signer.jar --apks rebuilt.apk
# Handles: zipalign + sign with debug keystore + verify
# Output: rebuilt-aligned-debugSigned.apk

# With custom keystore
java -jar uber-apk-signer.jar \
    --apks rebuilt.apk \
    --ks ~/apk-testing.keystore \
    --ksAlias testing \
    --ksPass your_password

# Sign multiple APKs at once (splits)
java -jar uber-apk-signer.jar --apks splits/

8.1.6 Common Signing Mistakes & Symptoms

Mistake What Happens Fix
zipalign AFTER sign INSTALL_FAILED_VERIFICATION Always zipalign first
Used jarsigner instead of apksigner v2/v3 signatures missing; Android 7.0+ rejects Use apksigner
Split APKs signed with different keys INSTALL_FAILED_SESSION_INVALID Sign ALL with same keystore
Modified APK after signing Signature broken Never modify post-sign
Wrong keystore password Keystore was tampered with, or password was incorrect Verify with keytool -list
Not aligned at all App installs but runs slow; INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION on some ROMs Always run zipalign -v -p 4
Missing v2 scheme on API 24+ Silent rejection or INSTALL_PARSE_FAILED_NO_CERTIFICATES apksigner defaults to v1+v2; verify with apksigner verify -v

8.2 Redroid: Android in Docker for Headless APK Testing

8.2.1 What Is Redroid?

Redroid (Remote-android) runs a full Android system inside a Docker container. It does NOT use QEMU or virtualization — it runs Android userspace natively on the host Linux kernel using LXC primitives.

Key characteristics:

  • Runs as a Docker container — fully containerized, reproducible, scriptable
  • Root by default (uid=0 inside the container)
  • ADB access via TCP on port 5555
  • No display by default (headless) — use scrcpy for screen mirroring if needed
  • Supports Android 11 through 15
  • Perfect for CI/CD, batch testing, and automated APK validation

Official resources:

8.2.2 Prerequisites & Kernel Setup

# 1. Install Docker
sudo apt install docker.io docker-compose
sudo usermod -aG docker $USER   # Log out and back in

# 2. Install binder kernel module
sudo apt install linux-modules-extra-$(uname -r)

# 3. Load binder module
sudo modprobe binder_linux

# 4. Verify binder is available
ls /dev/binderfs 2>/dev/null && echo "OK: binderfs found" || echo "MISSING"

# 5. For Android 12+: ashmem is replaced by memfd (no extra module needed)
# For Android 11: also load ashmem
sudo modprobe ashmem_linux

Kernel version requirement: 4.14+ (virtually all modern distros satisfy this).

WSL2 support: Possible but requires a custom WSL2 kernel with binder modules. See https://github.com/remote-android/redroid-doc/blob/master/deploy/wsl.md. macOS is NOT directly supported (Docker Desktop on macOS lacks binder).

8.2.3 Basic Docker Setup

Minimal headless container (for pure APK install/run testing):

docker run -d \
    --privileged \
    --name redroid14 \
    -p 5555:5555 \
    redroid/redroid:14.0.0-latest

With GPU acceleration (Intel/AMD via Mesa/virgl):

docker run -d \
    --privileged \
    --name redroid14 \
    -p 5555:5555 \
    -v /dev/dri:/dev/dri \
    redroid/redroid:14.0.0-latest \
    androidboot.redroid_width=1080 \
    androidboot.redroid_height=1920 \
    androidboot.redroid_dpi=320

With persistent data (apps survive container restart):

docker volume create redroid_data

docker run -d \
    --privileged \
    --name redroid14 \
    -p 5555:5555 \
    -v /dev/dri:/dev/dri \
    -v redroid_data:/data \
    redroid/redroid:14.0.0-latest \
    androidboot.redroid_width=1080 \
    androidboot.redroid_height=1920 \
    androidboot.redroid_dpi=320

Docker Compose (recommended for reproducible setups):

# docker-compose.yml
services:
  redroid:
    image: redroid/redroid:14.0.0-latest
    container_name: redroid14
    privileged: true
    ports:
      - "5555:5555"
    volumes:
      - /dev/dri:/dev/dri
      - redroid_data:/data
    command:
      - "androidboot.redroid_width=1080"
      - "androidboot.redroid_height=1920"
      - "androidboot.redroid_dpi=320"

volumes:
  redroid_data:
docker compose up -d      # Start
docker compose logs -f    # View boot logs (wait for "Boot completed")
docker compose down       # Stop

8.2.4 Available Docker Image Tags

Tag Android Notes
redroid/redroid:11.0.0-latest 11 Stable, legacy
redroid/redroid:12.0.0-latest 12 Stable
redroid/redroid:13.0.0-latest 13 Stable
redroid/redroid:14.0.0-latest 14 Recommended — most stable
redroid/redroid:15.0.0-latest 15 Newer, check stability
redroid/redroid:14.0.0_64only-latest 14 64-bit only (smaller, fewer compat issues)
erstt/redroid Various Pre-built with ARM translation

8.2.5 ADB Connection & APK Installation

# Wait for container to boot (check logs: "Boot completed")
docker logs redroid14 2>&1 | tail -5

# Connect ADB via TCP
adb connect localhost:5555
adb devices
# Expected: localhost:5555    device

# === Install patched APK ===
# Basic install
adb -s localhost:5555 install rebuilt_aligned.apk

# Reinstall over existing
adb -s localhost:5555 install -r rebuilt_aligned.apk

# Force install (bypass version/signature conflicts)
adb -s localhost:5555 install -d -t --force-install rebuilt_aligned.apk

# Install split APKs
adb -s localhost:5555 install-multiple base_aligned.apk \
    split_config.arm64_v8a_aligned.apk \
    split_config.xxhdpi_aligned.apk

# Grant all runtime permissions
adb -s localhost:5555 install -r -g rebuilt_aligned.apk

# === App management ===
adb -s localhost:5555 shell pm list packages          # List all
adb -s localhost:5555 shell pm list packages -3       # Third-party only
adb -s localhost:5555 uninstall com.example.app        # Remove
adb -s localhost:5555 shell am force-stop com.example.app  # Force stop
adb -s localhost:5555 shell am start -n com.example.app/.MainActivity  # Launch

# === Shell access (root by default!) ===
adb -s localhost:5555 shell
whoami   # root
id       # uid=0(root) gid=0(root)

# === Screen mirroring (if you need to see the UI) ===
# Use scrcpy (install: sudo apt install scrcpy)
scrcpy -s localhost:5555

8.2.6 GApps, Magisk & ARM Translation on Redroid

All three can be installed via redroid-script without rebuilding the Docker image:

git clone https://github.com/abing7k/redroid-script.git
cd redroid-script

# Install everything in one go
sudo python3 redroid-script.py redroid14 --gapps --magisk --libndk

# Or individually:
sudo python3 redroid-script.py redroid14 --gapps    # OpenGApps
sudo python3 redroid-script.py redroid14 --magisk   # Magisk
sudo python3 redroid-script.py redroid14 --libndk   # ARM translation (libndk_translation)
sudo python3 redroid-script.py redroid14 --houdini  # ARM translation (Intel Houdini)

# Restart container after installation
docker restart redroid14

Note: Magisk installation may require 2-3 container restarts to fully initialize, especially with Zygisk enabled.

8.2.7 Complete Redroid APK Testing Workflow

# === One-time setup ===
sudo modprobe binder_linux
docker volume create redroid_data
docker run -d --privileged --name redroid14 -p 5555:5555 \
    -v redroid_data:/data redroid/redroid:14.0.0-latest
# Wait ~30s for boot, then:
adb connect localhost:5555

# === GApps + ARM translation (one-time, optional) ===
git clone https://github.com/abing7k/redroid-script.git
sudo python3 redroid-script.py redroid14 --gapps --libndk
docker restart redroid14
sleep 30
adb connect localhost:5555

# === Per-APK test cycle ===
# 1. Decompile, modify, recompile (see Section 2)
apktool d target.apk -o dec/ -f
# ... make modifications ...
apktool b dec/ -o rebuilt.apk

# 2. Sign
zipalign -v -p 4 rebuilt.apk rebuilt_aligned.apk
apksigner sign --ks ~/apk-testing.keystore \
    --ks-key-alias testing --ks-pass pass:your_password \
    --key-pass pass:your_password rebuilt_aligned.apk

# 3. Uninstall previous version (if exists)
adb -s localhost:5555 uninstall com.example.app 2>/dev/null

# 4. Install
adb -s localhost:5555 install rebuilt_aligned.apk

# 5. Launch and check logs
adb -s localhost:5555 shell am start -n com.example.app/.MainActivity
adb -s localhost:5555 logcat -s "AndroidRuntime:E" "*:S"

# 6. If needed, mirror screen with scrcpy
scrcpy -s localhost:5555

# === Cleanup ===
docker stop redroid14
docker rm redroid14
docker volume rm redroid_data

8.2.8 Redroid Known Issues

Issue Workaround
Container won't start (binder missing) sudo modprobe binder_linux + linux-modules-extra-$(uname -r)
Apps can't access internet Use --net=host in docker run
Long first boot on WSL2 Store data as Docker volume (not bind mount)
ARM app crashes on x86 host Install ARM translation: redroid-script.py <id> --libndk
No audio output Expected in headless mode; use scrcpy for visual only
Magisk instability after install Restart container 2-3 times
GPU artifacts on NVIDIA Use software rendering (remove -v /dev/dri:/dev/dri)

8.3 Waydroid: Android Container with Desktop UI

8.3.1 What Is Waydroid?

Waydroid runs Android as an LXC container with native desktop window integration. Unlike redroid, it displays Android apps as regular windows on your Linux desktop. It requires a Wayland compositor (GNOME Wayland, KDE Plasma Wayland, Sway, Hyprland, etc.).

Key characteristics:

  • Android apps appear as native desktop windows
  • Clipboard sync between Linux and Android (Wayland only)
  • Audio via PulseAudio/PipeWire
  • Requires Wayland compositor (or nested weston for X11)
  • ADB access via local socket
  • Single Android session (not multi-container like redroid)

Official resources:

8.3.2 Installation

# === Ubuntu 22.04 / 24.04 ===
sudo apt install curl ca-certificates
curl https://repo.waydro.id | sudo bash
sudo apt install waydroid

# === Debian ===
curl https://repo.waydro.id | sudo bash
sudo apt install waydroid

# === Arch Linux ===
sudo pacman -S waydroid

# === Fedora ===
sudo dnf install waydroid

# === Initialize (choose one) ===
sudo waydroid init                  # Vanilla (no Google services)
sudo waydroid init -s GAPS         # With OpenGApps (Play Store etc.)

# === Start ===
waydroid session start
waydroid show-full-ui               # Opens Android desktop window

8.3.3 GApps, Magisk & ARM Translation via waydroid_script

casualsnek/waydroid_script is the Swiss army knife for Waydroid:

git clone https://github.com/casualsnek/waydroid_script.git
cd waydroid_script
sudo pip3 install requests pyyaml   # Dependencies

# Install everything:
sudo python3 waydroid_script.py -g -m -l
# -g = GApps (OpenGApps)
# -m = Magisk
# -l = libndk_translation (ARM translation)

# Individual options:
sudo python3 waydroid_script.py -g                  # GApps only
sudo python3 waydroid_script.py -g --variant pico   # GApps, minimal variant
sudo python3 waydroid_script.py -g --microg         # MicroG instead of OpenGApps
sudo python3 waydroid_script.py -m                  # Magisk only
sudo python3 waydroid_script.py -l                  # libndk_translation
sudo python3 waydroid_script.py -L                  # libhoudini (alternative ARM translation)

# Restart Waydroid after installation
waydroid session stop
sudo systemctl restart waydroid-container
waydroid session start && waydroid show-full-ui

ARM translation critical requirement: Your CPU must support SSE 4.2 instruction set:

# Check
cat /proc/cpuinfo | grep sse4_2
# If empty: your CPU doesn't support it — ARM translation won't work

8.3.4 ADB Connection & APK Installation

# Waydroid exposes ADB via local socket (auto-configured)
adb devices
# Expected: waydroid0    device

# === Install patched APK ===
# Using waydroid CLI (recommended)
waydroid app install /path/to/rebuilt_aligned.apk

# Using ADB directly
adb install /path/to/rebuilt_aligned.apk
adb install -r /path/to/rebuilt_aligned.apk           # Reinstall
adb install -d -t --force-install /path/to/app.apk    # Force

# Install split APKs via ADB
adb install-multiple base.apk split_config.arm64_v8a.apk

# === App management ===
waydroid app list                     # List installed packages
waydroid app launch com.example.app   # Launch app
waydroid app remove com.example.app   # Uninstall
waydroid app list --show-package-name # Show package names

# === Shell access ===
adb shell                              # Regular shell
sudo waydroid shell                    # Root shell (if configured)

# === Screen recording / screenshots ===
waydroid ctrl +p                       # Screenshot (shortcut, if mapped)

8.3.5 Complete Waydroid APK Testing Workflow

# === One-time setup ===
curl https://repo.waydro.id | sudo bash
sudo apt install waydroid
sudo waydroid init   # or: sudo waydroid init -s GAPS

# Install ARM translation + Magisk
git clone https://github.com/casualsnek/waydroid_script.git
cd waydroid_script
sudo python3 waydroid_script.py -g -m -l
cd ..
waydroid session stop && sudo systemctl restart waydroid-container
waydroid session start && waydroid show-full-ui

# === Per-APK test cycle ===
# 1. Decompile, modify, recompile
apktool d target.apk -o dec/ -f
# ... make modifications ...
apktool b dec/ -o rebuilt.apk

# 2. Sign
zipalign -v -p 4 rebuilt.apk rebuilt_aligned.apk
apksigner sign --ks ~/apk-testing.keystore \
    --ks-key-alias testing --ks-pass pass:your_password \
    --key-pass pass:your_password rebuilt_aligned.apk

# 3. Uninstall previous version
waydroid app remove com.example.app 2>/dev/null

# 4. Install
waydroid app install rebuilt_aligned.apk

# 5. Launch
waydroid app launch com.example.app

# 6. Check logs
adb logcat -s "AndroidRuntime:E" "*:S"

8.3.6 NVIDIA GPU: Known Pain Point

Waydroid relies on Mesa/GBM for GPU rendering. NVIDIA's proprietary driver doesn't use Mesa:

# Workaround 1: Force software rendering
WAYDROID_DISABLE_GPU=1 waydroid session start

# Workaround 2: Switch to integrated GPU (dual-GPU laptops)
# Use prime-select or DRI_PRIME=1

# Workaround 3: NVIDIA open kernel module 575.51.02+
# Recent reports (mid-2025) show Waydroid "works" with open driver
# But GPU acceleration may still be partial

8.3.7 Waydroid Known Issues

Issue Workaround
NVIDIA GPU: no/flickering rendering WAYDROID_DISABLE_GPU=1 or switch to iGPU
X11: no display Run nested Wayland: weston & then WAYLAND_DISPLAY=wayland-1 waydroid show-full-ui
Camera not working Very limited support (v4l2 only, no PipeWire)
Magisk flaky install Check waydroid_script version; may need manual Magisk flash
Bluetooth/USB not working Not natively supported
Dual GPU flickering Force iGPU only or use software rendering
SELinux blocks Waydroid Set permissive: sudo setenforce 0 (temp) or configure policy


9. Advanced Patching Techniques

Full reference: references/advanced-patching.md

This section covers:

  • Dynamic instrumentation with Frida (SSL pinning bypass, root detection bypass, signature bypass)
  • Dealing with obfuscation (R8/ProGuard/DexGuard)
  • Bypassing app integrity checks (file hash verification, tamper detection, DEX integrity, Play Integrity)
  • Creating Magisk modules as an alternative to direct patching.

10. Adding Features to an APK

Full reference: references/adding-features.md

This section covers:

  • Creating new smali classes from scratch
  • Adding a new Activity to the app
  • Adding external libraries (.jar / .aar)
  • Injecting code into the app lifecycle
  • Handling multi-DEX when adding code
  • Practical example: Adding a "Debug Panel" to any app.

11. Delivering the APK to an End User

Full reference: references/delivery.md

This section covers:

  • Release signing (not debug!)
  • What the end user must do before installing
  • Distribution methods (direct APK, .apks bundle, .apkm, ADB install)
  • Preventing Play Store overwrites
  • Preparing a user-friendly delivery package.

12. End-to-End Workflow: Zero to Delivery

Full reference: references/end-to-end-workflow.md

A complete checklist-driven workflow from toolchain setup to final delivery:

  • Phase 1: Setup (one-time)
  • Phase 2: Analysis
  • Phase 3: Decompile
  • Phase 4: Modify
  • Phase 5: Recompile & Fix
  • Phase 6: Sign & Test (Local)
  • Phase 7: Prepare for Delivery
  • Phase 8: Deliver
  • Phase 9: Maintenance.

13. Troubleshooting: Common Failures & Solutions

Full reference: references/troubleshooting.md

Quick reference tables for:

  • Decompilation failures
  • Recompilation failures
  • Installation failures
  • Runtime failures (app crashes after install)
  • Performance issues.

14. Quick Reference Cheat Sheet

Full reference: references/quick-reference.md

Includes:

  • Command summary (decompile, recompile, align, sign, install)
  • Smali quick reference
  • Key file paths
  • Common patterns cheat sheet.

References