package com.gh.download; import android.content.Context; import android.text.TextUtils; import android.util.Log; import com.gh.common.util.HttpsUtils; import com.gh.common.util.Utils; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; public class DownloadThread extends Thread { private static final int CONNECT_TIME = 5000; private static final int READ_TIME = 5000; private DownloadEntity entry; private DownloadListener listener; private DownloadStatus status; private Context context; public DownloadThread(Context context, DownloadEntity entry, DownloadListener listener) { this.entry = entry; this.listener = listener; this.context = context; } @Override public void run() { super.run(); download(); } private void download() { Utils.log("url = " + entry.getUrl()); if (TextUtils.isEmpty(entry.getUrl())) { listener.onStatusChanged(DownloadStatus.notfound); Utils.log(DownloadThread.class.getSimpleName(), "error-->url is empty"); return; } BufferedInputStream bis = null; BufferedOutputStream bos = null; try { File targetFile = new File(entry.getPath()); if (!targetFile.exists()) { File dir = targetFile.getParentFile(); if (dir.exists() || dir.mkdirs()) { targetFile.createNewFile(); } } HttpURLConnection connection = openConnection(new URL(entry.getUrl()), targetFile.length()); Utils.log(DownloadThread.class.getSimpleName(), "startPosition-->" + targetFile.length()); int code = connection.getResponseCode(); if (code == HttpURLConnection.HTTP_MOVED_PERM || code == HttpURLConnection.HTTP_MOVED_TEMP) { //未自动重定向 String location = connection.getHeaderField("Location"); Utils.log("location = " + location); connection = openConnection(new URL(location), targetFile.length()); code = connection.getResponseCode(); } Utils.log("code = " + code); if (code == HttpURLConnection.HTTP_NOT_FOUND) { // 404 Not Found listener.onStatusChanged(DownloadStatus.notfound); Utils.log(DownloadThread.class.getSimpleName(), "error-->404 Not Found"); return; } String eTag = connection.getHeaderField("ETag"); if (!TextUtils.isEmpty(eTag) && eTag.startsWith("\"") && eTag.endsWith("\"")) { eTag = eTag.substring(1, eTag.length() - 1); } String eTag2 = entry.getETag(); if (!TextUtils.isEmpty(eTag2) && !eTag2.equals(eTag)) { // 链接被劫持,抛出异常 if (!entry.isChange() && "download.ghzhushou.com".equals(new URL(entry.getUrl()).getHost()) && ("apk2.ghzhushou.com".equals(connection.getURL().getHost()) || "apk.ghzhushou.com".equals(connection.getURL().getHost()))) { String newETag = getETag(entry.getUrl()); if (!TextUtils.isEmpty(newETag)) { entry.setETag(newETag); entry.setChange(true); download(); return; } } Utils.log("eTag = " + eTag); Utils.log("eTag2 = " + eTag2); listener.onStatusChanged(DownloadStatus.hijack, connection.getURL().toString()); Utils.log(DownloadThread.class.getSimpleName(), "error-->链接被劫持"); return; } long conentLength = connection.getContentLength(); // 第一次下载记录文件长度 if (entry.getSize() == 0) { entry.setSize(conentLength); DownloadDao.getInstance(context).newOrUpdate(entry); Utils.log(DownloadThread.class.getSimpleName(), "记录第一次长度"); } Utils.log(DownloadThread.class.getSimpleName(), "progress:" + entry.getProgress() + "/curfilesize:" + targetFile.length() + "=====contentLength:" + conentLength + "/ totalSize:" + entry.getSize()); bis = new BufferedInputStream(connection.getInputStream()); if (targetFile.length() > 0) { bos = new BufferedOutputStream(new FileOutputStream(entry.getPath(), true)); } else { bos = new BufferedOutputStream(new FileOutputStream(entry.getPath())); } byte[] buffer = new byte[2048]; int len; while ((len = bis.read(buffer)) != -1) { bos.write(buffer, 0, len); listener.onProgressChanged(targetFile.length(), len); if (status == DownloadStatus.pause || status == DownloadStatus.cancel) { listener.onStatusChanged(status); break; } } bos.flush(); Utils.log(DownloadThread.class.getSimpleName(), "flush==>" + targetFile.length() + ",progress==>" + entry.getProgress() + ",size==>" + entry.getSize()); if (entry.getPath().contains("/data/data/com.gh.gamecenter")) { // 存储在/data/data/包名目录下,添加apk的权限,避免权限导致的解析出错 try { Runtime.getRuntime().exec("chmod 755 " + entry.getPath()); } catch (IOException e) { e.printStackTrace(); } } if (targetFile.length() == entry.getSize()) { listener.onStatusChanged(DownloadStatus.done); } } catch (Exception e) { if (!entry.isReset()) { entry.setReset(true); download(); } else { String errorMsg = Log.getStackTraceString(e); if (!TextUtils.isEmpty(e.getMessage()) && e.getMessage().contains("connection timeout")) { listener.onStatusChanged(DownloadStatus.timeout, errorMsg); } else { listener.onStatusChanged(DownloadStatus.neterror, errorMsg); } Utils.log(DownloadThread.class.getSimpleName(), "exception-->" + e.toString()); } } finally { if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } if (bos != null) { try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } } } private HttpURLConnection openConnection(URL url, long range) throws Exception { HttpURLConnection connection; if ("https".equals(url.getProtocol())) { connection = HttpsUtils.getHttpsURLConnection(url); } else { connection = (HttpURLConnection) url.openConnection(); } connection.setRequestMethod("GET"); connection.setConnectTimeout(CONNECT_TIME); connection.setReadTimeout(READ_TIME); connection.setDoInput(true); connection.setRequestProperty("RANGE", "bytes=" + range + "-"); //设置自动重定向 connection.setInstanceFollowRedirects(true); return connection; } private String getETag(String url) { try { String newUrl = "http://download.ghzhushou.com/etag" + "?url=" + URLEncoder.encode(url, "utf-8") + "&" + System.currentTimeMillis(); HttpURLConnection connection = (HttpURLConnection) new URL(newUrl).openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(CONNECT_TIME); connection.setReadTimeout(READ_TIME); connection.setDoInput(true); connection.connect(); int code = connection.getResponseCode(); if (code == 200) { InputStream is = connection.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[2048]; int len; while ((len = is.read(buffer)) != -1) { baos.write(buffer, 0, len); } baos.flush(); JSONObject response = new JSONObject(baos.toString("utf-8")); return response.getString("etag"); } } catch (IOException | JSONException e) { e.printStackTrace(); } return null; } public void setStatus(DownloadStatus status) { this.status = status; } }