• android 卸载程序、清除数据、停止服务用法


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

    1. // 加入过滤 ,得到所有程序,系统程序,用户自己安装的程序

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

      AppInfo是我自定义的一个类,里面包括了应用程序的包名、数据区大小、代码区大小、等等一些属性。
      好,如今我们来获取app包的数据区大小、缓存区大小、代码区大小,这里要用反射的机制去获取PackageManager类的隐藏方法getPackageSizeInfo(),这种方法的详细实现是通过回调函数来实现的,这里要用到IPackageStatsObserver这个类生成的桩。
      java代码 

    1. // aidl文件形成的Bindler机制服务类

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

      或得到app的大小数据后,封装成消息发送出去,这是最好的方法!!
      这里也介绍一个将long型数据转换成文件大小格式的数据。
      java代码 

    1. // 系统函数,字符串转换 long -String (kb)

    2.   private String formateFileSize(long size) {
    3.   return Formatter.formatFileSize(MainActivity.this, size);
    4.   }
    复制代码

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

    1. // 清除用户数据的操作

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

      好,如今到卸载程序的时候了,看代码
      java代码 

    1. // 卸载apk

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

      关于apk的管理就差点儿相同了,如今来看看正在执行的服务的管理
      首先,获取正在执行的服务:
      这里我的RunningInfo是我自定义的一个类,主要服务的一些属性,比方包名、uid、pid等等那些
      java代码 

    1. // 得到正在执行的服务

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

      好,获取到了正在执行的服务之后,就能够任意停止服务了,停止服务的代码是:
      java代码 

    1. // 强行停止一个app

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

      相同也是用反射的机制来得到隐藏类。
      到这里,应用程序管理的功能就差点儿相同了,
      剩下就仅仅是界面上的事情和程序的处理流程上的事情,应该还好!
  • 相关阅读:
    是什么意思
    Hql查询
    java的LINQ :Linq4j简明介绍
    Sqlite内存数据库
    ACE中的Proactor介绍和应用实例
    mysql的锁表问题
    消息:'null'为空或不是对象
    FusionChart中引入图类型和数据源方法
    实现FusionChart动态获取数据(二)
    JSP页面解决文件路径方法
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4269283.html
Copyright © 2020-2023  润新知