android文件下载成功后自动安装,Android之DownloadManager实现软件更新并自动安装

龙凯
2023-12-01

为之于未有,治之于未乱。

在Android开发中,软件更新可以说是必不可少的,而隔壁的iOS喝着咖啡,无情的嘲笑着这个他们不用再实现的功能,因为苹果会无情的拒绝所有包含软件更新,哪怕是版本检测的APP。作为苦逼的Android攻城狮,我们还是老老实实地研究一下如何实现软件更新吧。

一、软件升级的实现思路

下载APK

应用内下载文件

应用内实现文件下载,如果退出程序,下载将结束。

Service下载文件

利用Service实现文件后台下载,不受程序是否退出的影响。

安装APK

手动安装

自动安装

对于用户而言,后台下载并自动安装必然是一个好的使用体验。使用Service去实现文件下载的话,还需要我们自己维护网络请求,这可是非常麻烦又头痛的事情,有没有一个更方便快捷的方式呢?下面将介绍一种简单粗暴的实现方法!

二、DownloadManager实现文件下载

使用DownloadManager实现APK下载

通过DownloadManager来实现文件下载,我们就可以完全不用考虑网络请求、异步问题了,系统帮我们处理了所有事情,你可以继续操作App,即便是退出程序也不会影响APK的下载。

/**

* 下载新版本

*

* @param context

* @param url

*/

public static void downLoadAPK(Context context, String url) {

if (TextUtils.isEmpty(url)) {

return;

}

try {

String serviceString = Context.DOWNLOAD_SERVICE;

final DownloadManager downloadManager = (DownloadManager) context.getSystemService(serviceString);

Uri uri = Uri.parse(url);

DownloadManager.Request request = new DownloadManager.Request(uri);

request.allowScanningByMediaScanner();

request.setVisibleInDownloadsUi(true);

request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

request.setMimeType("application/vnd.android.package-archive");

File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/juyoubang/","juyoubang.apk");

if (file.exists()){

file.delete();

}

request.setDestinationInExternalPublicDir(Environment.getExternalStorageDirectory().getAbsolutePath()+"/juyoubang/", "juyoubang.apk");

long refernece = downloadManager.enqueue(request);

SharePreHelper.getIns().setLongData("refernece", refernece);

} catch (Exception exception) {

ToastUtils.init(context).show("更新失败");

}

}

三、自动安装

这里的自动安装是指下载完成后,自动弹出安装界面,而不是静默安装APK。同时这里不得不提的一个大坑就是Android6.0这个分水岭,6.0以后的实现方式有所不同。

自定义Receiver接收系统广播,实现软件自动安装。

Android6.0之前的版本我们可以通过Intent的方式来实现,但是我们会发现6.0之后的手机上,下载完成后没有任何效果,解决办法就是通过打开文件的形式实现自动安装。

public class UpdataBroadcastReceiver extends BroadcastReceiver {

@SuppressLint("NewApi")

public void onReceive(Context context, Intent intent) {

long myDwonloadID = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);

long refernece = SharePreHelper.getIns().getLongData("refernece", 0);

if (refernece != myDwonloadID) {

return;

}

DownloadManager dManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);

Uri downloadFileUri = dManager.getUriForDownloadedFile(myDwonloadID);

installAPK(context,downloadFileUri);

}

private void installAPK(Context context,Uri apk ) {

if (Build.VERSION.SDK_INT < 23) {

Intent intents = new Intent();

intents.setAction("android.intent.action.VIEW");

intents.addCategory("android.intent.category.DEFAULT");

intents.setType("application/vnd.android.package-archive");

intents.setData(apk);

intents.setDataAndType(apk, "application/vnd.android.package-archive");

intents.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

context.startActivity(intents);

} else {

File file = queryDownloadedApk(context);

if (file.exists()) {

openFile(file, context);

}

}

}

/**

* 通过downLoadId查询下载的apk,解决6.0以后安装的问题

* @param context

* @return

*/

public static File queryDownloadedApk(Context context) {

File targetApkFile = null;

DownloadManager downloader = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);

long downloadId = SharePreHelper.getIns().getLongData("refernece", -1);

if (downloadId != -1) {

DownloadManager.Query query = new DownloadManager.Query();

query.setFilterById(downloadId);

query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);

Cursor cur = downloader.query(query);

if (cur != null) {

if (cur.moveToFirst()) {

String uriString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));

if (!TextUtils.isEmpty(uriString)) {

targetApkFile = new File(Uri.parse(uriString).getPath());

}

}

cur.close();

}

}

return targetApkFile;

}

private void openFile(File file, Context context) {

Intent intent = new Intent();

intent.addFlags(268435456);

intent.setAction("android.intent.action.VIEW");

String type = getMIMEType(file);

intent.setDataAndType(Uri.fromFile(file), type);

try {

context.startActivity(intent);

} catch (Exception var5) {

var5.printStackTrace();

Toast.makeText(context, "没有找到打开此类文件的程序", Toast.LENGTH_SHORT).show();

}

}

private String getMIMEType(File var0) {

String var1 = "";

String var2 = var0.getName();

String var3 = var2.substring(var2.lastIndexOf(".") + 1, var2.length()).toLowerCase();

var1 = MimeTypeMap.getSingleton().getMimeTypeFromExtension(var3);

return var1;

}

}

最后记得在AndroidManifest.xml中注册广播

还未实现功能:安装成功后删除apk文件。

大功告成。

小插曲:当我把文件名称"juyoubang.apk"写成静态常量来引用的时候,下载并安装时,会提示文件已损坏,无法安装,这让我百思不得其解。

 类似资料: