Android에서 PackageManager를 이용하면 디바이스에 설치된 앱 리스트를 가져올 수 있습니다. PackageManager는 디바이스에 설치된 패키지를 관리하며, 패키지에 대한 정보를 찾을 수 있는 Query API를 제공합니다.
다음 API를 사용하면 디바이스에 설치된 Package 리스트를 얻을 수 있습니다.
PackageManager.getInstalledPackages()
PackageManager.getInstalledApplications()
PackageManager.getInstalledPackages()
getInstalledPackages()
는 설치된 앱들의 정보를 PackageInfo 리스트로 리턴합니다.
인자로 flags를 전달합니다. 특별한 플래그를 설정하고 싶지 않다면 0을 전달하면 됩니다. 그럼 기본적으로 설치된 앱 리스트들이 리턴됩니다.
val packageManager = context.packageManager
val packages: List<PackageInfo> = packageManager.getInstalledPackages(0)
for (info: PackageInfo in packages) {
Log.d("Test", "packageName: ${info.packageName}"
+ ", versionName: ${info.versionName}"
+ ", lastUpdateTime: ${info.lastUpdateTime}"
+ ", targetSdk: ${info.applicationInfo.targetSdkVersion}"
+ ", minSdk: ${info.applicationInfo.minSdkVersion}"
+ ", sourceDir: ${info.applicationInfo.sourceDir}"
+ ", uid: ${info.applicationInfo.uid}"
+ ", label: ${info.applicationInfo.loadLabel(packageManager)}")
}
로그를 확인해보면 다음과 같이 설치된 앱들의 정보들이 출력됩니다.
09-13 15:56:22.717 13291 13323 D Test : packageName: com.google.android.youtube, versionName: 14.19.57, lastUpdateTime: 1569045019000, targetSdk: 28, minSdk: 21, sourceDir: /system/product/app/YouTube/YouTube.apk, uid: 10132, label: YouTube
....
시스템 앱 리스트만 리턴
설치된 시스템 앱 리스트만 얻고 싶다면, 플래그 인자로 MATCH_SYSTEM_ONLY
를 전달하면 됩니다.
val packages: List<PackageInfo> = packageManager.getInstalledPackages(
PackageManager.MATCH_SYSTEM_ONLY)
삭제된 앱 리스트도 함께 리턴
안드로이드는 멀티 유저 시스템을 지원합니다. 어떤 앱이 현재 실행 중인 User에는 설치되어있지 않고, 다른 User에 설치되어있을 수 있습니다.
이런 경우, 이 앱은 현재 User에는 설치되어있지 않은 상태이기 때문에 getInstalledPackages(0)
의 결과로 리턴되지 않습니다.
현재 User에 삭제된 앱들의 정보도 모두 얻고 싶다면, 플래그 인자로 MATCH_UNINSTALLED_PACKAGES
를 인자로 전달하면 됩니다.
val packages: List<PackageInfo> = packageManager.getInstalledPackages(
PackageManager.MATCH_UNINSTALLED_PACKAGES)
비활성화된 앱 리스트도 함께 리턴
어떤 앱은 설치되어있지만 비활성화되어있을 수 있습니다. 비활성화(disabled)되면 실행이 불가능한 상태로, Launcher에도 아이콘이 보이지 않는 상태입니다.
이런 앱들의 정보도 모두 얻고 싶다면, 플래그 인자로 MATCH_DISABLED_COMPONENTS
를 전달하면 됩니다.
val packages: List<PackageInfo> = packageManager.getInstalledPackages(
PackageManager.MATCH_DISABLED_COMPONENTS)
User Locked 시점에 설치된 모든 앱 리스트 가져오기
Android 7.0부터 Direct Boot가 적용되었습니다.
Direct Boot가 적용된 디바이스의 경우, 만약 부팅 후 사용자가 Lock을 해제하지 않으면 User는 Locked 상태가 됩니다.
그리고 User Locked 상태일 때는 DIRECT_BOOT_AWARE
으로 설정되지 않은 앱은 실행이 불가능한 상태가 됩니다.
이 시점에 getInstalledPackages(0)
을 호출하면 DIRECT_BOOT_AWARE
으로 설정된 앱 리스트만 리턴됩니다.
만약 설치된 모든 앱 리스트를 얻고 싶다면 PackageManager.MATCH_DIRECT_BOOT_UNAWARE
플래그를 인자로 전달해야 합니다.
하지만 다음과 같이, 하나의 플래그만 전달하기 보다 AWARE와 UNAWARE 두개의 플래그를 모두 전달하도록 구현하시는 것이 좋습니다. (Direct boot에 영향을 받지 않고 모든 패키지를 찾고 싶다는 의도를 보여줄 수 있습니다.)
val flags = PackageManager.MATCH_DIRECT_BOOT_AWARE or PackageManager.MATCH_DIRECT_BOOT_UNAWARE
val packages: List<PackageInfo> = packageManager.getInstalledPackages(flags)
PackageManager.getInstalledApplications()
getInstalledPackages()
API는 PackageInfo 리스트를 리턴합니다. PackageInfo는 ApplicationInfo를 갖고 있습니다.
하지만 ApplicationInfo만 필요한 경우, getInstalledApplications()
API를 사용할 수도 있습니다. 이 API는 ApplicationInfo 리스트를 리턴합니다.
다음과 같이 구현할 수 있습니다.
val packageManager = context.packageManager
val flag = 0;
val applications: List<ApplicationInfo> = packageManager.getInstalledApplications(flag)
for (info: ApplicationInfo in applications) {
Log.d("Test", "packageName: ${info.packageName}"
+ ", targetSdk: ${info.targetSdkVersion}"
+ ", minSdk: ${info.minSdkVersion}"
+ ", sourceDir: ${info.sourceDir}"
+ ", uid: ${info.uid}"
+ ", label: ${info.loadLabel(packageManager)}")
}
플래그 설정 방법은 getInstalledPackages()
에서 사용한 것과 동일한 방식으로 사용하시면 됩니다.
특정 Package 설치 여부 확인
위의 API들은 모든 패키지 리스트를 리턴하였습니다.
만약 특정 App이 설치되어있는지 확인하고 싶을 때는 getPackageInfo(packageName, flags)
API를 사용할 수 있습니다.
다음과 같이 인자로 PackageName을 전달하면 이 앱에 대한 정보를 얻을 수 있습니다. PackageInfo가 리턴된다면 설치된 앱이고, NameNotFoundException가 발생한다면 설치되지 않은 앱입니다.
val packageManager = context.packageManager
val flag = 0;
val packageName = "com.google.android.youtube"
try {
val info: PackageInfo = packageManager.getPackageInfo(
packageName, flag
)
} catch (e: PackageManager.NameNotFoundException) {
Log.d("Test", "Not found package : $packageName")
}
다음과 같이 getApplicationInfo(packageName, flags)
를 사용할 수도 있습니다.
앱이 설치되어있지 않은 경우 NameNotFoundException가 리턴됩니다.
val info: ApplicationInfo = packageManager.getApplicationInfo(
"com.google.android.youtube", flag)
Package Visibility
Android 11에서 Package Visibility라는 기능이 추가되었습니다. Package Visibility는 Target SDK 30인 앱에게만 적용이 되며, 다른 앱의 정보를 얻으려면 AndroidManifest에 미리 정의를 해야 한다는 것입니다. 그렇지 않으면, 다른 앱의 정보를 얻을 수 없습니다.
만약 다른 앱의 정보를 얻으려고 PackageManager.getInstalledPackages()
를 호출했다면, 일부 중요 시스템 앱을 제외한 다른 앱들은 리스트에 포함안됩니다.
Manifest에 다음과 같은 퍼미션을 추가하면 모든 패키지의 정보를 얻을 수 있습니다.
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
더 자세한 정보는 Package Visibility를 확인해주세요.
adb 명령어로 설치된 패키지 정보 확인
adb shell pm list package
명령어를 입력하면 디바이스에 설치된 패키지 이름이 출력됩니다.
$ adb shell pm list package
package:com.android.cts.priv.ctsshim
package:com.google.android.youtube
package:com.android.internal.display.cutout.emulation.corner
package:com.google.android.ext.services
package:com.android.internal.display.cutout.emulation.double
package:com.android.providers.telephony
package:com.android.dynsystem
package:com.google.android.googlequicksearchbox
package:com.android.providers.calendar
package:com.android.providers.media
....
특정 패키지에 대해서 자세한 정보를 알고 싶다면, adb shell dumpsys package [package name]
으로 확인할 수 있습니다.
$ adb shell dumpsys package com.google.android.youtube
Packages:
Package [com.google.android.youtube] (3d92a10):
userId=10132
pkg=Package{4e1cc5 com.google.android.youtube}
codePath=/system/product/app/YouTube
resourcePath=/system/product/app/YouTube
legacyNativeLibraryDir=/system/product/app/YouTube/lib
primaryCpuAbi=x86
secondaryCpuAbi=null
versionCode=1419573700 minSdk=21 targetSdk=28
versionName=14.19.57
splits=[base]
apkSigningVersion=3
applicationInfo=ApplicationInfo{ed73c com.google.android.youtube}
flags=[ SYSTEM HAS_CODE ALLOW_CLEAR_USER_DATA ALLOW_BACKUP KILL_AFTER_RESTORE RESTORE_ANY_VERSION LARGE_HEAP ]
privateFlags=[ PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE HAS_DOMAIN_URLS PRODUCT ]
dataDir=/data/user/0/com.google.android.youtube
....
Related Posts
- Android 14 - 사진/동영상 파일, 일부 접근 권한 소개
- Android - adb push, pull로 파일 복사, 다운로드
- Android 14 - 암시적 인텐트 변경사항 및 문제 해결
- Jetpack Compose - Row와 Column
- Android 13, AOSP 오픈소스 다운로드 및 빌드
- Android 13 - 세분화된 미디어 파일 권한
- Android 13에서 Notification 권한 요청, 알림 띄우기
- Android 13에서 'Access blocked: ComponentInfo' 에러 해결
- 에러 해결: android gradle plugin requires java 11 to run. you are currently using java 1.8.
- 안드로이드 - 코루틴과 Retrofit으로 비동기 통신 예제
- 안드로이드 - 코루틴으로 URL 이미지 불러오기
- Android - 진동, Vibrator, VibrationEffect 예제
- Some problems were found with the configuration of task 에러 수정
- Query method parameters should either be a type that can be converted into a database column or a List
- 우분투에서 Android 12 오픈소스 다운로드 및 빌드
- Android - ViewModel을 생성하는 방법
- Android - Transformations.map(), switchMap() 차이점
- Android - Transformations.distinctUntilChanged() 소개
- Android - TabLayout 구현 방법 (+ ViewPager2)
- Android - 휴대폰 전화번호 가져오는 방법
- Android 12 - Splash Screens 알아보기
- Android 12 - Incremental Install (Play as you Download) 소개
- Android - adb 명령어로 bugreport 로그 파일 추출
- Android - adb 명령어로 App 데이터 삭제
- Android - adb 명령어로 앱 비활성화, 활성화
- Android - adb 명령어로 특정 패키지의 PID 찾기
- Android - adb 명령어로 퍼미션 Grant 또는 Revoke
- Android - adb 명령어로 apk 설치, 삭제
- Android - adb 명령어로 특정 패키지의 프로세스 종료
- Android - adb 명령어로 screen capture 저장
- Android - adb 명령어로 System 앱 삭제, 설치
- Android - adb 명령어로 settings value 확인, 변경
- Android 12 - IntentFilter의 exported 명시적 선언
- Android - adb 명령어로 공장초기화(Factory reset)
- Android - adb logcat 명령어로 로그 출력