我想确保在我的 Android 应用程序(Java 和 Kotlin 代码中)中不会调用特定类的特定方法。假设,我有一个名为Bar
有两种方法:allowed()
and disallowed()
。这是代码:
package com;
public class Bar {
public void disallowed() {
}
public void allowed() {
}
}
假设客户端代码可以调用allowed()
并且不应该打电话disallowed()
。我找到了Google的内置源代码添加Javascript接口检测器 https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/AddJavascriptInterfaceDetector.kt这与我的情况类似。
这是我的 lint 规则的代码:
样本代码检测器
package com.sample.mobile.lint
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.JavaContext
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.SourceCodeScanner
import com.intellij.psi.PsiMethod
import org.jetbrains.uast.UCallExpression
class SampleCodeDetector : Detector(), SourceCodeScanner {
companion object {
@JvmField
val ISSUE = Issue.create(
// ID: used in @SuppressLint warnings etc
"Usage of Bar#disallowed()",
// Title -- shown in the IDE's preference dialog, as category headers in the
// Analysis results window, etc
"Usage of Bar#disallowed() - Summary",
// Full explanation of the issue; you can use some markdown markup such as
// `monospace`, *italic*, and **bold**.
"This check highlights the usage of Bar#disallowed()",
Category.CORRECTNESS,
8,
Severity.ERROR,
Implementation(
SampleCodeDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
const val FULLY_QUALIFIED_CLASS_NAME = "com.Bar"
const val METHOD_NAME = "disallowed"
}
override fun getApplicableMethodNames() = listOf(METHOD_NAME)
override fun visitMethod(context: JavaContext, node: UCallExpression, method: PsiMethod) {
val evaluator = context.evaluator
if (!evaluator.methodMatches(method, FULLY_QUALIFIED_CLASS_NAME, true)) {
return
}
val message = "`Bar.disallowed()` should not be called"
context.report(ISSUE, node, context.getNameLocation(node), message)
}
}
样本问题注册表
package com.sample.mobile.lint
import com.android.tools.lint.client.api.IssueRegistry
import com.android.tools.lint.detector.api.Issue
class SampleIssueRegistry : IssueRegistry() {
override val issues: List<Issue> get() = listOf(SampleCodeDetector.ISSUE)
}
构建.gradle
apply plugin: 'java-library'
dependencies {
String lintVersion = "26.1.1"
compileOnly "com.android.tools.lint:lint-api:$lintVersion"
compileOnly "com.android.tools.lint:lint-checks:$lintVersion"
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.60"
testImplementation "com.android.tools.lint:lint:$lintVersion"
testImplementation "com.android.tools.lint:lint-tests:$lintVersion"
}
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
jar {
manifest {
// Only use the "-v2" key here if your checks have been updated to the
// new 3.0 APIs (including UAST)
attributes("Lint-Registry-v2": "com.sample.mobile.lint.SampleIssueRegistry")
}
}
样本代码检测器测试
package com.sample.mobile.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
class SampleCodeDetectorTest : LintDetectorTest() {
private val javaFile = "package com.sample.mobile.app;\n" +
"\n" +
"import android.util.Log;\n" +
"\n" +
"import com.Bar;\n" +
"\n" +
"public class Foo {\n" +
"\n" +
" public void calLLog() {\n" +
" int a = 2;\n" +
" int b = 8;\n" +
" Log.d(\"Tag\", \"a+b=\" + (a + b));\n" +
" \n" +
" Bar bar = new Bar();\n" +
" bar.allowed();\n" +
" bar.disallowed();\n" +
" }\n" +
"}\n"
fun testJava() {
lint().files(LintDetectorTest.java(javaFile))
.run()
.expect("")
}
override fun getDetector(): Detector? {
return SampleCodeDetector()
}
override fun getIssues() = listOf(SampleCodeDetector.ISSUE)
}
不幸的是,测试失败了:
org.junit.ComparisonFailure:
Expected :
Actual :No warnings.
当然,预期的结果不是空字符串,但无论如何,“没有警告”。是不正确的,因为有一个调用Bar#disallowed()
in class Foo