Lint

Android Lint is the code scanning tool provided by Android Studio in ADT(Android Developer Tools)16 to help us find and correct problems with the quality of code structure. Each problem detected by the tool is reported with a message describing the problem and the severity level to quickly determine which changes need to be prioritized. In addition, we can reduce the severity level of the problem to ignore issues that are not relevant to the project, or raise the severity level to highlight specific issues.

advantages

  • No actual application is required
  • You don’t have to write test cases

Lint workflow

The following figure shows how the Lint tool handles application source files.

  • App Source Files: Contains the Files that make up the Anroid project, including Java, Kotlin and XML Files, ICONS, and Progurad configuration Files.
  • Lint. XML: a configuration file that can be used to specify any Lint checks to exclude and to customize the severity level of the problem.
  • Lint Tool: a static code scanning Tool that can be run against Android projects from the command line or from Inside Android Studio.
  • Lint Output: Lint Inspection Results can be viewed on the console or in the Android Studio Inspection Results window

Lint checks manually

  1. In turn, selectAnalyze > Inspect Code, manually run configured Lint and other IDE checks.

In the left pane tree view, view the results of the review by expanding and selecting the error category, type, and problem.

The right pane displays a check report for the selected error category, type, or problem, with the name and location of the error. Where applicable, the review report displays additional information, such as a problem summary, to help you correct the problem.

The allowBackup attribute determines whether the application’s data can be backed up and restored.

In SDK versions 23 and later, your application data will be automatically backed up and restored when the application is installed. Consider adding the attribute “Android: fullBackupContent” to specify the “@xml” resource that configures the files to back up. This issue belongs to Security.

  1. In the Gradle command line environment, can be used directly./gradlew lintPerform Lint checks.

To use the Lint command, you need to configure the Lint environment variable, or go to %ANDROID_HOME%\tools\bin

The corresponding information is printed on the command line:

> Task :app:lint
Ran lint on variant debug: 2 issues found
Ran lint on variant release: 2 issues found
Wrote HTML report to file:///D:/Develop/Project/AndroidLint/app/build/reports/lint-results.html
Wrote XML report to file:///D:/Develop/Project/AndroidLint/app/build/reports/lint-results.xml
Lint found no errors or warnings (1 error filtered by baseline lint-baseline.xml)
Copy the code

Run Lint to check a list of files in a project directory, using the following command:

 lint [flags] <project directory>
Copy the code

For example, you can execute the following command to scan files in the project directory and its subdirectories.

The MissingPrefix problem ID tells Lint to scan only XML attributes that lack the Android namespace prefix

lint --check MissingPrefix myproject
Copy the code
  1. Check whether there is a problem in the project

This feature allows us to enter an Issue ID to check whether the Issue id exists in the project

The corresponding problem information is displayed in the Inspection Results window

Lint helps us find and optimize which problems

  • Missing translations (such as internationalized untranslated fields)
  • Layout performance (to solve the problem of layout not being used or too many, too many nesting)
  • No referenced resource file
  • Inconsistent array size
  • Hard coding problems with internationalization
  • Icon duplication problem
  • Availability issues (text input type not specified)
  • Error in the manifest file

Each problem Lint finds has a description and level, making it easy to locate the problem and fix it by severity. Of course, this “severity” can be manually adjusted, some principle issues are inviolable and must be raised to error, and some individual issues can be ignored.

Lint Problem types

  • Correctness such as hardcoding, using outdated apis, etc
  • Performanc: Encoding that affects performance, such as static reference, circular reference, etc
  • Internationalization: using Chinese characters directly without using resource references, etc
  • Security: Security, such as allowing JavaScriptInterface in WebView
  • Usability: there are better alternatives such as layout, icon format suggestions. PNG format, etc
  • Accessibility: Accessibility. For example, the contentDescription of an ImageView is often suggested in an attribute
1. DuplicatedIds Layout id should be unique 2) Some APIS used in NewApi code are higher than M in ManifestinSDK 3) InconsistentArrays string internationalization String - an Array of the corresponding item of the same name values are not the same 4) Registered Activity/Service/ContentProvider is not Registered by AndroidManifest 5) Deprecated Using abandoned px, API 6) PxUsage avoided using dp 7) AppCompatCustomView Appcompat custom widget will typically let you inherit from android. Support. V7. Widget. Appcompat... Do not expand android directly. The widget class, but should expand android. Support. V7. Widget. AppCompat a delegate in the class. 2. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3) StringFormatInvalid if the string containsThe '%'Character, the String may be a format String, passed from Java code to string.format to replace each with a specific valueThe '%'Events. 4) Typos is typically spelled Spelling Error, which checks the string definition and flags any word that looks like a misspelling. Although it is common, it is generally not processed. 3. Assert (Warning) Try to use other options such asif(BuildConfig.DEBUG && ! (speed > 0)) {throw new AssertionError()} Instead of assert maxSize > 0; 2) UnusedAttribute This check will look for properties set in the XML file and will be prompted if the imported version of the file is newer than the oldest version (with the minSdkVersion attribute) that the application is targeting. If appearance/functionality is significant/important, another implementation should be considered, otherwise ignore it. 3) DuplicateIncludedIds It is ok to use the same ID for two separate layouts. However, if the layout is used in conjunction with include tags, then the ID must be unique in all cases. (for example, Layout_A includes Layout_B. The two layouts should not have the same ID tag. Do not execute SetJavaScriptEnabled unless you are sure that your program really needs JavaScript. 2)ExportedContentProvider/ExportedReceiver/ExportedService/ExportedActivity ContentProvider/Receiver/Service/exported for the Activitytrue, set a Permission, and let the user obtain the Permission to use. 3) HardcodedDebugMode Do not set Android :debuggable in manifest. Set it to the specified debug mode for any version compiled. If this parameter is not set, Eng version is compiled in debug mode. The User version is compiled in release mode. 5. Performance 1) DrawAllocation avoids assigning objects while drawing or parsing a layout. E.g., instantiate the Paint object in Ondraw(). 2) Obsolete arguments in the ObsoleteLayoutParam Layout. 3) UseCompoundDrawables can be optimized for layout: for example, a linear layout containing an Imageview and a TextView can be replaced by a CompoundDrawable TextView. 5) DisableBaselineAlignment If the LinearLayout is used for nested layout space calculation, Its Android :baselineAligned attribute should be set tofalseTo speed up layout calculation. 6) FloatMath Use FloatMath instead of Math. 7) NestedWeights avoid nesting weights, It will drag on the execution efficiency of 8) UnusedResources/UnusedIds unused resources will make the application become bigger and slow down the speed of building 9) if Overdraw specify a background Drawable for RootView, will be made in the background of the Theme again, Then use the specified background, which is called "Overdraw". This can be avoided by setting the background of the theme to NULL. 10) UselessLeaf/UselessParent without children or background layout can be removed (because it is not visible) levels have child with no brothers, not scroll view or root level distribution, and there is no background layout can be deleted, and its level directly will be moved to the parent. 6. The Usability of Icons 1) IconNoDpi Icon appears in both nodpi and dPI directories, delete one of them. 2) GifDo not use GIF, it is best to use PNG, can use JPG. Do not have a Back button in Android, there is usually a hard Back button in Android. 2) "Ok"/" Cancel "of ButtonCase Button must be displayed in case, not all uppercase or all lowercase. A string that has a standard resource, don't define it yourself, but use a system-defined string: @android:string/ok @android:string/cancel 8.accessibility 1) ContentDescription ImageView and ImageButton should provide contentDescription 9. Internationalization 1) HardcodeText should be defined in resources 2) EnforceUTF8 All XML resource files should be encoded in UTF-8...Copy the code
lint --list
Valid issue categories:
    Correctness
    Correctness:Messages
    Correctness:Chrome OS
    Security
    Performance
    Usability:Typography
    Usability:Icons
    Usability
    Accessibility
    Internationalization
    Internationalization:Bidirectional Text

Valid issue id's:
"ContentDescription": Image without contentDescription
"AddJavascriptInterface": addJavascriptInterface Called
"ShortAlarm": Short or Frequent Alarm
"AllCaps": Combining textAllCaps and markup
"AllowAllHostnameVerifier": Insecure HostnameVerifier
"AlwaysShowAction": Usage of showAsAction=always
"InvalidUsesTagAttribute": Invalid name attribute for uses element.
"MissingIntentFilterForMediaSearch": Missing intent-filter with action
      android.media.action.MEDIA_PLAY_FROM_SEARCH
"MissingMediaBrowserServiceIntentFilter": Missing intent-filter with action
      android.media.browse.MediaBrowserService.
"MissingOnPlayFromSearch": Missing onPlayFromSearch.
"ImpliedTouchscreenHardware": Hardware feature touchscreen not explicitly
      marked as optional
"MissingTvBanner": TV Missing Banner
"MissingLeanbackLauncher": Missing Leanback Launcher Intent Filter.
"MissingLeanbackSupport": Missing Leanback Support.
"PermissionImpliesUnsupportedHardware": Permission Implies Unsupported
      Hardware
"UnsupportedTvHardware": Unsupported TV Hardware Feature
"SupportAnnotationUsage": Incorrect support annotation usage
"ShiftFlags": Dangerous Flag Constant Declaration
"LocalSuppress": @SuppressLint on invalid element
"SwitchIntDef": Missing @IntDef in Switch
"UniqueConstants": Overlapping Enumeration Constants
"InlinedApi": Using inlined constants on older versions
"Override": Method conflicts with new inherited method
"ObsoleteSdkInt": Obsolete SDK_INT Version Check
"NewApi": Calling new methods on older versions
"UnusedAttribute": Attribute unused on older versions
"AppCompatMethod": Using Wrong AppCompat Method
"AppCompatCustomView": Appcompat Custom Widgets
"AppCompatResource": Menu namespace
"GoogleAppIndexingApiWarning": Missing support for Firebase App Indexing Api
"GoogleAppIndexingWarning": Missing support for Firebase App Indexing
"AppLinksAutoVerifyError": App Links Auto Verification Failure
"AppLinksAutoVerifyWarning": Potential App Links Auto Verification Failure
"AppLinkUrlError": URL not supported by app for Firebase App Indexing
"TestAppLink": Unmatched URLs
"InconsistentArrays": Inconsistencies in array element counts
"Assert": Assertions
"BadHostnameVerifier": Insecure HostnameVerifier
"BatteryLife": Battery Life Issues
"BackButton": Back button
"ButtonCase": Cancel/OK dialog button capitalization
"ButtonOrder": Button order
"ButtonStyle": Button should be borderless
"ByteOrderMark": Byte order mark inside files
"MissingSuperCall": Missing Super Call
"AdapterViewChildren": AdapterViews cannot have children in XML
"ScrollViewCount": ScrollViews can have only one child
"PermissionImpliesUnsupportedChromeOsHardware": Permission Implies Unsupported
      Chrome OS Hardware
"UnsupportedChromeOsHardware": Unsupported Chrome OS Hardware Feature
"GetInstance": Cipher.getInstance with ECB
"CommitTransaction": Missing commit() calls
"Recycle": Missing recycle() calls
"CommitPrefEdits": Missing commit() on SharedPreference editor
"ApplySharedPref": Use apply() on SharedPreferences
"ClickableViewAccessibility": Accessibility in Custom Views
"EasterEgg": Code contains easter egg
"StopShip": Code contains STOPSHIP marker
"MissingConstraints": Missing Constraints in ConstraintLayout
"VulnerableCordovaVersion": Vulnerable Cordova Version
"CustomViewStyleable": Mismatched Styleable/Custom View Name
"CutPasteId": Likely cut & paste mistakes
"SimpleDateFormat": Implied locale in date format
"SetTextI18n": TextView Internationalization
"Deprecated": Using deprecated resources
"MissingPrefix": Missing Android XML namespace
"MangledCRLF": Mangled file line endings
"DuplicateIncludedIds": Duplicate ids across layouts combined with include
      tags
"DuplicateIds": Duplicate ids within a single layout
"DuplicateDefinition": Duplicate definitions of resources
"ReferenceType": Incorrect reference types
"StringEscaping": Invalid string escapes
"UnpackedNativeCode": Missing android:extractNativeLibs=false
"UnsafeDynamicallyLoadedCode": load used to dynamically load code
"UnsafeNativeCodeLocation": Native code outside library directory
"EllipsizeMaxLines": Combining Ellipsize and Maxlines
"ExifInterface": Using android.media.ExifInterface
"ExtraText": Extraneous text in resource files
"FieldGetter": Using getter instead of field
"InvalidAnalyticsName": Invalid Analytics Name
"MissingFirebaseInstanceTokenRefresh": Missing Firebase Instance ID Token
      Refresh
"FontValidationError": Validation of font files
"FontValidationWarning": Validation of font files
"FullBackupContent": Valid Full Backup Content File
"ValidFragment": Fragment not instantiatable
"GetContentDescriptionOverride": Overriding getContentDescription() on a View
"PackageManagerGetSignatures": Potential Multiple Certificate Exploit
"AccidentalOctal": Accidental Octal
"UseOfBundledGooglePlayServices": Use of bundled version of Google Play
      services
"GradleCompatible": Incompatible Gradle Versions
"GradleDependency": Obsolete Gradle Dependency
"GradleDeprecated": Deprecated Gradle Construct
"DevModeObsolete": Dev Mode Obsolete
"DuplicatePlatformClasses": Duplicate Platform Classes
"GradleGetter": Gradle Implicit Getter Call
"GradlePluginVersion": Incompatible Android Gradle Plugin
"HighAppVersionCode": VersionCode too high
"GradleIdeError": Gradle IDE Support Issues
"GradlePath": Gradle Path Issues
"GradleDynamicVersion": Gradle Dynamic Version
"NotInterpolated": Incorrect Interpolation
"StringShouldBeInt": String should be int
"NewerVersionAvailable": Newer Library Versions Available
"MinSdkTooLow": API Version Too Low
"GridLayout": GridLayout validation
"HandlerLeak": Handler reference leaks
"HardcodedDebugMode": Hardcoded value of android:debuggable in the manifest
"HardcodedText": Hardcoded text
"HardwareIds": Hardware Id Usage
"IconDuplicatesConfig": Identical bitmaps across various configurations
"IconDuplicates": Duplicated icons under different names
"GifUsage": Using .gif format for bitmaps is discouraged
"IconColors": Icon colors do not follow the recommended visual style
"IconDensities": Icon densities validation
"IconDipSize": Icon density-independent size validation
"IconExpectedSize": Icon has incorrect size
"IconExtension": Icon format does not match the file extension
"IconLauncherShape": The launcher icon shape should use a distinct silhouette
"IconLocation": Image defined in density-independent drawable folder
"IconMissingDensityFolder": Missing density folder
"IconMixedNinePatch": Clashing PNG and 9-PNG files
"IconNoDpi": Icon appears in both -nodpi and dpi folders
"IconXmlAndPng": Icon is specified both as .xml file and as a bitmap
"ConvertToWebp": Convert to WebP
"WebpUnsupported": WebP Unsupported
"IncludeLayoutParam": Ignored layout params on include
"DisableBaselineAlignment": Missing baselineAligned attribute
"InefficientWeight": Inefficient layout weight
"NestedWeights": Nested layout weights
"Orientation": Missing explicit orientation
"Suspicious0dp": Suspicious 0dp dimension
"InstantApps": Instant App Issues
"DuplicateDivider": Unnecessary Divider Copy
"TrustAllX509TrustManager": Insecure TLS/SSL trust manager
"InvalidImeActionId": Invalid imeActionId declaration
"InvalidPackage": Package not included in Android
"DrawAllocation": Memory allocations within drawing code
"UseSparseArrays": HashMap can be replaced with SparseArray
"UseValueOf": Should use valueOf instead of new
"JavascriptInterface": Missing @JavascriptInterface on methods
"JobSchedulerService": JobScheduler problems
"KeyboardInaccessibleWidget": Keyboard inaccessible widget
"LabelFor": Missing labelFor attribute
"InconsistentLayout": Inconsistent Layouts
"InflateParams": Layout Inflation without a Parent
"StaticFieldLeak": Static Field Leaks
"DefaultLocale": Implied default locale in case conversion
"LocaleFolder": Wrong locale name
"GetLocales": Locale crash
"InvalidResourceFolder": Invalid Resource Folder
"WrongRegion": Suspicious Language/Region Combination
"UseAlpha2": Using 3-letter Codes
"LogConditional": Unconditional Logging Calls
"LongLogTag": Too Long Log Tags
"LogTagMismatch": Mismatched Log Tags
"AllowBackup": AllowBackup/FullBackupContent Problems
"MissingApplicationIcon": Missing application icon
"DeviceAdmin": Malformed Device Admin
"DuplicateActivity": Activity registered more than once
"DuplicateUsesFeature": Feature declared more than once
"GradleOverrides": Value overridden by Gradle build script
"IllegalResourceRef": Name and version must be integer or string, not
      resource
"MipmapIcons": Use Mipmap Launcher Icons
"MockLocation": Using mock location provider in production
"MultipleUsesSdk": Multiple <uses-sdk> elements in the manifest
"ManifestOrder": Incorrect order of elements in manifest
"MissingVersion": Missing application name/version
"OldTargetApi": Target SDK attribute is not targeting latest version
"UniquePermission": Permission names are not unique
"UsesMinSdkAttributes": Minimum SDK and target SDK attributes not defined
"WearableBindListener": Usage of Android Wear BIND_LISTENER is deprecated
"WrongManifestParent": Wrong manifest parent
"InvalidPermission": Invalid Permission Attribute
"ManifestResource": Manifest Resource References
"ManifestTypo": Typos in manifest tags
"FloatMath": Using FloatMath instead of Math
"MergeMarker": Code contains merge marker
"MergeRootFrame": FrameLayout can be replaced with <merge> tag
"IncompatibleMediaBrowserServiceCompatVersion": Obsolete version of
      MediaBrowserServiceCompat
"InnerclassSeparator": Inner classes should use $ rather than .
"Instantiatable": Registered class is not instantiatable
"MissingRegistered": Missing registered class
"MissingId": Fragments should specify an id or tag
"LibraryCustomView": Custom views in libraries should use res-auto-namespace
"ResAuto": Hardcoded Package in Namespace
"NamespaceTypo": Misspelled namespace declaration
"UnusedNamespace": Unused namespace
"NegativeMargin": Negative Margins
"NestedScrolling": Nested scrolling widgets
"NetworkSecurityConfig": Valid Network Security Config File
"MissingBackupPin": Missing Backup Pin
"PinSetExpiry": Validate <pin-set> expiration attribute
"NfcTechWhitespace": Whitespace in NFC tech lists
"UnlocalizedSms": SMS phone number missing country code
"ObjectAnimatorBinding": Incorrect ObjectAnimator Property
"AnimatorKeep": Missing @Keep for Animated Properties
"ObsoleteLayoutParam": Obsolete layout params
"OnClick": onClick method does not exist
"Overdraw": Overdraw: Painting regions more than once
"DalvikOverride": Method considered overridden by Dalvik
"OverrideAbstract": Not overriding abstract methods on older platforms
"ParcelCreator": Missing Parcelable CREATOR field
"UnusedQuantity": Unused quantity translations
"MissingQuantity": Missing quantity translation
"ImpliedQuantity": Implied Quantities
"ExportedPreferenceActivity": PreferenceActivity should not be exported
"PrivateApi": Using Private APIs
"PackagedPrivateKey": Packaged private key
"PrivateResource": Using private resources
"ProguardSplit": Proguard.cfg file contains generic Android rules
"Proguard": Using obsolete ProGuard configuration
"PropertyEscape": Incorrect property escapes
"UsingHttp": Using HTTP instead of HTTPS
"SpUsage": Using dp instead of sp for text sizes
"InOrMmUsage": Using mm or in dimensions
"PxUsage": Using 'px' dimension
"SmallSp": Text size is too small
"ParcelClassLoader": Default Parcel Class Loader
"PendingBindings": Missing Pending Bindings
"RecyclerView": RecyclerView Problems
"Registered": Class is not registered in the manifest
"RelativeOverlap": Overlapping items in RelativeLayout
"RequiredSize": Missing layout_width or layout_height attributes
"AaptCrash": Potential AAPT crash
"ResourceCycle": Cycle in resource definitions
"ResourceName": Resource with Wrong Prefix
"ValidRestrictions": Invalid Restrictions Descriptor
"RtlCompat": Right-to-left text compatibility issues
"RtlEnabled": Using RTL attributes without enabling RTL support
"RtlSymmetry": Padding and margin symmetry
"RtlHardcoded": Using left/right instead of start/end attributes
"ScrollViewSize": ScrollView size validation
"SdCardPath": Hardcoded reference to /sdcard
"SecureRandom": Using a fixed seed with SecureRandom
"TrulyRandom": Weak RNG
"ExportedContentProvider": Content provider does not require permission
"ExportedReceiver": Receiver does not require permission
"ExportedService": Exported service does not require permission
"SetWorldReadable": File.setReadable() used to make file world-readable
"SetWorldWritable": File.setWritable() used to make file world-writable
"GrantAllUris": Content provider shares everything
"WorldReadableFiles": openFileOutput() or similar call passing
      MODE_WORLD_READABLE
"WorldWriteableFiles": openFileOutput() or similar call passing
      MODE_WORLD_WRITEABLE
"ServiceCast": Wrong system service casts
"WifiManagerLeak": WifiManager Leak
"WifiManagerPotentialLeak": WifiManager Potential Leak
"SetJavaScriptEnabled": Using setJavaScriptEnabled
"SignatureOrSystemPermissions": signatureOrSystem permissions declared
"SQLiteString": Using STRING instead of TEXT
"SSLCertificateSocketFactoryCreateSocket": Insecure call to
      SSLCertificateSocketFactory.createSocket()
"SSLCertificateSocketFactoryGetInsecure": Call to
      SSLCertificateSocketFactory.getInsecure()
"StateListReachable": Unreachable state in a <selector>
"AuthLeak": Code might contain an auth leak
"StringFormatCount": Formatting argument types incomplete or inconsistent
"StringFormatMatches": String.format string doesn't match the XML format
      string
"StringFormatInvalid": Invalid format string
"PluralsCandidate": Potential Plurals
"UseCheckPermission": Using the result of check permission calls
"CheckResult": Ignoring results
"ResourceAsColor": Should pass resolved color instead of resource id
"MissingPermission": Missing Permissions
"Range": Outside Range
"ResourceType": Wrong Resource Type
"RestrictedApi": Restricted API
"WrongThread": Wrong Thread
"WrongConstant": Incorrect constant
"VisibleForTests": Visible Only For Tests
"ProtectedPermissions": Using system app permission
"TextFields": Missing inputType or hint
"TextViewEdits": TextView should probably be an EditText instead
"SelectableText": Dynamic text should probably be selectable
"MenuTitle": Missing menu title
"ShowToast": Toast created but not shown
"TooDeepLayout": Layout hierarchy is too deep
"TooManyViews": Layout has too many views
"ExtraTranslation": Extra translation
"MissingTranslation": Incomplete translation
"Typos": Spelling error
"TypographyDashes": Hyphen can be replaced with dash
"TypographyEllipsis": Ellipsis string can be replaced with ellipsis character
"TypographyFractions": Fraction string can be replaced with fraction
      character
"TypographyOther": Other typographical problems
"TypographyQuotes": Straight quotes can be replaced with curvy quotes
"UnsafeProtectedBroadcastReceiver": Unsafe Protected BroadcastReceiver
"UnprotectedSMSBroadcastReceiver": Unprotected SMS BroadcastReceiver
"UnusedResources": Unused resources
"UnusedIds": Unused id
"UseCompoundDrawables": Node can be replaced by a TextView with compound
      drawables
"UselessLeaf": Useless leaf layout
"UselessParent": Useless parent layout
"EnforceUTF8": Encoding used in resource files is not UTF-8
"VectorRaster": Vector Image Generation
"VectorDrawableCompat": Using VectorDrawableCompat
"VectorPath": Long vector paths
"InvalidVectorPath": Invalid vector paths
"ViewConstructor": Missing View constructors for XML inflation
"ViewHolder": View Holder Candidates
"ViewTag": Tagged object leaks
"WrongViewCast": Mismatched view type
"FindViewByIdCast": Add Explicit Cast
"Wakelock": Incorrect WakeLock usage
"WakelockTimeout": Using wakeLock without timeout
"InvalidWearFeatureAttribute": Invalid attribute for Wear uses-feature
"WearStandaloneAppFlag": Invalid or missing Wear standalone app flag
"WebViewLayout": WebViews in wrap_content parents
"WrongCall": Using wrong draw/layout method
"WrongCase": Wrong case for view tag
"InvalidId": Invalid ID declaration
"NotSibling": RelativeLayout Invalid Constraints
"UnknownId": Reference to an unknown id
"UnknownIdInLayout": Reference to an id that is not in the current layout
"SuspiciousImport": 'import android.R' statement
"WrongFolder": Resource file in the wrong res folder
"WrongThreadInterprocedural": Wrong Thread (Interprocedural)
Copy the code
See more detailed information: lint - show or visit http://tools.android.com/tips/lint-checksCopy the code

Lint Problem Level

From high to low:

  • Fatal: This type of error will interrupt the ADT export to APK directly.
  • Error: Specifies the errors that need to be resolved, including Crash, clear bugs, serious performance problems, and code specifications noncompliance. The errors must be fixed.
  • Warning: Indicates warnings, including suggestions on code writing, possible bugs, and performance optimization. Relax the requirements appropriately.
  • Information
  • Ignore

Set Lint problem checking

By default, when running a Lint scan, the Lint tool checks for any problems it supports. However, we can limit the problems lint checks and assign severity levels to those problems. For example, lint can be disabled for specific problems that are not relevant to a project, or lint can be configured to report non-critical problems at a lower severity level.

Configure different levels of Lint checks:

  • Overall (entire project)
  • The project module
  • Production module
  • Test module
  • Open file
  • Class hierarchy
  • Version control system (VCS) scope

Configure Lint in Android Studio

Create a lint. XML file in the project root directory

Lint. XML consists of a closed parent tag that contains one or more child tags. Lint defines a unique id attribute value for each one. By setting the security attribute of the identifier, you can change the security level of an issue, or the Lint check for that issue, and you can specify whether the issue applies to the specified file or the current project. By placing lint. XML in the app directory (lint. XML needs to be in the build.gradle directory), lint will use the rules in Lint. XML when the command line is executed. In addition, lint can specify a global configuration for all projects with the -config parameter. When lint. XML is already in the project, the customization of the issue in the file specified by -config takes effect only if there is no specific customization for the issue in Lint. XML.

<? xml version="1.0" encoding="UTF-8"? > <lint> <! -- Disable detection of IconMissingDensityFolder in projects --> <issue ID ="IconMissingDensityFolder" severity="ignore"/ > <! -- Ignore the ObsoleteLayoutParam issue in the specified file --> <issue ID ="ObsoleteLayoutParam">
            <ignore path="res/layout/activation.xml" />
            <ignore path="res/layout-xlarge/activation.xml"/> </issue> <! -- Ignore UselessLeaf issues in the specified file --> <issue ID ="UselessLeaf">
            <ignore path="res/layout/main.xml"/> </issue> <! -- Change the severity of HardcodedText to "error" --> < Issue ID ="HardcodedText" severity="error" />
    </lint>
    
Copy the code

Configure Java or Kotlin checks

To disable Lint specifically for a class or method in an Android project, add an @SuppressLint annotation to the code.

    @SuppressLint("NewApi")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
Copy the code

Configure XML Lint checking

Lint can be disabled for specific parts of an XML file using the Tools :ignore attribute. Add the following namespace values to the Lint.xml file so that the Lint tool can recognize this property

    namespace xmlns:tools="http://schemas.android.com/tools"
Copy the code

Turn off Lint for SmallSp problems in the

element of an XML layout file,

If a parent element declares the ignore attribute, the child elements of that element inherit it. In this case, lint checking is also disabled for

child elements.

No SmallSp error is displayed

<?xml version="1.0" encoding="utf-8"? >
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"   ------Adding a namespacexmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"       
    tools:ignore="SmallSp">    <! -- Not checking SmallSp -->  
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:textSize="9sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
    
Copy the code

Disables Lint to check for all problems in XML elements:

Tools :ignore="all" Use the all keywordCopy the code

Prohibit checking more than one problem:

Tools: ignore = "NewApi, StringFormatInvalid" separated by a commaCopy the code

Configure the Lint rule in Gradle

Android {// remove errors checked by Lint to avoid compilation problems due to strict compilation conditionstrue, stop the Gradle build when Lint finds an error (defaulttrue)
        abortOnError false/ / if it istrue, only the error ignoreWarnings is reportedtrue// Do not check the given problem ID. InvalidPackage: Package not includedin Android
        disable 'InvalidPackage'// Do not check for resource type error given problem IDdisable "ResourceType"// Ignore Build Failed due to MissingTranslation"app_name"
        disable 'MissingTranslation'// Check the given problem IDenable 'RtlHardcoded'.'RtlCompat'.'RtlEnabled'// * Only * check the given problem id check'NewApi'.'InlinedApi'// Configure where to write the output; It can be a file or a "stdout" (standard output) textOutput'stdout'// If true, an XML report will be generated for Jenkins and the like to use xmlReportfalse// The file to write the report to (default: lint-results.xml if not specified) xmlOutput file("lint-report.xml") // If true, an HTML report is generated (including an explanation of the problem, the source code for the problem, etc.) htmlReporttrue// The path to write the report, which is optional (default is lint-results.html in the build directory) htmlOutput file("lint-report.html") // Set totrueWill cause all release builds to be fatal with the severity level of ISSUs // (Severity =false) to run Lint // and, if fatal problems are found, the build will be aborted // (controlled by abortOnError mentioned above) checkReleaseBuildstrue// Set the severity of the given problem to FATAL (this means they will be checked for // during release builds (even if the problem to be checked by Lint is not contained in the code)'NewApi'.'InlineApi'// Set the severity level of the given problem to ERROR error'Wakelock'.'TextViewEdits'// Set the severity level of the given problem to warning warning'ResourceAsColor'// Set the severity of the given problem to ignore (same as not checking the problem)'TypographyQuotes'/ / if it istrue, all problems are checked, including the default unchecked problem checkAllWarningstrue// Reset the Lint configuration (with default severity Settings, etc.). lintConfig file("default-lint.xml") // Set totrue, the full or absolute path of the file is displayed in case of an error (default istrue)
        absolutePaths true}}Copy the code

Before:

add this:

After:

For example, this SmallSp is usually a yellow warning, but when you set it to fatal in Gradle, it displays a red error. In addition, when gralde builds, if there are SmallSp problems, the build will stop.

Lint logs error messages

You can create a snapshot of the current set of warnings for a project and then use that snapshot as a benchmark for running future checks so that only new problems are reported. With a baseline snapshot, you can start using Lint to fail builds without having to go back and resolve all existing issues first.

Benchmark: current problem set

Create Lint baseline snapshot

Modify the project’s build.gradle file

    android {
      lintOptions {
        baseline file("lint-baseline.xml")}}Copy the code

The first time this line is added, the lint-baseline. XML file is created to establish the baseline. After that, the Lint tool only reads the file to determine the benchmark.

If you want to create a new benchmark, manually delete the file and run Lint again to recreate it.

Next, run Lint from the IDE (select Analyze > Inspect Code in turn) or from the command line, as shown below. The system prints the location of the lint-baseline. XML file.

Running Lint records all current issues in the Lint-basel.xml file. The current problem set is called a “baseline,” and if you want to share the Lint-baseline. XML file with others, you can put it under versioning.

If any new warnings are added to the code base after the benchmark is created, Lint will list only newly introduced errors.

As shown in the figure above, all issues are put into lint-baseline. Any new issues that arise after this are shown separately, such as Activity_main saaa not found in the figure above

View and modify the check configuration file

Android Studio comes with a number of Lint and other check configuration files that can be updated with Android updates. You can use these profiles as they are, or you can change their name, description, severity level, and scope. You can also activate and disable an entire group of profiles or individual profiles within a group of profiles.

To access the Inspections dialog, do the following:

  1. Select Analyze > Inspect Code.

  2. Under Inspection Profile in the Specify Scope dialog, click More(ellipsis).

    The Frames dialog box displays, which lists the supported checks and their descriptions.

  3. Select the Profile drop-down list to switch between the Default (Android Studio) and Project Default (active Project) checks. For more details, see the IntelliJ page below: “Specify Inspection Scope” dialog box.

  4. In the Frames Dialog box in the left pane, select a top-level profile category, or expand a group and select specific profiles. After selecting a profile category, you can modify all the check items in that category as if they were a single check item.

  5. Select the Manage drop-down list to copy, rename, add descriptions to, and export/import check items.

  6. When you’re done, click OK.

Item Description
Whole project Select this option to analyze the entire project.
File Select this option to analyze files currently selected in the Project tool window or open in the editor.
Selected files Select this option to analyze the currently selected file in the Project tool window.
Custom scope Select this option to use a custom scope. Select one of the predefined ranges from the list, or click “(more) Ellipses “and select the ranges to analyze
Include test sources Select this check box to perform analysis on Test Sources.
Inspection profile Select a profile to check the specified range. Select a profile from the list. If the required profile is not in the list, click the ellipsis button, and then configure the required profile on the page.

Custom Lint

Android Lint has a number of built-in Lint rules to detect common code problems (for example, correctness issues, security issues, performance issues, and so on). Android Lint also supports custom Lint rules, giving developers the flexibility to apply them and improve the quality of their project code. Using custom Lint rules can be used both to detect code quality problems in a project and to ensure code specification execution.

Detector

An Detector is the core of a custom rule. It scans the code to get various information in the code, and then alerts and reports based on that information.

The following are the possible scanner interfaces, which one you choose to implement depends on the scanning range you want.

  • The Detector. BinaryResourceScanner for binary resources, such as various Bitmap res/raw directory
  • Detector.JavaScanner/JavaPsiScanner/UastScanner Scans Java code
  • Comparing with Detector.JavaScanner, Detector.ClassScanner scans for classes more and can obtain various information of classes
  • Detector.GradleScanner scans Gradle
  • The Detector. ResourceFolderScanner resource directory for scanning, will only scan the directory itself
  • The Detector.XmlScanner scans XML files
  • Detector. OtherFileScanner used in other files in addition to the above 6 kinds of circumstances

The Scanner that scans Java source files has experienced three versions.

  1. Starting with JavaScanner, Lint parses Java source code through Lombok libraries into an AST(abstract syntax tree), which is then scanned by JavaScanner.

  2. In Android Studio 2.2 and Lint-API 25.2.0, the Lint tool replaced Lombok AST with PSI and deprected JavaScanner in lieu of JavaPsiScanner.

    PSI is an API provided by JetBrains after parsing Java source code in IDEA to generate a syntax tree. Compared to previous Lombok AST, it supports Java 1.8, type resolution, and more. Custom Lint rules implemented using JavaPsiScanner can be loaded into Android Studio 2.2+ and executed in real time as Android code is written.

  3. In Android Studio 3.0 and Version 25.4.0 of Lint-API, the Lint tool replaced PSI with UAST(General Abstract Syntax Tree) and recommended the new UastScanner.

    UAST is the API used by JetBrains to replace PSI in the new version of IDEA. UAST is more language-independent and can support Kotlin in addition to Java.

PSI is introduced

PSI(Program Structure Interface) is a set of API for parsing code in IDEA, the full name is: Program Structure Interface. The contents of a file can be represented as a hierarchy of elements in a particular programming language.

A PSI (Program Structure Interface) file is the root of a structure representing the contents of a file as a hierarchy of elements in a particular programming language.

Each Psi elements corresponding to a class that is inherited from com. Intellij. Psi. PsiElement. Examples include PsiMethodCallExpression, which represents method invocation statements, and PsiNewExpression, which represents object instantiation statements.

The official documentation

IntelliJ Platform SDK DevGuide www.jetbrains.org/intellij/sd…

UAST

UAST stands for universal Abstract Syntax tree, and UAST nodes are essentially supersets supported by Java and Kotlin.

When writing rules using UAST, the rules apply to both Java files and Kotlin files, rather than writing two sets of rules for the same object.

JavaPsiScanner introduction

JavaPsiScanner contains six groups and 12 callback methods, as follows:

  1. whengetApplicablePsiTypesReturns a list of Psi element types to check when the type matches the Psi element (PsiElementIt will becreatePsiVisitorThe returnedJavaElementVisitorCheck.
  2. whengetApplicableMethodNamesReturns a list of method names when the name matches the method call (PsiMethodCallExpressionIt will bevisitMethodCheck.
  3. whengetApplicableConstructorTypesReturns a list of class names that match the constructor (PsiNewExpressionIt will bevisitConstructorCheck.
  4. whengetApplicableReferenceNamesWhen a list of reference names is returned, the name matches the reference statement (PsiJavaCodeReferenceElementIt will bevisitReferenceCheck.
  5. whenappliesToResourceRefsWhen true is returned, a resource reference in the Java code (for exampleR.layout.mainIt will bevisitResourceReferenceCheck.
  6. whenapplicableSuperClassesWhen a list of superclass names is returned, the superclass name matches the class declaration (PsiClassIt will becheckClassCheck.

The second is used here as an example

Key code:

MyIssueDetector

public class MyIssueDetector extends Detector implements Detector.UastScanner {

    static final Issue ISSUE_NOT_USE_LOG_UTIL = Issue.create(
            "LOG_UTIL".//id
            "should use log util"./ / profile
            "this is explanation".//explanation 
            Category.USABILITY,
            10./ / priority
            Severity.ERROR,
            new Implementation(MyIssueDetector.class, Scope.JAVA_FILE_SCOPE)
    );

    @Override
    public List<String> getApplicableMethodNames(a) {
        return Arrays.asList("v"."d"."i"."w"."e"."wtf"."Log");
    }

    / * * *@paramContext Lint Specifies the context * of the request@paramNode The node * on which the method is called@paramMethod Specifies the method to be called
    @Override
    public void visitMethodCall(@NotNull JavaContext context, @NotNull UCallExpression node, @NotNull PsiMethod method) {
        super.visitMethodCall(context, node, method);
        if(context.getEvaluator().isMemberInClass(method,"android.util.Log")){
            context.report(ISSUE_NOT_USE_LOG_UTIL, context.getLocation(node), "Do not directly call android.util.Log, you should use the unified tool class"); }}}Copy the code

We get a callback visitMethodCall whenever we see a method called v(),d(), etc., because we’re looking at the method name, not the class, so we need to check with the eveluator.

Make sure it is in android.util.log and report a use case if it is.

Id: a unique value that should briefly describe the current problem. This id is used when masking using Java annotations or XML attributes.

Summary: A short summary, usually 5-6 characters, describing the problem rather than the fix.

Explanation: Complete problem explanation and repair suggestions.

Category: question category.

Priority: indicates the priority. 1-10.

Severity: Fatal, Error, Warning, Informational, Ignore.

Implementation: Provides a mapping between Issue and Detector, which is the current Detector. Specifies the scope of the scan

Scope: Describes the set of files that the Detector needs to consider when analyzing, including: Resource files or directories, Java files, and Class files.

The getApplicableMethodNames return value specifies the method to be checked

VisitMethodCall. [getApplicableMethodNames] return with any name match any method call and call the method.

Arguments to context.report:

The first argument: is the Issue we defined; Second parameter: return the current location information according to the current node, so that the location can be displayed in the report; The third argument: string is used to add an explanation to the warning.

MyIssueRegistry

The created Issue must be registered in IssueRegistry

Android Lint issues are registered in IssueRegistry, while custom issues can be passed in through the getIssues series of methods

public class MyIssueRegistry extends IssueRegistry {

    @NotNull
    @Override
    public List<Issue> getIssues(a) {
         return Arrays.asList(
                MyIssueDetector.ISSUE_NOT_USE_LOG_UTIL
              // , AttrPrefixDetector.ISSUE_XML_NAME); }}Copy the code

build.gradle

Add lint dependencies and generate jar packages

apply plugin: 'java-library'

sourceCompatibility = "Seven"
targetCompatibility = "Seven"

configurations {
    lintChecks
}

dependencies {
    implementation fileTree(dir: 'libs'.include: ['*.jar'])

    implementation "Com. Android. Tools. Lint: lint - API: 27.0.0"
    implementation "Com. Android. Tools. Lint: lint - checks: 27.0.0"

    lintChecks files(jar)
}

jar {
    manifest {
        attributes('Lint-Registry': 'com.example.lint_lib.MyIssueRegistry')}}Copy the code

Lint-api is the official interface for Android Lint, based on which source code information can be obtained for analysis.

Lint-checks is an official existing check rule.

Lint-registry represents registration for custom rules and packaging as jars.

use

1. Use custom Lint globally

Put the generated JAR package in the ~ Android/Lint folder (create one if you don’t have one) in my own C:\Users\zhuoy.android\lint

Then use the command line tool to check whether it is added successfully:

lint --show issue_id
Copy the code

In the meantime, lint –show/list can see this Issue

Code being tested:

Use custom Lint for individual projects

Google’s official solution is to put jar files in ~/. Android/Lint /. If there is no local lint directory, you can create your own. This is easier to use, but it makes Android Lint less flexible for all local projects. Create a new Module in the main project and introduce the JAR into the Module so that each project can introduce its own custom Lint as a Module, which is flexible and does not interfere between projects.

Create a new Android Library and add the following code to build.gradle:

configurations {
    lintJarImport
}

dependencies {
    // Get the jar package by calling lintJarOutput of lintjar
    lintJarImport project(path: ':lint_lib'.configuration: 'lintChecks')}// Call lintJarImport to get the jar package and copy it to the specified directory
task copyLintJar(type: Copy) {
    from(configurations.lintJarImport) {
        rename {
            String fileName ->
                'lint.jar'
        }
    }
    into 'build/intermediates/lint/'
}

// Execute the copyLintJar method when the project prepareLintJar step is performed (note: this timing needs to change depending on the project)
project.afterEvaluate {
    def compileLintTask = project.tasks.find { it.name == 'prepareLintJar' }
    compileLintTask.dependsOn(copyLintJar)
}
Copy the code

Here, we create a Gradle configuration called “lintJarImport”, which refers to the Gradle configuration “lintChecks” of the module “:lint_lib”.

We also changed the built-in Gradle task ‘compileLint’ to rely on a task ‘copyLintJar’ that we defined. In the task “copyLintJar”, the output module “: lint_lib” jar package copy to build/intermediates/lint/lint. Jar.

Then run gradLew build to see the result

Lint rules defined in this LintLibrary can be used by other projects simply by introducing it.

You can also see the highlighting in the code.

The intelligent error correction

Sometimes an IDE will give you a prompt with an ALT+ENTER shortcut that allows you to change the code directly using the suggestion. We can also do this:

Here is what I have changed to check: when I find log.wtf (), I give a prompt and a suggestion to use log.e instead of log.wtf.

WTF is not what the fuck, but what a terrible failure

Implementation method:

 private void reportUsage(@NotNull JavaContext context, @NotNull UCallExpression node, @NotNull PsiMethod method) {
        LintFix lintFix = LintFix.create()
                .name("Use Log.(e)")
                .replace()
                .text(method.getName())
                .with("e")
                .robot(true)
                .independent(true)
                .build();
        context.report(ISSUE_NOT_USE_LOG_UTIL,
                context.getLocation(node),
                " reportUsage Do not directly call android.util.Log, you should use the unified tool class",
                lintFix);
    }
Copy the code

Instead of reporting information, we call the report method with a lintFix parameter.

LintFix is a quick fix for Lint.

Independent: Whether this patch is independent of other patches to be applied.

Robot: These types of fixes can be applied automatically when running Lint in fix-mode, where it will apply all recommended (qualified) fixes.