Resolución de valores de recursos en reglas personalizadas de pelusa

Tengo una base de código Android grande y estoy escribiendo una regla de pelusa personalizada que comprueba si los valores de ciertos atributos se encuentran dentro de un rango determinado.

Por ejemplo, tengo este componente:

<MyCustomComponent my:animation_factor="0.7" ...> </MyCustomComponent> 

Y quiero escribir una regla de pelusa que avisa a los desarrolladores que los valores de my:animation_factor > = 1 deben utilizarse con precaución.

Seguí las instrucciones en http://tools.android.com/tips/lint-custom-rules y logré recuperar el valor de my:animation_factor usando este código:

 import com.android.tools.lint.detector.api.*; public class XmlInterpolatorFactorTooHighDetector { .... @Override public Collection<String> getApplicableElements() { return ImmutableList.of("MyCustomComponent"); } @Override public void visitElement(XmlContext context, Element element) { String factor = element.getAttribute("my:animation_factor"); ... if (value.startsWith("@dimen/")) { // How do I resolve @dimen/xyz to 1.85? } else { String value = Float.parseFloat(factor); } } } 

Este código funciona bien cuando atributos como my:animation_factor tienen valores literales (por ejemplo, 0.7 ).

Sin embargo, cuando el valor del atributo es un recurso (por ejemplo, @dimen/standard_anim_factor ) entonces element.getAttribute(...) devuelve el valor de cadena del atributo en lugar del valor resuelto real.

Por ejemplo, cuando tengo un MyCustomComponent que se parece a esto:

 <MyCustomComponent my:animation_factor="@dimen/standard_anim_factory" ...> </MyCustomComponent> 

Y @dimen/standard_anim_factor se define en otra parte:

 <dimen name="standard_anim_factor">1.85</dimen> 

Entonces el factor cadena se convierte en "@ dimen / standard_anim_factor" en lugar de "1.85".

¿Hay una manera de resolver "@ dimen / standard_anim_factor" al valor real del recurso (es decir, "1.85") mientras se procesa el elemento MyCustomComponent ?

El problema general con la resolución de valores es que dependen del contexto de ejecución de Android en el que se encuentre. Puede haber varias carpetas de values con diferentes valores concretos para su clave @dimen/standard_anim_factory , de modo que usted sepa.

Sin embargo, AFAIK existen dos opciones:

  • Realice una detección de dos fases:

    • Fase 1: Escanee sus recursos
    • Busca tu atributo y ponlo en una lista (en lugar de evaluarlo inmediatamente)
    • Analiza tus valores de dimensión y ponlos en una lista también
    • Fase 2:
    • Anule Detector.afterProjectCheck y resuelva sus atributos iterando sobre las dos listas llenadas dentro de la fase 1
  • Por lo general la clase LintUtils [1] es un lugar perfecto para ese material, pero por desgracia no hay ningún método que resuelve los valores de las dimensiones. Sin embargo, hay un método llamado getStyleAttributes que demuestra cómo resolver valores de recursos. Así que usted podría escribir su propio método conveniente para resolver valores de dimensión:

 private int resolveDimensionValue(String name, Context context){ LintClient client = context.getDriver().getClient(); LintProject project = context.getDriver().getProject(); AbstractResourceRepository resources = client.getProjectResources(project, true); return Integer.valueOf(resources.getResourceItem(ResourceType.DIMEN, name).get(0).getResourceValue(false).getValue()); } 

Nota: No he probado el código anterior todavía. Así que por favor verlo como un consejo teórico 🙂

  1. https://android.googlesource.com/platform/tools/base/+/master/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/LintUtils.java

Sólo un consejo más leve para su código de regla Lint personalizado, ya que sólo están interesados ​​en el atributo:

En lugar de hacer algo como esto en visitElement :

 String factor = element.getAttribute("my:animation_factor"); 

… puede que desee hacer algo como esto:

 @Override public Collection<String> getApplicableAttributes() { return ImmutableList.of("my:animation_factor"); } @Override void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute){ ... } 

Pero es sólo una cuestión de preferencia 🙂

Creo que estás buscando buscar getResources().getDimension() .

Fuente: http://developer.android.com/reference/android/content/res/Resources.html#getDimension%28int%29

Asumiendo que el nodo xml después de analizar sus datos, intente lo siguiente

 Element element = null; //It is your root node. NamedNodeMap attrib = (NamedNodeMap) element; int numAttrs = attrib.getLength (); for (int i = 0; i < numAttrs; i++) { Attr attr = (Attr) attrib.item (i); String attrName = attr.getNodeName (); String attrValue = attr.getNodeValue (); System.out.println ("Found attribute: " + attrName + " with value: " + attrValue); } 
  • ¿Cómo habilitar la verificación de pelusa de Android para la anotación @Nullable?
  • Lint encuentra advertencias en log4j utilizadas en el proyecto de Android
  • Limpieza de los permisos de Android no utilizados
  • Analizar código con Lint para llamadas que requieren permisos
  • Android: Buscar llamadas de la API que requieren permisos
  • La regla de la lechada personalizada no aparece en el estudio de eclipse / android
  • Error: El recurso esperado de tipo styleable error
  • Sonar Android Lint sin problemas encontrados
  • Cómo suprimir Android Lint advertencia en Gradle script
  • Doctype Android lint.xml con declaración dtd
  • Lint falla en la compilación con el error de seguridad "WrongConstant: Incorrect constant". Anotación de IntDef
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.