1.情况:在android版本>=7.0.0 && android 版本<8.0.0 更新下载app失败:
解决:配置provider
1.清单文件:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.xx.xxx.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
2.res-xml-file-paths.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path path="" name="download" />
</paths>
</resources>
3.安装代码:
/**
* 通过隐式意图调用系统安装程序安装APK
*/
public static void install2(Context context) {
File file = new File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "xxx.apk");
Intent intent = new Intent(Intent.ACTION_VIEW);
// 由于没有在Activity环境下启动Activity,设置下面的标签
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if(Build.VERSION.SDK_INT>=24) { //判读版本是否在7.0以上
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build()); builder.detectFileUriExposure();
//参数1 上下文, 参数2 Provider主机地址 和配置文件中保持一致 参数3 共享的文件
Uri apkUri = FileProvider.getUriForFile(context, "com.xx.xxx.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");
}
context.startActivity(intent);
}
2.情况:android 版本>8.0.0 更新下载app失败:
报错:
java.lang.SecurityException: Need to declare android.permission.REQUEST_INSTALL_PACKAGES to call this api
解决: 缺失权限,在主配置文件添加,然后代码里面添加,没有的话去跳转用户手动允许。
之前是fragment的权限请求写错了,写成了activity的请求方式:
1.fragment中请求:
UpdateAppDialogFragment.this.requestPermissions( new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, 10010);
2.activity中请求:
ActivityCompat.requestPermissions( new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, 10010);
主要代码:
1.判断是否是8.0以上的android手机,如果是的话,判断权限
public void checkIsAndroidO() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //>=26
boolean b = getActivity().getPackageManager().canRequestPackageInstalls();
if (b) {
download(); //安装apk
Toast.makeText(getActivity(),"安装apk"+b+b,Toast.LENGTH_LONG).show();
} else {
//请求安装未知应用来源的权限
Toast.makeText(getActivity(),"请求安装未知应用来源的权限:"+b,Toast.LENGTH_LONG).show();
UpdateAppDialogFragment.this.requestPermissions( new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, 10010);
}
} else {
Toast.makeText(getActivity(),"安装apk",Toast.LENGTH_LONG).show();
download(); //安装apk
}
}
2.权限请求回调:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
// super.onRequestPermissionsResult(requestCode, permissions, grantResults);
LogUitl.e("===requestCode==:"+requestCode);
Toast.makeText(getActivity(),"requestCode:"+requestCode,Toast.LENGTH_LONG).show();
switch (requestCode) {
case 10010:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
download(); //安装apk
} else {
Uri packageURI = Uri.parse("package:"+getActivity().getPackageName());//设置包名,可直接跳转当前软件的设置页面
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,packageURI);
startActivityForResult(intent, 10012);
}
break;
case 4:
LogUitl.e("======onRequestPermissionsResult======更新权限回调========");
LogUitl.e("======length======更新权限回调========" + grantResults.length);
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
download();
} else {
DialogUtil.showPermissionDialogFragment(getFragmentManager(), "存储");
}
}
}
3.用户授权之后,继续判断是否可以安装:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 10012:
checkIsAndroidO();
break;
}
}
4.清单配置的权限:
<!--8.0 android安装-->
<uses-permission android:name="android.REQUEST_INSTALL_PACKAGES.GET_TASKS" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
参考:
https://blog.youkuaiyun.com/u012483116/article/details/73798383
二:使用外链更新:
Intent intent = new Intent();
intent.setData(Uri.parse(downloadDir));//Url 就是你要打开的网址
intent.setAction(Intent.ACTION_VIEW);
this.startActivity(intent); //启动浏览器
1.测试的手机:
2.小米 Mi 4LTE更新不成功,报错,不知道怎么解决。
10-25 19:49:51.448 5272-5272/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.packageinstaller, PID: 5272
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.packageinstaller/com.android.packageinstaller.PackageInstallerActivity}: java.lang.NullPointerException: Attempt to read from field 'int android.content.pm.ApplicationInfo.privateFlags' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2517)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2577)
at android.app.ActivityThread.access$1100(ActivityThread.java:156)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1428)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:746)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)
Caused by: java.lang.NullPointerException: Attempt to read from field 'int android.content.pm.ApplicationInfo.privateFlags' on a null object reference
at com.android.packageinstaller.PackageInstallerActivity.getOriginatingUid(PackageInstallerActivity.java:625)
at com.android.packageinstaller.PackageInstallerActivity.onCreate(PackageInstallerActivity.java:553)
at android.app.Activity.performCreate(Activity.java:6362)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2470)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2577)
at android.app.ActivityThread.access$1100(ActivityThread.java:156)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1428)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:746)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)