通过 PackageManager 获得你想要的 App 信息
一、前言
开门见山,开篇明义。有些场景下,我们会需要获取一些其它 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项目源码。
推荐阅读:
点赞或者分享吧~