# Android Compatibility Module This module provides Android framework compatibility for running Aniyomi/Tachiyomi extensions on desktop JVM. ## How It Works This module uses a **hybrid approach** inspired by Suwayomi: 1. **Base Android SDK**: Downloads the official Android SDK `android.jar` from [Sable/android-platforms](https://github.com/Sable/android-platforms) 2. **Custom Stubs**: Provides desktop-specific implementations for classes that need different behavior 3. **Jar Patching**: Removes SDK classes that have custom implementations to avoid conflicts ## Architecture ``` androidcompat/ ├── src/main/java/ │ └── android/ # Custom stub implementations │ ├── app/ # Application, Service │ ├── content/ # Context, SharedPreferences │ ├── graphics/ # Bitmap, Canvas │ ├── net/ # Uri │ ├── os/ # Handler, Looper, Build, Environment │ ├── webkit/ # WebView, WebSettings, WebViewClient │ ├── widget/ # Toast │ └── util/ # Log, Base64 ├── src/main/java/ │ └── androidx/ # AndroidX compatibility │ ├── core/ # ContextCompat │ └── preference/ # Preference classes ├── scripts/ │ └── get-android.sh # Downloads and patches android.jar └── pom.xml ``` ## Custom Stubs The following classes have custom desktop implementations: ### android.app - `Application.java` - Application lifecycle and preferences - `Service.java` - Background service stub ### android.content - `Context.java` - Application context with resource access - `SharedPreferences.java` - Preference storage interface - `SharedPreferencesImpl.java` - Desktop file-based preferences ### android.os - `Handler.java` - Message handling (synchronous on desktop) - `Looper.java` - Message loop (simplified for desktop) - `Build.java` - Build information - `Environment.java` - Environment paths ### android.webkit - `WebView.java` - WebView using JavaFX WebView - `WebSettings.java` - WebView settings - `WebViewClient.java` - WebView callbacks - `CookieManager.java` - Cookie management ### android.graphics - `Bitmap.java` - Image handling ### android.net - `Uri.java` - URI parsing ### android.widget - `Toast.java` - Toast notifications (logs to console) ### android.util - `Log.java` - Logging to stdout/stderr - `Base64.java` - Base64 encoding/decoding ## Adding New Stubs 1. Identify which Android class needs a desktop implementation 2. Create the class in `src/main/java/android//` 3. Add the class path to `scripts/get-android.sh` in `CUSTOM_CLASSES` array 4. Run `mvn clean compile` to rebuild with patched JAR ## How to Use The androidcompat module is automatically included as a dependency in the core module. The build process: 1. Downloads official `android.jar` from [Sable/android-platforms](https://github.com/Sable/android-platforms) 2. Removes classes that have custom implementations (to avoid conflicts with our stubs) 3. Compiles custom stubs alongside the patched JAR 4. Packages everything into the final JAR ## IntelliJ IDEA Setup (Code Navigation) The stripped `android.jar` (SDK classes minus our stubs) is added as a **system dependency** in `pom.xml`. This lets IntelliJ index it so you can navigate Android SDK source code with Ctrl+Click. ### First-Time Setup 1. **Download the JAR** (one-time): ```bash cd androidcompat ./scripts/get-android.sh ``` Or just run a build: ```bash mvn clean compile -pl androidcompat ``` 2. **Reload the Maven project** in IntelliJ: - Right-click `androidcompat/pom.xml` → **Maven** → **Reload Project** - Or press `Ctrl+Shift+O` (Linux/Windows) / `Cmd+Shift+O` (Mac) 3. **Verify it's working**: - Open `androidcompat/src/main/java/android/content/Context.java` - Press `Ctrl+B` on `ApplicationInfo` (or any SDK class not in our stubs) - IntelliJ should decompile and show the SDK source ### What You'll See In the **Project Structure** (`Ctrl+Alt+Shift+S`) → **Libraries**, you should see: ``` Maven: com.google.android:android-sdk-stripped:34 └── androidcompat/target/android.jar ``` This JAR contains **only SDK classes we haven't stubbed** — so when you navigate to `android.app.Activity`, you see the real Android implementation, but when you navigate to `android.content.Context`, you see **our stub**. ### Troubleshooting **"Library not found" or red text in pom.xml:** - The JAR hasn't been downloaded yet. Run `./scripts/get-android.sh` or `mvn clean compile`. **"Cannot resolve symbol" for Android classes:** - Reload the Maven project: right-click `pom.xml` → **Maven** → **Reload Project** - Or: **File** → **Invalidate Caches** → **Invalidate and Restart** **Want to see our stubs instead of SDK classes?** - Our stubs are regular source files in `src/main/java/android/...` - If IntelliJ shows the decompiled SDK version, it means that class is **not in our stubs** (which is useful info!) - To stub it, create the class in `src/main/java/android//` and add it to `get-android.sh` ### Skipping the Download If you already have `android.jar` downloaded or want to skip the download: ```bash mvn clean package -Dexec.skip=true ``` ### Manual Download If automatic download fails, you can manually download: ```bash # Download from Sable/android-platforms curl -o androidcompat/target/android.jar \ https://raw.githubusercontent.com/Sable/android-platforms/master/android-34/android.jar # Then build mvn clean package -Dexec.skip=true ``` ## Extending Android Support When an extension requires an Android class that doesn't exist: ### Option 1: Minimal Stub (Recommended for quick fixes) Create a stub that throws `RuntimeException` for unimplemented methods: ```java package android.some.package; public class SomeClass { public void someMethod() { throw new RuntimeException("Not implemented: SomeClass.someMethod()"); } } ``` ### Option 2: Full Desktop Implementation Provide a desktop-compatible implementation (e.g., using JavaFX instead of Android UI). ### Option 3: Use Android SDK Class If the class works as-is on desktop, just add it to the exclusions list in `get-android.sh` so it's downloaded from the SDK. ## Troubleshooting ### ClassNotFoundException for Android classes - Check if the class is in the downloaded `android.jar` - If not, create a stub in `src/main/java/android/...` - Add the class to `CUSTOM_CLASSES` in `get-android.sh` ### MethodNotFoundError - The Android SDK version might be too old - Update `ANDROID_SDK_VERSION` in `get-android.sh` - Or create a custom stub with the required method ### Class cast exceptions - Custom stub might conflict with SDK class - Ensure class is in `CUSTOM_CLASSES` exclusion list - Run `mvn clean` to rebuild android.jar ## References - Suwayomi's AndroidCompat: https://github.com/Suwayomi/Suwayomi-Server/tree/master/AndroidCompat - Android SDK: https://developer.android.com/reference/ - dex2jar: https://github.com/pxb1988/dex2jar