Merge branch 'v_2.0'

pull/330/head
AriaLyy 8 years ago
commit 2231be017c
  1. 19
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  2. 36
      Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java
  3. 7
      Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
  4. 16
      Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java
  5. 41
      Aria/src/main/java/com/arialyy/aria/core/task/DownloadUtil.java
  6. 2
      Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java
  7. 25
      Aria/src/main/java/com/arialyy/aria/util/CAConfiguration.java
  8. 112
      Aria/src/main/java/com/arialyy/aria/util/SSLContextUtil.java
  9. 21
      README.md
  10. 7
      app/src/main/java/com/arialyy/simple/single_task/SingleTaskActivity.java

@ -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;
@ -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;
}
/** /**
* 获取下载列表 * 获取下载列表
*/ */

@ -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, "停止任务失败,【任务已经停止】");
if (mExecutePool.removeTask(task)) {
task.stop(); task.stop();
//if (task.isDownloading()) { } else {
// if (mExecutePool.removeTask(task)) { 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() {
@Override public void run() {
final Configuration config = Configuration.getInstance(); final Configuration config = Configuration.getInstance();
CountDownTimer timer = new CountDownTimer(config.getReTryInterval(), 1000) {
@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,9 +31,13 @@ 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.
@ -223,7 +229,7 @@ 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;
}
/** /**
* 处理断点 * 处理断点
*/ */
@ -409,7 +443,8 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
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

@ -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;
}

@ -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;
}
};
}

@ -8,6 +8,7 @@
- 支持多线程、多任务下载 - 支持多线程、多任务下载
- 支持任务自动切换 - 支持任务自动切换
- 支持下载速度直接获取 - 支持下载速度直接获取
- 支持https地址下载
[Aria怎样使用?](#使用) [Aria怎样使用?](#使用)
@ -16,11 +17,9 @@
## 下载 ## 下载
[![Download](https://api.bintray.com/packages/arialyy/maven/Aria/images/download.svg)](https://bintray.com/arialyy/maven/Aria/_latestVersion)</br> [![Download](https://api.bintray.com/packages/arialyy/maven/Aria/images/download.svg)](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'
``` ```
## 示例 ## 示例
![多任务下载](https://github.com/AriaLyy/DownloadUtil/blob/v_2.0/img/download_img.gif) ![多任务下载](https://github.com/AriaLyy/DownloadUtil/blob/v_2.0/img/download_img.gif)
![Dialog使用](https://github.com/AriaLyy/DownloadUtil/blob/v_2.0/img/dialog_use.gif "") ![Dialog使用](https://github.com/AriaLyy/DownloadUtil/blob/v_2.0/img/dialog_use.gif "")
@ -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);

Loading…
Cancel
Save