天天看點

PackageManager解析

PackageManager:管理應用程式包

功能:

  • 安裝,解除安裝應用
  • 查詢permission相關資訊
  • 查詢Application相關資訊(application,activity,receiver,service,provider及相應屬性等)
  • 查詢已安裝應用
  • 增加,删除permission
  • 清除使用者資料、緩存,代碼段等

使用方法:

在Android中,為應用包的安裝,删除各種操作服務的,是PackageManagerSerivce,簡稱PMS.

如果想要調用PMS的服務,則可以通過Context去調用getPackageManager方法。

/** Return PackageManager instance to find global package information. */
    public abstract PackageManager getPackageManager();
           

這個定義于Context.java中:

PackageManager解析

查詢Application相關資訊

應用元件集合查詢API

一、根據包名擷取應用資訊

ApplicationInfo getApplicationInfo (String packageName,int flags)
           

參數:flags

  • GET_SHARED_LIBRARY_FILES:擷取so庫的安裝路徑,然後可以通過ApplicationInfo的sharedLibraryFiles屬性來讀取相關資訊。
  • MATCH_SYSTEM_ONLY:隻包括帶有系統屬性的
  • MATCH_UNINSTALLED_PACKAGES:即使是應用被uninstall了,但隻要保留了資料,也可以被搜出來。

二、擷取目前系統上安裝的所有的應用程式

List<ApplicationInfo> getInstalledApplications (int flags);
           

參數:flags

  • GET_META_DATA:
  • GET_SHARED_LIBRARY_FILES:擷取so庫的安裝路徑,然後可以通過ApplicationInfo的sharedLibraryFiles屬性來讀取相關資訊。
  • MATCH_SYSTEM_ONLY:隻包括帶有系統屬性的
  • MATCH_UNINSTALLED_PACKAGES:即使是應用被uninstall了,但隻要保留了資料,也可以被搜出來。

三、擷取目前系統中安裝的所有包

List<PackageInfo> getInstalledPackages (int flags)
           

參數:flags

* PackageManager.GET_ACTIVITIES

* PackageManager.GET_CONFIGURATIONS

* PackageManager.GET_GIDS

* PackageManager.GET_INSTRUMENTATION

* PackageManager.GET_INTENT_FILTERS

* PackageManager.GET_META_DATA

* PackageManager.GET_PERMISSIONS

* PackageManager.GET_PROVIDERS

* PackageManager.GET_RECEIVERS

* PackageManager.GET_SERVICES

* PackageManager.GET_SHARED_LIBRARY_FILES

* PackageManager.GET_SIGNATURES

* PackageManager.GET_URI_PERMISSION_PATTERN

四、根據包名擷取一個包的資訊

PackageInfo getPackageInfo (String packageName, int flags);
           

參數:flags

* PackageManager.GET_ACTIVITIES

* PackageManager.GET_CONFIGURATIONS

* PackageManager.GET_GIDS

* PackageManager.GET_INSTRUMENTATION

* PackageManager.GET_INTENT_FILTERS

* PackageManager.GET_META_DATA

* PackageManager.GET_PERMISSIONS

* PackageManager.GET_PROVIDERS

* PackageManager.GET_RECEIVERS

* PackageManager.GET_SERVICES

* PackageManager.GET_SHARED_LIBRARY_FILES

* PackageManager.GET_SIGNATURES

* PackageManager.GET_URI_PERMISSION_PATTERN

五、從封包件中讀取getPackageArchiveInfo

public PackageInfo getPackageArchiveInfo(String archiveFilePath,  int flags)
           

參數:flags

* PackageManager.GET_ACTIVITIES

* PackageManager.GET_CONFIGURATIONS

* PackageManager.GET_GIDS

* PackageManager.GET_INSTRUMENTATION

* PackageManager.GET_INTENT_FILTERS

* PackageManager.GET_META_DATA

* PackageManager.GET_PERMISSIONS

* PackageManager.GET_PROVIDERS

* PackageManager.GET_RECEIVERS

* PackageManager.GET_SERVICES

* PackageManager.GET_SHARED_LIBRARY_FILES

* PackageManager.GET_SIGNATURES

* PackageManager.GET_URI_PERMISSION_PATTERN

六、根據Activity的名稱來擷取ActivityInfo

ActivityInfo getActivityInfo (ComponentName component, int flags)
           

ComponentName是個什麼類呢?其實就是包名和類名的組合:

//Create a new component identifier.
ComponentName(String pkg, String cls);
           

特别要注意,類名是要全路徑名,不然會找不到的!

try {
            final ActivityInfo ai = mPm.getActivityInfo(new ComponentName("com.android.htmlviewer","com.android.htmlviewer.HTMLViewerActivity"),
                    PackageManager.GET_META_DATA | PackageManager.MATCH_ALL);
            Log.d(TAG,"ActivityInfo:"+ai.toString());
            Log.d(TAG,"ActivityInfo,parentActivityName is:"+ai.parentActivityName);
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG,"testGetActivityInfo error",e);
        }
           

參數:

flags

七、根據名字擷取Instrumentation資訊,這個資訊在AndroidManifest.xml中的中定義

InstrumentationInfo getInstrumentationInfo (ComponentName className, int flags);
           

八、通過ComponentName擷取ServiceInfo

ServiceInfo getServiceInfo (ComponentName component, int flags);
           

九、根據ComponentName擷取ReceiverInfo

有同學問了,既然可以查詢ActivityInfo,ServiceInfo,ReceiverInfo,四大元件中都有三個了,那麼為什麼沒有查詢ProviderInfo的呢?

getProviderInfo這個API直到Android 2.3時才有

ActivityInfo getReceiverInfo (ComponentName component, int flags);
           

十、Android 2.3新增API - getProviderInfo

ProviderInfo getProviderInfo (ComponentName component, int flags);
           

Uid/Gid相關查詢API

一、讀取和包名相關的Group id

ProviderInfo getProviderInfo (ComponentName component, int flags);
           
public void testGetPackageGids(){
        try {
            int[] gids = mPm.getPackageGids("com.android.externalstorage");
            if(gids!=null){
                for(int gid:gids){
                    Log.d(TAG,"gid:"+gid);
                }
            }
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG,"testGetPackageGids error",e);
        }
    }
           

輸出

- :: -/? D/TestPackageManager: gid:
- :: -/? D/TestPackageManager: gid:
           

二、getPackagesForUid

ProviderInfo getProviderInfo (ComponentName component, int flags);
           
public void testGetPackagesForUid(){
        String[] packagesForUid = mPm.getPackagesForUid();
        if(packagesForUid!=null){
            for(String package1 : packagesForUid){
                Log.d(TAG, "Package name in 1000:"+package1);
            }
        }
    }
           

輸出

- :: -/? D/TestPackageManager: Package name in :com.mediatek
- :: -/? D/TestPackageManager: Package name in :com.mediatek.thermalmanager
- :: -/? D/TestPackageManager: Package name in :com.mediatek.batterywarning
- :: -/? D/TestPackageManager: Package name in :com.mediatek.connectivity
- :: -/? D/TestPackageManager: Package name in :com.android.server.telecom
- :: -/? D/TestPackageManager: Package name in :com.android.inputdevices
- :: -/? D/TestPackageManager: Package name in :com.android.settings
- :: -/? D/TestPackageManager: Package name in :android
- :: -/? D/TestPackageManager: Package name in :com.mediatek.atci.service
- :: -/? D/TestPackageManager: Package name in :com.android.providers.settings
- :: -/? D/TestPackageManager: Package name in :com.android.vpndialogs
- :: -/? D/TestPackageManager: Package name in :com.mediatek.ppl
- :: -/? D/TestPackageManager: Package name in :com.android.location.fused
- :: -/? D/TestPackageManager: Package name in :com.mediatek.nlpservice
- :: -/? D/TestPackageManager: Package name in :com.mediatek.schpwronoff
- :: -/? D/TestPackageManager: Package name in :com.android.keychain
           

三、查詢一個uid對應的名字

String getNameForUid (int uid);
           
public void testGetNameForUid(){
        String name = mPm.getNameForUid();
        Log.d(TAG,"Name for uid 1000 is:"+name);
    }
           

輸出

- :: -/? D/TestPackageManager: Name for uid  is:android.uid.system:
           

Uid/Gid相關查詢API

一、查詢系統中運作的ContentProvider

List<ProviderInfo> queryContentProviders (String processName,int uid,int flags)
           

參數:

程序名:如果希望列出所有的,就為空

uid:如果程序名不為空,需要指定uid

标志位:match的屬性

public void testQueryContentProviders() {
        List<ProviderInfo> pis = mPm.queryContentProviders(null, , PackageManager.MATCH_ALL);
        if (pis != null) {
            for (ProviderInfo pri : pis) {
                Log.d(TAG, "Provider info:" + pri);
            }
        }
    }
           

輸出

- :: -/? D/TestPackageManager: Provider info:ContentProviderInfo{name=settings className=com.android.providers.settings.SettingsProvider}
- :: -/? D/TestPackageManager: Provider info:ContentProviderInfo{name=com.tencent.mm.plugin.ext.NearBy className=com.tencent.mm.plugin.ext.provider.ExtControlProviderNearBy}
- :: -/? D/TestPackageManager: Provider info:ContentProviderInfo{name=mwimsg className=com.android.providers.telephony.MwiProvider}
           

二、根據包名查詢Instrumentation

List<InstrumentationInfo> queryInstrumentation (String targetPackage,int flags);
           

參數:

包名:如果是所有的包,則給null

标志:隻支援GET_META_DATA這一個。

public void testQueryInstrumentation(){
        List<InstrumentationInfo> list = mPm.queryInstrumentation(null,PackageManager.GET_META_DATA);
        if(list!=null){
            for(InstrumentationInfo ii : list){
                Log.d(TAG,"Instrumentation info:"+ii.toString());
            }
        }
    }
           

根據Intent查詢相關元件的API

一、根據Intent查詢可以處理這個Intent的所有BroadcastReceivers

List<ResolveInfo> queryBroadcastReceivers (Intent intent,int flags);
           

二、查詢可以處理這個Intent的所有Activity

List<ResolveInfo> queryIntentActivities (Intent intent,int flags);
           

參數:

Intent

參數:MATCH_ALL等

三、queryIntentActivityOptions跟queryIntentActivities基本一樣,支援更多的查詢條件

List<ResolveInfo> queryIntentActivityOptions (ComponentName caller, Intent[] specifics, Intent intent,int flags);
           

四、查詢可以處理這個Intent的所有Service

List<ResolveInfo> queryIntentServices (Intent intent,int flags);
           

大家都知道,Android有四大元件:Activity, Service, BroadcastReceiver和ContentProvider。前面三個元件都可以通過Intent查詢了,為什麼沒有queryIntentContentProviders呢?

queryIntentContentProviders直到Android 4.4才增加進來。

五、Android 4.4新增API: queryIntentContentProviders,查詢可以處理這個Intent的所有ContentProvider們

List<ResolveInfo> queryIntentContentProviders (Intent intent, int flags);
           

根據Intent查詢最佳應用元件API

一、resolveActivity:查找最适合些Intent的Activity

ResolveInfo resolveActivity (Intent intent, int flags);
           

二、resolveContentProvider:查找最适合些Intent的ContentProvider

ResolveInfo resolveContentProvider (Intent intent, int flags);
           

三、resolveService:查找最适合些Intent的服務

ResolveInfo resolveService (Intent intent, int flags);
           

上面3個API都是拿到了Intent再去判斷它最适合的應用元件。那麼,我們想要做逆運算,知道一個包了,如何去得到啟動它的Intent呢?

這個API直到Android 1.5(API 3)時才加入系統中:getLaunchIntentForPackage

事、resolveService:查找最适合些Intent的服務

Intent getLaunchIntentForPackage (String packageName);
           

例程:我們想擷取微信的啟動Intent:

public void testGetLaunchIntentForPackage() {
        Intent intent = mPm.getLaunchIntentForPackage("com.tencent.mm");
        if (intent != null) {
            Log.d(TAG, "Intent for Launch this is:" + intent.toString());
        }
    }
           

運作結果如下,原來啟動微信的界面是com.tencent.mm.ui.LauncherUI。

- :: -/? D/TestPackageManager: Intent for Launch this is:Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=x10000000 pkg=com.tencent.mm cmp=com.tencent.mm/.ui.LauncherUI }
           

一個查詢應用資訊的例子

package com.bourne.android_common.PackageManagerDemo;

import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import com.bourne.android_common.R;
import com.bourne.common_library.utils.Logout;

import java.util.Collections;
import java.util.List;

public class PackagerManagerActivity extends AppCompatActivity {
    // 所有應用程式
    public static final int FILTER_ALL_APP = ;
    // 系統程式
    public static final int FILTER_SYSTEM_APP = ;
    // 第三方應用程式
    public static final int FILTER_THIRD_APP = ;
    // 安裝在SDCard的應用程式
    public static final int FILTER_SDCARD_APP = ;

    private PackageManager pm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_packager_manager);
//        Logout.e("擷取所有程式資訊");
//        getPackageInfo();
//        Logout.e("根據包名擷取應用資訊");
//        getAppInfoByPackageName("com.bourne.android_common");
//        Logout.e("擷取所有程式的Activity");
//        getInstalledPackages();
        Logout.e("系統程式");
        filterApp(FILTER_SYSTEM_APP);
        Logout.e("第三方應用程式");
        filterApp(FILTER_THIRD_APP);
        Logout.e("安裝在SDCard的應用程式");
        filterApp(FILTER_SDCARD_APP);

    }

    /**
     * 擷取所有程式資訊
     * 通過PackageManager的queryIntentActivities方法,
     * 查詢系統中所有滿足ACTION_MAIN和CATEGORY_LAUNCHER的應用程式,
     * 擷取他們的程式名、包名、入口類名。
     */
    private void getPackageInfo() {
        pm = this.getPackageManager();
        //action為ACTION_MAIN的
        Intent intent = new Intent(Intent.ACTION_MAIN, null);
        intent.addCategory(Intent.CATEGORY_DEFAULT);

        List<ResolveInfo> list = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);

        //根據顯示名稱排序
        Collections.sort(list, new ResolveInfo.DisplayNameComparator(pm));

        for (ResolveInfo info : list) {
            //應用名
            String appName = info.loadLabel(pm).toString();
            //包名
            String packageName = info.activityInfo.packageName;
            //入口類名
            String launchClassName = info.activityInfo.name;
            Logout.i("應用名:" + appName + "\n包名:" + packageName + "\n入口類名:" + launchClassName);
        }
    }

    /**
     * 篩選
     *
     * @param type
     */
    private void filterApp(int type) {
        pm = this.getPackageManager();

        //getInstalledApplications:擷取目前系統上安裝的所有的應用程式
        List<ApplicationInfo> list = pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);

        Collections.sort(list, new ApplicationInfo.DisplayNameComparator(pm));

        switch (type) {
            case FILTER_ALL_APP:
                for (ApplicationInfo info : list) {
                    getAppInfo(info);
                }
                break;
            case FILTER_SYSTEM_APP:
                for (ApplicationInfo info : list) {
                    if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != ) {
                        getAppInfo(info);
                    }
                }
                break;
            case FILTER_THIRD_APP:
                for (ApplicationInfo info : list) {
                    if ((info.flags & ApplicationInfo.FLAG_SYSTEM) <= ) {
                        getAppInfo(info);
                    }
                }
                break;
            case FILTER_SDCARD_APP:
                for (ApplicationInfo info : list) {
                    if (info.flags == ApplicationInfo.FLAG_SYSTEM) {
                        getAppInfo(info);
                    }
                }
                break;

        }
    }

    /**
     * 擷取應用資訊
     */
    private void getAppInfo(ApplicationInfo applicationInfo) {
        // 應用名
        String appName = applicationInfo.loadLabel(pm).toString();
        // 包名
        String packageName = applicationInfo.packageName;
        //入口類名
        String launchClassName = applicationInfo.name;
        //程序名
        String processName = applicationInfo.processName;

        Logout.i("應用名:" + appName + "\n包名:" + packageName + "\n入口類名:" + launchClassName + "\n程序名:" + processName);
    }

    /**
     * 根據包名擷取應用資訊
     */
    private void getAppInfoByPackageName(String packageName) {
        pm = this.getPackageManager();

        ApplicationInfo ai = null;
        try {
            ai = pm.getApplicationInfo(packageName,
                    PackageManager.GET_META_DATA | PackageManager.GET_SHARED_LIBRARY_FILES);
            // 應用名
            String appName = ai.loadLabel(pm).toString();
            //入口類名
            String launchClassName = ai.name;
            //程序名
            String processName = ai.processName;
            //描述
            String loadDescription = "" + ai.loadDescription(pm);
            //共享庫
            String nativeLibraryDir = ai.nativeLibraryDir;

            Logout.i("應用名:" + appName + "\n入口類名:" + launchClassName + "\n程序名:" + processName + "\n描述:" + loadDescription + "\n共享庫:" + nativeLibraryDir);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 擷取目前系統中安裝的所有包
     */
    public void getInstalledPackages() {
        pm = this.getPackageManager();
        List<PackageInfo> piList = pm.getInstalledPackages(PackageManager.GET_ACTIVITIES |
                PackageManager.GET_CONFIGURATIONS |
                PackageManager.GET_GIDS |
                PackageManager.GET_INSTRUMENTATION |
                PackageManager.GET_INTENT_FILTERS |
                PackageManager.GET_META_DATA |
                PackageManager.GET_PERMISSIONS |
                PackageManager.GET_PROVIDERS |
                PackageManager.GET_RECEIVERS |
                PackageManager.GET_SERVICES |
                PackageManager.GET_SHARED_LIBRARY_FILES |
                PackageManager.GET_SIGNATURES |
                PackageManager.GET_URI_PERMISSION_PATTERNS);
        if (piList != null) {
            for (PackageInfo pi : piList) {
                Logout.i("包資訊:" + pi.toString());
                Logout.i("包名:" + pi.packageName);
                Logout.i("包共享user id" + pi.sharedUserId);
                final ActivityInfo[] ais = pi.activities;
                if (ais != null) {
                    for (ActivityInfo ai : ais) {
                        Logout.i("Activity:{" + pi.packageName + "}:" + ai.name);
                    }
                }

                final InstrumentationInfo[] iis = pi.instrumentation;
                if (iis != null) {
                    for (InstrumentationInfo is : iis) {
                        Logout.i("Instrumentation資訊" + is.toString());
                    }
                }

                final ProviderInfo[] pis = pi.providers;
                if (pis != null) {
                    for (ProviderInfo pri : pis) {
                        Logout.i("Provider資訊:" + pri);
                    }
                }
            }
        }
    }
}
           

系統應用資訊:

PackageManager解析

第三方應用資訊

PackageManager解析

擷取所有的activity

PackageManager解析

參考文章

  • Android應用生死輪回的那些事兒(4) - 武器庫(2)-應用元件查詢相關
  • Android應用生死輪回的那些事兒(2) - PackageManager
  • 幾個Info系列的種的總結
  • Android随筆之——PackageManager詳解
  • Android中擷取應用程式(包)的資訊—–PackageManager的使用(一)
  • Android擷取應用程式資訊——PackageManager的基本使用

繼續閱讀