Android 7.0自动安装
Android7.0的自动安装想必网上的有很多,此处想自己写下加深印象。
Intent intent = new Intent(Intent.ACTION_VIEW);
// 由于没有在Activity环境下启动Activity,设置下面的标签
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//此文件为apk的安装文件,如果放置在SD卡中,记住加读取SD卡的权限
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);
在7.0以后,谷歌加强了应用私有目录访问访问权限,当在执行上述代码会出现android.os.FileUriExposedException 错误,对于这个异常描述有
1,对于面向 Android N 的应用,Android 框架执行的 StrictMode,API 禁止向您的应用外公开 file://URI。
如果一项包含文件 URI 的 Intent 离开您的应用,应用失败,并出现 FileUriExposedException异常。
2,若要在应用间共享文件,您应发送一项 content://URI,并授予 URI 临时访问权限。
进行此授权的最简单方式是使用 FileProvider类。 如需有关权限和共享文件的更多信息,
所以提供了一下方法使用 FileProvider 解决:
第一步需要在AndroidManifest.xml文件中注册provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="包名.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
provider>
解释下上述代码:
android:authorities:官方说明为:包名+fileprovider
android:name:为包名,v4包下新增的类
android:resource:指向之前的xml文件
android:exported:引用官方解释如下:
这个属性用于指示该服务是否能够被其他应用程序组件调用或跟它交互。如果设置为true,则能够被调用或交互,否则不能。设置为false时,只有同一个应用程序的组件或带有相同用户ID的应用程序才能启动或绑定该服务。
它的默认值依赖与该服务所包含的过滤器。没有过滤器则意味着该服务只能通过指定明确的类名来调用,这样就是说该服务只能在应用程序的内部使用(因为其他外部使用者不会知道该服务的类名),因此这种情况下,这个属性的默认值是false。另一方面,如果至少包含了一个过滤器,则意味着该服务可以给外部的其他应用提供服务,因此默认值是true。这个属性不是限制把服务暴露给其他应用程序的唯一方法。还可以使用权限来限制能够跟该服务交互的外部实体。
讲了一大推,答案就是false写死的!因为这是调用系统的安装界面,没有跟其他应用程序组件交互或者相互调用。
android:grantUriPermissions:true为授权url ,false为禁止
第二步:在res目录下创建相应的文件
下面的元数据需要创建相应的xml文件,这里根据名字创建file_paths.xml如下:
<resources >
<paths>
<external-path path="" name="download"/>
paths>
resources>
主要这里的 path=”“,是有特殊意义的,它代表根目录,也就是说你可以向其它的应用共享根目录及其子目录下任何一个文件了。
比如
表示可以访问外部存储目录下,images文件夹下的文件。
其他标签对应代码位置为:
代表的根目录: Context.getFilesDir()
代表的根目录: Environment.getExternalStorageDirectory()
代表的根目录: getCacheDir()
第三步:代码中使用provide
Intent intent = new Intent(Intent.ACTION_VIEW);
// 由于没有在Activity环境下启动Activity,设置下面的标签
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if(Build.VERSION.SDK_INT>=24) { //判读版本是否在7.0以上
//参数1 上下文, 参数2 Provider主机地址 和配置文件中保持一致 参数3 共享的文件
Uri apkUri = FileProvider.getUriForFile( this, "包名.fileprovider", file);
//添加这一句表示对目标应用临时授权该Uri所代表的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
}else{
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
}
startActivity(intent);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 来对目标应用临时授权该 Uri 所代表的文件,而且 getUriForFile 中的 authority 参数需要填写清单文件中的 authorities 的值。
附加addFlags的相关参数:
FLAG_GRANT_READ_URI_PERMISSION
如果设置了,Intent的接受者将被准许执行read操作(Intent 携带的URI数据和任何Clipdata中特定的URIs数据)的权限。
FLAG_GRANT_WRITE_URI_PERMISSION
如果设置了,Intent的接受者将被准许执行write操作(Intent 携带的URI数据和任何Clipdata中特定的URIs数据)的权限。
FLAG_GRANT_PERSISTABLE_URI_PERMISSION
当结合使用 flag_grant_read_uri_permission 和/或 flag_grant_write_uri_permission,URI权限授予可以坚持在设备重新启动直到明确撤销 用revokeuripermission(URI,int)。
FLAG_GRANT_PREFIX_URI_PERMISSION
当结合使用 flag_grant_read_uri_permission 和/或 flag_grant_write_uri_permission,URI权限授予适用于任何前缀匹配不同于原始的授予的URI。
FLAG_DEBUG_LOG_RESOLUTION
使能够使用调试功能的flag。设置之后,日志信息将在intent处理过程被输出,为了告诉你最后的解决列表被发现已创建。
FLAG_FROM_BACKGROUND
可以由调用者设置,以指示此意图来自后台操作,而不是来自直接用户交互.。
FLAG_ACTIVITY_BROUGHT_TO_FRONT
这个flag不能正常地被应用程序代码设置,而是系统为你设置由于在 launchMode 设置为singleTask模式
FLAG_ACTIVITY_CLEAR_TASK
如果通过 Context.startactivity()去设置/启动一个Intent,这个flag将导致任何存在的task,将与活动开始前清除的活动相关联.
FLAG_ACTIVITY_CLEAR_TOP
如果已设置,并且正在启动的活动已经在当前任务(backstack)中运行,那么,而不是启动该活动的新实例,而且它上面的所有其他活动都将被关闭,而这个意图将作为一个新的意图传递到(现在的顶部)旧活动中.。
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
这个常数是在API级别21废弃掉。在API 21执用 flag_activity_new_document 替代
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
如果设置,新活动不保存在最近启动的活动列表中。
FLAG_ACTIVITY_FORWARD_RESULT
如果设置这个intent是被用来从一个现有的acitivity启动到新的acitivity,现有activity的回复目标将被转移到新的activity。
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
这个flag不能正常地被应用程序代码设置,而是系统为你设置,如果这个活动正在展开的历史堆栈(长按 Home键)。
FLAG_ACTIVITY_MULTIPLE_TASK
此标志用来创建一个新的task和启动一个活动到此任务
FLAG_ACTIVITY_NEW_DOCUMENT
此标志用于将文档打开到一个新的任务中,该任务源于intent启动的活动。
FLAG_ACTIVITY_NEW_TASK
设置此标志使activity将成为此历史堆栈上新任务的开始
FLAG_ACTIVITY_NO_ANIMATION
如果通过 Context.startactivity()去设置/启动一个Intent,这个标志将阻止系统执行一个活动去下一个活动的过渡动画。
FLAG_ACTIVITY_NO_HISTORY
设置此标志activity将不添加到回退栈(backStack)
FLAG_ACTIVITY_NO_USER_ACTION
设置此标志,将阻止onuserleavehint()正常回调发生在当前最前的活动,在它被停下来作为新启动活动被带到前面。
FLAG_ACTIVITY_PREVIOUS_IS_TOP
如果设置并使用此意图从现有的一个activity a启动到新activity b,新avitivity b将不会被视为栈顶而是activity a,而是决定是否新意图传递到顶部而不是启动新的活动。
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
设置此标志使这个活动要么开始在一个新的任务或带到现有的任务的顶部,那么它将被启动作为任务的前门。
FLAG_ACTIVITY_REORDER_TO_FRONT
如果在通过 Context.startactivity()去设置/启动一个Intent,如果需要启动的activity已经运行,此标志使被启动的活动被带到任务的历史堆栈的前面.。
FLAG_ACTIVITY_SINGLE_TOP
如果设置,activity将不会被启动如果其正在backstack的栈顶
FLAG_ACTIVITY_TASK_ON_HOME
如果在通过 Context.startactivity()去设置/启动一个Intent,此flag将使新启动任务置于当前活动任务的顶部(如果只有一个task时)。
FLAG_RECEIVER_REGISTERED_ONLY
如果设置,当发送一个广播只有注册接收器将被调用,没有BroadcastReceiver组件将被启动。
好了!基本安装就没问题了.