Lint란?
먼저 Lint가 무엇인지를 정리해본다. Android Lint는 앱을 구성하는 코드(소스, 리소스, manifest를 포함)들을 정적 분석하는 도구이다.
Test Code의 작성 없이 코드의 구조적 품질 문제를 식별하고 수정할 수 있다. Lint 검사 도구에서 감지된 각 문제는 설명 메시지 및 심각도 수준과 함께 보고되므로 개선이 시급한 순서대로 우선순위를 정할 수 있다.
lint.xml 파일은 제외하려는 린트 검사를 지정하고 문제 심각도 수준 등을 변경하여 맞춤 설정하는 데에 사용할 수 있는 구성 파일이다.
Lint의 결과는 Android Studio의 Inspection Results 창에서 린트 결과를 확인하거나 커맨드를 통한 수동 검사를 실행하여 결과를 확인할 수 있다. 물론 CI/CD에서도 커맨드를 통해 가능하다.
Custom Lint가 필요한 이유
사실 안드로이드 자체에서 제공하고 있는 기본 lint도 강력하므로 Custom Lint의 필요성을 크게 느끼지 못할 수도 있다. 하지만 다수의 인원이 작업하는 프로젝트에 있어서 공통으로 지켜야 하는 룰 중에서 강제화할 필요가 있는 것들에 대해서는 Custom Lint를 사용하면 좋은 경우도 있다.
Android Studio IDE 환경에서 warning, error 표시를 해주고 설명과 자동 변경 등도 제공할 수 있으나 이번 포스팅에서는 lint 검사 빌드를 통한 결과를 확인할 수 있는 방법만 정리해본다.
Custom Lint 적용 구조
Custom Lint를 구현하고 적용하기 위해서는 2개의 모듈을 추가해야 한다. 앱은 library 모듈에 dependency를 가지면 되고, library 모듈은 checks 모듈에 dependency를 가지면 된다. 실제 린트 검사를 위해 필요한 내용들은 checks에 있고 library는 이 checks 모듈을 lintPublish dependency를 가진다. (이름은 맘대로 가능)
문서나 자료들을 찾다 보면 lintPublish 말고 lintChecks가 있는데 특정 버전 이후부터는 lintPublish만 사용하면 된다. 근데 이게 예전에 나온 거라 요새는 별 고민 없이 lintPublish를 사용하면 된다.
Lint Version
프로젝트에서 사용해야 하는 Lint Version은 Gradle Plugin Version에 23.0.0을 더해준 것으로 사용하면 된다. 다음의 예시처럼 gradlePlugin 버전에서 그대로 23을 더하면 된다.
checks module
먼저, 실제로 lint check를 하는 checks 모듈을 추가해준다.
dependency는 compileOnly로 해야 한다.
META-INF 등록
- service registration file을 등록해줘야 한다. IssueRegistry 클래스에 대한 이름으로 생성해주고, 프로젝트에서 이 class 파일을 생성할 위치를 명시해주면 된다.
- resources/META-INF/services 아래에 com.android.tools.lint.client.api.IssueRegistry 파일 생성
cf. 일반적으로 하나의 Issue Registry가 여러 개의 이슈를 제공하기 때문에 하나의 IssueRegistry만 명시해주면 되지만, 여러 개의 IssueRegistry를 포함해도 상관은 없다.
IssueRegistry
다음으로, 앞에서 명시해준 IssueRegistry를 구현해야 한다. Lint는 이 클래스를 인스턴스화시켜서 Issue 리스트를 받아간다. 가장 기본적인 형태로는 아래의 코드처럼 minApi, api 버전과 이슈 목록만 제공해주면 된다.
issues의 이슈들을 직접 구현하면 되는데 다음에 이어지는 Detector에서 설명한다.
Detector Example
예시와 함께 설명하는 것이 나을 것 같아 kotlin에서 강제로 nullable을 unwrapping하는 detector에 대한 샘플로 설명하려 한다.
기본적으로 Detector를 상속받아서 사용하며, 어떤 이슈를 디텍팅하는 지에 따라 필요한 Scanner를 상속받아서 사용하면 된다. 이슈에 따라 제공되는 함수와 방법이 다양해서 그건 어떤 이슈를 디텍팅하고 싶은 지에 따라 api 문서를 보면서 구현하면 된다.
Detector를 구현해주고 나서 companion object에 Issue를 하나 선언해주면 된다. 여기에서 해당 이슈가 어떤 종류인지, 이슈가 감지되었을 때 어떤 이름과 설명으로 제공할지, 중요도와 우선순위를 설정해주면 된다. 링크도 연결해줄 수 있다. 이 이슈의 이름은 NonNullAssertion이고 @SuppressLint("NonNullAssertion")과 같이 SuppressLint Annotation을 사용할 때 쓰는 이슈 이름으로도 사용된다.
이런식으로 필요한 Detector들을 구현하고 Issue로 제공하여 IssueRegistry에 등록하면 된다.
lintpublisher module
다음으로 lintpublisher 모듈이 필요하다. 앞쪽에 있던 그림에서의 library 모듈이다. lintPublish 구성을 사용할 것인데, 이를 사용하면 다른 모듈을 참조할 수 있으며, 프로젝트의 jar를 사용하여 AAR 파일 내부에 lint.jar로 패키징할 수 있다.
checks 모듈은 Lint API에 dependency를 가지고 detector를 구현하고 META-INF/서비스에서 연결된 IssueRegistry를 적용하는 순수 Kotlin 라이브러리이다.
Android Gradle Library 플러그인을 적용하는 lintpublisher 모듈에서 이 checks 모듈을 참조하여 lintPublish를 구성해준다.
lintpublisher는 구현부가 필요 없어서 다음과 같이 build.gradle과 AndroidManifest만 구성해주면 된다.
lint checks
./gradelew lint 명령어나 ./gradelew module_name:lint 명령어를 통해 할 수 있다.
lint-baseline.xml
lint-baseline.xml에 있는 lint error들은 이후 린트 검사에서 예외처리할 수 있다(build 중 이것들은 발견시 멈추지 않음). lint-baseline.xml이 없는 상태에서 lint 검사를 진행하면 해당 검사시의 error와 warning을 기록해준다.
References
- Google Sample : https://github.com/googlesamples/android-custom-lint-rules
- Android Lint API Guide : https://googlesamples.github.io/android-custom-lint-rules/api-guide.html
- Document : https://googlesamples.github.io/android-custom-lint-rules/index.html
'Android > Android Development' 카테고리의 다른 글
DataStore of Android Jetpack (828) | 2021.10.24 |
---|---|
Android LiveData setValue vs postValue (2) | 2021.10.21 |
Google I/O '21 (1785) | 2021.06.20 |
Android Shortcuts (안드로이드 앱 숏컷) - 3. 관리하기 (2) | 2020.08.31 |
Android App Shortcuts (안드로이드 앱 숏컷) - 2. 만들기 (4) | 2020.08.31 |
댓글