Análisis del código fuente de la sombra
Si todavía estás esperando, creo que después de leer este artículo, tendrás más confianza en esta biblioteca de complementos. Por supuesto, si va a los mercados extranjeros o de Google, es posible que deba pensarlo dos veces antes de usar Shadow. Después de todo, para Google el comportamiento de las actualizaciones dinámicas no es el que quiere.
Los amigos que no estén familiarizados con los principios de los complementos pueden leer mis artículos anteriores sobre complementos Horizontal Analysis Small y RePlugin, dos marcos de complementos, que explicaron en profundidad los principios de los complementos hace 3 años.
Si tiene alguna pregunta, consulte este artículo /p/e1738998abd1 para analizarla.
Shadow tiene varios conceptos más especiales que otras bibliotecas de complementos. Mucha gente simplemente tiene una idea de cómo usarla, pero de hecho es difícil usar esta biblioteca sin una comprensión preliminar de Shadow en su conjunto.
Para Shadow, otras bibliotecas de complementos se pueden dividir en partes de host y complementos. Desde una perspectiva de diseño, está más cerca de RePlugin, que requiere operaciones tanto de host como de complemento y depende de la biblioteca de host y la biblioteca de complementos, respectivamente.
De hecho, para Shadow, el paquete de complementos generado por el negocio de complementos no es solo una aplicación comercial de complementos. A menudo se compone de las siguientes 4 partes:
Antes de hablar sobre el uso y la implementación de Shadow, revisemos brevemente el marco RePlugin con la menor cantidad de puntos de enlace.
¿Se te ocurre alguna manera de lograr la función del complemento de administración de host sin conectar ninguna ubicación? Por supuesto, todavía no lo he descubierto, pero mucha gente lo ha descubierto y lo ha implementado.
La idea de RePlugin En resumen, RePlugin divide el marco del complemento en dos partes:
¿Por qué se necesita Hook Context? Para permitir que el complemento y el host se comuniquen entre sí. RePlugin generará un PluginClassLoader para que el host y el complemento encuentren las clases de cada uno. El cargador de clases del apk se almacena primero en el contexto, por lo que debe conectarse al contexto.
Ahora que sabes por qué necesitas enganchar el Contexto, ¿puedes pensar en una forma de evitarlo? ¿Podemos descubrir cómo manejar esto y evitar el uso de Hook Context?
Tomemos la actividad Pit como ejemplo. PluginActivity convertido por la biblioteca de complementos de Gradle requiere Hook Context para funcionar correctamente, entonces, ¿por qué no hacemos lo siguiente y simplemente le damos el contexto a nuestro proxy? No hereda ninguna clase. La Actividad implementará todas las interfaces externas de la Actividad y todo su comportamiento vendrá directamente de la Actividad Pit del host.
Pensando en lo que dije hace cuatro años, hay tres problemas principales que deben superarse en la plug-inización.
Pensándolo de esta manera, parece posible lograr la plug-inización a través del patrón de diseño de proxy y 0 ganchos. Eso es lo que piensa Sombra. Veamos cómo lo usa y cómo desacopla la biblioteca de complementos de la biblioteca principal.
Para evitar que la biblioteca de complementos afecte la lógica empresarial original, generalmente existe un módulo de shell. Este módulo se utiliza como módulo principal y depende de él para los proyectos comerciales.
Agregue un nuevo build.gradle en el directorio raíz del proyecto
Tenga en cuenta que el complemento classpath com.tencent.shadow.core:gradle-plugin reemplazará los cuatro componentes principales. y agregue la clase de proxy correspondiente para Shadow. Estas clases de proxy entregarán el trabajo a la implementación real del componente de actividad en tiempo de ejecución
Usando esta implementación de tarea paralela, puede generar directamente el apk en tiempo de ejecución, cargar el complemento apk, business apk zip usando el comando ./gradlew packageDebugPlugin.
Por último, recuerde depender del módulo empresarial
El host inicia el complemento
creando un proyecto a nivel de aplicación que depende de
Actividad:
A continuación, genere un loader-apk.
Estas actividades se pueden registrar sin el AndroidManifest de la apk actual. Deben registrarse en el AndroidManifest de la apk host. Para Shadow, es solo cuestión de poder encontrar la clase en la apk.
Registre la actividad declarada anteriormente en el AndroidManifest del host.
Host:
Tenga en cuenta que también debe declarar android:process=":plugin", y el negocio del complemento MainPluginProcessService debe alojarse en el mismo proceso para que estas clases se puedan encontrar desde ClassLoader en el proceso del complemento.
Cree un proyecto a nivel de aplicación que dependa de
CoreLoaderFactoryImpl:
Tenga en cuenta que el nombre de clase CoreLoaderFactoryImpl debe corregirse, este es el punto de enlace del propio Shadow. El anfitrión lo buscará a través del administrador.
Core está construyendo el ComponentManager. En esta clase, el cargador implementará una asignación uno a uno entre la actividad del proxy escrita en tiempo de ejecución y la actividad del negocio del complemento.
Aquí hay un ejemplo:
En tiempo de ejecución, todo el comportamiento de GameActivity dependerá de la implementación de PluginNativeProxyActivity.
Las otras actividades se asignarán al PluginDefaultProxyActivity normal.
Es necesario crear un proyecto de Android específicamente para esto, que se puede encontrar en los ejemplos de github.
Agregar configuración:
Agregar dependencias:
Heredar FastPluginManager
Comencemos con los principios del host. Si el host desea iniciar una actividad en el complemento, debe seguir los siguientes pasos:
En este método, en realidad verifica si el md5 de manager.apk es el mismo que el anterior. uno. Si no es el mismo, entonces es necesario actualizarlo.
Cuando se encuentra una actualización, se realizan los siguientes pasos:
ManagerImplLoader realmente obtiene el archivo manager.apk,
y genera dos objetos basados en Archivo manager.apk:
Finalmente, el apk se encuentra a través de ApkClassLoader.
El siguiente paso lógico es entrar en Manager.apk, que es un poco como Replugin.
Entonces, en el proyecto Manager, debes escribir una clase llamada ManagerFactoryImpl como punto de entrada para la lógica en Manager.apk. Entonces, el PluginManagerImpl devuelto por el host es en realidad la clase SamplePluginManager devuelta por su propio proyecto de administrador.
En este caso, SamplePluginManager hereda de PluginManagerThatUseDynamicLoader. Luego llame a onCreate y onDestroy de SamplePluginManager.
Ingrese a la demostración
Generalmente, en SampleManager, el comportamiento de ejecución actual se determinará en función del tipo de negocio de fromId. Tomemos FROM_ID_START_ACTIVITY como ejemplo. Aquí estamos intentando iniciar el complemento desde el paquete plugin-debug.zip.
Este paquete de complementos contiene tres apk, a saber, loader.apk, runtime.apk y $plugin-business.apk. Por lo tanto, se puede decir que manager.apk es responsable de gestionar la lógica de carga del complemento actual.
Para no bloquear el proceso, generalmente se abre un hilo para cargar los datos apk del paquete del complemento.
Puedes ver la relación entre estos tres métodos:
Recuerda el método getPluginProcessServiceName que está sobrecargado en SampleManager, que escribe el nombre de clase del servicio hasta la muerte:
En realidad, es el nombre de clase del servicio sobrecargado por el método bindPluginProcessServiceName:
En realidad, es el nombre de clase del servicio sobrecargado en SampleManager. En realidad, el servicio se inicia a través del método bindPluginProcessService:
Puede ver que el proceso de inicio es muy simple. En realidad, inicia un servicio con un nombre de clase fijo utilizando el método bindService del contexto del host y escucha<. /p> p>
onPluginServiceConnected tiene dos implementaciones. BaseDynamicPluginManager tiene dos subclases:
A continuación se explica cómo elegir utilizar el PluginManagerThatUseDynamicLoader del cargador dinámico para la resolución.
Puede ver el proceso de encapsulación de objetos Binder para otras devoluciones de llamada del lado del servidor en objetos PpsController.
Luego llame a setUuidManager del objeto PpsController para configurar el uuid del proceso de servicio remoto. Luego obtenga el objeto Binder del servicio remoto a través de getPluginLoader y encapsúlelo en BinderPluginLoader para la comunicación.
Después de eso, todos los datos se transferirán a PpsController y PluginLoader, lo que equivale a dejar que el proceso donde se encuentra el servicio remoto maneje todas las acciones.
Dado que el host pasa el contexto, el nombre de la clase de servicio correspondiente a getPluginProcessServiceName debe registrarse en el host y declarar la clase en el host.
Comprende rápidamente el funcionamiento del host.
Ahora necesitas declarar en el host:
Luego MainPluginProcessService hereda de PluginProcessService.
Todas las transacciones se entregarán al PluginProcessService. Como puede ver aquí, generalmente hay un proceso completamente diferente, etiquetado con android:proceso. Todos los componentes también se ejecutarán en este proceso, por lo que al declarar el pozo debe marcarlo como el mismo proceso que MainPluginProcessService.