prefacio
Recientemente, ayudé a un colega a resolver un problema difícil y el proceso de excavación fue bastante interesante. Documéntalo aquí. (PD: la razón principal es que el proyecto es relativamente grande y solo tenemos Android
la autoridad de desarrollo para una parte del código comercial de todo el proyecto. Por lo tanto, no se pueden usar algunos medios convencionales para resolver problemas).
pregunta
Requisitos: Web
página H5
e native
interacción, guardar base64图片
.
Problema: Usando el Hybrid
protocolo encapsulado existente, se encontró en la prueba de integración final que algunos teléfonos móviles no se pudieron guardar con éxito.
- Durante la depuración, se descubrió
H5
que el formato del protocolo original se usaba para llamar al nuevo protocolo y quenative
los registros y los puntos de interrupción del nuevo protocolo registrado en el lado comercial no se podían activar.
- Sospecha del problema del formato del protocolo original, cuando H5 usa el formato del protocolo original para llamar al nuevo protocolo que ya existe en la línea, se encuentra que la
native
llamada puede ser exitosa y este problema se descarta; - Al sospechar el problema del parámetro en el nuevo protocolo, H5 elimina el parámetro en el nuevo protocolo y descubre que se puede llamar a la
native
implementación del nuevo protocolo. Se supone que el problema puede deberse a los parámetros del protocolo;- Encuentre el lugar donde se dispara la llamada de protocolo a través del punto de interrupción, es decir,
H5
elnative
lugar donde se comunican los datos. Se encuentra que elHybrid
protocolo actual utiliza el métodonative
de replicación de extremo a extremoonJsPrompt
y elJavaScript
método de interceptaciónprompt()
. - Vuelva a cambiar los parámetros del nuevo protocolo y vuelva a llamar. El punto de interrupción encontró que los datos transmitidos se truncaron en el método
native
de replicación de un extremo a otro , y el análisis de datos falló y no se pudo reenviar a la siguiente prueba de servicio.onJsPrompt
- Encuentre el lugar donde se dispara la llamada de protocolo a través del punto de interrupción, es decir,
Problemas
El puente de comunicación original Hybrid协议
utilizado en el proyecto ahora enfrenta **una gran inundación (datos más grandes)** y hay un problema de obstáculos.复写prompt方法
selección de solución
-
Cambie la imagen en el formato a
H5
la imagen en el formato;base64
http
La imagen está
H5
dibujada originalmente y la experiencia interactiva de la descarga del cliente después de la carga es demasiado pobre; -
Nuestro lado comercial implementa nuestro propio conjunto de
Hybrid
protocolos; -
Que el departamento de infraestructura del proyecto modifique el
Hybrid
acuerdo existente;El error descubierto por la noche requerirá pruebas cerradas mañana. Es difícil completar el cambio de infraestructura interdepartamental en 24 horas.
Al final, elegimos la segunda opción, implementando Hybrid
nosotros mismos un conjunto de protocolos.
realización de la solución
- Get
WebView
llamaaddJavascriptInterface
al método paraH5
agregarJS
objetos al entorno. - La
JS
herramienta de desarrollo le permite llamar al nuevoJS
método de comunicación de acuerdo con el formato del protocolo anterior. - Analice los datos obtenidos y tírelos al
onJsPrompt
objeto de la clase contenedora que originalmente procesó los datos en el método.
Si podemos cambiar todo el código del proyecto, entonces no hay dificultad en esta solución. La dificultad es que solo tenemos H5
el caparazón más externo de esta página Activity
, y la encapsulación WebView
no expone el método que queremos al mundo exterior. Entonces, la implementación del tercer paso del programa tiene problemas.
Tenemos dos soluciones a este problema:
- Esta vez, se hacen dos juegos de lógica inyectando el protocolo de comunicación
JS
del objetoHybrid
y elHybrid
protocolo original del proyecto; - Métodos de llamada
hook
en otras clases originales a través de tecnología negra múltiple ;dispatch
Si ese fuera el caso, no habría artículo para este artículo.
Bueno, después de tanto divagar, finalmente comencé a llegar al punto. No sé cuántos estudiantes planean seguir leyendo.
Podemos tomar todos AAR
los archivos del proyecto, pensar si podemos modificar el código fuente para proporcionar lo que queremos API
y luego resolver el problema actualizando AAR
la versión . Bueno, el enfoque de este artículo ha salido a modificar el archivo de clase en AAR .
Modificar el archivo de clase en AAR
opcion uno
Primero elimine
AAR
los que desea modificarclass
y vuelva a empaquetarlos como nuevosAAR
. El proyecto depende de la nueva versiónAAR
y luego crea una clase idéntica en el paquete correspondiente del proyecto.
- Descompile el contenido del archivo original
class
y cópielo en la clase recién creada y ejecútelo directamente.- Descompile el contenido del archivo original
class
y cópielo en la clase recién creada. Finalmente, vuelva a compilar el generadoclass
y agrégueloAAR
a repackage para generar uno nuevoAAR
.
Si la clase está ofuscada, entonces esta solución básicamente se elimina. Debido a que hay una gran cantidad de paquetes con el mismo nombre de clase en el class
contenido descompilado, es imposible confirmar que la clase utilizada en esta llamada siga siendo un paquete durante esta recompilación.
Como ejemplo, la siguiente estructura se ve a menudo después de la ofuscación.
com.xx.a
com.xx.a.a
Al escribir el siguiente código, le indicará que a
no hay ninguna clase debajo de la clase a
, en lugar de a
buscar la clase debajo del paquete a
.
a ma = new com.xx.a.a();
Opción II
De acuerdo con la figura anterior, se puede ver que este esquema es para la programación de aspectos. Solo necesitamos agregar uno o dos métodos a una clase para resolver el problema del acceso limitado. Teniendo en cuenta la dificultad del problema actual que elegimos Javassist
. Debido a que la manipulación del código de bytes real en Javassist
el nivel del código fuente API
es más fácil de usar, se puede usar sin un conocimiento profundo de la especificación.ASM
JVM
Javassist
documento oficial
jar
Dirección de descarga del paquete Github:javassist
//需要添加的方法
//public void executeJSCmd(String var1) {
// if (this.mActionDispatcher != null) {
// Message var2 = this.mActionHandler.obtainMessage(0);
// var2.obj = var1;
// this.mActionHandler.sendMessage(var2);
// }
//}
//需要操作的class的类名:com.xxx.android.web.webview.BaseWebChromeClient
public class Test {
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
ClassPool classPool = ClassPool.getDefault();
// 必须将class文件放在这个工程编译后的class文件中,路径也对应起来
CtClass ctClass = classPool.get("com.xxx.android.web.webview.BaseWebChromeClient");
CtMethod newmethod = CtNewMethod.make("public void executeJSCmd(String message) { if (this.mActionDispatcher != null) { android.os.Message msg = this.mActionHandler.obtainMessage(0); msg.obj = message; this.mActionHandler.sendMessage(msg); } }",ctClass);
ctClass.addMethod(newmethod);
ctClass.writeFile();
}
}
Cabe señalar que, por ejemplo, el método que agregamos involucra otras clases que necesitan escribir la ruta completa android.os.Message
, y el paquete relacionado con esta clase jar
también debe agregarse al entorno en ejecución (también puede colocar el archivo de clase de esta clase en el directorio de archivos de clases del proyecto compilado); de lo contrario, se informará un error durante la ejecución.
Exception in thread "main" javassist.CannotCompileException: [source error] no such class: android.os.Message
at javassist.CtNewMethod.make(CtNewMethod.java:78)
at javassist.CtNewMethod.make(CtNewMethod.java:44)
at com.test.pattern.Test.main(Test.java:13)
punto importante
Al reemplazar o eliminar, jar
es class
mejor no descomprimir y luego usar el paquete nombrado.Cuando use el Max
comando jar
para empaquetar habrá un .DS_Store
archivo. BetterZip
La herramienta de compresión y descompresión que uso es muy conveniente para agregar y eliminar en jar
el paquete sin descomprimir .class
El artículo está completo aquí, si tiene otras necesidades para comunicarse, ¡puede dejar un mensaje ! !
Si quieres leer más artículos del autor, puedes consultar mi blog personal y cuenta pública: