Shadow Android Plugin Framework

repository·master·Indexed 25 days ago

https://github.com/tencent/shadow

A high-performance, dynamic Android plugin framework developed by Tencent. Shadow allows developers to load and run plugin APKs within a host application without relying on non-public system APIs or reflection. It supports major Android components, Fragments, DataBinding, and native library loading, while maintaining a minimal host footprint (~15KB). The framework is fully dynamic, allowing the framework code itself to be updated via the plugin.

Tokens
2K
Snippets
1
Records
9
Agent score
93%

What's inside Shadow

  1. Overview of Shadow Android Plugin Framework

    master

    Shadow is an Android plugin framework developed by Tencent, designed to support large-scale production environments. Unlike many other frameworks, Shadow focuses on high compatibility and minimal host impact.

    Key Features:

    • Source Code Reuse: Plugin App source code can be installed and run normally without modification.
    • Zero Reflection/No Hack Implementation: Does not rely on hidden system APIs or reflection, making it compatible with Google's restrictions on non-public SDK interfaces.
    • Fully Dynamic Framework: The plugin framework code is part of the plugin itself. This allows the framework to be updated dynamically via the plugin without requiring a new host app build.
    • Minimal Host Footprint: The code required in the host application is extremely small (~15KB, ~160 methods).
    • Kotlin Implementation: Core components like core.loader and core.transform are implemented in Kotlin for maintainability.

    Supported Capabilities:

    • Four major Android components (Activity, Service, etc.)
    • Fragments (via both code and XML)
    • DataBinding (works out-of-the-box)
    • Cross-process usage of plugin Services
    • Custom Themes
    • Accessing host classes from plugins
    • SO (Native library) loading
    • Segmented loading (loading multiple APKs or dependent APKs)
    • Loading multiple Views from different APKs within a single Activity
  2. Understand the Shadow Framework Architecture

    master

    Shadow is a plugin framework where an application consists of several components:

    • Host Application: Contains minimal interfaces and registers proxy components in the Manifest. It includes the dynamic upgrade logic for the Plugin Manager.
    • Plugin Manager (manager): Responsible for downloading and installing plugins. It includes a dynamic View to represent loading states.
    • Plugin: A package that includes the business App, the Loader, and the Runtime.
      • Loader: A multi-instance component that can contain business logic for special processing. It interacts with the business App via a Binder (plugins should run in independent processes to avoid native library conflicts).
      • Runtime: Defines the actual classes for the proxy components.

    In a typical lifecycle, the manager first loads the runtime and loader from the plugin, then uses the loader to load the business App.

  3. Understand the dynamic API demonstration architecture

    master

    This sample project demonstrates how to make custom interfaces dynamic, allowing a host application to use implementations contained within a separate APK. The architecture is split into two main components:

    1. sample-hello-api: Defines the API interface that the host expects to use.
    2. sample-hello-api-holder: Handles the dynamic implementation logic. It provides methods that the host calls to retrieve the actual implementation residing inside the target APK.
  4. Dynamically load custom API implementations from an APK

    master

    Shadow allows you to make custom interfaces dynamic, enabling a host application to use implementations contained within a separate APK.

    To achieve this, you need two components:

    1. sample-hello-api: Defines the host's API interface.
    2. sample-hello-api-holder: Provides the mechanism to dynamically retrieve the implementation from the APK.

    To use this pattern in your host application, include the holder project as a dependency.

  5. Run the Source-based SDK Sample

    master

    Use this sample if you want to modify the Shadow SDK source code directly and see changes immediately. This version uses source-level dependencies instead of Maven artifacts.

    Setup Instructions:

    1. Clone the repository.
    2. Open the root directory of the cloned repository in Android Studio.
    3. Run the sample-host module.

    Module Breakdown:

    • sample-host: The host application.
    • sample-manager: Dynamic implementation of the Plugin Manager.
    • sample-plugin/sample-loader: Dynamic implementation of the loader (defines component pairings).
    • sample-plugin/sample-runtime: Dynamic implementation of the runtime (defines actual proxy classes).
    • sample-plugin/sample-base: An APK shell used to compile sample-base-lib or as a plugin.
    • sample-plugin/sample-app: Business code that depends on sample-base-lib and sample-base (configured via dependsOn = ['sample-base'] in build.gradle).
  6. Run the Maven-based SDK Sample

    master

    Use this sample for production-like integration where components (Host, Manager, Plugin) reside in different code repositories and depend on Shadow via Maven artifacts.

    Setup Instructions:

    1. Open the following three directories separately in Android Studio:
      • projects/sample/maven/host-project
      • projects/sample/maven/manager-project
      • projects/sample/maven/plugin-project
    2. Note that each project configures its own shadow_version independently.

    Manual Deployment (Required): Since this sample does not implement a download server, you must manually push files to the device using adb.

    1. Compile and push the Plugin: In plugin-project:

      ./gradlew packageDebugPlugin
      adb push build/plugin-debug.zip /data/local/tmp
    2. Compile and push the Plugin Manager: In manager-project:

      ./gradlew assembleDebug
      adb push sample-manager/build/outputs/apk/debug/sample-manager-debug.apk /data/local/tmp
    3. Run the Host: Open host-project in Android Studio and run the sample-host module.

    # In plugin-project
    ./gradlew packageDebugPlugin
    adb push build/plugin-debug.zip /data/local/tmp
    
    # In manager-project
    ./gradlew assembleDebug
    adb push sample-manager/build/outputs/apk/debug/sample-manager-debug.apk /data/local/tmp
  7. Set up the Shadow development environment

    master

    To develop with or contribute to Shadow, follow these environment requirements:

    Requirements:

    • Android Studio: It is recommended to use the latest stable version. The project is currently adapted for Android Studio Arctic Fox | 2020.3.1. Older versions may fail to open due to high Gradle version requirements.

    Project Structure:

    • projects/sdk: Contains all SDK source code.
    • projects/test: Contains automated test code for the SDK.
    • projects/sample: Contains demonstration code. This is the recommended environment for experiencing Shadow.

    Running Samples: In your IDE, you can run the sample-app or sample-host modules directly to compare the behavior of the same code when installed normally versus when running as a plugin.

  8. Publish Shadow SDK to a Maven Repository

    master

    Shadow provides Maven publishing scripts located in buildScripts/gradle/maven.gradle. To publish to your own repository, follow these steps:

    1. Configure Group IDs: In buildScripts/gradle/maven.gradle, update coreGroupId and dynamicGroupId.
    2. Configure SCM: Update the URLs in the setScm method to point to your version control system.
    3. Set Target Repository: Change mavenLocal() in your configuration to your target Maven repository URL.
    4. Execute Publish: Run the following command:
      ./gradlew publish
    5. Verify Version: Check the generated .pom files in the build/pom directory to find the exact version number produced.
    6. Update Dependencies: In your projects, update the shadow_version in build.gradle to match the newly published version.
  9. Troubleshoot ShadowActivity Method Not Found errors

    master

    Because Shadow is designed to be fully dynamic, the plugin package contains both the plugin code and the plugin framework code. If your business logic requires specific Activity methods that are not currently implemented in ShadowActivity, you may encounter a Method Not Found error.

    Solution: Implement the missing method in ShadowActivity. Most implementations only require a simple delegation (forwarding the call) to work correctly. If you encounter a feature that is difficult to implement, please open an issue on GitHub and provide your test code.