일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 커스텀린트
- 면접
- 북한살둘레길
- 소프시스
- 어떻게 나답게 살 것인가
- 슬기로운 온라인 게임
- 베드트레이
- 한달어스
- 안드로이드
- 캐치마인드
- 한달브런치북만들기
- 끝말잇기
- 함수형 프로그래밍
- 테트리스
- 1일1커밋
- 브런치작가되기
- 리얼하다
- 재택근무
- 지지않는다는말
- 아비투스
- 한달독서
- 목적중심리더십
- T자형인재
- 좌식테이블
- 소프시스 밤부 좌식 엑슬 테이블
- 한단어의힘
- 프래그먼트
- 목적 중심 리더십
- 자취필수템
- 베드테이블
- Today
- Total
정상에서 IT를 외치다
[Android, Custom Lint] 커스텀 린트 적용기 (구글 예제) 본문
안녕하세요. 블랙진입니다.
정적 분석 도구인 린트에 대해서 알아보고 커스텀 린트 관련 구글 예제를 같이 살펴보고자 합니다.
린트란?
린트는 정적 분석 도구 (static analysis tool) 라고 부릅니다. 정확성, 퍼포먼스, 안정성, 국제 규격, 사용성 등등의 오류나 버그를 컴파일 타임에서 알 수 있게 해 줍니다. 이러한 린트를 통해 컨벤션에 맞는 코드를 작성할 수 있게 도와주고 버그 또한 사전에 발견하여 프로그래머가 좀 더 코딩에 집중할 수 있게 도와줍니다. 이를 통해 코딩 중에 자주 하는 실수를 피함으로써 안전하고 더욱 멋진 코드를 만드는데 없어서는 안 될 존재가 바로 린트입니다.
커스텀 린트 적용하기
구글 예제를 통해 커스텀 린트를 적용해 보도록 해보겠습니다. 커스텀 린트를 구현하기 위해서는 2개의 모듈을 추가해 주어야 합니다.
1. 코틀린 라이브러리 모듈 추가 ( : checks )
checks는 순수 코틀린 또는 자바 모듈입니다. 실제 린트와 관련된 코드는 여기에 작성합니다.
환경 설정을 위해 아래와 같이 build.gradle 작성해 줍니다.
- com.android.lint 플러그인 추가
plugins {
id 'java-library'
id 'kotlin'
id 'com.android.lint'
}
- lint 의존성 추가
린트 버전은 Android Gradle Plugin (AGP) Version에 +23 을 해줍니다. AGP Version을 따로 설정해 주지 않으신 분은 아래와 같이 Project Structure에서 확인할 수 있습니다. 만약 AGP 버전이 7.2.2이라면 린트 버전은 30.2.2 가 됩니다
이때 컴파일에서만 동작될 수 있게 compileOnly를 사용하여 추가해주어야 합니다.
dependencies {
def lintVersion = '30.2.2'
compileOnly "com.android.tools.lint:lint-api:$lintVersion"
compileOnly "com.android.tools.lint:lint-checks:$lintVersion"
def kotlinVersion = '1.7.10'
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
}
- 자바 버전 설정을 위해 아래 값을 추가
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
이렇게 설정해 주시면 checks 모듈 설정은 완료됩니다. 아래는 checks 모듈의 전체 코드입니다.
plugins {
id 'java-library'
id 'kotlin'
id 'com.android.lint'
}
dependencies {
def lintVersion = '30.2.2'
compileOnly "com.android.tools.lint:lint-api:$lintVersion"
compileOnly "com.android.tools.lint:lint-checks:$lintVersion"
def kotlinVersion = '1.7.10'
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
}
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
2. 안드로이드 라이브러리 모듈을 추가 ( : library )
library는 안드로이드 모듈입니다. 여기에는 아무런 코드도 없습니다. 단지 build.gradle 설정만 아래와 같이 추가해줍니다.
- checks 의존성 추가
새로 생성해준 안드로이드 모듈에 위에서 생성한 checks 코틀린 모듈의 의존성을 lintPublish를 사용해 추가해 줍니다.
dependencies {
implementation project(':checks')
lintPublish project(':checks')
}
Gradle plugin은 lintPublish 요소를 제공하며 이는 checks 모듈의 결과를 가져와 "lint.jar" 파일을 AAR 파일안에 넣습니다. 이것이 완료되면 다른 프로젝트에서는 lintlibrary를 의존함으로써 자동으로 checks에 구현되어 있는 린트를 적용할 수 있습니다.
3. App 모듈에 library Dependency 추가
마지막으로 app 모듈에 위에서 생성했던 library 모듈을 추가해 줍니다. 라이브러리 추가 시 compileOnly와 implemnt 둘 다 동작됩니다.
dependencies {
implementation project(':library')
}
4. 커스텀 린트 등록
이제 커스텀 린트를 등록할 준비는 모두 마쳤습니다. 구글 예제에서는 lint라는 문구가 있는 경우 오류 메시지를 보여줍니다. 이를 위한 IssueRegistry 와 Dector 두 개의 클래스를 생성해 주어야 합니다. 실재 린트 검사를 위해 필요한 코드는 checks 모듈에서 생성해 줍니다.
- IssueRegistry 생성
IssueRegistry에 대한 자세한 설명은 링크를 참고해주세요.
구글 예제 SampleIssueRegistry 링크
/*
* The list of issues that will be checked when running <code>lint</code>.
*/
@Suppress("UnstableApiUsage")
class SampleIssueRegistry : IssueRegistry() {
override val issues = listOf(SampleCodeDetector.ISSUE)
override val api: Int
get() = CURRENT_API
override val minApi: Int
get() = 8 // works with Studio 4.1 or later; see com.android.tools.lint.detector.api.Api / ApiKt
// Requires lint API 30.0+; if you're still building for something
// older, just remove this property.
override val vendor: Vendor = Vendor(
vendorName = "Android Open Source Project",
feedbackUrl = "https://github.com/googlesamples/android-custom-lint-rules/issues",
contact = "https://github.com/googlesamples/android-custom-lint-rules"
)
}
- Detector 생성
Detector에 대한 자세한 설명은 링크를 참고해주세요.
구글 예제 SampleCodeDector 링크
/**
* Sample detector showing how to analyze Kotlin/Java code. This example
* flags all string literals in the code that contain the word "lint".
*/
@Suppress("UnstableApiUsage")
class SampleCodeDetector : Detector(), UastScanner {
override fun getApplicableUastTypes(): List<Class<out UElement?>> {
return listOf(ULiteralExpression::class.java)
}
override fun createUastHandler(context: JavaContext): UElementHandler {
return object : UElementHandler() {
override fun visitLiteralExpression(node: ULiteralExpression) {
val string = node.evaluateString() ?: return
if (string.contains("lint") && string.matches(Regex(".*\\blint\\b.*"))) {
context.report(
ISSUE, node, context.getLocation(node),
"This code mentions `lint`: **Congratulations**"
)
}
}
}
}
companion object {
/**
* Issue describing the problem and pointing to the detector
* implementation.
*/
@JvmField
val ISSUE: Issue = Issue.create(
// ID: used in @SuppressLint warnings etc
id = "SampleId",
// Title -- shown in the IDE's preference dialog, as category headers in the
// Analysis results window, etc
briefDescription = "Lint Mentions",
// Full explanation of the issue; you can use some markdown markup such as
// `monospace`, *italic*, and **bold**.
explanation = """
This check highlights string literals in code which mentions the word `lint`. \
Blah blah blah.
Another paragraph here.
""", // no need to .trimIndent(), lint does that automatically
category = Category.CORRECTNESS,
priority = 6,
severity = Severity.WARNING,
implementation = Implementation(
SampleCodeDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
}
}
5. META-INF 등록
checks 모듈에서 resources/META-INF/services 아래에 com.android.tools.lint.client.api.IssueRegistry 파일을 생성해 줍니다.
위 파일 안에는 4번에서 생성한 IssueRegustry를 등록해 주어야 합니다. 현재 제 예제의 패키지 명은 com.example 이기 때문에 SampleIssueRegistry 파일을 아래와 같이 등록해 줍니다.
com.example.checks.SampleIssueRegistry
6. 실행하기
Sync Project with Gradle File을 해주시면 모든 변경 사항이 적용됩니다. 그다음 터미널을 실행시켜 app 모듈의 lint를 동작시켜 줍니다.
$ ./gradlew :app:lint
위 예제의 Detector에서는 아래와 같은 커스텀 린트 설정이 적용되어 있습니다.
override fun visitLiteralExpression(node: ULiteralExpression) {
val string = node.evaluateString() ?: return
if (string.contains("lint") && string.matches(Regex(".*\\blint\\b.*"))) {
context.report(
ISSUE, node, context.getLocation(node),
"This code mentions `lint`: **Congratulations**"
)
}
}
lint 문구가 있으면 This code mentions `lint` : **Congratulations** 를 보여주라고 되어 있는데 실재 프로젝트에서 잘 적용되는 것을 확인할 수 있었습니다.
마무리
구글 예제를 다운로드하여서 실행해 보면 위와 같이 잘 동작됨을 확인할 수 있습니다. 하지만 이를 다른 프로젝트에 설정하는 과정에서 생각한 대로 잘 동작되지 않았습니다. 이러한 경험을 바탕으로 step by step 형식으로 환경 설정하는 글을 작성해 보았는데요. 이제 환경 설정을 했으니 제 입맛대로 여러 커스텀 린트를 생성해 볼러고 합니다 :)
참고 링크
https://googlesamples.github.io/android-custom-lint-rules/api-guide.html
https://github.com/googlesamples/android-custom-lint-rules
'안드로이드' 카테고리의 다른 글
[Android, Custom Font] 커스텀 폰트 적용하기 (0) | 2022.10.25 |
---|---|
[AndroidStudio] 파일 타입 인식 에러 (1) | 2022.01.04 |
[Android] 텍스트 길이에 따른 아이콘 고정 (1) | 2021.08.03 |
SavedStateHandle 기록용 포스팅 (0) | 2021.07.08 |
[Android] 한눈에 보는 ViewModel 초기화 방법 A to Z (feat Koin, Hilt) (0) | 2021.07.01 |