1.首先清单文件中加入权限
<!--安装包相关权限-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
2. application中加入, 注意 android:authorities="${applicationId}.provider" 这部分要和后面使用对应上
<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>
3.进行逻辑上相关判断, 8.0以上要设置未知来源的权限, targetSdkVersion需要设置要大于等于26, 否则 haveInstallPermission 只能获取到false
boolean haveInstallPermission;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
haveInstallPermission = getPackageManager().canRequestPackageInstalls();
if (!haveInstallPermission) {
//没有未知来源安装权限权限
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("提示");
builder.setMessage("安装应用需要打开未知来源权限,请去设置中开启应用权限,以允许安装来自此来源的应用");
builder.setPositiveButton("去设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startInstallPermissionSettingActivity();
}
}
});
builder.show();
return;//防止系统执行默认的方法会跳转页面后弹窗提示,所以会重复 return 掉
}else {
showProgressDialog("正在下载:0%");
ToolUtils.downloadApk(MainActivity.this, verUrl);
}
}else {
showProgressDialog("正在下载:0%");
ToolUtils.downloadApk(MainActivity.this, verUrl);
}
@RequiresApi(api = Build.VERSION_CODES.O)
private void startInstallPermissionSettingActivity() {
//注意这个是8.0新API
Uri packageURI = Uri.parse("package:" + getPackageName());
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI);
startActivityForResult(intent, REQUEST_CODE_INSTALL_PERMISSION);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_INSTALL_PERMISSION) {
showProgressDialog("正在下载:0%");
ToolUtils.downloadApk(MainActivity.this, verUrl);//再次执行安装流程,包含权限判等
}
}
4.下载处理相关:
public static void downloadApk(final Context context, final String fileUrl) {
((BaseActivity) context).showProgressDialog("正在下载:" + 0 + "%");
String mPath;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
mPath = Environment.getExternalStorageDirectory() + "/download";
final File dir = new File(mPath);
dir.getAbsolutePath().toString();
if (!dir.exists()) {
dir.mkdir();
}
final File apkFile = new File(dir, getFileName(fileUrl));
if (apkFile.exists()) {
apkFile.delete();
}
// 请求Api
new AsyncTask<Void, Integer, String>() {
@Override
protected String doInBackground(Void... voids) {
try {
// 构造URL
URL url = new URL(fileUrl);
// 打开连接
URLConnection con = url.openConnection();
//获得文件的长度
int contentLength = con.getContentLength();
System.out.println("长度 :" + contentLength);
// 输入流
InputStream is = con.getInputStream();
// 1K的数据缓冲
byte[] bs = new byte[1024];
// 读取到的数据长度
int len;
// 输出的文件流
OutputStream os = new FileOutputStream(apkFile);
// 开始读取
int count = 0;
while ((len = is.read(bs)) != -1) {
os.write(bs, 0, len);
count += len;
if (count == contentLength) {
((BaseActivity) context).cancelProgressDialog();
}
publishProgress((int) ((count / (float) contentLength) * 100));
}
// 完毕,关闭所有链接
os.close();
is.close();
installApk(context, apkFile);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Integer... integers) {
((BaseActivity) context).showProgressDialog("正在下载:" + integers[0] + "%");
}
@Override
protected void onPostExecute(String result) {
}
}.execute();
}
}
//安装
public static void installApk(Context context, File apkFile) {
Intent intent = new Intent(Intent.ACTION_VIEW);
//兼容7.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
FileProvider7.setIntentDataAndType(context,
intent, "application/vnd.android.package-archive", apkFile, true);
} else {
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
if (context.getPackageManager().queryIntentActivities(intent, 0).size() > 0) {
context.startActivity(intent);
}
context.startActivity(intent);
android.os.Process.killProcess(android.os.Process.myPid());
}
5.工具类
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import java.io.File;
import java.util.List;
/**
* Created by zhanghongyang01 on 17/5/31.
*/
public class FileProvider7 {
public static Uri getUriForFile(Context context, File file) {
Uri fileUri = null;
if (Build.VERSION.SDK_INT >= 24) {
fileUri = getUriForFile24(context, file);
} else {
fileUri = Uri.fromFile(file);
}
return fileUri;
}
public static Uri getUriForFile24(Context context, File file) {
Uri fileUri = android.support.v4.content.FileProvider.getUriForFile(context,
context.getPackageName() + ".provider",
file);
return fileUri;
}
public static void setIntentDataAndType(Context context,
Intent intent,
String type,
File file,
boolean writeAble) {
if (Build.VERSION.SDK_INT >= 24) {
intent.setDataAndType(getUriForFile(context, file), type);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (writeAble) {
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
} else {
intent.setDataAndType(Uri.fromFile(file), type);
}
}
public static void setIntentData(Context context,
Intent intent,
File file,
boolean writeAble) {
if (Build.VERSION.SDK_INT >= 24) {
intent.setData(getUriForFile(context, file));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (writeAble) {
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
} else {
intent.setData(Uri.fromFile(file));
}
}
public static void grantPermissions(Context context, Intent intent, Uri uri, boolean writeAble) {
int flag = Intent.FLAG_GRANT_READ_URI_PERMISSION;
if (writeAble) {
flag |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
}
intent.addFlags(flag);
List<ResolveInfo> resInfoList = context.getPackageManager()
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, uri, flag);
}
}
}