在android7.0之前
String str = "/myApk/game.apk";
String fileName = Environment.getExternalStorageDirectory() + str;
File file18 = new File(fileName);
Intent intent = new Intent(Intent.ACTION_VIEW);
fileURI = Uri.fromFile(file18);
intent.setDataAndType(fileURI, "application/vnd.android.package-archive");
startActivity(intent);
为了提高私有目录的安全性,防止应用信息的泄漏,从 Android 7.0 开始,应用私有目录的访问权限被做限制。具体表现为,开发人员不能够再简单地通过 file:// URI 访问其他应用的私有目录文件或者让其他应用访问自己的私有目录文件。
开发中,如果我们在使用 file:// URI 时忽视了这两条规定,将导致用户在 7.0 及更高版本系统的设备中使用到相关功能时,出现 FileUriExposedException 异常,导致应用出现崩溃闪退问题。而这两个过程的替代解决方案便是使用 FileProvider。
具体说明可以看这里
所以我们应该使用FileProvider.getUriForFile()方法
- 注册FileProvider并添加安装权限
<!-- file provider -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="你的包名.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
- 在res目录下新建xml目录或者在已有xml目录下添加文件
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<external-path path="/myApk" name="external_files"/>
<!--path:需要临时授权访问的路径(.代表所有路径),属性值不能使用具体的独立文件名,只能是目录名-->
<!--name:就是给 path 属性所指定的子目录名称取一个别名,后续生成 content:// Uri 时,
会使用这个别名代替真实目录名。这样做的目的,是为了提高安全性-->
<!--外部存储又分为SD卡和扩展卡内存,此处外部存储空间对应为内置SD卡内存-->
<!--内部存储,我们称为InternalStorage,外部存储我们称为ExternalStorage-->
<!--<files-path>:内部存储空间应用私有目录下的 files/ 目录,等同于 Context.getFilesDir() 所获取的目录路径;-->
<!--<cache-path>:内部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getCacheDir() 所获取的目录路径;-->
<!--<external-path>:外部存储空间根目录,等同于 Environment.getExternalStorageDirectory() 所获取的目录路径;-->
<!--<external-files-path>:外部存储空间应用私有目录下的 files/ 目录,等同于 Context.getExternalFilesDir(null) 所获取的目录路径;-->
<!--<external-cache-path>:外部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getExternalCacheDir();-->
<!--</paths>-->
</resources>
- 然后在你执行安装逻辑的activity中检测android版本区别处理访问URI
String str = "/myApk/game.apk";
String fileName = Environment.getExternalStorageDirectory() + str;
Log.e("Himi",fileName);
File file18 = new File(fileName);
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri fileURI;
if(android.os.Build.VERSION.SDK_INT > 23 ){
// 参数2 清单文件中provider节点里面的authorities ; 参数3 共享的文件,即apk包的file类
fileURI = FileProvider.getUriForFile(Myd2Activity.m_instance, this.getApplicationContext().getPackageName() + ".provider", file18);
Log.e("Himi",this.getApplicationContext().getPackageName() + ".provider");
//对目标应用临时授权该Uri所代表的文件
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}else{
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
fileURI = Uri.fromFile(file18);
}
intent.setDataAndType(fileURI, "application/vnd.android.package-archive");
try
{
this.startActivity(intent);
}
catch(Exception a)
{
a.printStackTrace();
}