DownloadManager系统自带下载实现apk后台下载功能
DownloadManager是android2.3以后,系统下载的方法,是处理长期运行的HTTP下载的系统服务。客户端可以请求的URI被下载到一个特定的目标文件。客户端将会在后台与http交互进行下载,或者在下载失败,或者连接改变,重新启动系统后重新下载。还可以进入系统的下载管理界面查看进度。DownloadManger有两个内部类,Request 和Query。Request类可设置下载的一些属性。Query类可查询当前下载的进度,下载地址,文件存放目录等数据。
DownloadManager
1、所需权限
<uses-permission android:name="android.permission.INTERNET" />;
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>;
2、获得对象,开始下载
DownloadManager downloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl));
long id = downloadManager.enqueue(request);
//每下载的一个文件对应一个id,通过此id可以查询数据。
3、取消下载
downloadManager.remove(REFERENCE_1, REFERENCE_2, REFERENCE_3);
该方法返回成功取消的下载的个数,如果一个下载被取消了,所有相关联的文件,部分下载的文件和完全下载的文件都会被删除.
Request类
1.指定下载位置,及文件名称
/**
* 方法1:
* 目录: Android -> data -> com.app -> files -> Download -> dxtj.apk
* 这个文件是你的应用所专用的,软件卸载后,下载的文件将随着卸载全部被删除
*/
request.setDestinationInExternalFilesDir( this , Environment.DIRECTORY_DOWNLOADS , "dxtj.apk" ); /**
* 方法2:
* 下载的文件存放地址 SD卡 download文件夹,dxtj.apk
* 软件卸载后,下载的文件会保留
*/
//在SD卡上创建一个文件夹
request.setDestinationInExternalPublicDir( "/epmyg/" , "dxtj.apk" ) ; /**
* 方法3:
* 如果下载的文件希望被其他的应用共享
* 特别是那些你下载下来希望被Media Scanner扫描到的文件(比如音乐文件)
*/
request.setDestinationInExternalPublicDir( Environment.DIRECTORY_MUSIC, "告白气球.mp3" ); /**
* 方法4
* 文件将存放在外部存储的确实download文件内,如果无此文件夹,创建之,如果有,下面将返回false。
* 系统有个下载文件夹,比如小米手机系统下载文件夹 SD卡--> Download文件夹
*/
//创建目录
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).mkdir() ; //设置文件存放路径
request.setDestinationInExternalPublicDir( Environment.DIRECTORY_DOWNLOADS , "dxtj.apk" ) ;
}
2、指定下载的网络类型
//指定在WIFI状态下,执行下载操作。
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
//指定在MOBILE状态下,执行下载操作
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE);
//是否允许漫游状态下,执行下载操作
request.setAllowedOverRoaming(boolean);
//是否允许“计量式的网络连接”执行下载操作
request.setAllowedOverMetered(boolean); //默认是允许的。
3、定制Notification样式
//设置Notification的标题和描述
request.setTitle("标题");
request.setDescription("描述");
//设置Notification的显示,和隐藏。
request.setNotificationVisibility(visibility);
VISIBILTY_HIDDEN: Notification:将不会显示,如果设置该属性的话,必须要添加权限
Android.permission.DOWNLOAD_WITHOUT_NOTIFICATION.
VISIBILITY_VISIBLE: Notification显示,但是只是在下载任务执行的过程中显示,下载完成自动消失。(默认值)
VISIBILITY_VISIBLE_NOTIFY_COMPLETED : Notification显示,下载进行时,和完成之后都会显示。
VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION :只有当任务完成时,Notification才会显示。
对Notification的设定方法相对较少。
4、设置下载文件类型:
request.setMimeType("application/vnd.android.package-archive");
这是安卓.apk文件的类型。有些机型必须设置此方法,才能在下载完成后,点击通知栏的Notification时,才能正确的打开安装界面。不然会弹出一个Toast(can not open file).其他文件类型的MimeType ,去百度一下 。
5、添加请求下载的网络链接的http头,比如User-Agent,gzip压缩等:
request.addRequestHeader(String header, String value);
Query 类
我们的需求,可能不只是在Notification 中显示进度就好了,也许,在app中也需要获取实时下载进度。所以Query类就是提供查询的一些方法。
但API中就只有两个方法,原来,他把数据保存在数据库中去了。我们需要获得一个Cursor 结果集,通过结果集获得我们想要的数据。
DownloadManager.Query query = new DownloadManager.Query();
Cursor cursor = downloadManager.query(query.setFilterById(id));
if (cursor != null && cursor.moveToFirst()) {
//下载的文件到本地的目录
String address = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
//已经下载的字节数
int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
//总需下载的字节数
int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
//Notification 标题
String title =cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE));
//描述
String description =cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION));
//下载对应id
long id =cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_ID));
//下载文件名称
String filename =cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
//下载文件的URL链接
String url =cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_URI));
}
这只能获取一次,数据库中的信息。我们可以使用Timer类,每隔一段时间去查询数据库即可。也可以使用ContentProvider去访问。
不足之处:
1、我发现,在下载的时候,发送Notification时 是没有声音的。也没有设置声音的方法。不过这影响不大。主要的功能实现就好。
2、因为这是系统的类,每个系统的Notification界面是不一样的。这就是每个rom厂家的自定义了。小米和魅族的就大不一样。魅族Notification上有一个下载暂停的按钮,而小米没有。所以导致Notification是不能统一的。其实,暂停的话用户可以点击notification,进入到下载管理界面,就有暂停按钮了。
实现代码
import android.app.DownloadManager;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView; import java.util.Timer;
import java.util.TimerTask; public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView down;
private TextView progress;
private TextView file_name;
private ProgressBar pb_update;
private DownloadManager downloadManager;
private DownloadManager.Request request;
public static String downloadUrl = "http://ucdl.25pp.com/fs08/2017/01/20/2/2_87a290b5f041a8b512f0bc51595f839a.apk";
Timer timer;
long id;
TimerTask task;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
int pro = bundle.getInt("pro");
String name = bundle.getString("name");
pb_update.setProgress(pro);
progress.setText(String.valueOf(pro) + "%");
file_name.setText(name);
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
down = (TextView) findViewById(R.id.down);
progress = (TextView) findViewById(R.id.progress);
file_name = (TextView) findViewById(R.id.file_name);
pb_update = (ProgressBar) findViewById(R.id.pb_update);
down.setOnClickListener(this);
downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
request = new DownloadManager.Request(Uri.parse(downloadUrl)); request.setTitle("大象投教");
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
request.setAllowedOverRoaming(false);
request.setMimeType("application/vnd.android.package-archive");
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
//创建目录
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).mkdir(); //设置文件存放路径
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "app-release.apk");
pb_update.setMax(100);
final DownloadManager.Query query = new DownloadManager.Query();
timer = new Timer();
task = new TimerTask() {
@Override
public void run() {
Cursor cursor = downloadManager.query(query.setFilterById(id));
if (cursor != null && cursor.moveToFirst()) {
if (cursor.getInt(
cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
pb_update.setProgress(100);
install(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/app-release.apk");
task.cancel();
}
String title = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE));
String address = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
int pro = (bytes_downloaded * 100) / bytes_total;
Message msg = Message.obtain();
Bundle bundle = new Bundle();
bundle.putInt("pro", pro);
bundle.putString("name", title);
msg.setData(bundle);
handler.sendMessage(msg);
}
cursor.close();
}
};
timer.schedule(task, 0, 1000);
} @Override
public void onClick(View v) {
id = downloadManager.enqueue(request);
task.run();
down.setClickable(false);
down.setBackgroundResource(R.drawable.background); } private void install(String path) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + path), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//4.0以上系统弹出安装成功打开界面
startActivity(intent);
}
}
progressbar_color.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@android:id/background">
<shape>
<corners android:radius="10dip"/>
<gradient
android:angle="0"
android:centerColor="#e4e4e4"
android:centerY="0.75"
android:endColor="#e4e4e4"
android:startColor="#e4e4e4"/>
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="10dip"/>
<gradient
android:angle="0"
android:centerColor="#e4e4e4"
android:centerY="0.75"
android:endColor="#e4e4e4"
android:startColor="#e4e4e4"/>
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="10dip"/>
<gradient
android:angle="0"
android:endColor="@color/red"
android:startColor="@color/red"/>
</shape>
</clip>
</item>
</layer-list>
效果:
本文学习来源地址:http://blog.csdn.net/u012209506/article/details/56012744
AKP更新案例学习代码:
import android.app.DownloadManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast; import com.loaderman.group09.redboy11.R;
import com.loaderman.group09.redboy11.utils.PrefUtils;
import com.zhy.http.okhttp.OkHttpUtils;
import com.zhy.http.okhttp.callback.FileCallBack;
import com.zhy.http.okhttp.callback.StringCallback; import org.json.JSONException;
import org.json.JSONObject; import java.io.File; import okhttp3.Call; import static com.loaderman.global.GlobalConstants.URL_PREFIX; /*
* @author: Ji.C.F
* Desc : 关于
* date : 2016/12/23 19:29
*/
public class AboutActivity extends BaseActivity { private TextView tvVersion;
private Button btnUpdateApk;
private String mDownloadUrl;
private String versionMessage;
private boolean isUpdateVersion; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
ivLeft.setVisibility(View.VISIBLE);
ivCenter.setVisibility(View.GONE);
tvCenter.setText("关于");
tvCenter.setVisibility(View.VISIBLE);
btnUpdateApk = (Button) findViewById(R.id.btn_update_apk);
tvVersion = (TextView) findViewById(R.id.tv_version);
tvVersion.setText(getVersionName());
isUpdateVersion = PrefUtils.getBoolean(AboutActivity.this, "isUpdateVersion", false);
if (!isUpdateVersion) {
btnUpdateApk.setText("当前已经是最新版本");
} else {
//Toast.makeText(AboutActivity.this, "有新版本可以更新了", Toast.LENGTH_SHORT).show();
btnUpdateApk.setText("有新版本可以更新了");
}
btnUpdateApk.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!isUpdateVersion) {
Toast.makeText(AboutActivity.this, "当前已经是最新版本了", Toast.LENGTH_SHORT).show();
} else {
updateVersion();
}
}
});
} private void updateVersion() {
OkHttpUtils.get().addParams("ver", getVersionCode() + "").url(URL_PREFIX + "index/index_checkVersion.html").build().execute(new StringCallback() {
@Override
public void onError(Call call, Exception e, int i) {
e.printStackTrace();
Toast.makeText(AboutActivity.this, "网络异常", Toast.LENGTH_SHORT).show();
} @Override
public void onResponse(String result, int i) {
try {
JSONObject json = new JSONObject(result);
String version = json.optString("version");
JSONObject json2 = new JSONObject(version);
String versionCode = json2.optString("versionCode");
versionMessage = json2.optString("versionMessage");
System.out.println(versionMessage);
mDownloadUrl = json2.optString("downloadUrl");
System.out.println(mDownloadUrl);
showUpdateDialog(versionCode);
} catch (JSONException e) {
e.printStackTrace();
} }
}); } private void showUpdateDialog(String mVersionName) {
System.out.println("showUpdateDialog");
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("发现新版本:" + mVersionName);
builder.setMessage(versionMessage);
builder.setPositiveButton("前台更新", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
download();
}
});
builder.setNegativeButton("后台更新", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
download(URL_PREFIX + mDownloadUrl);
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
private void download(String downloadUrl) {
DownloadManager manager = (DownloadManager) getApplicationContext()
.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(
Uri.parse(downloadUrl));
request.setTitle("红孩子下载中...");
request.setDescription("让你的购物从此与众不同!!!");
request.allowScanningByMediaScanner();// 设置可以被扫描到
request.setVisibleInDownloadsUi(true);// 设置下载可见
String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));// 解析fileName
request.setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS, fileName);// 设置下载位置,sdcard/Download/fileName
long refernece = manager.enqueue(request);// 加入下载并取得下载ID
SharedPreferences sPreferences = getApplicationContext()
.getSharedPreferences("downloadplato", 0);
sPreferences.edit().putLong("plato", refernece).commit();//保存此次下载ID
}
private void download() {
//设置进度条
final ProgressDialog progressDialog = new ProgressDialog(this);
//水平显示
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setTitle("拼命下载中");
//显示
progressDialog.show();
OkHttpUtils.get().url(URL_PREFIX + mDownloadUrl).build().execute(new FileCallBack(Environment.getExternalStorageDirectory().getAbsolutePath(), "RedBoy.apk") {
@Override
public void onError(Call call, Exception e, int i) {
progressDialog.dismiss();
} @Override
public void inProgress(float progress, long total, int id) {
super.inProgress(progress, total, id);
progressDialog.setProgress((int) (progress * 100));
} @Override
public void onResponse(File file, int i) {
progressDialog.dismiss();
installAPK(file);
}
});
} private void installAPK(File file) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivityForResult(intent, 0);
} private String getVersionName() {
PackageManager pm = getPackageManager();
try {
PackageInfo info = pm.getPackageInfo(getPackageName(), 0);
String versionName = info.versionName;
return versionName;
} catch (Exception e) {
e.printStackTrace();
}
return "";
} private int getVersionCode() {
PackageManager pm = getPackageManager();
try {
PackageInfo info = pm.getPackageInfo(getPackageName(), 0);
int versionCode = info.versionCode;
return versionCode;
} catch (Exception e) {
e.printStackTrace();
}
return -1;
} }
DownloadManager系统自带下载实现apk后台下载功能的更多相关文章
- ios开发视频播放后台下载功能实现 :1,ios播放视频 ,包含基于AVPlayer播放器,2,实现下载,iOS后台下载(多任务同时下载,单任务下载,下载进度,下载百分比,文件大小,下载状态)(真机调试功能正常)
ABBPlayerKit ios开发视频播放后台下载功能实现 : 代码下载地址:https://github.com/niexiaobo/ABBPlayerKit github资料学习和下载地址:ht ...
- 背水一战 Windows 10 (117) - 后台任务: 后台下载任务
[源码下载] 背水一战 Windows 10 (117) - 后台任务: 后台下载任务 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台下载任务 示例演示 uwp 的后台下 ...
- ios 后台下载,断点续传总结
2018年12月05日 16:09:00 weixin_34101784 阅读数:5 https://blog.csdn.net/weixin_34101784/article/details/875 ...
- 如何在Mac上切换python2和python3以及下载安装包 & 在Mac上如何查找系统自带python2.7的路径
电脑:系统是Mac OS 系统自带python2.7 自己下载安装了python3.6 问题:一开始我想在终端下执行python2的相关代码 例如 python kNN.py (kNN.py这 ...
- 如何获取安卓系统自带应用的package和activity
之前在做appium自动化测试的时候,参考网上的例子,运行安卓系统自带的app,所以,就需要获取系统自带的package(包名)和activity.这里简单记录一下,不一定适合所有的系统应用. 运行环 ...
- XP系统电脑带安卓手机上网教程(无需adhoc补丁)
XP系统电脑带安卓手机上网教程(无需adhoc补丁) WIN7系统可以虚拟wifi热点,安卓手机连上这个热点就能上网.XP系统虚拟出来的wifi热点是adhoc形式的,原生的安卓系统并不支持adhoc ...
- ShareIntentUtil【调用系统自带的分享的工具类】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 根据参考资料的文章,整理了调用系统自带分享的工具类(实现了适配7.0FileProvider的功能),需要搭配<Android ...
- 下载安装APK(兼容Android7.0)
我们使用手机的时候经常会看到应用程序提示升级,大部分应用内部都需要实现升级提醒和应用程序文件(APK文件)下载. 一般写法都差不多,比如在启动app的时候,通过api接口获得服务器最新的版本号,然后和 ...
- Notepad2替代系统自带的记事本
事情是这样的,平时我经常把一些文字复制到记事本中编辑好了再复制到目标位置,可以在系统自带的记事本中替换删除一些内容,记事本小巧,占用很少的资源,我很喜欢:但今天复制的内容中有很多数字和一些我不想要的内 ...
随机推荐
- Delphi WaitCommEvent函数
- 【异常】Caused by: java.lang.IllegalStateException: Zip64 archives are not supported
1 自己打包Spring boot项目依赖了第三方的Phoenix jar包过大,导致启动后报错 参考了这篇博客:https://cloud.tencent.com/developer/ask/135 ...
- Manjaro18+kde 更换壁纸重启失效
更换壁纸 在kde的桌面右键->配置桌面 壁纸里更换壁纸,我不能直接添加图像并应用.我的系统在这样操作后重启就会发现一切都被重置了.刚刚添加的图片也不见了. 于是,我就模范原本存在壁纸文 ...
- python函数:函数阶段练习
1.写函数,用户传入修改的文件名,与要修改的内容,执行函数,完成批了修改的操作def modify_file(filename,old,new): import os with open(filena ...
- 第二章 Vue快速入门--12 事件修饰符的介绍
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- kubernetes 创建超级管理员和密匙
# 创建一个超级管理员adm_account="k8s-dash-admin"kubectl create serviceaccount ${adm_account} -n kub ...
- pro git 读书笔记 3 Git 分支
分支 新建分支:git branch 分支名 切换到该分支:git checkout 分支名 补充:以上两条语句等价于一句:git checkout -b 分支名 转换分支的时候最好保持一个清洁的工作 ...
- hdu 6041 I Curse Myself
题目: 点这里OvO http://acm.hdu.edu.cn/showproblem.php?pid=6041 2017 Multi-University Training Contest - T ...
- .NET面试题系列(二十一)C#中Equals和==的比较
序言 值类型的比较 ; ; Console.WriteLine("Equals和= =(等于号)的比较"); Console.WriteLine("i.Equals(j) ...
- BZOJ1968: [Ahoi2005]COMMON 约数研究 线性筛
按照积性函数的定义筛一下这个积性函数即可. #include <cstdio> #include <algorithm> #define N 1000004 #define s ...