要实现卸载程序、清除数据、停止正在运行的服务这几大模块,现在将代码粗略总结如下:
  主要运用到的类有
  PackageManager
  ActivityManager
  ApplicationInfo
  RunningServiceInfo
  Method
  还有两个android.pm下的源文件用于生成桩,IPackageStatsObserver.java 和 IPackageDataObserver.java,由名字可以看出,他们是跟包的状态和大小有关的,在网上找到这两个文件的源码后,把他们放在工程src目录下的android.pm包下,自己建包。
  首先要获得系统中已经装了的apk,apk分为两类第一是系统的apk,第二是第三方的apk,所以在获取apk时可以指定一个过滤器,见如下代码:
  java代码 

1.  // 添加过滤 ,得到全部程序,系统程序,用户自己安装的程序
2.  
3.    private List queryFilterAppInfo(int filter) {
4.    // 查询所有已经安装的应用程序
5.    List listAppcations = 
6.  pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
7.    Collections.sort(listAppcations,new 
8.  ApplicationInfo.DisplayNameComparator(pm));// 排序
9.    List appInfos = new ArrayList(); // 保存过滤查到的AppInfo
10.    // 根据条件来过滤
11.    switch (filter) {
12.    case FILTER_ALL_APP: // 所有应用程序
13.    appInfos.clear();
14.    for (ApplicationInfo app : listAppcations) {
15.    if (app.packageName.equals("com.android.appmanager")) { // 过滤自己
16.    continue;
17.    }
18.    appInfos.add(getAppInfo(app));
19.    }
20.    return appInfos;
21.    case FILTER_SYSTEM_APP: // 系统程序
22.    appInfos.clear();
23.    for (ApplicationInfo app : listAppcations) {
24.    if ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
25.    if (app.packageName.equals("com.android.appmanager""font-family:Arial, 
26.  Helvetica, sans-serif;">)// wifi { // 过滤自己
27.    continue;
28.    }
29.    appInfos.add(getAppInfo(app));
30.    }
31.    }
32.    return appInfos;
33.    case FILTER_THIRD_APP: // 第三方应用程序
34.    appInfos.clear();
35.    for (ApplicationInfo app : listAppcations) {
36.    // 非系统程序
37.    if ((app.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) {
38.    if (app.packageName.equals("com.android.appmanager"))
39.    continue;
40.    }
41.    appInfos.add(getAppInfo(app));
42.    }
43.    // 本来是系统程序,被用户手动更新后,该系统程序也成为第三方应用程序了
44.    else if ((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) 
45.  {
46.    if (app.packageName.equals("geeya.android.appmanage")) { // 过滤自己
47.    continue;
48.    }
49.    appInfos.add(getAppInfo(app));
50.    }
51.    }
52.    break;
53.    default:
54.    return null;
55.    }
56.    return appInfos;
57.    }


复制代码



  AppInfo是我自己定义的一个类,里面包含了应用程序的包名、数据区大小、代码区大小、等等一些属性。

  好,现在我们来获取app包的数据区大小、缓存区大小、代码区大小,这里要用反射的机制去获取PackageManager类的隐藏方法getPackageSizeInfo(),这个方法的具体实现是通过回调函数来实现的,这里要用到IPackageStatsObserver这个类生成的桩。


  java代码 

1.  // aidl文件形成的Bindler机制服务类
2.  
3.    public class PkgSizeObserver extends IPackageStatsObserver.Stub {
4.    /***
5.    * 回调函数,
6.    *
7.    * @param pStatus
8.    * ,返回数据封装在PackageStats对象中
9.    * @param succeeded
10.    * 代表回调成功
11.    */
12.    @Override
13.    public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) 
14.  throws RemoteException {
15.    long cachesize; // 缓存大小
16.    long datasize; // 数据大小
17.    long codesize; // 应用程序大小
18.    long totalsize; // 总大小
19.    // System.out.println("data start init!");
20.    synchronized (Integer.class) {
21.    cachesize = pStats.cacheSize; // 缓存大小
22.    datasize = pStats.dataSize; // 数据大小
23.    codesize = pStats.codeSize; // 应用程序大小
24.    totalsize = cachesize + datasize + codesize;
25.    Message msg = mHandler.obtainMessage();
26.    msg.what = MSG_SIZE_CHANGE;
27.    Bundle bundle = new Bundle();
28.    bundle.putLong("cachesize", cachesize);
29.    bundle.putLong("datasize", datasize);
30.    bundle.putLong("codesize", codesize);
31.    bundle.putLong("totalsize", totalsize);
32.    bundle.putString("packageName", pStats.packageName);
33.    msg.obj = bundle;
34.    mHandler.sendMessage(msg);
35.    }
36.    }
37.    }
38.    //获取每个apk的大小信息,包括数据区、代码区、缓存区
39.    // 查询包的大小信息
40.    public void queryPacakgeSize(String pkgName) throws Exception {
41.    if (pkgName != null) {
42.    // 使用放射机制得到PackageManager类的隐藏函数getPackageSizeInfo
43.    PackageManager pm = getPackageManager(); // 得到pm对象
44.    try {
45.    // 通过反射机制获得该隐藏函数
46.    Method getPackageSizeInfo = 
47.  pm.getClass().getDeclaredMethod("getPackageSizeInfo", String.class,
48.    IPackageStatsObserver.class);
49.    getPackageSizeInfo.invoke(pm, pkgName, new PkgSizeObserver());
50.    } catch (Exception ex) {
51.    // Log.e(TAG, "NoSuchMethodException");
52.    ex.printStackTrace();
53.    throw ex; // 抛出异常
54.    }
55.    }
56.    }


复制代码



  或得到app的大小数据后,封装成消息发送出去,这是最好的方法!!

  这里也介绍一个将long型数据转换成文件大小格式的数据。


  java代码 

1.  // 系统函数,字符串转换 long -String (kb)
2.  
3.    private String formateFileSize(long size) {
4.    return Formatter.formatFileSize(MainActivity.this, size);
5.    }


复制代码



  好,现在我们来清除用户数据,这里要用到之前下载的那个文件IPackageDataObserver,跟获取app大小一样的,通过回调来实现。

  java代码 


1.  // 清除用户数据的操作
2.  
3.    class ClearUserDataObserver extends IPackageDataObserver.Stub {
4.    public void onRemoveCompleted(final String packageName,final boolean 
5.  succeeded) {
6.    final Message msg = mHandler.obtainMessage();
7.    if (succeeded) {
8.    msg.what = CLEAR_USER_DATA;
9.    } else {
10.    msg.what = NOT_CLEAR_USER_DATA;
11.    }
12.    mHandler2.sendMessage(msg);
13.    }
14.    }
15.    // 清除apk的数据
16.    public void clearAppUserData(String pkgname){
17.    // 经测试,该方法不能用反射得到,没办法,我只好这样写,只能在源码下编译。
18.    pm.clearApplicationUserData(pkgname, new ClearUserDataObserver());
19.    }


复制代码



  好,现在到卸载程序的时候了,看代码

  java代码 


1.  // 卸载apk
2.  
3.    ublic void unInstallApp(String pkgname) {
4.    Log.e("unInstallApp(String pkgname)","pkgname is"+ pkgname);
5.    Intent intent = new Intent();
6.    // 该动作是我在android框架层自己定义的一个动作,DELETE.HIDE,表明直接就卸载了。不经过系统原生的那一个对话。
7.    intent.setAction("android.intent.action.DELETE.HIDE"); // 
8.  自己定义的动作,DELETE.HIDE,不需要经过系统的确认卸载界面。直接卸载!
9.    Uri packageURI = Uri.parse("package:" + pkgname);
10.    intent.setData(packageURI);
11.    startActivity(intent);


复制代码



  关于apk的管理就差不多了,现在来看看正在运行的服务的管理

  首先,获取正在运行的服务:


  这里我的RunningInfo是我自己定义的一个类,主要服务的一些属性,比如包名、uid、pid等等那些


  java代码 


1.  // 得到正在运行的服务
2.  
3.    public List getRunningService() {
4.    List runServiceList = am.getRunningServices(30);
5.    List Services_List = new ArrayList(); // 
6.  保存过滤查到的AppInfo
7.    Log.e("getRunningService.size = ",
8.    new Integer(runServiceList.size()).toString());
9.    String pkgname = "";
10.    ApplicationInfo appByPkgName = null;
11.    for (RunningServiceInfo info : runServiceList) {
12.    pkgname = info.service.getPackageName();
13.    // System.out.println("service package is :" + pkgname +
14.    // " pid = "+ info.pid); // 程序的ID号
15.    // 过滤掉这些系统本身的服务。只显示用户安装的服务
16.    if (pkgname.equals("com.android.appmanager") ) { // 过滤自己
17.    continue;
18.    }
19.    try {
20.    appByPkgName = pm.getApplicationInfo(pkgname,
21.    PackageManager.GET_UNINSTALLED_PACKAGES); // 最后一个参数一般为0
22.    // 就好。
23.    } catch (NameNotFoundException e) {
24.    // Log.e("MainActivity 841 line","appByPkgName = 
25.  pm.getApplicationInfo(pkgname, PackageManager.GET_UNINSTALLED_PACKAGES) 
26.  Exception !");
27.    e.printStackTrace();
28.    }
29.    Services_List.add(getRunningInfo(appByPkgName)); // 
30.  里面含有相同的包的服务。这里哦我们只要求显示一个即可。
31.    }
32.    // 放入set中过滤相同包名的, 这里我复写了RunningInfo 的compareTo方法你 规则是 
33.  pkgName相等两个对象就算相等!
34.    Set set = new HashSet();
35.    for (RunningInfo x : Services_List) {
36.    set.add(x);
37.    }
38.    for (RunningInfo y : set) {
39.    Services_List.add(y);
40.    }
41.    return Services_List;
42.    }


复制代码



  好,获取到了正在运行的服务之后,就可以随意停止服务了,停止服务的代码是:

  java代码 


1.  // 强行停止一个app
2.  
3.    ublic boolean stopApp(String pkgname) {
4.    boolean flag = false;
5.    ActivityManager am = (ActivityManager) 
6.  mContext.getSystemService(Context.ACTIVITY_SERVICE);
7.    try {
8.    Method forceStopPackage;
9.    forceStopPackage = am.getClass().getDeclaredMethod("forceStopPackage", 
10.  String.class); // 反射得到隐藏方法(hide)
11.    forceStopPackage.setAccessible(true);//获取私有成员变量的值
12.    forceStopPackage.invoke(am, pkgname);
13.    flag = true;
14.    } catch (IllegalArgumentException e) {
15.    e.printStackTrace();
16.    flag = false;
17.    } catch (IllegalAccessException e) {
18.    e.printStackTrace();
19.    flag = false;
20.    } catch (InvocationTargetException e) {
21.    e.printStackTrace();
22.    flag = false;
23.    } catch (SecurityException e) {
24.    e.printStackTrace();
25.    flag = false;
26.    } catch (NoSuchMethodException e) {
27.    e.printStackTrace();
28.    flag = false;
29.    }
30.    return flag;


复制代码



  同样也是用反射的机制来得到隐藏类。

  到这里,应用程序管理的功能就差不多了,


  剩下就只是界面上的事情和程序的处理流程上的事情,应该还好!