Lintphp
Android Lint 是Android Studio 在ADT(Android Developer Tools)16提供的代碼掃描工具,能夠幫助咱們發現和更正代碼結構質量的問題。系統會報告該工具檢測到的每一個問題並提供問題的描述消息和嚴重級別,以便快速肯定須要優先進行的修改。此外,咱們還能夠經過下降問題的嚴重級別以忽略與項目無關的問題,或者提升嚴重級別以突出特定問題。html
下圖顯示了 lint 工具如何處理應用源文件。java
在左側窗格樹狀視圖中,經過展開並選擇錯誤類別、類型和問題來查看檢查結果。node
右側窗格顯示選定錯誤類別、類型或問題的檢查報告,並提供錯誤的名稱和位置。在適用狀況下,檢查報告會顯示問題概要等其餘信息,以幫助您更正問題。android
allowBackup屬性肯定是否能夠備份應用程序的數據並恢復。編程
在SDK版本23及更高版本中,您的應用程序數據將在應用程序安裝時自動備份和還原。考慮添加屬性「 android:fullBackupContent」以指定「 @xml」資源,該資源配置要備份的文件。這個問題屬於Security。api
./gradlew lint
執行Lint檢查。想使用Lint命令須要配置Lint環境變量,或者進入%ANDROID_HOME%\tools\bin目錄下數組
會在命令行中輸出相應信息:安全
> 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)
複製代碼
在一個項目目錄下運行lint檢查一系列文件,使用下面的命令:性能優化
lint [flags] <project directory>
複製代碼
例如,你能夠執行下面的命令,來掃描項目目錄下和它的子目錄下的文件。
MissingPrefix問題ID告訴lint只掃描缺乏Android命名空間前綴的XML屬性
lint --check MissingPrefix myproject
複製代碼
該功能容許咱們輸入一個Issue的id來檢查項目中是否存在該id對應的Issue的問題
會在Inspection Results窗口顯示對應的問題信息
Lint 發現的每一個問題都有描述信息和等級,咱們能夠很方便地定位問題,同時按照嚴重程度進行解決。固然這個「嚴重程度」咱們能夠手動調節,有些原則問題不容侵犯,必須提高到 error,而有的個別問題也能夠無視。
1. Correctness
1) DuplicatedIds
Layout中id應該惟一
2) NewApi
代碼中使用的某些API高於Manifest中的Min SDK
3) InconsistentArrays
字符串國際化中,同一名字的的String-Array對應的item值不相同
4) Registered
Activity/Service/ContentProvider沒有經過AndroidManifest註冊
5) Deprecated
使用已經廢棄的API
6) PxUsage
避免使用px,使用dp
7) AppCompatCustomView
Appcompat自定義小部件通常會讓你繼承自 android.support.v7.widget.AppCompat...
不要直接擴展android.widget類,而應該擴展android.support.v7.widget.AppCompat中的一個委託類。
2. Correctness:Messeges
1) MissingTranslation
字符串國際化不徹底
2) ExtraTranslation
國際化的字符串,在默認位置(defaultlocale),沒有定義
3) StringFormatInvalid
若是字符串包含'%'字符,則該字符串多是格式化字符串,將從Java代碼傳遞給String.format以用特定值替換每一個'%'事件。(有可能誤報錯誤)
4) Typos
通常爲Spelling error,該檢查將檢查字符串定義,若是發現任何看起來像拼寫錯誤的單詞,則會對其進行標記。
雖然很常見,但通常不作處理。
3. Correctness:Assertions
1) Assert (warning)
儘可能使用其餘方式替代`Assert`,例如
if (BuildConfig.DEBUG && !(speed > 0)) { throw new AssertionError() }
替代
assert maxSize > 0;
2) UnusedAttribute
此檢查將查找在XML文件中設置的屬性,若是文件的引入版本比應用程序所針對的最舊版本(具備minSdkVersion屬性)要新就會有提示。
若是外觀/功能影響很大/很重要,應考慮其餘實現方式,不然能夠忽略。
3) DuplicateIncludedIds
兩個獨立的佈局使用相同的ID是能夠的。可是,若是佈局與include標籤結合使用,那麼ID在任何狀況下都必須是惟一的。
(例如 Layout_A 經過include引入Layout_B,這兩個佈局不該該有相同ID的標籤)
4. Security
1) SetJavaScriptEnabled
不肯定你的程序中確實須要JavaScript就不要執行SetJavaScriptEnabled。
2)ExportedContentProvider/ExportedReceiver/ExportedService/ExportedActivity
ContentProvider/Receiver/Service/Activity的exported爲true時,設置一個Permission,讓使用者獲取了Permission才能使用。
3) HardcodedDebugMode
不要在manifest中設置android:debuggable。
設置它,編譯的任何版本都要採用指定的debug模式。不設置,編譯Eng版本採用debug模式;編譯User版本採用release模式。
5. Performance
1) DrawAllocation
避免在繪製或者解析佈局(draw/layout)時分配對象。E.g.,Ondraw()中實例化Paint對象。
2) ObsoleteLayoutParam
Layout中無用的參數。
3) UseCompoundDrawables
可優化的佈局:如包含一個Imageview和一個TextView的線性佈局,可被採用CompoundDrawable的TextView代替。
4) UseSparseArrays
儘可能用Android的SparseArray代替Hashmap
5) DisableBaselineAlignment
若是LinearLayout被用於嵌套的layout空間計算,它的android:baselineAligned屬性應該設置成false,以加速layout計算。
6) FloatMath
使用FloatMath代替Math。
7) NestedWeights
避免嵌套weight,那將拖累執行效率
8) UnusedResources/UnusedIds
未使用的資源會讓應用程序變大並減慢了構建速度
9) Overdraw
若是爲RootView指定一個背景Drawable,會先用Theme的背景繪製一遍,而後才用指定的背景,這就是所謂的「Overdraw」。
能夠設置theme的background爲null來避免。
10) UselessLeaf/UselessParent
沒有子級或者背景的layout能夠刪除(由於它是不可見的)
具備子級且沒有兄弟級,不是滾動視圖或根級佈局,且沒有背景的佈局能夠刪除,並將其子級直接移到父級中。
6. Usability:Icons
1) IconNoDpi
Icon在nodpi和指定dpi的目錄下都出現,應刪除一個。
2) GifUsage
Image不要用GIF,最好用PNG,能夠用JPG。
7. Usability
1) BackButton
Android中不要設計有Back的按鈕,Android中通常有Back的硬按鍵。
2) ButtonCase
Button的「Ok」/「Cancel」顯示大小寫必定,不要全大寫或全小寫。有標準的資源的字符串,不要本身再定義,而要用系統定義的:@android:string/ok和@android:string/cancel
8. Accessibility
1) ContentDescription
ImageView和ImageButton應該提供contentDescription
9. Internationalization
1) HardcodeText
硬編碼的字符串應該在資源裏定義
2) EnforceUTF8
全部XML資源文件都應該以UTF-8編碼
...
複製代碼
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)
複製代碼
查看更詳細的信息:
lint --show
或者
訪問 http://tools.android.com/tips/lint-checks
複製代碼
從高到低:
默認狀況下,運行 lint 掃描時,lint 工具會檢查它支持的全部問題。 可是咱們能夠限制 lint 要檢查的問題,併爲這些問題分配嚴重級別。例如,禁止對與項目無關的特定問題進行 lint 檢查,也能夠將 lint 配置爲以較低的嚴重級別報告非關鍵問題。
在項目根目錄建立一個lint.xml文件
lint.xml文件由一個封閉的父標籤組成,它包含了一個或者多個子標籤。Lint爲每個定義了惟一的id屬性值,經過設置標識的安全屬性,你能夠改變一個問題的安全級別,或者這個問題的lint檢查,而且能夠指定該issue做用於指定的文件仍是當前項目。把lint.xml放在app的目錄下(lint.xml
須要放在build.gradle同級目錄),命令行執行lint時候,lint就會用lint.xml中的規則。另外,執行lint時還能夠用參數–config指定一個全局的配置用於全部的項目。當項目中已有lint.xml,則對於某個issue而言,在lint.xml中沒有對該issue特別定製的狀況下,–config指定的文件中的該issue的定製才起做用。
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- 在項目中禁止檢測 id爲 IconMissingDensityFolder的問題 -->
<issue id="IconMissingDensityFolder" severity="ignore" />
<!-- 忽略指定文件中的ObsoleteLayoutParam問題 -->
<issue id="ObsoleteLayoutParam">
<ignore path="res/layout/activation.xml" />
<ignore path="res/layout-xlarge/activation.xml" />
</issue>
<!-- 忽略指定文件中的UselessLeaf問題 -->
<issue id="UselessLeaf">
<ignore path="res/layout/main.xml" />
</issue>
<!-- 將硬編碼字符串(HardcodedText)的嚴重性更改成「錯誤」 -->
<issue id="HardcodedText" severity="error" />
</lint>
複製代碼
要專門對 Android 項目中的某個類或方法停用 lint 檢查,能夠向該代碼添加 @SuppressLint
註釋。
@SuppressLint("NewApi")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
複製代碼
可使用 tools:ignore
屬性對 XML 文件的特定部分停用 lint 檢查。在 lint.xml
文件中添加如下命名空間值,以便 lint 工具可以識別該屬性
namespace xmlns:tools="http://schemas.android.com/tools"
複製代碼
對 XML 佈局文件的 <ConstraintLayout>
元素中的 SmallSp
問題關閉 lint 檢查,
若是某個父元素聲明瞭 ignore
屬性,則該元素的子元素會繼承此屬性。在本例中,也會對 <TextView>
子元素停用 lint 檢查。
此時不會提示SmallSp錯誤
<?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" ------添加命名空間 xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" tools:ignore="SmallSp"> <!--不對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>
複製代碼
禁止 lint 檢查 XML 元素中的全部問題:
tools:ignore="all" 使用關鍵字all
複製代碼
禁止檢查多個問題:
tools:ignore="NewApi,StringFormatInvalid" 使用逗號分隔
複製代碼
android {
// 移除lint檢查的error,能夠避免因爲編譯條件太過嚴格而編譯不過的問題
lintOptions {
// 若是爲 true,則當lint發現錯誤時中止 gradle構建 (默認爲true)
abortOnError false
// 若是爲 true,則只報告錯誤
ignoreWarnings true
// 不檢查給定的問題id InvalidPackage: Package not included in Android
disable 'InvalidPackage'
// 不檢查給定的問題id 資源類型錯誤
disable "ResourceType"
// 忽略因MissingTranslation致使Build Failed錯誤 "app_name"
disable 'MissingTranslation'
// 檢查給定的問題 id
enable 'RtlHardcoded','RtlCompat', 'RtlEnabled'
// * 僅 * 檢查給定的問題 id
check 'NewApi', 'InlinedApi'
// 配置寫入輸出結果的位置;它能夠是一個文件或 「stdout」(標準輸出)
textOutput 'stdout'
// 若是爲真,會生成一個XML報告,以給Jenkins之類的使用
xmlReport false
// 用於寫入報告的文件(若是不指定,默認爲lint-results.xml)
xmlOutput file("lint-report.xml")
// 若是爲真,會生成一個HTML報告(包括問題的解釋,存在此問題的源碼,等等)
htmlReport true
// 寫入報告的路徑,它是可選的(默認爲構建目錄下的 lint-results.html )
htmlOutput file("lint-report.html")
// 設置爲 true, 將使全部release 構建都以issus的嚴重性級別爲fatal
//(severity=false)的設置來運行lint
// 而且,若是發現了致命(fatal)的問題,將會停止構建
//(由上面提到的 abortOnError 控制)
checkReleaseBuilds true
// 設置給定問題的嚴重級別(severity)爲fatal (這意味着他們將會
// 在release構建的期間檢查 (即便 lint 要檢查的問題沒有包含在代碼中)
fatal 'NewApi', 'InlineApi'
// 設置給定問題的嚴重級別爲error
error 'Wakelock', 'TextViewEdits'
// 設置給定問題的嚴重級別爲warning
warning 'ResourceAsColor'
// 設置給定問題的嚴重級別(severity)爲ignore (和不檢查這個問題同樣)
ignore 'TypographyQuotes'
// 若是爲 true,則檢查全部的問題,包括默認不檢查問題
checkAllWarnings true
// 重置 lint 配置(使用默認的嚴重性等設置)。
lintConfig file("default-lint.xml")
// 設置爲 true,則當有錯誤時會顯示文件的全路徑或絕對路徑 (默認狀況下爲true)
absolutePaths true
}
}
複製代碼
before:
add this:
after:
好比這個SmallSp,通常狀況下是一個黃色的警告,在gradle中配置成fatal以後,此處提示爲紅色錯誤,而且在gralde構建時,若是存在SmallSp問題會中止構建。
能夠爲項目的當前警告集建立快照,而後將該快照用做未來運行檢查的基準,以便只報告新問題。 有了基準快照,您即可開始使用 lint 讓構建失敗,而沒必要先返回並解決全部現有問題。
基準 :當前問題集
建立Lint基準快照
修改項目的 build.gradle
文件
android {
lintOptions {
baseline file("lint-baseline.xml")
}
}
複製代碼
首次添加此代碼行時,系統會建立 lint-baseline.xml
文件以創建基準。此後,lint 工具僅讀取該文件以肯定基準。
若是要建立新基準,請手動刪除該文件並再次運行 lint 以從新建立它。
而後,從 IDE(依次選擇 Analyze > Inspect Code)或從命令行運行 lint,以下所示。系統會輸出 lint-baseline.xml
文件的位置。
運行 lint
會將全部當前問題記錄在 lint-baseline.xml
文件中。當前問題集稱爲「基準」,若是要與其餘人共享 lint-baseline.xml
文件,能夠將其加入版本控制。
建立基準後,若是向代碼庫添加任何新警告,lint 將僅列出新引入的錯誤。
如上圖所示,執行上述操做後,會把全部問題都放入 lint-baseline.xml
中,在此以後出現的新問題,會單獨展現出來,例如上圖中的 activity_main saaa not found
Android Studio 附帶了許多 lint 及其餘檢查配置文件,這些配置文件可經過 Android 更新進行更新。您能夠原封不動地使用這些配置文件,也能夠修改它們的名稱、說明、嚴重級別和範圍。您還能夠激活和禁用整組的配置文件或一組配置文件中的個別配置文件。
要訪問 Inspections 對話框,請執行如下操做:
依次選擇 Analyze > Inspect Code。
在 Specify Scope 對話框的 Inspection Profile 下,點擊 More(省略號)。
此時將顯示 Inspections 對話框,其中列出了支持的檢查及其說明。
選擇 Profile 下拉列表,以在 Default (Android Studio) 與 Project Default(活動的項目)檢查之間切換。如需瞭解詳情,請參閱如下 IntelliJ 頁面:「Specify Inspection Scope」對話框。
在左側窗格的 Inspections 對話框中,選擇一個頂級配置文件類別,或展開一個組並選擇特定的配置文件。選擇一個配置文件類別後,您能夠將該類別中的全部檢查項目看成一個檢查項目進行修改。
選擇 Manage 下拉列表,以複製檢查項目、對檢查項目進行重命名、向檢查項目添加說明以及導出/導入檢查項目。
操做完成後,點擊 OK。
Item | Description |
---|---|
Whole project | 選擇此選項能夠對整個項目進行分析。 |
File | 選擇此選項可分析當前在「項目」工具窗口中選擇或在編輯器中打開的文件。 |
Selected files | 選擇此選項可分析「項目」工具窗口中當前選定的文件。 |
Custom scope | 選擇此選項以使用自定義範圍。從列表中選擇一個預約義的範圍,或單擊"(更多)省略號",而後選擇分析的範圍 |
Include test sources | 選擇此複選框以對test sources執行分析。 |
Inspection profile | 選擇一個配置文件以檢查指定範圍。從列表中選擇一個配置文件。若是所需的配置文件不在列表中,請單擊省略號按鈕,而後在頁面上配置所需的配置文件。 |
Android Lint內置了不少lint規則,用來檢測一些常見的代碼問題(例如,正確性問題、安全問題、性能問題,等等)。同時,Android Lint也支持自定義lint規則,以便開發者靈活應用,更好地提高項目代碼質量 。利用自定義lint規則,既能夠用來在項目中檢測代碼質量問題,也能夠用來保證編碼規範的執行。
Detector 是自定義規則的核心,它的做用是掃描代碼,從而獲取代碼中的各類信息,而後基於這些信息進行提醒和報告。
如下是能夠實現的掃描器接口,選擇實現哪一種接口取決於你想要的掃描範圍。
掃描Java源文件的Scanner前後經歷了三個版本。
最開始使用的是JavaScanner,Lint經過Lombok庫將Java源碼解析成AST(抽象語法樹),而後由JavaScanner掃描。
在Android Studio 2.2和lint-api 25.2.0版本中,Lint工具將Lombok AST替換爲PSI,同時棄用JavaScanner,推薦使用JavaPsiScanner。
PSI是JetBrains在IDEA中解析Java源碼生成語法樹後提供的API。相比以前的Lombok AST,能夠支持Java 1.八、類型解析等。使用JavaPsiScanner實現的自定義Lint規則,能夠被加載到Android Studio 2.2+版本中,在編寫Android代碼時實時執行。
在Android Studio 3.0和lint-api 25.4.0版本中,Lint工具將PSI替換爲UAST(通用抽象語法樹),同時推薦使用新的UastScanner。
UAST是JetBrains在IDEA新版本中用於替換PSI的API。UAST更加語言無關,除了支持Java,還能夠支持Kotlin。
PSI(Program Structure Interface)是IDEA中用於解析代碼的一套API,全稱是:程序結構接口 。可將文件的內容表示爲特定編程語言中的元素的層級結構。
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.
每種Psi元素對應一個類,均繼承自com.intellij.psi.PsiElement
。例如PsiMethodCallExpression表示方法調用語句,PsiNewExpression表示對象實例化語句等。
官方文檔
IntelliJ Platform SDK DevGuide www.jetbrains.org/intellij/sd…
UAST全稱是通用抽象語法樹,UAST節點本質上是Java和Kotlin所支持的超集。
使用UAST編寫規則的時候,這個規則會同時適用Java文件和Kotlin文件,無需爲同一個對象編寫兩套規則。
JavaPsiScanner中包含6組、12個回調方法,以下。
getApplicablePsiTypes
返回了須要檢查的Psi元素類型列表時,類型匹配的Psi元素(PsiElement
)就會被createPsiVisitor
返回的JavaElementVisitor
檢查。getApplicableMethodNames
返回方法名的列表時,名稱匹配的方法調用(PsiMethodCallExpression
)就會被visitMethod
檢查。getApplicableConstructorTypes
返回類名的列表時,類名匹配的構造語句(PsiNewExpression
)就會被visitConstructor
檢查。getApplicableReferenceNames
返回引用名的列表時,名稱匹配的引用語句(PsiJavaCodeReferenceElement
)就會被visitReference
檢查。appliesToResourceRefs
返回true時,Java代碼中的資源引用(例如R.layout.main
)就會被visitResourceReference
檢查。applicableSuperClasses
返回父類名的列表時,父類名匹配的類聲明(PsiClass
)就會被checkClass
檢查。此處用第二種作了示例
關鍵代碼:
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", //簡介
"this is explanation", //explanation
Category.USABILITY,
10, //優先級
Severity.ERROR,
new Implementation(MyIssueDetector.class, Scope.JAVA_FILE_SCOPE)
);
@Override
public List<String> getApplicableMethodNames() {
return Arrays.asList("v", "d", "i", "w", "e", "wtf", "Log");
}
/** * @param context lint請求的上下文 * @param node 調用方法的節點 * @param method 被調用的方法 */
@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");
}
}
}
複製代碼
當發現有調用v(),d()
等方法的時候,咱們都會收到回調visitMethodCall
, 由於咱們只是看了方法名,而不知道類,因此須要使用鑑別器(eveluator)進行檢查,
確保它是位於android.util.Log
中的,若是是的話就上報一個用例。
id : 惟一值,應該能簡短描述當前問題。利用Java註解或者XML屬性進行屏蔽時,使用的就是這個id。
summary : 簡短的總結,一般5-6個字符,描述問題而不是修復措施。
explanation : 完整的問題解釋和修復建議。
category : 問題類別。
priority : 優先級。1-10 遞增。
severity : 嚴重級別:Fatal, Error, Warning, Informational, Ignore。
Implementation : 爲Issue和Detector提供映射關係,Detector就是當前Detector。聲明掃描檢測的範圍
Scope:用來描述Detector須要分析時須要考慮的文件集,包括:Resource文件或目錄、Java文件、Class文件。
getApplicableMethodNames
返回值指定了須要被檢查的方法
visitMethodCall
找到與[.getApplicableMethodNames]返回的任何名稱匹配的任何方法調用而調用的方法。
context.report的參數:
第一個參數:是咱們定義的Issue; 第二個參數:根據當前節點返回當前的位置信息,便於在報告中顯示定位; 第三個參數:字符串用來爲警告添加解釋。
MyIssueRegistry
建立好的Issue
要在IssueRegistry
中註冊
IssueRegistry 中註冊了 Android Lint 自帶的 Issue,而自定義的 Issue 則能夠經過 getIssues 系列方法傳入
public class MyIssueRegistry extends IssueRegistry {
@NotNull
@Override
public List<Issue> getIssues() {
return Arrays.asList(
MyIssueDetector.ISSUE_NOT_USE_LOG_UTIL
// , AttrPrefixDetector.ISSUE_XML_NAME
);
}
}
複製代碼
build.gradle
添加lint相關依賴,並生成jar包
apply plugin: 'java-library'
sourceCompatibility = "7"
targetCompatibility = "7"
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')
}
}
複製代碼
其中 lint-api 是 Android Lint 的官方接口,基於這些接口能夠獲取源代碼信息,從而進行分析。
lint-checks 是官方已有的檢查規則。
Lint-Registry 表示給自定義規則註冊,以及打包爲 jar。
將生成的jar包放入~android/lint文件夾中(若是沒有就本身建一個) 我本身的 C:\Users\zhuoy.android\lint
以後使用命令行工具查看是否添加成功:
lint --show issue_id
複製代碼
與此同時,lint --show/list 都可以查看到這條Issue
被測試的代碼:
Google 官方的方案是把 jar 文件放到 ~/.android/lint/,若是本地沒有 lint 目錄能夠自行建立,這個使用方式較爲簡單,但也使得 Android Lint 做用於本地全部的項目,不大靈活。 在主項目中新建一個 Module,將jar引入module,這樣各個項目能夠以 module 的方式自行引入自定義 Lint,比較靈活,項目之間不會形成干擾。
新建一個Android Library, 在build.gradle中添加如下代碼:
configurations {
lintJarImport
}
dependencies {
// 調用lintjar的lintJarOutput方法,得到jar包
lintJarImport project(path: ':lint_lib', configuration: 'lintChecks')
}
// 調用lintJarImport獲得jar包,拷貝到指定目錄
task copyLintJar(type: Copy) {
from(configurations.lintJarImport) {
rename {
String fileName ->
'lint.jar'
}
}
into 'build/intermediates/lint/'
}
// 當項目執行到prepareLintJar這一步時執行copyLintJar方法(注意:這個時機須要根據項目具體狀況改變)
project.afterEvaluate {
def compileLintTask = project.tasks.find { it.name == 'prepareLintJar' }
compileLintTask.dependsOn(copyLintJar)
}
複製代碼
這裏,建立了一個叫「lintJarImport」的Gradle configuration,其引用了模塊 「:lint_lib」的Gradle configuration 「lintChecks」。
同時,對內置的Gradle task 「compileLint」作了修改,讓其依賴於咱們定義的一個task 「copyLintJar」。在task 「copyLintJar」中,把模塊 「:lint_lib」輸出的jar包拷貝到了build/intermediates/lint/lint.jar。
而後執行 gradlew build
看結果
其餘項目只要引入這個lintlibrary便可使用其中定義的Lint規則。
在代碼中也能夠看到高亮提示。
有時IDE給出提示的同時,會有一個ALT+ENTER的快捷鍵來讓咱們直接使用它的建議修改代碼,方便快捷,咱們也能夠如此:
下圖是我修改了一下檢查的內容:發現使用Log.wtf()
的時候,給出提示,而且給一個建議使用Log.e
來代替Log.wtf
。
wtf不是what the fuck,而是 What a terrible failure
實現方式:
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);
}
複製代碼
相較於以前的上報信息,咱們在調用report
方法時,後面加了一個lintFix的參數。
LintFix是Lint的一個快速修復的方式。
independent :此修補程序是否獨立於要應用的其餘修補程序。
robot:當在 fix-mode下運行lint時,能夠自動應用這些類型的修復程序,在該模式下,它將應用全部建議的(合格)修復程序。