问题描述:Android 8.0之后,在开发过程中通过代码自动安装APP的时候,安装界面弹不出来,即不显示。而在Android 8.0之前没有这个问题。
原因:Android 8.0 Oreo 中,Google 移除掉了容易被滥用的“允许位置来源”应用的开关,在安装 Play Store 之外的第三方来源的 Android 应用的时候,竟然没有了“允许未知来源”的检查框,如果你还是想要安装某个被自己所信任的开发者的 app,则需要在每一次都手动授予“安装未知应用”的许可。
但是,每次总不能让用户去找这个应用开关吧,还是得我们从代码端解决问题。
解决方案如下:
1、在清单文件中添加权限:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
2、Android 7.0之后,读取修改本地sd卡的权限也得动态获取。
// 判断android版本号,弹出申请权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { showConfirmAppPermissions(MainActivity.this); }
// 7.0 动态申请权限 public void showConfirmAppPermissions(Context mContext) { if (ContextCompat. checkSelfPermission(mContext , Manifest.permission. WRITE_EXTERNAL_STORAGE) != PackageManager. PERMISSION_GRANTED) { if (ActivityCompat. shouldShowRequestPermissionRationale((Activity)mContext , Manifest.permission. WRITE_EXTERNAL_STORAGE)) { } else { ActivityCompat. requestPermissions((Activity)mContext , new String[]{Manifest.permission. WRITE_EXTERNAL_STORAGE , Manifest.permission. READ_EXTERNAL_STORAGE , Manifest.permission. REQUEST_INSTALL_PACKAGES} , 1) ; } }}
3、引导用户打开允许未知来源的开关
package com.deepreality.installappdemo; import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.provider.Settings; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; public class MainActivity extends AppCompatActivity { private final static int INSTALL_PACKAGES_REQUESTCODE = 0x12; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 判断android版本号,弹出申请权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { showConfirmAppPermissions(MainActivity.this); } checkIsAndroidO(); } // 7.0动态申请权限 public void showConfirmAppPermissions(Context mContext) { if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.shouldShowRequestPermissionRationale((Activity)mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { } else { ActivityCompat.requestPermissions((Activity)mContext, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.REQUEST_INSTALL_PACKAGES}, 1); } } } /** * 判断是否是8.0系统,是的话需要获取此权限,判断开没开,没开的话处理未知应用来源权限问题,否则直接安装 */ public void checkIsAndroidO() { if (Build.VERSION.SDK_INT >= 26) { //PackageManager类中在Android Oreo版本中添加了一个方法:判断是否可以安装未知来源的应用 boolean b = getPackageManager().canRequestPackageInstalls(); if (b) { Log.e("结果", "开始安装"); //安装应用的逻辑(写自己的就可以) } else { //请求安装未知应用来源的权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, INSTALL_PACKAGES_REQUESTCODE); } } else { Log.e("结果", "版本<26,开始安装"); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case INSTALL_PACKAGES_REQUESTCODE: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { //installApk(); Log.e("结果", "开始安装"); } else { Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES); startActivityForResult(intent, 0x12); } break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == 0x12) { checkIsAndroidO(); } } }
至此,Android 8.0的安装App的兼容问题已解决。下面贴一下通过代码安装Apk文件的方法:
1、清单文件里,添加用户权限
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.deepreality.installappdemo"> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application> </manifest>
2、安装app,输入apk文件目录以及文件名
// TODO 试验静默安装 安装app private static void installApk(String resourcePath, String resourceName) { File file = new File(resourcePath, resourceName); Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { CommonMethod.Log("e","sdk版本低于7"); Uri uriForFile = FileProvider.getUriForFile(MainActivity.mainActivity, MainActivity.mainActivity.getApplicationContext().getPackageName() + ".provider", file); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(uriForFile, MainActivity.mainActivity.getContentResolver().getType(uriForFile)); }else { intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); } MainActivity.mainActivity.startActivity(intent); }