public static void installApk(Context context, File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data = Uri.fromFile(file);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(data, "application/vnd.android.package-archive");
context.startActivity(intent);
}
Android 7.0
7.0以上会报FileUriExposedException. 使用FileProvider解决
FileProvider官方文档
https://developer.android.google.cn/reference/android/support/v4/content/FileProvider.html
<manifest>
...
<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.csdn.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
...
</application>
</manifest>
这里最好不直接用android.support.v4.content.FileProvider,新建一个MyProvider 继承android.support.v4.content.FileProvider,以防与其他lib定义的冲突。
res/xml 目录下新建file_paths.xml文件,xml文件夹不存在就创建.
<paths>
<external-cache-path name="my_download" path="download/" />
</paths>
external-cache-path 对应Context.getExternalCacheDir(),也就是我的apk文件是放在
Context.getExternalCacheDir()/download文件夹下面的.
其他还(复制过来,直接看文档比较好)
The <paths> element must contain one or more of the following child elements:
<files-path name="name" path="path" />
Represents files in the files/ subdirectory of your app's internal storage area. This subdirectory is the same as the value returned by Context.getFilesDir().
<cache-path name="name" path="path" />
Represents files in the cache subdirectory of your app's internal storage area. The root path of this subdirectory is the same as the value returned by getCacheDir().
<external-path name="name" path="path" />
Represents files in the root of the external storage area. The root path of this subdirectory is the same as the value returned by Environment.getExternalStorageDirectory().
<external-files-path name="name" path="path" />
Represents files in the root of your app's external storage area. The root path of this subdirectory is the same as the value returned by Context#getExternalFilesDir(String) Context.getExternalFilesDir(null).
<external-cache-path name="name" path="path" />
Represents files in the root of your app's external cache area. The root path of this subdirectory is the same as the value returned by Context.getExternalCacheDir().
<external-media-path name="name" path="path" />
Represents files in the root of your app's external media area. The root path of this subdirectory is the same as the value returned by the first result of Context.getExternalMediaDirs().
Note: this directory is only available on API 21+ devices.
然后代码中判断版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// "com.csdn.fileprovider"即manifest中的authorities
data = FileProvider.getUriForFile(context, "com.csdn.fileprovider", file);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //授权
} else {
data = Uri.fromFile(file);
}
Android 8.0
8.0开始安装未知来源的apk,需要用户设置授权.
声明权限
加上一些判断
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !context.getPackageManager().canRequestPackageInstalls()){
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
activity.startActivityForResult(intent);
}else{
//install
}