一、前言
開門見山,開篇明義。有些場景下,我們會需要獲取一些其它 App 的各項資訊,例如:App 名稱,包名、Icon 等。這個時候就需要使用到 PackageManager 這個類了。
本篇就 PackageManager 的使用,做一個詳盡的講解,助你拿到各項 App 的資訊,當然也包括一些未安裝的 App 的資訊。
二、需要提前瞭解的一些類
當你需要獲取到指定 App 的各項資訊的時候,你需要操作一些 Android 為我們提供的對應的 Api。
你首先需要獲取 PackageManager(以下簡稱 PM) 物件,通過 PM 物件,你就可以獲取到你需要的各項 App 的資訊類。
這裡涉及到的 App 資訊類包括:PackageInfo、ApplicationInfo、ActivityInfo/ServiceInfo/ProviderInfo 等,還有一個 ResolveInfo 類,它比較特殊一點,不和前面的結構為從屬關係。
這些類,都可以在根據 AndroidManifest.xml 中定義的元件進行劃分,大概的結構如下。
可以看到,它們之間的關係還它挺複雜的。
一個 PackageInfo 對應一個 ApplicationInfo,而其中又包含若干個 ActivityInfo、ServiceInfo、ProviderInfo。
2.1 PackageManager
PackageManager 是一個抽象類,我們一般操作的 PackageManager ,實際上是它的實現類 ApplicationPackageManager 這個物件。
在 Context 中,就有獲取 PM 物件的方法,getPackageManager()
,所以四大元件想要獲取它是非常簡單的。
PM 中,提供了非常多的方法,供我們通過不同的條件,獲取到 PackageInfo 物件、ApplicationInfo 物件等,它是本文的基礎。
2.2 PackageInfo
PackageInfo 從名稱上也可以看出來,它主要用於儲存獲取到的 Package 的一些資訊,包括:包名(packageName)、版本號(versionCode)、版本名(versionName)。
基本上拿到了 PackageInfo ,你就可以拿到大部分此 Apk 相關的資訊了。
並且,PackageInfo 中有一個 applicationInfo 的欄位,是可以直接獲取到與它相關的 ApplicationInfo 物件的。
這裡介紹幾個 PackageInfo 中,比較常用的欄位:
- packageName:包名。
- versionCode:版本號
- versionName:版本名。
- firstInstallTime:首次安裝時間。
- lastUpdateTime:最後一次覆蓋安裝時間。
2.3 ApplicationInfo
ApplicationInfo 相對於 PackageInfo 用的會比較少一些。它主要用於獲取 Apk 定義在 AndroidManifest.xml 中的一些資訊。
這裡介紹幾個比價常用的:
- packageName:包名
- targetSdkVersion:目標 SDK 版本。
- minSdkVersion:最小支援 SDK 版本,有 Api 限制,最低在 Api Level 24 及以上支援。
- sourceDir:App 的 Apk 原始檔存放的目錄。
- dataDir:data 目錄的全路徑。
- metaData:Manifest 中定義的 meta 標籤資料。
- uid:當前 App 分配的 uid。
可以看到 ApplicationInfo 涵蓋的資訊,基本上都是在 AndroidManifest.xml 中定義的資訊,並且有一些屬性是有 Api Level 限制的,所以不確定的屬性,提前看一下文件,確定是否全版本支援。
2.4 ActivityInfo
ActivityInfo、ServiceInfo、ProviderInfo 這三個是平級的,熟悉的一眼就能看出來,它們就是 Android 定義的四大元件中的幾個。各自涵蓋了一部分資訊。一般在外部獲取其他 App 的資訊的時候,不會獲取到這麼細緻的資料,如果有,看看這幾個類準沒錯。
那麼就不再費時去介紹它們了。
三、基本操作
到現在基本上就已經瞭解到在當前裝置上獲取到 Apk 資訊的各項類了。
直接擺原始碼說屬性有點枯燥。接下來我們就帶著實際問題,來看看具體如何使用 PM。
3.1 獲取所有安裝的 App
如果想要獲取當前裝置上已經安裝的所有 App,可以使用 getInstalledPackages()
方法獲取到它所有的已安裝 App 的 PackageInfo 。
PackageManager 中,很多方法都會需要傳遞一個 flags 的欄位,它表示你當前需要獲取到的 App 的資訊。取值範圍有挺多的,獲取不同的資訊使用不同的 Flags,通常如果沒有額外的要求,直接使用 GET_ACTIVITYS 即可。
3.2 判斷 App 是否安裝
這裡主要說的是通過包名,判斷 App 是否安裝在當前裝置上。
最簡單的邏輯就是去獲取 PackageInfo ,如果能拿回來資料,就說明是有安裝的。
3.3 通過包名獲取PackageInfo
其實前面判斷 App 是否安裝的時候,就已經獲取到了 PackageInfo 資訊,這裡只需要將它返回出去即可。
3.4 獲取版本號和版本名
這裡只需要根據 PackageInfo 中的欄位,獲取到對應的值就好了。
3.5 獲取 App 的名稱
獲取 App 的名稱,就需要用到 ApplicationInfo 這個物件了,其中 loadLabel()
方法返回的,就是 App 的名稱。
3.6 獲取 App 的 Icon
在 ApplicationInfo 中,還可以通過 loadIcon()
獲取到 App 的 Icon。它返回的是一個 Drawable 物件,可以直接使用。
3.5 根據Apk 檔案,獲取 PackageInfo
前面介紹的方法,都是基於一個已安裝的 App 的包名,來獲取額外的資訊。
但是有時候,我們只有一個未安裝的 Apk 檔案,想要解析出 Apk 檔案中的額外資訊,PM 中,也有對應的 Api。非常的方便,直接使用 getPackageArchiveInfo()
即可。
只要拿到這個 Apk 檔案相關的 PackageInfo 資訊,就有辦法拿到其他的名稱、icon 、版本號、版本名、包名等資訊。和前面介紹的例子類似,這裡就不再一一列舉了。
四、查缺補漏
整體來說,到這裡已經講解清楚如何使用 PM 獲取 App 的基本資訊。
但是並不包含 App 在執行時的一些記憶體的情況,哪些資料你想獲取,單單依靠 PackageManager 是做不到的,就不再這裡展開說了,有機會再詳細說明一下。
還有就是,PM 中,很多方法,都是有可能觸發 『Package manager has died』這個 RuntimeException 的,其實就是很多個執行緒在頻繁呼叫。如果想要避免,加鎖加快取即可。具體的情況,可以看看我之前的文章《PackageManager可以亂用嗎?》。
今天在承香墨影公眾號的後臺,回覆『成長』。我會送你一些我整理的學習資料,包含:Android反編譯、演算法。Web專案原始碼。
推薦閱讀:
點贊或者分享吧~