2015年1月24日 星期六

使用 Lint 檢查是否使用大於 minSDKVersion 的 API

Lint 是一個 Android SDK 內建的靜態分析工具,放在 SDK 的 tools 資料夾底下,如果已經將編譯工具轉換至 Gradle 後,每次編譯皆會自動執行 Lint 來檢查專案的安全性、效能等潛在問題。

一般來說,在專案的 AndroidManifest.xml 我們會撰寫 minSdkVersion 和 targetSdkVersion 兩個值,假設我們 min 設為 14 且 target 設為 21 時,在使用了某些 Level 19 才提供的 API 例如 PackageManager.queryIntentContentProviders 時,將會讓 Level 14~18 的 Device 發生 Exception 而 Crash,這種狀況預設的 Lint 檢查是無法預防的,必須加上特定的參數如下。

lintOptions {
   abortOnError false
   fatal 'NewApi', 'InlineApi', 'ResourceType'
}

在設定了 NewApi 為 fatal 後,在 min 14 與 + target 21 專案若使用了上一段所說的 queryIntentContentProviders API 編譯完後,即會在 Linet Report 中被列為以下 Error

Call requires API level 19 (current min is 14): `android.content.pm.PackageManager#queryIntentContentProviders`
This check scans through all the Android API calls in the application and warns about any calls that are not available on *all* versions targeted by this application (according to its minimum SDK attribute in the manifest). If you really want to use this API and don't need to support older devices just set the `minSdkVersion` in your `build.gradle` or `AndroidManifest.xml` files. If your code is *deliberately* accessing newer APIs, and you have ensured (e.g. with conditional execution) that this code will only ever be called on a supported platform, then you can annotate your class or method with the `@TargetApi` annotation specifying the local minimum SDK to apply, such as `@TargetApi(11)`, such that this check considers 11 rather than your manifest file's minimum SDK as the required API level. If you are deliberately setting `android:` attributes in style definitions, make sure you place this in a `values-vNN` folder in order to avoid running into runtime conflicts on certain devices where manufacturers have added custom attributes whose ids conflict with the new ones on later platforms. Similarly, you can use tools:targetApi="11" in an XML file to indicate that the element will only be inflated in an adequate context.

  return getPackageManager().queryIntentContentProviders(null, 0);
                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~


如果你不想讓這段 Error 持續出現,有兩個解法,一是換另個 API,另一個是為使用這支 API 的 function 或 class 加上 annotation 如下範例

private void checkPackageInformation() {
  List<ResolveInfo> list = getResolveInfoList();
}

@TargetApi(19)
private List<ResolveInfo> getResolveInfoList() {
 // 在使用此 API 的 function 加上對應 Level 值的 annotation
 return getPackageManager().queryIntentContentProviders(null, 0);
}


沒有留言:

張貼留言