我們可以通過PackageManager獲取PackageInfo,既而獲得應用包相關的各種信息,除了之前說過的可以獲取包名、版本號、圖標、入口Activity、Application、文件md5/sha1/sha256等等,我們還可以獲取應用的四大組件列表,以及組件具體詳情。
PackageInfo info = pm.getPackageInfo(mPackageName, PackageManager.GET_ACTIVITIES
| PackageManager.GET_RECEIVERS
| PackageManager.GET_SERVICES
| PackageManager.GET_PROVIDERS
| PackageManager.GET_INTENT_FILTERS
| PackageManager.GET_META_DATA
| PackageManager.GET_DISABLED_COMPONENTS);
獲取PackageInfo要注意flags參數,否則獲取不到相應信息。
info.activities; //activity列表, ActivityInfo[]類型
info.receivers; //broadcast receiver列表 ActivityInfo[]類型
info.services; //service列表, ServiceInfo[]類型
info.activities; //provider列表, ProviderInfo[]類型
其中,對於組件來說,有兩個字段我最關心:
info.exported;
info.enabled;
自此,我們做一個顯示應用的四大組件列表功能所需的一切就都齊了。
截圖來自 android開發工具箱, 點我下載 android開發工具箱
組件詳情就比較麻煩了,因爲四大組件的屬性都不一樣,而且由於android版本不同,字段也有所區別。下面只拿Activity舉例。
有一些字段我們是可以直接從ActivityInfo獲取的,比如
info.enabled;
info.exported;
info.processName;
info.permission;
info.parentActivityName;
有一些字段,我們需要做一下映射,比如launchMode。info.launchMode是int類型
public class ActivityInfo extends ComponentInfo implements Parcelable {
public static final int LAUNCH_MULTIPLE = 0;
public static final int LAUNCH_SINGLE_TOP = 1;
public static final int LAUNCH_SINGLE_TASK = 2;
public static final int LAUNCH_SINGLE_INSTANCE = 3;
}
除了launchMode之外,colorMode、screenOrientation、uiOptions等等也是需要進行類似的轉換的。
如果不想寫很多的switch-case之類的代碼,也可以使用反射。比如launchMode,我們可以將`ActivityInfo`類中,所有靜態且以LAUNCH_開頭的常量一一遍歷,與info.launchMode值相同的話,我們顯示field.getName()即可。
還有一種情況,比如flags等字段,是多種類型的組合,我們也一樣可以使用反射。以flags爲例:
public static final int FLAG_MULTIPROCESS = 0x0001;
public static final int FLAG_FINISH_ON_TASK_LAUNCH = 0x0002;
public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 0x0004;
...
只是我們不能使用相等來作爲判斷條件了,需要做個位運算:
if ((flags & fieldValue) == fieldValue) {
//滿足條件,field.getName()
}
除此之外,還有兩個特殊的,一個是theme一個是softInputMode。
先說theme,通過PackageInfo,我們只能拿到themeId,我們知道,想要獲取theme名字,可以通過如下方式:
resources.getResourceName(themeId);
//或者
resources.getResourceEntryName(themeId);
需要注意的是,我們不能使用自己的Resources對象來獲取其他應用的主題信息,我們需要拿到對應應用的Resources
context.getPackageManager().getResourcesForApplication(packageName);
再看softInputMode,我們也是沒有辦法直接拿到softInputMode對應的可讀的描述,但是InputMethodClient提供了相應的方法,不過也是hide方法,複製出來即可。
public static String softInputModeToString(final int softInputMode) {
final StringBuilder sb = new StringBuilder();
final int state = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE;
final int adjust = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
final boolean isForwardNav =
(softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0;
switch (state) {
case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
sb.append("stateUnspecified");
break;
case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
sb.append("stateUnchanged");
break;
case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
sb.append("stateHidden");
break;
case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
sb.append("stateAlwaysHidden");
break;
case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
sb.append("stateVisible");
break;
case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
sb.append("stateAlwaysVisible");
break;
default:
sb.append("stateUnknown(");
sb.append(state);
sb.append(")");
break;
}
switch (adjust) {
case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED:
sb.append("|adjustUnspecified");
break;
case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE:
sb.append("|adjustResize");
break;
case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN:
sb.append("|adjustPan");
break;
case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING:
sb.append("|adjustNothing");
break;
default:
sb.append("|adjustUnknown(");
sb.append(adjust);
sb.append(")");
break;
}
if (isForwardNav) {
// This is a special bit that is set by the system only during the window navigation.
sb.append("|isForwardNavigation");
}
return sb.toString();
}
這樣,我們就拿到Activity相關的所有信息。另外三個組件也類似,不再一一演示。
截圖來自 android開發工具箱, 點我下載 android開發工具箱