热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android通过代码安装APK的方法详解

这篇文章主要介绍了Android通过代码安装APK的方法详解,本文通过实例代码给大家介绍的非常详细,对大家的学习火锅工作具有一定的参考借鉴价值,需要的朋友可以参考下

在 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 {
     // 权限被拒绝
    }
   }
  });
 }

Android更多权限得查询:https://www.jianshu.com/p/24f79a70025b

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

确实是,但它真正的区别并没有在 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 属性填写的是 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文件加下得,该文件的内容如下所示:
<&#63;xml version="1.0" encoding="utf-8"&#63;>

 

其他路径的的配置方式请参考:https://editor.csdn.net/md&#63;articleId=106670247

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

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 

这表示我们想开放 程序内存里面的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内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • Android 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • 构建基于BERT的中文NL2SQL模型:一个简明的基准
    本文探讨了将自然语言转换为SQL语句(NL2SQL)的任务,这是人工智能领域中一项非常实用的研究方向。文章介绍了笔者在公司举办的首届中文NL2SQL挑战赛中的实践,该比赛提供了金融和通用领域的表格数据,并标注了对应的自然语言与SQL语句对,旨在训练准确的NL2SQL模型。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 如何配置Unturned服务器及其消息设置
    本文详细介绍了Unturned服务器的配置方法和消息设置技巧,帮助用户了解并优化服务器管理。同时,提供了关于云服务资源操作记录、远程登录设置以及文件传输的相关补充信息。 ... [详细]
  • 尽管某些细分市场如WAN优化表现不佳,但全球运营商路由器和交换机市场持续增长。根据最新研究,该市场预计在2023年达到202亿美元的规模。 ... [详细]
  • 网络攻防实战:从HTTP到HTTPS的演变
    本文通过一系列日记记录了从发现漏洞到逐步加强安全措施的过程,探讨了如何应对网络攻击并最终实现全面的安全防护。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本文详细分析了Hive在启动过程中遇到的权限拒绝错误,并提供了多种解决方案,包括调整文件权限、用户组设置以及环境变量配置等。 ... [详细]
  • 解决MongoDB Compass远程连接问题
    本文记录了在使用阿里云服务器部署MongoDB后,通过MongoDB Compass进行远程连接时遇到的问题及解决方案。详细介绍了从防火墙配置到安全组设置的各个步骤,帮助读者顺利解决问题。 ... [详细]
  • 本文详细介绍了如何使用ActionScript 3.0 (AS3) 连接并操作MySQL数据库。通过具体的代码示例和步骤说明,帮助开发者理解并实现这一过程。 ... [详细]
  • 在即将迎来26岁生日之际,作者的人生陷入了低谷。经过近三年的硕士学习后,最终决定退学,并且面临没有工作经验的困境。尽管如此,作者依然坚定地选择为自己的人生负责。 ... [详细]
author-avatar
右心1477
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有