版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33718648/article/details/79726402
一、首先需要判断版本号,根据版本号显示提示更新的弹窗,并启动下载服务
//
DialogUtil是一个弹出弹窗的工具类,可以根据自己的需求定制。
DialogUtil.showupdataDialog(mWXSDKInstance.getUIContext(), title, content, new View.OnClickListener() {
@Override
public void onClick(View view) {
//下面几行代码用来判断是否在使用wifi下载
ConnectivityManager connectivityManager=(ConnectivityManager)getSystemService(mWXSDKInstance.getContext(),Context.CONNECTIVITY_SERVICE);
TelephonyManager mTelephony = (TelephonyManager)getSystemService(mWXSDKInstance.getContext(),Context.TELEPHONY_SERVICE);
NetworkInfo info = connectivityManager.getActiveNetworkInfo();
int netType = info.getType();
if (netType == ConnectivityManager.TYPE_WIFI) { //是在使用WIFI
//这里的
ApkDownloadUtils是下载的工具类,用于启动下载服务
ApkDownloadUtils.startDownload(mWXSDKInstance.getContext(), url, FileUtils.getApkFile(Constant.FILE_NAME_APK) + "yunyigc.apk", fileSize);
} else {
//在使用流量
//弹出confirm弹窗,确定是否用流量更新
DialogUtil.showDialogConfirm(mWXSDKInstance.getContext(), "提醒", "当前非WiFi环境,继续使用会产生流量费用,是否继续下载??",
"取消",new View.OnClickListener() {
@Override
public void onClick(View v) {
}
}, "确定", new View.OnClickListener() {
@Override
public void onClick(View v) {
ApkDownloadUtils.startDownload(mWXSDKInstance.getContext(), url, FileUtils.getApkFile(Constant.FILE_NAME_APK) + "yunyigc.apk", fileSize);
}
},View.VISIBLE).show();
}
}
}, isCancel).show();
//
DialogUtil是一个弹出弹窗的工具类,可以根据自己的需求定制。
public class ApkDownloadUtils {
/**
* @param context
* @param url
* @param filePath
* @param fileSize
*/
public static void startDownload(Context context, String url, String filePath, long fileSize) {
Intent i = new Intent(context, DownloadService.class);
i.putExtra(DownloadService.DOWNLOAD_URL, url);
i.putExtra(DownloadService.DOWNLOAD_PATH, filePath);
i.putExtra(DownloadService.DOWNLOAD_SIZE, fileSize);
context.startService(i);
}
}
//得到要下载到的文件路径
public class FileUtils {
public static String getApkFile(String path) {
String savePath = null;
String storageState = Environment.getExternalStorageState();
if (storageState.equals(Environment.MEDIA_MOUNTED)) {
savePath = Environment.getExternalStorageDirectory()
.getAbsolutePath() + path;
File file = new File(savePath);
if (!file.exists()) {
file.mkdirs();
}
}
if (TextUtils.isEmpty(savePath)) {
return null;
}
return savePath;
}
public static final boolean saveBytesToFile(byte[] bytes, File file) {
if (bytes == null) {
return false;
}
ByteArrayInputStream bais = null;
BufferedOutputStream bos = null;
try {
file.getParentFile().mkdirs();
file.createNewFile();
bais = new ByteArrayInputStream(bytes);
bos = new BufferedOutputStream(new FileOutputStream(file));
int size;
byte[] temp = new byte[1024];
while ((size = bais.read(temp, 0, temp.length)) != -1) {
bos.write(temp, 0, size);
}
bos.flush();
return true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
bos = null;
}
if (bais != null) {
try {
bais.close();
} catch (IOException e) {
e.printStackTrace();
}
bais = null;
}
}
return false;
}
}
二、在服务中下载文件,网络请求用的是okhttp3框架
下载服务,在下载服务中,首先在开启服务的时候需要传递必要的参数给通知控制工具类
UploadUtil,该类主要是用于对通知栏下载进度和点击事件的控制。
public class DownloadService extends Service {
private List<String> urls = new ArrayList<String>();
private final String FILE_DIR = Environment.getExternalStorageDirectory().toString() + "";
private final int DOWNLOAD_ERROR = 0;
private final int DOWNLOAD_SUCCESS = 1;
private final int DOWNLOAD_PROGRESS = 2;
private final int DOWNLOAD_PASUE=3;
public static final String DOWNLOAD_URL = "url";
public static final String DOWNLOAD_PATH = "path";
public static final String DOWNLOAD_SIZE = "size";
public static final String IS_PASUE="isPasue";
public static final String NOTIFY_LARGE_ICON = "large_icon";
public static final String NOTIFY_SMALL_ICON = "small_icon";
private String url;
private String path;
private long size;
//静态变量用于控制下载的暂停和开始
public static boolean isPasue=false;
Handler handler;
UploadUtil downloadUtil;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
initHandler();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
url = intent.getStringExtra(DOWNLOAD_URL);
path = intent.getStringExtra(DOWNLOAD_PATH);
size = intent.getLongExtra(DOWNLOAD_SIZE, 0);
//初始化通知栏下载通知栏工具类,传入必要的参数下载地址,下载到的文件路径,文件大小
downloadUtil=new UploadUtil(DownloadService.this,url,path,size);
//开始下载
startDownload(url, path, size);
}
return super.onStartCommand(intent, flags, startId);
}
//更新UI的处理器
private void initHandler() {
handler = new Handler(getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == DOWNLOAD_PROGRESS || msg.what == DOWNLOAD_SUCCESS) {
Bundle b = msg.getData();
String file = b.getString("file");
long max = b.getLong("max");
long current = b.getLong("current");
String url = b.getString("url");
int percent = (int) (current * 100 / max);
downloadUtil.notifyChange(DownloadService.this, getString(R.string.app_name), percent);
if (msg.what == DOWNLOAD_SUCCESS && urls.contains(url)) {
File filetemp = new File(file);
if (filetemp.exists()) {
Log.i("lllttt", "DownloadService : " + filetemp.getAbsolutePath());
update(filetemp, DownloadService.this.getApplicationContext(),size);
Toast.makeText(DownloadService.this, R.string.completed_download, Toast.LENGTH_SHORT).show();
}
urls.remove(url);
}
} else if (msg.what == DOWNLOAD_ERROR) {
Bundle b = msg.getData();
String name = b.getString("name");
String url = b.getString("url");
String file = b.getString("file");
String message = b.getString("error_message");
Toast.makeText(DownloadService.this, message, Toast.LENGTH_LONG).show();
if (urls.contains(url)) {
urls.remove(url);
}
File fileTemp = new File(file);
if (fileTemp != null && fileTemp.exists()) {
fileTemp.delete();
}
Toast.makeText(DownloadService.this, String.format(getString(R.string.download_fail), name), Toast.LENGTH_LONG).show();
}else{
if (urls.contains(url)) {
urls.remove(url);
}
Bundle b = msg.getData();
long current = b.getLong("current");
long max = b.getLong("max");
int percent = (int) (current * 100 / max);
downloadUtil.notifyPasue(DownloadService.this,"已暂停下载",percent);
Toast.makeText(DownloadService.this,"已暂停下载", Toast.LENGTH_LONG).show();
}
}
};
}
File dir;
long downloadLength=0; //记录已经下载的文件长度
/**
* @param url
* @param filePath
* @param size
*/
private void startDownload(final String url, String filePath, final long size) {
dir= new File(filePath);
try {
//如果文件已经存在,并且文件大小大于等于要下载的文件大小,就将文件删除
if (dir.exists()&&dir.length()>=size) {
dir.delete();
}
else if(dir.exists()){//如果文件只是已存在,那么获取文件大小
downloadLength=dir.length();
}
dir.createNewFile();//如果文件不存在,创建新文件,文件存在,不作处理
} catch (IOException e) {
e.printStackTrace();
}
if (!TextUtils.isEmpty(url) && !urls.contains(url)) {
urls.add(url);
} else {
return;
}
OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.build();
/**
* HTTP请求是有一个Header的,里面有个Range属性是定义下载区域的,它接收的值是一个区间范围,
* 比如:Range:bytes=0-10000。这样我们就可以按照一定的规则,将一个大文件拆分为若干很小的部分,
* 然后分批次的下载,每个小块下载完成之后,再合并到文件中;这样即使下载中断了,重新下载时,
* 也可以通过文件的字节长度来判断下载的起始点,然后重启断点续传的过程,直到最后完成下载过程。
* 这里是需要后台来做配合的
*/
Request request;
String downPoint=String.valueOf(downloadLength);
request = new Request.Builder().url(url).header("Range",downPoint).build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call,final IOException e) {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(DownloadService.this, "请求失败", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("message-----","正在下载2"+"-code:"+response.code());
if (response != null && response.code() == 200) {
InputStream is = null;
Log.e("message-----","正在下载3");
FileOutputStream out = null;
long total = 0;
try {
ResponseBody body = response.body();
is = body.byteStream();
//可以看一下
RandomAccessFile的用法
RandomAccessFile savedFile=null;
savedFile=new RandomAccessFile(dir,"rw");
//跳过已经下载的字节
savedFile.seek(downloadLength);
total = size;
byte[] buf = new byte[2048];
int len = 0;
long lastTime = System.currentTimeMillis();
while ((len = is.read(buf)) != -1&&!isPasue) {//当文件还没有读完,并且不是暂停状态,也就是暂停状态下停止
savedFile.write(buf, 0, len);
downloadLength += len;
long currentTime = System.currentTimeMillis();
if (currentTime - lastTime > 1000) {
Message msg = handler.obtainMessage();
msg.what = DOWNLOAD_PROGRESS;
Bundle b = msg.getData();
b.putString("file", dir.getAbsolutePath());
b.putLong("max", total);
b.putLong("current", downloadLength);
b.putString("name", "xinao.apk");
handler.sendMessage(msg);
lastTime = currentTime;
}
}
Message msg = handler.obtainMessage();
if(isPasue){//更新下载通知栏的视图效果
msg.what=DOWNLOAD_PASUE;
is.close();
}else{
msg.what = DOWNLOAD_SUCCESS;
}
Bundle b = msg.getData();
b.putString("file", dir.getAbsolutePath());
b.putLong("max", total);
b.putLong("current", downloadLength);
b.putString("url", url);
//发送更新进度条的消息
handler.sendMessageDelayed(msg, 1000);
savedFile.close();
} catch (Exception e) {
if (downloadLength == 0 || downloadLength != total) {
Message msg = handler.obtainMessage();
Bundle b = msg.getData();
b.putString("url", url);
b.putString("name", "xinao.apk");
b.putString("file", dir.getAbsolutePath());
b.putString("error_message", "message: " + e.getMessage());
Log.e("Error-------",e.getMessage());
msg.what = DOWNLOAD_ERROR;
//发送包含错误信息的消息
handler.sendMessage(msg);
}
} finally {
if (is != null) {
is.close();
}
if (out != null) {
out.close();
}
}
}
}
});
}
/**
* 安装应用
*/
public static void update(File apkFile, Context context,long size) {
Intent intent = new Intent(Intent.ACTION_VIEW);
if (apkFile != null && apkFile.exists()&&apkFile.length()==size) {
chmod(apkFile.getAbsolutePath());//授权
intent.setDataAndType(Uri.fromFile(apkFile),
"application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else {
Toast.makeText(context, "安装失败,安装文件未找到", Toast.LENGTH_SHORT).show();
}
}
public static void chmod(String pathc) {
String chmodCmd = "chmod 666 " + pathc;
try {
Runtime.getRuntime().exec(chmodCmd);
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、用广播接收顶部通知栏的点击事件,并通过改变服务中的静态变量启动和暂停下载服务
public class ApkDownReceiver extends BroadcastReceiver{
/**
* @param context
* @param intent
*/
@Override
public void onReceive(Context context, Intent intent) {
isPasue=!isPasue;
if(isPasue){//改变完状态如果是暂停状态,那么不在通知中做其他操作,下载服务类中可以接收到全局变量pasue的变化
//然后在服务中停止下载,并更新下载的通知栏状态
Log.e("Error-------","是否暂停"+isPasue);
}else {//改变后是下载状态,那么就启动服务继续下载
String url=intent.getStringExtra(DownloadService.DOWNLOAD_URL);
String filePath=intent.getStringExtra(DownloadService.DOWNLOAD_PATH);
long fileSize=intent.getLongExtra(DownloadService.DOWNLOAD_SIZE,0);
Intent startService=new Intent(context,DownloadService.class);
startService.putExtra(DownloadService.DOWNLOAD_URL,url);
startService.putExtra(DownloadService.DOWNLOAD_PATH,filePath);
startService.putExtra(DownloadService.DOWNLOAD_SIZE,fileSize);
context.startService(startService);
}
}
}