Android学习-应用程序管理

Android学习-应用程序管理

在前段时间,公司要求做一个Android系统的应用程序管理,要实现卸载程序、清除数据、停止正在运行的服务这几大模块,现在将代码粗略总结如下:

主要运用到的类有

PackageManager

ActivityManager

ApplicationInfo

RunningServiceInfo

Method

还有两个android.pm下的源文件用于生成桩,IPackageStatsObserver.java  和 IPackageDataObserver.java,由名字可以看出,他们是跟包的状态和大小有关的,在网上找到这两个文件的源码后,把他们放在工程src目录下的android.pm包下,自己建包。

首先要获得系统中已经装了的apk,apk分为两类第一是系统的apk,第二是第三方的apk,所以在获取apk时可以指定一个过滤器,见如下代码:

[java] view plaincopy

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

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

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

[java] view plaincopy

  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) throws RemoteException {
  13. long cachesize; // 缓存大小
  14. long datasize; // 数据大小
  15. long codesize; // 应用程序大小
  16. long totalsize; // 总大小
  17. // System.out.println("data start init!");
  18. synchronized (Integer.class) {
  19. cachesize = pStats.cacheSize; // 缓存大小
  20. datasize = pStats.dataSize; // 数据大小
  21. codesize = pStats.codeSize; // 应用程序大小
  22. totalsize = cachesize + datasize + codesize;
  23. Message msg = mHandler.obtainMessage();
  24. msg.what = MSG_SIZE_CHANGE;
  25. Bundle bundle = new Bundle();
  26. bundle.putLong("cachesize", cachesize);
  27. bundle.putLong("datasize", datasize);
  28. bundle.putLong("codesize", codesize);
  29. bundle.putLong("totalsize", totalsize);
  30. bundle.putString("packageName", pStats.packageName);
  31. msg.obj = bundle;
  32. mHandler.sendMessage(msg);
  33. }
  34. }
  35. }
  36. //获取每个apk的大小信息,包括数据区、代码区、缓存区
  37. // 查询包的大小信息
  38. public void queryPacakgeSize(String pkgName) throws Exception {
  39. if (pkgName != null) {
  40. // 使用放射机制得到PackageManager类的隐藏函数getPackageSizeInfo
  41. PackageManager pm = getPackageManager(); // 得到pm对象
  42. try {
  43. // 通过反射机制获得该隐藏函数
  44. Method getPackageSizeInfo = pm.getClass().getDeclaredMethod("getPackageSizeInfo", String.class,
  45. IPackageStatsObserver.class);
  46. getPackageSizeInfo.invoke(pm, pkgName, new PkgSizeObserver());
  47. } catch (Exception ex) {
  48. // Log.e(TAG, "NoSuchMethodException");
  49. ex.printStackTrace();
  50. throw ex; // 抛出异常
  51. }
  52. }
  53. }

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

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

[java] view plaincopy

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

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

[java] view plaincopy

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

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

[java] view plaincopy

  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"); // 自己定义的动作,DELETE.HIDE,不需要经过系统的确认卸载界面。直接卸载!
  7. Uri packageURI = Uri.parse("package:" + pkgname);
  8. intent.setData(packageURI);
  9. startActivity(intent);

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

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

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

[java] view plaincopy

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

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

[java] view plaincopy

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

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

到这里,应用程序管理的功能就差不多了,剩下就只是界面上的事情和程序的处理流程上的事情,应该还好!

时间: 2024-10-08 11:19:07

Android学习-应用程序管理的相关文章

CentOS学习笔记--程序管理

程序管理 一个程序被加载到内存当中运行,那么在内存内的那个数据就被称为程序(process).程序是操作系统上非常重要的概念, 所有系统上面跑的数据都会以程序的型态存在.那么系统的程序有哪些状态?不同的状态会如何影响系统的运行? 程序之间是否可以互相控管等等的,这些都是我们所必须要知道的项目.本节节选自鸟哥的 Linux 私房菜 -- 基础学习篇目录 第十七章.程序管理与 SELinux 初探 什么是程序 (process) 程序 (program):通常为 binary program ,放置

iOS学习 - 应用程序管理

// // YJAppInfo.h // 05-应用程序管理的练习 // // Created by JACKY-MAC on 15-6-8. // Copyright (c) 2015年 www.train.com. All rights reserved. // 字典转模型 #import <UIKit/UIKit.h> @interface YJAppInfo : UIView @property(nonatomic,copy)NSString *name; @property(nona

Android学习之导航--摘自黑马程序员

Android学习路线参考: 第三阶段:Android核心基础 什么是3G/4G.3G/4G网络的特点,掌握Android编程的基本概念与要点,Android SDK及其开发环境搭建.Android项目结构分析.Android应用设计模式.文件系统.文件形式的数据存储与访问.SDCard卡读写.使用SAX/DOM/PULL解析XML.SharedPreferences.Intent.IntentFilter.Android四大核心组件(Activity.BroadcastReceiver.Ser

Linux 程序设计学习笔记----进程管理与程序开发(下)

转载请注明出处:http://blog.csdn.net/suool/article/details/38419983,谢谢! 进程管理及其控制 创建进程 fork()函数 函数说明具体参见:http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html 返回值:Upon successful completion, fork() shall return 0 to the child process and shall re

Android学习笔记(十七)——使用意图调用内置应用程序

使用意图调用内置应用程序 1.创建一个新的Android项目并命名为Intents,在main.xml文件中添加两个Button: <Button android:id="@+id/btn_webbrowser" android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="onClickWebBrowser&quo

Android学习——在Android中使用OpenCV的第一个程序

刚开始学习Android,由于之前比较熟悉OpenCV,于是就想先在Android上运行OpenCV试试 =================================================================================== 1.环境配置 JDK Eclipse ADT CDT Android SDK Android NDK cygwin OpenCV for Android 2.4.9 这部分网上很多,我就不再赘述了,可以参考:http://bl

Android学习--------实现增删改查数据库操作以及实现类似微信好友对话管理操作

最近的一个实验用到东西挺多,特地总结一下. 要求功能: 1.第一个页面添加歌曲名和歌手,跳到第二个页面列表显示所有记录,使用sqlite数据库 2.对于第二个页面显示的信息可以进行删除和修改操作,并自动刷新 最后我做的效果: 长按列表项弹出单个管理的菜单,像微信好友对话管理一样. 删除时可以直接删除这一条并在列表中直接显示,更新时弹出对话框更新内容提交后在列表中重新显示. 做此例遇到的困难: 1.菜单获取上下文 2.获取对话框中的内容 3.对话框按钮添加监听事件-----注意包不要导错:impo

Android学习路线(十一)管理Activity的生命周期

当一个用户进入,退出,再次进入你的应用时,你的应用中的Activity 会在它的生命周期的各个状态下切换.例如,当你的activity第一次启动,它出现在系统的前方接受用户的焦点.在这个过程中,Android系统调用了一系列的生命周期方法来设置UI和其他组件.如果用户执行了一个操作,启动了另一个activity或者切换到其它应用中,你的activity会移动到后台(这时activity已经不可见,但是它的实力和状态都保持不变),系统会调用另外的一些生命周期方法. 通过这些生命周期方法,你可以声明

Android学习——移植tr069程序到Android平台

原创作品,转载请注明出处,严禁非法转载.如有错误,请留言! email:[email protected] 声明:本系列涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅号:408797506) 本篇用到的代码下载路径:http://download.csdn.net/detail/eryunyong/9798889 Github维护: 代码结构说明: core目录是tr069程序的协议栈部分代码编译出来的可执行档案(不开源). etc_config目录是cwm