解析自定义lint规则中的资源值

Mik*_*ren 11 android lint android-lint

我有一个很大的Android代码库,我正在编写一个自定义lint规则,用于检查某些属性的值是否在给定范围内.

例如,我有这个组件:

<MyCustomComponent
    my:animation_factor="0.7"
    ...>
</MyCustomComponent>
Run Code Online (Sandbox Code Playgroud)

我想编写一个lint规则,提醒开发人员my:animation_factor应谨慎使用> = 1的值.

我按照http://tools.android.com/tips/lint-custom-rules上的说明操作,并设法检索my:animation_factor使用此代码的值:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

my:animation_factor具有文字值(例如0.7)的属性时,此代码可以正常工作.

但是,当属性值是资源(例如@dimen/standard_anim_factor)时,则element.getAttribute(...)返回属性的字符串值而不是实际解析的值.

例如,当我有一个MyCustomComponent看起来像这样:

<MyCustomComponent
    my:animation_factor="@dimen/standard_anim_factory"
    ...>
</MyCustomComponent>
Run Code Online (Sandbox Code Playgroud)

@dimen/standard_anim_factor在别处定义:

<dimen name="standard_anim_factor">1.85</dimen>
Run Code Online (Sandbox Code Playgroud)

然后字符串factor变为"@ dimen/standard_anim_factor"而不是"1.85".

有没有办法在处理MyCustomComponent元素时将"@ dimen/standard_anim_factor"解析为资源的实际值(即"1.85")?

And*_*ann 2

值解析的一般问题是,它们取决于您所在的 Android 运行时上下文。values您的 key 可能有多个文件夹具有不同的具体值@dimen/standard_anim_factory,因此您需要注意。

尽管如此,据我所知,存在两种选择:

  • 执行两相检测:

    • 第一阶段:扫描您的资源
    • 扫描您的属性并将其放入列表中(而不是立即评估它)
    • 扫描您的尺寸值并将它们也放入列表中
    • 阶段2:
    • Detector.afterProjectCheck通过迭代第 1 阶段填充的两个列表来覆盖并解析您的属性
  • 通常LintUtils类 [1] 是这些东西的完美位置,但不幸的是没有方法可以解析维度值。但是,有一个称为的方法getStyleAttributes演示了如何解析资源值。因此,您可以编写自己的便捷方法来解析维度值:


    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());
    }
Run Code Online (Sandbox Code Playgroud)

注意:我还没有测试上面的代码。所以请将其视为理论建议:-)

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

对于您的自定义 Lint 规则代码,还有一点建议,因为您只对属性感兴趣:

而不是在中做这样的事情visitElement

String factor = element.getAttribute("my:animation_factor");
Run Code Online (Sandbox Code Playgroud)

...你可能想做这样的事情:

@Override
public Collection<String> getApplicableAttributes() {
    return ImmutableList.of("my:animation_factor");
}

@Override    
void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute){
    ...
}
Run Code Online (Sandbox Code Playgroud)

但这只是一个偏好问题:-)