Merge branch 'v_2.0'
This commit is contained in:
@ -30,6 +30,7 @@ import android.text.TextUtils;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.PopupWindow;
|
import android.widget.PopupWindow;
|
||||||
import com.arialyy.aria.core.command.CmdFactory;
|
import com.arialyy.aria.core.command.CmdFactory;
|
||||||
|
import com.arialyy.aria.util.CAConfiguration;
|
||||||
import com.arialyy.aria.util.CheckUtil;
|
import com.arialyy.aria.util.CheckUtil;
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
import com.arialyy.aria.core.command.IDownloadCmd;
|
import com.arialyy.aria.core.command.IDownloadCmd;
|
||||||
@ -48,12 +49,12 @@ import java.util.Set;
|
|||||||
* Aria管理器,任务操作在这里执行
|
* Aria管理器,任务操作在这里执行
|
||||||
*/
|
*/
|
||||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public class AriaManager {
|
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public class AriaManager {
|
||||||
private static final String TAG = "AriaManager";
|
private static final String TAG = "AriaManager";
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
private static volatile AriaManager INSTANCE = null;
|
private static volatile AriaManager INSTANCE = null;
|
||||||
private Map<String, AMReceiver> mTargets = new HashMap<>();
|
private Map<String, AMReceiver> mTargets = new HashMap<>();
|
||||||
private DownloadManager mManager;
|
private DownloadManager mManager;
|
||||||
private LifeCallback mLifeCallback;
|
private LifeCallback mLifeCallback;
|
||||||
|
|
||||||
private AriaManager(Context context) {
|
private AriaManager(Context context) {
|
||||||
regAppLifeCallback(context);
|
regAppLifeCallback(context);
|
||||||
@ -73,6 +74,24 @@ import java.util.Set;
|
|||||||
return getTarget(obj);
|
return getTarget(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置CA证书信息
|
||||||
|
*
|
||||||
|
* @param caAlias ca证书别名
|
||||||
|
* @param caPath assets 文件夹下的ca证书完整路径
|
||||||
|
*/
|
||||||
|
public void setCAInfo(String caAlias, String caPath) {
|
||||||
|
if (TextUtils.isEmpty(caAlias)) {
|
||||||
|
Log.e(TAG, "ca证书别名不能为null");
|
||||||
|
return;
|
||||||
|
} else if (TextUtils.isEmpty(caPath)) {
|
||||||
|
Log.e(TAG, "ca证书路径不能为null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CAConfiguration.CA_ALIAS = caAlias;
|
||||||
|
CAConfiguration.CA_PATH = caPath;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取下载列表
|
* 获取下载列表
|
||||||
*/
|
*/
|
||||||
@ -100,7 +119,7 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public void stopAllTask() {
|
public void stopAllTask() {
|
||||||
List<DownloadEntity> allEntity = mManager.getAllDownloadEntity();
|
List<DownloadEntity> allEntity = mManager.getAllDownloadEntity();
|
||||||
List<IDownloadCmd> stopCmds = new ArrayList<>();
|
List<IDownloadCmd> stopCmds = new ArrayList<>();
|
||||||
for (DownloadEntity entity : allEntity) {
|
for (DownloadEntity entity : allEntity) {
|
||||||
if (entity.getState() == DownloadEntity.STATE_DOWNLOAD_ING) {
|
if (entity.getState() == DownloadEntity.STATE_DOWNLOAD_ING) {
|
||||||
stopCmds.add(CommonUtil.createCmd(entity, CmdFactory.TASK_STOP));
|
stopCmds.add(CommonUtil.createCmd(entity, CmdFactory.TASK_STOP));
|
||||||
@ -159,8 +178,8 @@ import java.util.Set;
|
|||||||
* 删除所有任务
|
* 删除所有任务
|
||||||
*/
|
*/
|
||||||
public void cancelAllTask() {
|
public void cancelAllTask() {
|
||||||
List<DownloadEntity> allEntity = mManager.getAllDownloadEntity();
|
List<DownloadEntity> allEntity = mManager.getAllDownloadEntity();
|
||||||
List<IDownloadCmd> cancelCmds = new ArrayList<>();
|
List<IDownloadCmd> cancelCmds = new ArrayList<>();
|
||||||
for (DownloadEntity entity : allEntity) {
|
for (DownloadEntity entity : allEntity) {
|
||||||
cancelCmds.add(CommonUtil.createCmd(entity, CmdFactory.TASK_CANCEL));
|
cancelCmds.add(CommonUtil.createCmd(entity, CmdFactory.TASK_CANCEL));
|
||||||
}
|
}
|
||||||
@ -174,9 +193,9 @@ import java.util.Set;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private AMReceiver putTarget(Object obj) {
|
private AMReceiver putTarget(Object obj) {
|
||||||
String clsName = obj.getClass().getName();
|
String clsName = obj.getClass().getName();
|
||||||
AMReceiver target = null;
|
AMReceiver target = null;
|
||||||
String key = "";
|
String key = "";
|
||||||
if (!(obj instanceof Activity)) {
|
if (!(obj instanceof Activity)) {
|
||||||
if (obj instanceof android.support.v4.app.Fragment) {
|
if (obj instanceof android.support.v4.app.Fragment) {
|
||||||
key = clsName + "_" + ((Fragment) obj).getActivity().getClass().getName();
|
key = clsName + "_" + ((Fragment) obj).getActivity().getClass().getName();
|
||||||
@ -249,12 +268,12 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
private void handleDialogLift(Dialog dialog) {
|
private void handleDialogLift(Dialog dialog) {
|
||||||
try {
|
try {
|
||||||
Field dismissField = CommonUtil.getField(dialog.getClass(), "mDismissMessage");
|
Field dismissField = CommonUtil.getField(dialog.getClass(), "mDismissMessage");
|
||||||
Message dismissMsg = (Message) dismissField.get(dialog);
|
Message dismissMsg = (Message) dismissField.get(dialog);
|
||||||
//如果Dialog已经设置Dismiss事件,则查找cancel事件
|
//如果Dialog已经设置Dismiss事件,则查找cancel事件
|
||||||
if (dismissMsg != null) {
|
if (dismissMsg != null) {
|
||||||
Field cancelField = CommonUtil.getField(dialog.getClass(), "mCancelMessage");
|
Field cancelField = CommonUtil.getField(dialog.getClass(), "mCancelMessage");
|
||||||
Message cancelMsg = (Message) cancelField.get(dialog);
|
Message cancelMsg = (Message) cancelField.get(dialog);
|
||||||
if (cancelMsg != null) {
|
if (cancelMsg != null) {
|
||||||
Log.e(TAG, "你已经对Dialog设置了Dismiss和cancel事件。为了防止内存泄露,"
|
Log.e(TAG, "你已经对Dialog设置了Dismiss和cancel事件。为了防止内存泄露,"
|
||||||
+ "请在dismiss方法中调用Aria.whit(this).removeSchedulerListener();来注销事件");
|
+ "请在dismiss方法中调用Aria.whit(this).removeSchedulerListener();来注销事件");
|
||||||
@ -316,12 +335,12 @@ import java.util.Set;
|
|||||||
* onDestroy
|
* onDestroy
|
||||||
*/
|
*/
|
||||||
private void destroySchedulerListener(Object obj) {
|
private void destroySchedulerListener(Object obj) {
|
||||||
Set<String> keys = mTargets.keySet();
|
Set<String> keys = mTargets.keySet();
|
||||||
String clsName = obj.getClass().getName();
|
String clsName = obj.getClass().getName();
|
||||||
for (Iterator<Map.Entry<String, AMReceiver>> iter = mTargets.entrySet().iterator();
|
for (Iterator<Map.Entry<String, AMReceiver>> iter = mTargets.entrySet().iterator();
|
||||||
iter.hasNext(); ) {
|
iter.hasNext(); ) {
|
||||||
Map.Entry<String, AMReceiver> entry = iter.next();
|
Map.Entry<String, AMReceiver> entry = iter.next();
|
||||||
String key = entry.getKey();
|
String key = entry.getKey();
|
||||||
if (key.equals(clsName) || key.contains(clsName)) {
|
if (key.equals(clsName) || key.contains(clsName)) {
|
||||||
AMReceiver receiver = mTargets.get(key);
|
AMReceiver receiver = mTargets.get(key);
|
||||||
if (receiver.obj != null) {
|
if (receiver.obj != null) {
|
||||||
|
@ -89,21 +89,15 @@ public class DownloadTaskQueue implements ITaskQueue {
|
|||||||
|
|
||||||
@Override public void stopTask(Task task) {
|
@Override public void stopTask(Task task) {
|
||||||
if (!task.isDownloading()) Log.w(TAG, "停止任务失败,【任务已经停止】");
|
if (!task.isDownloading()) Log.w(TAG, "停止任务失败,【任务已经停止】");
|
||||||
task.stop();
|
if (mExecutePool.removeTask(task)) {
|
||||||
//if (task.isDownloading()) {
|
task.stop();
|
||||||
// if (mExecutePool.removeTask(task)) {
|
} else {
|
||||||
// task.stop();
|
task.stop();
|
||||||
// }
|
Log.w(TAG, "停止任务失败,【任务已经停止】");
|
||||||
//} else {
|
}
|
||||||
// task.stop();
|
|
||||||
// Log.w(TAG, "停止任务失败,【任务已经停止】");
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void cancelTask(Task task) {
|
@Override public void cancelTask(Task task) {
|
||||||
//if (mExecutePool.removeTask(task) || mCachePool.removeTask(task)) {
|
|
||||||
// task.cancel();
|
|
||||||
//}
|
|
||||||
task.cancel();
|
task.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,10 +113,6 @@ public class DownloadTaskQueue implements ITaskQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Override public IDownloadSchedulers getDownloadSchedulers() {
|
|
||||||
// return mSchedulers;
|
|
||||||
//}
|
|
||||||
|
|
||||||
@Override public int size() {
|
@Override public int size() {
|
||||||
return mExecutePool.size();
|
return mExecutePool.size();
|
||||||
}
|
}
|
||||||
@ -159,12 +149,10 @@ public class DownloadTaskQueue implements ITaskQueue {
|
|||||||
@Override public Task createTask(String target, DownloadEntity entity) {
|
@Override public Task createTask(String target, DownloadEntity entity) {
|
||||||
Task task;
|
Task task;
|
||||||
if (TextUtils.isEmpty(target)) {
|
if (TextUtils.isEmpty(target)) {
|
||||||
//task = TaskFactory.getInstance().createTask(mContext, entity, mSchedulers);
|
|
||||||
task =
|
task =
|
||||||
TaskFactory.getInstance().createTask(mContext, entity, DownloadSchedulers.getInstance());
|
TaskFactory.getInstance().createTask(mContext, entity, DownloadSchedulers.getInstance());
|
||||||
} else {
|
} else {
|
||||||
task = TaskFactory.getInstance()
|
task = TaskFactory.getInstance()
|
||||||
//.createTask(target.getClass().getName(), mContext, entity, mSchedulers);
|
|
||||||
.createTask(target, mContext, entity, DownloadSchedulers.getInstance());
|
.createTask(target, mContext, entity, DownloadSchedulers.getInstance());
|
||||||
}
|
}
|
||||||
mCachePool.putTask(task);
|
mCachePool.putTask(task);
|
||||||
@ -197,29 +185,15 @@ public class DownloadTaskQueue implements ITaskQueue {
|
|||||||
return mCachePool.pollTask();
|
return mCachePool.pollTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Override public void setScheduler(IDownloadSchedulers schedulers) {
|
|
||||||
// mSchedulers = schedulers;
|
|
||||||
//}
|
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
Context context;
|
Context context;
|
||||||
IDownloadSchedulers schedulers;
|
|
||||||
|
|
||||||
public Builder(Context context) {
|
public Builder(Context context) {
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
//public Builder setDownloadSchedulers(IDownloadSchedulers schedulers) {
|
|
||||||
// this.schedulers = schedulers;
|
|
||||||
// return this;
|
|
||||||
//}
|
|
||||||
|
|
||||||
public DownloadTaskQueue build() {
|
public DownloadTaskQueue build() {
|
||||||
DownloadTaskQueue queue = new DownloadTaskQueue(context);
|
DownloadTaskQueue queue = new DownloadTaskQueue(context);
|
||||||
//if (schedulers == null) {
|
|
||||||
// schedulers = DownloadSchedulers.getInstance();
|
|
||||||
//}
|
|
||||||
//queue.setScheduler(schedulers);
|
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,11 +73,4 @@ public interface ITaskQueue extends IDownloader {
|
|||||||
* @return 下载任务 or null
|
* @return 下载任务 or null
|
||||||
*/
|
*/
|
||||||
public Task getNextTask();
|
public Task getNextTask();
|
||||||
|
|
||||||
///**
|
|
||||||
// * 设置下载调度器
|
|
||||||
// *
|
|
||||||
// * @param schedulers 下载调度器{@link IDownloadSchedulers}
|
|
||||||
// */
|
|
||||||
//public void setScheduler(IDownloadSchedulers schedulers);
|
|
||||||
}
|
}
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.arialyy.aria.core.scheduler;
|
package com.arialyy.aria.core.scheduler;
|
||||||
|
|
||||||
|
import android.os.CountDownTimer;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -154,10 +155,8 @@ public class DownloadSchedulers implements IDownloadSchedulers {
|
|||||||
|
|
||||||
private void callback(int state, Task task, OnSchedulerListener listener) {
|
private void callback(int state, Task task, OnSchedulerListener listener) {
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
//Task task = mQueue.getTask(entity);
|
|
||||||
if (task == null) {
|
if (task == null) {
|
||||||
//Log.e(TAG, "队列中没有下载链接【" + entity.getDownloadUrl() + "】的任务");
|
Log.e(TAG, "TASK 为null,回调失败");
|
||||||
Log.e(TAG, "传递的下载任务");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@ -195,9 +194,13 @@ public class DownloadSchedulers implements IDownloadSchedulers {
|
|||||||
* @param entity 失败实体
|
* @param entity 失败实体
|
||||||
*/
|
*/
|
||||||
@Override public void handleFailTask(final DownloadEntity entity) {
|
@Override public void handleFailTask(final DownloadEntity entity) {
|
||||||
new Thread(new Runnable() {
|
final Configuration config = Configuration.getInstance();
|
||||||
@Override public void run() {
|
CountDownTimer timer = new CountDownTimer(config.getReTryInterval(), 1000) {
|
||||||
final Configuration config = Configuration.getInstance();
|
@Override public void onTick(long millisUntilFinished) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onFinish() {
|
||||||
if (entity.getFailNum() <= config.getReTryNum()) {
|
if (entity.getFailNum() <= config.getReTryNum()) {
|
||||||
Task task = mQueue.getTask(entity);
|
Task task = mQueue.getTask(entity);
|
||||||
mQueue.reTryStart(task);
|
mQueue.reTryStart(task);
|
||||||
@ -210,7 +213,8 @@ public class DownloadSchedulers implements IDownloadSchedulers {
|
|||||||
startNextTask(entity);
|
startNextTask(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
};
|
||||||
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,7 +20,9 @@ import android.content.Context;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import com.arialyy.aria.core.DownloadEntity;
|
import com.arialyy.aria.core.DownloadEntity;
|
||||||
|
import com.arialyy.aria.util.CAConfiguration;
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
|
import com.arialyy.aria.util.SSLContextUtil;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -29,43 +31,47 @@ import java.net.HttpURLConnection;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.ProtocolException;
|
import java.net.ProtocolException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by lyy on 2015/8/25.
|
* Created by lyy on 2015/8/25.
|
||||||
* 下载工具类
|
* 下载工具类
|
||||||
*/
|
*/
|
||||||
final class DownloadUtil implements IDownloadUtil, Runnable {
|
final class DownloadUtil implements IDownloadUtil, Runnable {
|
||||||
private static final String TAG = "DownloadUtil";
|
private static final String TAG = "DownloadUtil";
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
/**
|
/**
|
||||||
* 线程数
|
* 线程数
|
||||||
*/
|
*/
|
||||||
private final int THREAD_NUM;
|
private final int THREAD_NUM;
|
||||||
//下载监听
|
//下载监听
|
||||||
private IDownloadListener mListener;
|
private IDownloadListener mListener;
|
||||||
private int mConnectTimeOut = 5000 * 4; //连接超时时间
|
private int mConnectTimeOut = 5000 * 4; //连接超时时间
|
||||||
private int mReadTimeOut = 5000 * 20; //流读取的超时时间
|
private int mReadTimeOut = 5000 * 20; //流读取的超时时间
|
||||||
/**
|
/**
|
||||||
* 已经完成下载任务的线程数量
|
* 已经完成下载任务的线程数量
|
||||||
*/
|
*/
|
||||||
private boolean isDownloading = false;
|
private boolean isDownloading = false;
|
||||||
private boolean isStop = false;
|
private boolean isStop = false;
|
||||||
private boolean isCancel = false;
|
private boolean isCancel = false;
|
||||||
private boolean isNewTask = true;
|
private boolean isNewTask = true;
|
||||||
private boolean isSupportBreakpoint = true;
|
private boolean isSupportBreakpoint = true;
|
||||||
private int mCompleteThreadNum = 0;
|
private int mCompleteThreadNum = 0;
|
||||||
private int mCancelNum = 0;
|
private int mCancelNum = 0;
|
||||||
private long mCurrentLocation = 0;
|
private long mCurrentLocation = 0;
|
||||||
private int mStopNum = 0;
|
private int mStopNum = 0;
|
||||||
private int mFailNum = 0;
|
private int mFailNum = 0;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private DownloadEntity mDownloadEntity;
|
private DownloadEntity mDownloadEntity;
|
||||||
private ExecutorService mFixedThreadPool;
|
private ExecutorService mFixedThreadPool;
|
||||||
private File mDownloadFile; //下载的文件
|
private File mDownloadFile; //下载的文件
|
||||||
private File mConfigFile;//下载信息配置文件
|
private File mConfigFile;//下载信息配置文件
|
||||||
private SparseArray<Runnable> mTask = new SparseArray<>();
|
private SparseArray<Runnable> mTask = new SparseArray<>();
|
||||||
|
|
||||||
DownloadUtil(Context context, DownloadEntity entity, IDownloadListener downloadListener) {
|
DownloadUtil(Context context, DownloadEntity entity, IDownloadListener downloadListener) {
|
||||||
@ -222,8 +228,8 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
|
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
try {
|
try {
|
||||||
URL url = new URL(mDownloadEntity.getDownloadUrl());
|
URL url = new URL(mDownloadEntity.getDownloadUrl());
|
||||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
HttpURLConnection conn = handleConnection(url);
|
||||||
setConnectParam(conn);
|
setConnectParam(conn);
|
||||||
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
|
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
|
||||||
conn.setConnectTimeout(mConnectTimeOut * 4);
|
conn.setConnectTimeout(mConnectTimeOut * 4);
|
||||||
@ -242,12 +248,16 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
handleBreakpoint(conn);
|
handleBreakpoint(conn);
|
||||||
} else if (code == HttpURLConnection.HTTP_OK || len < 0) {
|
} else if (code == HttpURLConnection.HTTP_OK || len < 0) {
|
||||||
//在conn.setRequestProperty("Range", "bytes=" + 0 + "-");下,200为不支持断点状态
|
//在conn.setRequestProperty("Range", "bytes=" + 0 + "-");下,200为不支持断点状态
|
||||||
|
if (len < 0) {
|
||||||
|
failDownload("任务【" + mDownloadEntity.getDownloadUrl() + "】下载失败,文件长度小于0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
isSupportBreakpoint = false;
|
isSupportBreakpoint = false;
|
||||||
mListener.supportBreakpoint(false);
|
mListener.supportBreakpoint(false);
|
||||||
Log.w(TAG, "该下载链接不支持断点下载");
|
Log.w(TAG, "该下载链接不支持断点下载");
|
||||||
handleBreakpoint(conn);
|
handleBreakpoint(conn);
|
||||||
} else {
|
} else {
|
||||||
failDownload("下载失败,返回码:" + code);
|
failDownload("任务【" + mDownloadEntity.getDownloadUrl() + "】下载失败,返回码:" + code);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
failDownload("下载失败【downloadUrl:"
|
failDownload("下载失败【downloadUrl:"
|
||||||
@ -259,6 +269,30 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理链接
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private HttpURLConnection handleConnection(URL url) throws IOException {
|
||||||
|
HttpURLConnection conn;
|
||||||
|
URLConnection urlConn = url.openConnection();
|
||||||
|
if (urlConn instanceof HttpsURLConnection) {
|
||||||
|
conn = (HttpsURLConnection) urlConn;
|
||||||
|
SSLContext sslContext =
|
||||||
|
SSLContextUtil.getSSLContext(CAConfiguration.CA_ALIAS, CAConfiguration.CA_ALIAS);
|
||||||
|
if (sslContext == null) {
|
||||||
|
sslContext = SSLContextUtil.getDefaultSLLContext();
|
||||||
|
}
|
||||||
|
SSLSocketFactory ssf = sslContext.getSocketFactory();
|
||||||
|
((HttpsURLConnection) conn).setSSLSocketFactory(ssf);
|
||||||
|
((HttpsURLConnection) conn).setHostnameVerifier(SSLContextUtil.HOSTNAME_VERIFIER);
|
||||||
|
} else {
|
||||||
|
conn = (HttpURLConnection) urlConn;
|
||||||
|
}
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理断点
|
* 处理断点
|
||||||
*/
|
*/
|
||||||
@ -301,15 +335,15 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int blockSize = fileLength / THREAD_NUM;
|
int blockSize = fileLength / THREAD_NUM;
|
||||||
int[] recordL = new int[THREAD_NUM];
|
int[] recordL = new int[THREAD_NUM];
|
||||||
int rl = 0;
|
int rl = 0;
|
||||||
for (int i = 0; i < THREAD_NUM; i++) {
|
for (int i = 0; i < THREAD_NUM; i++) {
|
||||||
recordL[i] = -1;
|
recordL[i] = -1;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < THREAD_NUM; i++) {
|
for (int i = 0; i < THREAD_NUM; i++) {
|
||||||
long startL = i * blockSize, endL = (i + 1) * blockSize;
|
long startL = i * blockSize, endL = (i + 1) * blockSize;
|
||||||
Object state = pro.getProperty(mDownloadFile.getName() + "_state_" + i);
|
Object state = pro.getProperty(mDownloadFile.getName() + "_state_" + i);
|
||||||
if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成
|
if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成
|
||||||
mCurrentLocation += endL - startL;
|
mCurrentLocation += endL - startL;
|
||||||
Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
|
Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
|
||||||
@ -377,12 +411,12 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
*/
|
*/
|
||||||
private static class ConfigEntity {
|
private static class ConfigEntity {
|
||||||
//文件大小
|
//文件大小
|
||||||
long fileSize;
|
long fileSize;
|
||||||
String downloadUrl;
|
String downloadUrl;
|
||||||
int threadId;
|
int threadId;
|
||||||
long startLocation;
|
long startLocation;
|
||||||
long endLocation;
|
long endLocation;
|
||||||
File tempFile;
|
File tempFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -391,7 +425,7 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
private class SingleThreadTask implements Runnable {
|
private class SingleThreadTask implements Runnable {
|
||||||
private static final String TAG = "SingleThreadTask";
|
private static final String TAG = "SingleThreadTask";
|
||||||
private ConfigEntity configEntity;
|
private ConfigEntity configEntity;
|
||||||
private String configFPath;
|
private String configFPath;
|
||||||
private long currentLocation = 0;
|
private long currentLocation = 0;
|
||||||
|
|
||||||
private SingleThreadTask(ConfigEntity downloadInfo) {
|
private SingleThreadTask(ConfigEntity downloadInfo) {
|
||||||
@ -406,10 +440,11 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
|
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
HttpURLConnection conn = null;
|
HttpURLConnection conn = null;
|
||||||
InputStream is = null;
|
InputStream is = null;
|
||||||
try {
|
try {
|
||||||
URL url = new URL(configEntity.downloadUrl);
|
URL url = new URL(configEntity.downloadUrl);
|
||||||
conn = (HttpURLConnection) url.openConnection();
|
//conn = (HttpURLConnection) url.openConnection();
|
||||||
|
conn = handleConnection(url);
|
||||||
if (isSupportBreakpoint) {
|
if (isSupportBreakpoint) {
|
||||||
Log.d(TAG, "线程_"
|
Log.d(TAG, "线程_"
|
||||||
+ configEntity.threadId
|
+ configEntity.threadId
|
||||||
@ -433,7 +468,7 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
//设置每条线程写入文件的位置
|
//设置每条线程写入文件的位置
|
||||||
file.seek(configEntity.startLocation);
|
file.seek(configEntity.startLocation);
|
||||||
byte[] buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
int len;
|
int len;
|
||||||
//当前子线程的下载位置
|
//当前子线程的下载位置
|
||||||
currentLocation = configEntity.startLocation;
|
currentLocation = configEntity.startLocation;
|
||||||
while ((len = is.read(buffer)) != -1) {
|
while ((len = is.read(buffer)) != -1) {
|
||||||
@ -593,8 +628,8 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
* 将记录写入到配置文件
|
* 将记录写入到配置文件
|
||||||
*/
|
*/
|
||||||
private void writeConfig(String key, String record) throws IOException {
|
private void writeConfig(String key, String record) throws IOException {
|
||||||
File configFile = new File(configFPath);
|
File configFile = new File(configFPath);
|
||||||
Properties pro = CommonUtil.loadConfig(configFile);
|
Properties pro = CommonUtil.loadConfig(configFile);
|
||||||
pro.setProperty(key, record);
|
pro.setProperty(key, record);
|
||||||
CommonUtil.saveConfig(configFile, pro);
|
CommonUtil.saveConfig(configFile, pro);
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,6 @@ public class DbUtil {
|
|||||||
params[i] = "'" + expression[i + 1] + "'";
|
params[i] = "'" + expression[i + 1] + "'";
|
||||||
}
|
}
|
||||||
sql = String.format(sql, params);
|
sql = String.format(sql, params);
|
||||||
Log.d(TAG, sql);
|
|
||||||
print(DEL_DATA, sql);
|
print(DEL_DATA, sql);
|
||||||
mDb.execSQL(sql);
|
mDb.execSQL(sql);
|
||||||
close();
|
close();
|
||||||
@ -185,7 +184,6 @@ public class DbUtil {
|
|||||||
params[i] = "'" + expression[i + 1] + "'";
|
params[i] = "'" + expression[i + 1] + "'";
|
||||||
}
|
}
|
||||||
sql = String.format(sql, params);
|
sql = String.format(sql, params);
|
||||||
Log.d(TAG, sql);
|
|
||||||
print(FIND_DATA, sql);
|
print(FIND_DATA, sql);
|
||||||
Cursor cursor = mDb.rawQuery(sql, null);
|
Cursor cursor = mDb.rawQuery(sql, null);
|
||||||
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
|
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.arialyy.aria.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/1/11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CAConfiguration {
|
||||||
|
public static String CA_PATH, CA_ALIAS;
|
||||||
|
}
|
112
Aria/src/main/java/com/arialyy/aria/util/SSLContextUtil.java
Normal file
112
Aria/src/main/java/com/arialyy/aria/util/SSLContextUtil.java
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package com.arialyy.aria.util;
|
||||||
|
|
||||||
|
import com.arialyy.aria.core.DownloadManager;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.KeyManagementException;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.UnrecoverableKeyException;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import javax.net.ssl.HostnameVerifier;
|
||||||
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSession;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/1/11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class SSLContextUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 颁发服务器证书的 CA 未知
|
||||||
|
*
|
||||||
|
* @param caAlias CA证书别名
|
||||||
|
* @param caPath 保存在assets目录下的CA证书完整路径
|
||||||
|
*/
|
||||||
|
public static SSLContext getSSLContext(String caAlias, String caPath) {
|
||||||
|
// Load CAs from an InputStream
|
||||||
|
// (could be from a resource or ByteArrayInputStream or ...)
|
||||||
|
CertificateFactory cf = null;
|
||||||
|
try {
|
||||||
|
cf = CertificateFactory.getInstance("X.509");
|
||||||
|
InputStream caInput = DownloadManager.APP.getAssets().open(caPath);
|
||||||
|
Certificate ca;
|
||||||
|
ca = cf.generateCertificate(caInput);
|
||||||
|
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
|
||||||
|
|
||||||
|
// Create a KeyStore containing our trusted CAs
|
||||||
|
String keyStoreType = KeyStore.getDefaultType();
|
||||||
|
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
|
||||||
|
keyStore.load(null, null);
|
||||||
|
keyStore.setCertificateEntry(caAlias, ca);
|
||||||
|
|
||||||
|
// Create a TrustManager that trusts the CAs in our KeyStore
|
||||||
|
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||||
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
|
||||||
|
tmf.init(keyStore);
|
||||||
|
KeyManagerFactory kmf =
|
||||||
|
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||||
|
kmf.init(keyStore, null);
|
||||||
|
|
||||||
|
// Create an SSLContext that uses our TrustManager
|
||||||
|
SSLContext context = SSLContext.getInstance("TLS");
|
||||||
|
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
|
||||||
|
return context;
|
||||||
|
} catch (CertificateException | NoSuchAlgorithmException | IOException | KeyStoreException | KeyManagementException | UnrecoverableKeyException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器证书不是由 CA 签署的,而是自签署时,获取默认的SSL
|
||||||
|
*/
|
||||||
|
public static SSLContext getDefaultSLLContext() {
|
||||||
|
SSLContext sslContext = null;
|
||||||
|
try {
|
||||||
|
sslContext = SSLContext.getInstance("TLS");
|
||||||
|
sslContext.init(null, new TrustManager[] { trustManagers }, new SecureRandom());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return sslContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建自己的 TrustManager,这次直接信任服务器证书。这种方法具有前面所述的将应用与证书直接关联的所有弊端,但可以安全地操作。
|
||||||
|
*/
|
||||||
|
private static TrustManager trustManagers = new X509TrustManager() {
|
||||||
|
|
||||||
|
@Override public void checkClientTrusted(X509Certificate[] chain, String authType)
|
||||||
|
throws CertificateException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void checkServerTrusted(X509Certificate[] chain, String authType)
|
||||||
|
throws CertificateException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public X509Certificate[] getAcceptedIssuers() {
|
||||||
|
return new X509Certificate[0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final HostnameVerifier HOSTNAME_VERIFIER = new HostnameVerifier() {
|
||||||
|
public boolean verify(String hostname, SSLSession session) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
21
README.md
21
README.md
@ -8,6 +8,7 @@
|
|||||||
- 支持多线程、多任务下载
|
- 支持多线程、多任务下载
|
||||||
- 支持任务自动切换
|
- 支持任务自动切换
|
||||||
- 支持下载速度直接获取
|
- 支持下载速度直接获取
|
||||||
|
- 支持https地址下载
|
||||||
|
|
||||||
[Aria怎样使用?](#使用)
|
[Aria怎样使用?](#使用)
|
||||||
|
|
||||||
@ -16,11 +17,9 @@
|
|||||||
## 下载
|
## 下载
|
||||||
[](https://bintray.com/arialyy/maven/Aria/_latestVersion)</br>
|
[](https://bintray.com/arialyy/maven/Aria/_latestVersion)</br>
|
||||||
```java
|
```java
|
||||||
compile 'com.arialyy.aria:Aria:2.3.8'
|
compile 'com.arialyy.aria:Aria:2.3.9'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 示例
|
## 示例
|
||||||

|

|
||||||

|

|
||||||
@ -52,6 +51,7 @@ compile 'com.arialyy.aria:Aria:2.3.8'
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
### 四、通过下载链接,你还能使用Aria执行很多操作,如:
|
### 四、通过下载链接,你还能使用Aria执行很多操作,如:
|
||||||
|
Aria支持https下载,如果你希望使用自己的ca证书,那么你需要进行[Aria https证书配置](#https证书配置)
|
||||||
- 添加任务(不进行下载)
|
- 添加任务(不进行下载)
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@ -118,8 +118,22 @@ compile 'com.arialyy.aria:Aria:2.3.8'
|
|||||||
Aria.get(this).openBroadcast(true);
|
Aria.get(this).openBroadcast(true);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### https证书配置
|
||||||
|
+ 将你的证书导入`assets`目录
|
||||||
|
+ 调用以下代码配置ca证书相关信息
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* 设置CA证书信息
|
||||||
|
*
|
||||||
|
* @param caAlias ca证书别名
|
||||||
|
* @param caPath assets 文件夹下的ca证书完整路径
|
||||||
|
*/
|
||||||
|
Aria.get(this).setCAInfo("caAlias","caPath");
|
||||||
|
```
|
||||||
|
|
||||||
***
|
***
|
||||||
## 开发日志
|
## 开发日志
|
||||||
|
+ v_2.3.9 支持https链接下载
|
||||||
+ v_2.3.8 修复数据错乱的bug、添加fragment支持
|
+ v_2.3.8 修复数据错乱的bug、添加fragment支持
|
||||||
+ v_2.3.6 添加dialog、popupWindow支持
|
+ v_2.3.6 添加dialog、popupWindow支持
|
||||||
+ v_2.3.3
|
+ v_2.3.3
|
||||||
@ -128,7 +142,6 @@ compile 'com.arialyy.aria:Aria:2.3.8'
|
|||||||
- 修复一个内存泄露的bug
|
- 修复一个内存泄露的bug
|
||||||
+ v_2.3.1 重命名为Aria,下载流程简化
|
+ v_2.3.1 重命名为Aria,下载流程简化
|
||||||
+ v_2.1.1 增加,选择最大下载任务数接口
|
+ v_2.1.1 增加,选择最大下载任务数接口
|
||||||
+ v_2.1.0 修复大量bug
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
@ -49,10 +49,10 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
|||||||
public static final int DOWNLOAD_RESUME = 0x05;
|
public static final int DOWNLOAD_RESUME = 0x05;
|
||||||
public static final int DOWNLOAD_COMPLETE = 0x06;
|
public static final int DOWNLOAD_COMPLETE = 0x06;
|
||||||
public static final int DOWNLOAD_RUNNING = 0x07;
|
public static final int DOWNLOAD_RUNNING = 0x07;
|
||||||
|
|
||||||
private static final String DOWNLOAD_URL =
|
private static final String DOWNLOAD_URL =
|
||||||
"http://static.gaoshouyou.com/d/3a/93/573ae1db9493a801c24bf66128b11e39.apk";
|
//"http://kotlinlang.org/docs/kotlin-docs.pdf";
|
||||||
//private static final String DOWNLOAD_URL =
|
"https://atom-installer.github.com/v1.13.0/AtomSetup.exe?s=1484074138&ext=.exe";
|
||||||
// "http://www.yangqiang.im/wp-content/uploads/2016/10/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F.png";
|
|
||||||
@Bind(R.id.progressBar) HorizontalProgressBarWithNumber mPb;
|
@Bind(R.id.progressBar) HorizontalProgressBarWithNumber mPb;
|
||||||
@Bind(R.id.start) Button mStart;
|
@Bind(R.id.start) Button mStart;
|
||||||
@Bind(R.id.stop) Button mStop;
|
@Bind(R.id.stop) Button mStop;
|
||||||
@ -114,6 +114,7 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
|||||||
setBtState(false);
|
setBtState(false);
|
||||||
break;
|
break;
|
||||||
case DOWNLOAD_COMPLETE:
|
case DOWNLOAD_COMPLETE:
|
||||||
|
mPb.setProgress(100);
|
||||||
Toast.makeText(SingleTaskActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
|
Toast.makeText(SingleTaskActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
|
||||||
mStart.setText("重新开始?");
|
mStart.setText("重新开始?");
|
||||||
mCancel.setEnabled(false);
|
mCancel.setEnabled(false);
|
||||||
|
Reference in New Issue
Block a user