在 APK 开发中,通过 Java 代码来打开系统的安装程序以安装 APK 并不是什么难事,一般的 Android 系统都有开放这一功能。

但随着 Android系统版本的迭代,其对于权限的把控越来越严格,或者说是变得越来越注重安全性。这就导致了以前可以通过很简单的几行代码就能实现的功能,现在要复杂很多。

对于通过代码打开系统安装程序这一功能的限制,其分水岭在 Android7.0,即 Android N 上。通常在 Android N以上的系统使用一种做法,以下则使用另一种做法。

传统的通过代码安装APK的方式

File apk = new File(...);

Uri uri = Uri.fromFile(apk);

Intent intent = new Intent();

intent.setClassName("com.android.packageinstaller", "com.android.packageinstaller.PackageInstallerActivity");

intent.setData(uri);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(intent);

这种方法简单粗暴且实用,只要知晓要安装的 APK 的位置,并拥有访问权限即可。

但现在市面上主流的 Android 手机系统版本都已经要高于 7.0 了,这一方法几乎已经没有用了

高版本系统上的通过代码安装APK的方式

File apk = new File(...);

Intent intent = new Intent(Intent.ACTION_VIEW);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

Uri uri = FileProvider.getUriForFile(this, "com.apk.demo.fileprovider", apk);

intent.setDataAndType(uri, "application/vnd.android.package-archive");

startActivity(intent);

说到权限问题,在Android版本不断提高的趋势下,系统得安全性也越来越高,很多权限不只是在清单文件里面注册那么简单,内存卡得读写权限属于危险权限,需要我们使用代码动态添加,这里我使用了RxPermiision框架,遇到9.0或者更高版本的系统时获取权限的方法可能会不同。

private void rxPermission() {

RxPermissions rxPermissions = new RxPermissions(this);

rxPermissions.request(Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(new Consumer() {

@Override

public void accept(Boolean granted) throws Exception {

if (granted) {

//权限允许

//在这里可以添加自己的操作

} else {

// 权限被拒绝

}

}

});

}

上面这段代码安装代码看起来似乎和传统的方式并没有太大的区别是吗?

确实是,但它真正的区别并没有在 Java 代码上体现出来。

在高版本系统中,APK 已经不能直接访问其它 APK 的私有数据了。

什么是APK的私有数据?

APK在安装过程中于 data 目录下创建的专属目录自然是其私有数据无疑。另外,只要是在应用程序中封装的 File 对象,不管这个文件本身是不是由该程序创建的,那这个文件都属于该程序的“私有数据”。举个例子来说,假设我们将手机连接到电脑,通过 adb push 的方式往 sdcard 目录下推了一个 APK 文件进去。然后我们自行编写了一段代码,将这个 sdcard 中的安装包传到系统的 PackageInstaller 中去安装,都会报安全错误,因为这个位于 sdcard 目录下文件对我们这段代码来说是“私有数据”,不允许直接暴露给 PackageInstaller。

下面就来看看在高版本系统中暴露“私有数据”给其它程序的方法。

在高版本中,Android7.0 及以上,开放(暴露)私有数据的唯一方式是通过 ContentProvider 来实现。

具体的步骤大致如下:

配置 AndroidManifest.xml 中的 ContentProvider 信息;

配置要开放的 paths 信息;

在 Java 代码中通过 FileProvider 封装文件信息。

1、AndroidManifest.xml 配置

前面说过,高版本系统中其实就是将以前的直接开放变成通过 ContentProvider 来间接开放。因此我们需要在 AndroidManifest.xml 中添加一个 provider 标签,示例如下:

android:name="androidx.core.content.FileProvider"

android:authorities="com.your.app.fileprovider"

android:exported="false"

android:grantUriPermissions="true">

android:name="android.support.FILE_PROVIDER_PATHS"

android:resource="@xml/file_paths" />

android:name 属性填写的是 FileProvider 类的完整名称。这个类可以填写两个值,一个是位于 support(android.support.v4.content.FileProvider) 包下的,另一个是位于 androidx(androidx.core.content.FileProvider) 包下的。这两种都可以填写,本质上没有区别。但是要根据实际情况来决定用哪个,即要看你的工程引的是 androidx 支援包还是 support 支援包。关于 support 与 androidx 的关系本文就不再赘述了。

android:authorities 属性就是和普通的 ContentProvider 一样的用于访问文件资源的 uri 标签头。值内容根据实际需要来填写即可。

android:exported这个属性表示的是:其他app能否访问这个provider

android:grantUriPermissions 这个属性用于给内容提供器的数据子集授权

如果内容提供器的grantUriPermissions属性被设置为true,那么权限能够被授予内容提供器范围内的任何数据。但是,如果grantUriPermission属性被设置为false,那么权限就只能授予这个元素所指定的数据子集。一个内容提供器能够包含任意多个元素。每个都只能指定一个路径(三个可能属性中的一个)。

meta-data 标签中的内容需要关注的是 android:resource 属性中的内容。这个属性的值引向一个自行配置的 xml 文件,这份 xml 文件记载的是设备中的路径信息,简单理解就是你想开放哪些目录中的文件资源给第三方使用的意思。关于这个 xml 的配置请看第 2 步的记载。

2、paths 配置

通常的做法是在工程 res 目录下新建一个 xml 目录,并在该 xml 目录下新建一个 xml 文件。文件的名称必须与第 1 步中 @xml/ 属性值中配置的一致。

根据第 1 步中的示例代码,我们需要新建一个 file_paths.xml 文件。这里我的apk是保留在程序的file文件加下得,该文件的内容如下所示:

简单来说,就是将你要开放出去的路径的类型选好,然后填上该类型下的相对路径即可。

我们以示例详细说说:

这表示我们想开放 程序内存里面的files目录,然后在 files 目录下的子路径是 /apk,组合成绝对路径就是 /data/con.xxx.xxx/files/apk 。至于 name 标签则是用于 ContentProvider 标识使用的,一般来讲按需要设置成不同的值就可以了,这里我有一个子目录。

3、Java 代码配置

Java 代码的配置就没什么特别的了,直接以章节首部的代码来用就可以了。关键的代码其实只有一行:

Uri uri = FileProvider.getUriForFile(context, authority, file);

这里的三个参数分别为:

context:这里表示需要传一个上下文过来

authority:可以通代码在AndroidManifest.xml里面获得

file:是你需要的安装的文件

String authority = new StringBuilder(packageName).append(".provider").toString();

//这里的strFile文件的路径+名称;例如:/data/file/apk/xxx.apk

File f=new File(strFile);

Uri uri = FileProvider.getUriForFile(context, authority, file);

通常我们都会兼顾 Android 高低版本的系统,因此会使用如下所示的“混合型”代码:

public void install(){

try{//这里有文件流的读写,需要处理一下异常

Intent intent = new Intent(Intent.ACTION_VIEW);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){

//如果SDK版本>=24,即:Build.VERSION.SDK_INT >= 24

String packageName = context.getApplicationContext().getPackageName();

String authority = new StringBuilder(packageName).append(".provider").toString();

uri = FileProvider.getUriForFile(context, authority, file);

intent.setDataAndType(uri, "application/vnd.android.package-archive");

} else{

uri = Uri.fromFile(file);

intent.setDataAndType(uri, "application/vnd.android.package-archive");

}

context.startActivity(intent);

}catch (Exception e) {

e.printStackTrace();

}

}

总结

到此这篇关于Android 通过代码安装 APK的方法详解的文章就介绍到这了,更多相关android 代码安装apk内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

安卓java安装apk代码_Android 通过代码安装 APK的方法详解相关推荐

  1. python画图代码大全-Python实现画图软件功能方法详解

    概述 虽然Python的强项在人工智能,数据处理方面,但是对于日常简单的应用,Python也提供了非常友好的支持(如:Tkinter),本文主要一个简单的画图小软件,简述Python在GUI(图形用户 ...

  2. java this关键字的使用_Java this 关键字的使用方法详解

    Java this 关键字的使用方法详解 构造方法中的this关键字 构造方法是一个类的对象在通过new关键字创建时自动调用的,在程序中不能向调用其他方法一样通过方法名(也就是类名)来调用.但如果一个 ...

  3. [Java入门笔记] 面向对象编程基础(二):方法详解

    2019独角兽企业重金招聘Python工程师标准>>> 什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能 ...

  4. java 发送客服消息,Java调用微信客服消息实现发货通知的方法详解

    本文实例讲述了java调用微信客服消息实现发货通知的方法.分享给大家供大家参考,具体如下: 个人说明:这是一个样例,微信客户消息有很多种,我现在用的是公众号发送消息.样子如下图. 说明:下面开始代码部 ...

  5. java 字符串为空_java判断字符串为空,方法详解

    之前给大家介绍过关于java输出字符串的方法,那么下面要给大家带来的就是java判断字符串为空的方法,一起来通过下面的文章内容进行一下详细的了解吧. java判断字符串最常见的四种方法: 方法1if  ...

  6. android java 写文件操作_Android编程之文件的读写实例详解

    本文实例分析了Android编程之文件的读写方法.分享给大家供大家参考,具体如下: Android的文件读写与JavaSE的文件读写相同,都是使用IO流.而且Android使用的正是JavaSE的IO ...

  7. webview代码实例化_WebView常用类和基本方法详解

    上一篇文章我们实现了一个简单的WebView,并且能够在程序中的不调用浏览器进行网页的展示和浏览,Android给WebView提供了一些子类,其子类下的方法能够让我们的WebView功能更加完善.性 ...

  8. 安卓开发mysql数据库_Android编程之数据库的创建方法详解

    本文实例讲述了Android编程之数据库的创建方法.分享给大家供大家参考,具体如下: 主java package com.itheima.createdatabase; import android. ...

  9. java join yield_Java多线程中join、yield、sleep方法详解

    在Java多线程编程中,Thread类是其中一个核心和关键的角色.因此,对该类中一些基础常用方法的理解和熟练使用是开发多线程代码的基础.本篇主要总结一下Thread中常用的一些静态方法的含义及代码中的 ...

  10. java封装数组_Java封装数组之动态数组实现方法详解

    本文实例讲述了Java封装数组之动态数组实现方法.分享给大家供大家参考,具体如下: 前言:在此之前,我们封装的数组属于静态数组,也即数组空间固定长度,对于固定长度的数组当元素超过容量时会报数组空间不足 ...

最新文章

  1. SQL Server基础知识之:设计和实现视图
  2. iOS开发-照片选择
  3. DirectFB的架构介绍
  4. android 页面标题,Android v4包下的PagerTitleStrip,ViewPager的页面标题
  5. Android 控件之RatingBar评分条
  6. Java八岁生日快乐!
  7. 3.Contructor(构造器)模式—精读《JavaScript 设计模式》Addy Osmani著
  8. QIcon 给按钮和动作添加图片
  9. 【LeetCode笔记】剑指 Offer 16. 数值的整数次方(Java、分治)
  10. maven打包不用eclipse插件
  11. Maven学习总结(21)——Maven常用的几个核心概念
  12. jsTree工作笔记001---jsTree的基本使用_js实现树形结构
  13. Netflix如何设计一个能满足5倍增长量的时序数据存储新架构?
  14. 新大陆java工程师笔试题_完美世界,中兴,新大陆支付面经
  15. 多款 D-Link 路由器受多个 RCE 漏洞影响
  16. apache+fastcgi+php
  17. 【zk开发】让eclipse识别×.zul文件为xml格式
  18. ValueError: 2 columns passed, passed data had 5 columns
  19. 5G/NR LTE: 物理层抽象 PHY abstraction - SLS LLS 系统级仿真和链路级仿真
  20. Java三大版本及 JVM JDK JRE 及 SDK API

热门文章

  1. (原创)Android apk应用加固、字节对齐、二次签名全流程
  2. 泛游链FPCO白皮书
  3. 分享一款简易的游戏框架
  4. SOLIDWORKS钣金设计基础命令
  5. 图解让你了解常用锁的种类以及解决方案(内含代码演示)【建议新手收藏】
  6. 智慧社区建设指南参考规范汇总
  7. MySQL复习笔记(燕十八)
  8. 区块链通证经济的本质与落地路径/通证经济的趋势与发展
  9. 分析仪器宜选用微型真空水泵作采样泵
  10. 《微波技术基础》第二版 阅读随笔2