首先是下载的时候,文件下不下来,加了权限也不行。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
需要在AndroidManifest中配置一下
<application
...
android:requestLegacyExternalStorage="true" // 这样就可以采用原有的存储策略
参考:https://blog.csdn.net/hgy413/article/details/105902424?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allsobaiduend~default-3-105902424.nonecase&utm_term=android%E6%B2%A1%E6%9D%83%E9%99%90%E5%88%9B%E5%BB%BA%E6%96%87%E4%BB%B6&spm=1000.2123.3001.4430
下载后就是打开apk文件,7.0以上加上FileProvider和file_paths.xml。
但是依然打不开apk文件。
此时需要加一个权限<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
参考:https://blog.csdn.net/chxc_yy/article/details/81536875
注意,若代码里已经有了FileProvider和file_paths.xml,比喻,下载图片时也需要。
此时需要重新为下载apk再来自定义一个FileProvider
注意android:authorities和android:resource要不一样,区分开
参考:https://www.pianshen.com/article/7748702374/
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="包名.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<provider
android:name="包名.utils.MyFileProvider"
android:authorities="包名.download.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/download_file_paths" />
</provider>
附上下载安装代码:
/**
* 版本控制
*/
@SuppressWarnings("ALL")
public class VersionUpdateHelper {
public static final String TAG = VersionUpdateHelper.class.getSimpleName();
private static final int UPDATE_NOTIFICATION_PROGRESS = 0x1;
private static final int COMPLETE_DOWNLOAD_APK = 0x2;
private static final int DOWNLOAD_NOTIFICATION_ID = 0x3;
private static final int FAILED_DOWNLOAD_APK = 0x4;
private static final String CURRENT_TIME = "current_time";
private static final String VERSION_CODE = "version_code";
private Context mContext;
private NotificationManager notificationManager;
private NotificationCompat.Builder ntfBuilder;
private static String sPath;
private static final String SUFFIX = ".apk";//下载完成后的文件名后缀
private static final String APP_NAME = "APP_NAME";//app名
private HashMap<String, String> cache = new HashMap<String, String>();//存放路径名和app的名字
private boolean isAutoInstall;//是否自动安装
private static final int PUSH_NOTIFICATION_ID = (0x001);
private static final String PUSH_CHANNEL_ID = "NOTIFY_ID";
private static final String PUSH_CHANNEL_NAME = "PUSH_NOTIFY_NAME";
ProgressDialog pd; //进度条对话框
public VersionUpdateHelper(Context mContext, boolean isAutoInstall) {
this.mContext = mContext;
this.isAutoInstall = isAutoInstall;
getApkPath(mContext);
}
public static String getApkPath(Context context) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
sPath = Environment.getExternalStorageDirectory().getAbsolutePath();
} else {
SDCardUtils.StorageList storageList = new SDCardUtils.StorageList(context);
sPath = storageList.getVolumePaths()[1];
}
return sPath + File.separator + context.getString(R.string.app_name)
+ File.separator + context.getString(R.string.app_name)
+ SUFFIX;
}
private Handler handler = new DownloadHandler();
public void loadVersion(Context mContext,String downloadURL) {
downloadApk(mContext,downloadURL);
}
/**
* 下载apk
*
* @param url apkUrl
*/
private void downloadApk(Context mContex, String url) {
pd = new ProgressDialog(mContex);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMessage("正在下载...");
pd.show();
pd.setCancelable(false);
Log.e("downloadApk", url);
AsyncDownLoad asyncDownLoad = new AsyncDownLoad();
asyncDownLoad.execute(url);
}
/**
* 异步下载app任务
*/
private class AsyncDownLoad extends AsyncTask<String, Integer, Boolean> {
@Override
protected Boolean doInBackground(String... params) {
try {
URL url = new URL(params[0]);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(10000); // 连接超时时间 毫秒级 10S
conn.setReadTimeout(10000); //读取超时时间
conn.setRequestMethod("GET"); //请求方式
conn.setDoInput(true); //打开输入流
conn.connect(); //获取连接
long beforeTime = System.currentTimeMillis();
pd.setProgressNumberFormat("%1d M/%2d M");
pd.setMax((int)conn.getContentLength()/1024/1024);
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
//获得网络字节输入流对象
InputStream is = conn.getInputStream();
long total = conn.getContentLength();
String apkName = mContext.getString(R.string.app_name)
+ SUFFIX;
cache.put(APP_NAME, mContext.getString(R.string.app_name));
File savePath = new File(sPath + File.separator
+ mContext.getString(R.string.app_name));
if (!savePath.exists())
savePath.mkdirs();
File apkFile = new File(savePath, apkName);
//如果文件已经存在,或者已经下载完成了,就不做下载操作
Log.v("ver","apkFile.exists()=="+apkFile.exists());
/*if (apkFile.exists() && apkFile.length() == total) {
return true;
}*/
FileOutputStream fos = null;
fos = new FileOutputStream(apkFile);
byte[] buf = new byte[1024];
int count = 0;
int length = -1;
while ((length = is.read(buf)) != -1) {
fos.write(buf, 0, length);
count += length;
pd.setProgress((int)count/1024/1024);
}
is.close();
fos.close();
return true;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
protected void onPostExecute(Boolean flag) {
pd.dismiss(); //结束掉进度条对话框
if (flag) {
handler.obtainMessage(COMPLETE_DOWNLOAD_APK).sendToTarget();
} else {
Log.e("Error", "下载失败。");
}
}
}
/**
* 安装APK
*
* @param data
*/
private void installApk(File file) {
if (mContext != null) {
if(Build.VERSION.SDK_INT>=24) {//判读版本是否在7.0以上
Uri apkUri = MyFileProvider.getUriForFile(mContext, "包名.download.fileprovider", file);
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
mContext.startActivity(install);
if (notificationManager != null) {
notificationManager.cancel(DOWNLOAD_NOTIFICATION_ID);
}
}else {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(i);
if (notificationManager != null) {
notificationManager.cancel(DOWNLOAD_NOTIFICATION_ID);
}
}
} else {
Log.e("NullPointerException", "The context must not be null.");
}
}
//负责接收进度以及下载完成后启动安装的activity
@SuppressLint("HandlerLeak")
private class DownloadHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case COMPLETE_DOWNLOAD_APK:
if (isAutoInstall) {
installApk(new File(getApkPath(mContext)));
} else {
if (ntfBuilder == null) {
ntfBuilder = new NotificationCompat.Builder(mContext);
}
ntfBuilder.setSmallIcon(mContext.getApplicationInfo().icon)
.setContentTitle(mContext.getString(R.string.app_name))
.setContentText("下载完成,点击安装").setTicker("任务下载完成");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file://" + getApkPath(mContext)),
"application/vnd.android.package-archive");
PendingIntent pendingIntent = PendingIntent.getActivity(
mContext, 0, intent, 0);
ntfBuilder.setContentIntent(pendingIntent);
if (notificationManager == null) {
notificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
}
notificationManager.notify(DOWNLOAD_NOTIFICATION_ID,
ntfBuilder.build());
}
break;
case FAILED_DOWNLOAD_APK:
if (ntfBuilder == null) {
ntfBuilder = new NotificationCompat.Builder(mContext);
}
ntfBuilder.setSmallIcon(mContext.getApplicationInfo().icon)
.setContentTitle(mContext.getString(R.string.app_name))
.setContentText("下载失败,请检查网络").setTicker("新版本下载失败");
notificationManager.notify(DOWNLOAD_NOTIFICATION_ID,
ntfBuilder.build());
break;
}
}
}
}
网友评论