除了发送彩信需要文件提供器,安装应用也需要FileProvider。不单单彩信的附件图片能到媒体库中查询,应用的APK安装包也可在媒体库找到。查找安装包依然借助于内容解析器,具体的实现过程和查询图片类似,比如事先声明如下的对象变量:

private List<ApkInfo> mApkList = new ArrayList<ApkInfo>(); // 安装包列表
private Uri mFilesUri = MediaStore.Files.getContentUri("external"); // 存储卡的Uri
private String[] mFilesColumn = new String[]{ // 媒体库的字段名称数组MediaStore.Files.FileColumns._ID, // 编号MediaStore.Files.FileColumns.TITLE, // 标题MediaStore.Files.FileColumns.SIZE, // 文件大小MediaStore.Files.FileColumns.DATA, // 文件路径MediaStore.Files.FileColumns.MIME_TYPE}; // 媒体类型

再如通过内容解析器到媒体库查找安装包列表,具体的加载代码示例如下:

// 加载安装包列表
private void loadApkList() {mApkList.clear(); // 清空安装包列表// 查找存储卡上所有的apk文件,其中mime_type指定了APK的文件类型,或者判断文件路径是否以.apk结尾Cursor cursor = getContentResolver().query(mFilesUri, mFilesColumn,"mime_type='application/vnd.android.package-archive' or _data like '%.apk'", null, null);if (cursor != null) {// 下面遍历结果集,并逐个添加到安装包列表。简单起见只挑选前十个文件for (int i=0; i<10 && cursor.moveToNext(); i++) {ApkInfo apk = new ApkInfo(); // 创建一个安装包信息对象apk.setId(cursor.getLong(0)); // 设置安装包编号apk.setName(cursor.getString(1)); // 设置安装包名称apk.setSize(cursor.getLong(2)); // 设置安装包的文件大小apk.setPath(cursor.getString(3)); // 设置安装包的文件路径mApkList.add(apk); // 添加至安装包列表}cursor.close(); // 关闭数据库游标}
}

找到安装包之后,通常还要获取它的包名、版本名称、版本号等信息,此时可调用应用包管理器的getPackageArchiveInfo方法,从安装包文件中提取PackageInfo包信息。包信息对象的packageName属性值为应用包名,versionName属性值为版本名称,versionCode属性值为版本号。下面是利用弹窗展示包信息的代码例子:

// 显示安装apk的提示对话框
private void showAlert(final ApkInfo apkInfo) {PackageManager pm = getPackageManager(); // 获取应用包管理器// 获取apk文件的包信息PackageInfo pi = pm.getPackageArchiveInfo(apkInfo.getPath(), PackageManager.GET_ACTIVITIES);if (pi != null) { // 能找到包信息String desc = String.format("应用包名:%s\n版本名称:%s\n版本编码:%s\n文件路径:%s",pi.packageName, pi.versionName, pi.versionCode, apkInfo.getPath());AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("是否安装该应用?"); // 设置提醒对话框的标题builder.setMessage(desc); // 设置提醒对话框的消息内容builder.setPositiveButton("是", new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {installApk(apkInfo.getPath()); // 安装指定路径的APK}});builder.setNegativeButton("否", null);builder.create().show(); // 显示提醒对话框} else { // 未找到包信息ToastUtil.show(this, "该安装包已经损坏,请选择其他安装包");}
}

有了安装包的文件路径,就能打开系统的安装程序执行安装操作了,此时一样要把安装包的Uri对象传过去。应用安装的详细调用代码如下所示:

// 安装指定路径的APK
private void installApk(String path) {Uri uri = Uri.parse(path); // 根据指定路径创建一个Uri对象// 兼容Android7.0,把访问文件的Uri方式改为FileProviderif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {// 通过FileProvider获得安装包文件的Uri访问方式uri = FileProvider.getUriForFile(this,BuildConfig.APPLICATION_ID + ".fileProvider", new File(path));}Intent intent = new Intent(Intent.ACTION_VIEW); // 创建一个浏览动作的意图intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 另外开启新页面intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 需要读权限// 设置Uri的数据类型为APK文件intent.setDataAndType(uri, "application/vnd.android.package-archive");startActivity(intent); // 启动系统自带的应用安装程序
}

注意,Android8.0开始安装应用需要申请权限REQUEST_INSTALL_PACKAGES,于是打开AndroidManifest.xml,补充下面的权限申请配置:

<!-- 安装应用请求,Android8.0需要 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

这下大功告成,编译运行App,打开测试页面自动加载安装包列表的界面如下图所示。

点击某项安装包,弹出如下图所示的确认对话框。

点击确认对话框的“是”按钮,便跳到了如下图所示的应用安装页面,剩下的安装操作就交给系统了。

点此查看Android开发笔记的完整目录

Android开发笔记(一百七十七)借助FileProvider安装应用相关推荐

  1. Android开发笔记(七十七)图片缓存算法

    ImageCache 由于手机流量有限,又要加快app的运行效率,因此好的app都有做图片缓存.图片缓存说起来简单,做起来就用到很多知识点,可算是集Android技术之大全了.只要理解图片缓存的算法, ...

  2. Android开发笔记(七十九)资源与权限校验

    硬件资源 因为移动设备的硬件配置各不相同,为了防止使用了不存在的设备资源,所以要对设备的硬件情况进行检查.一般情况下,前置摄像头.部分传感器在低端手机上是没有的,像SD卡也可能因为用户没插卡使得找不到 ...

  3. Android开发笔记(七十三)代码混淆与反破解

    代码混淆 ProGuard是ADT自带的apk混淆器,它的用途有: 1.压缩apk包的大小,能删除无用的代码,并简化部分类名和方法名. 2.加大破解源码的难度,因为部分类名和方法名被重命名,使得程序逻 ...

  4. Android开发笔记(九十七)图片的特效处理

    图片特效用到的函数 本文讲述的图片特效处理包括:怀旧.光照.光晕.底片.浮雕.模糊.锐化.黑白.冰冻.素描,所有这些特效都是基于一定的算法,对图像每个点的RGB值进行计算,并汇总所有点的计算结果生成新 ...

  5. Android开发笔记(八十七)几个修饰关键字

    原生native native是方法修饰符,表示该方法是由其他一种语言(如C/C++)实现的原生方法.其实native只在JNI接口中使用,java代码中只有原生方法的定义,具体的实现代码在其他语言( ...

  6. Android开发笔记(七十八)异常容错处理

    Exception Java的异常分两类,运行时异常RuntimeException和非运行时异常. 运行时异常包括空指针异常NullPointerException.数组越界异常IndexOutOf ...

  7. Android开发笔记(七十五)内存泄漏的处理

    内存泄漏的原因 一直以来以为只有C/C++才存在内存泄漏的问题,没想到拥有内存回收机制的Java也可能出现内存泄漏.C/C++存在指针的概念,程序中需要使用指针变量时,就从内存中开辟一块区域,并把该区 ...

  8. Android开发笔记(七十四)布局文件优化

    include/merge 布局优化中常常用到include/merge标签,include的含义类似C代码中的include,意思是直接把指定布局片段包含进当前的布局文件.include适用于多个布 ...

  9. Android开发笔记(七十二)数据加密算法

    编码算法 URL编码 URL编码其实并非加解密算法,只是对特殊字符进行字符转义,从而方便在URL中传输参数.URL编码有两种方式,一种是狭义的URL编码,另一种是广义的URL编码. 狭义的URL编码指 ...

  10. Android开发笔记(七十一)区分开发模式和上线模式

    为什么要区分两种模式 许多开发者(包括博主在内)都是闷骚的程序员,为了开发调试方便,常常在代码里加上日志,还经常在页面上各种弹窗提示.这固然有利于发现bug.提高软件质量,但过多的调试信息往往容易泄露 ...

最新文章

  1. 算法在哈啰顺风车中的实践应用
  2. 附录:PyTorch记事本
  3. Windows Phone 7 中的页面和弹出框
  4. hadoop快速入门之DKH安装准备
  5. 建站之前做好规划方案会为网站带来意外之喜
  6. GDCM:gdcm::Command的测试程序
  7. oracle9i新建数据库的用户有哪些,Oracle 9i数据库的用户创造以及权限分配
  8. Java生成随机数的几种高级用法
  9. SQL基础E-R图画法(一)
  10. CMFCPropertySheet的使用及PROPSHEETHEADER结构体介绍
  11. dubbo 自定义路由_爱奇艺在 Dubbo 生态下的微服务架构实践
  12. django权限系统实现步骤_博主营地 | Unity红点系统如何实现?超全步骤分享
  13. 如何使用Java逐行读取大文本文件?
  14. STC学习:485双机通信
  15. 读取xml中的指定节点的值
  16. python破解压缩包密码(密码字典)
  17. pytorch_geometric(pyg)复现T-GCN
  18. java案例--根据规则验证身份证号码正确性
  19. 零基础学javaDay06
  20. kodi教程_kodi下载使用教程教学

热门文章

  1. arXiv 注册流程介绍——详细图解
  2. python接口自动化(四十一)- 发xml格式参数的post请求(超详解)
  3. 第三:Python发送邮件时中文附件下载乱码
  4. html track标签,HTML track标签
  5. wps 选择 高亮_简单实用:一组WPS表格技巧
  6. 11.11 Ext JS Tooltip 出错 Uncaught TypeError: Cannot read property ‘contains‘ of null
  7. byte转换为string乱码_Python如何将String转换为int ?
  8. linux挂载磁盘组,11G ASM磁盘组不能自动MOUNT处理
  9. 本地提交到yarn_Yarn运行Flink作业 0449
  10. python中字典和json的区别_详解python中的json和字典dict