Compare commits
32 Commits
3.8.12
...
aa292e4389
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa292e4389 | ||
|
|
cba9483f3a | ||
|
|
eeb0bea97a | ||
|
|
3fc99cd01e | ||
|
|
48af5509f5 | ||
|
|
56893b0d88 | ||
|
|
ada1f9f993 | ||
|
|
7392eba667 | ||
|
|
3e2c3bc055 | ||
|
|
6e9f674fab | ||
|
|
afa6434664 | ||
|
|
00a81220cb | ||
|
|
ebbbbee1f8 | ||
|
|
6eab496b6a | ||
|
|
3679e0cb23 | ||
|
|
66f9aa9cd5 | ||
|
|
edb3e66a96 | ||
|
|
1c0765be02 | ||
|
|
5853fe9e3e | ||
|
|
9db8f1e9c0 | ||
|
|
35e66caab5 | ||
|
|
bcfb78109b | ||
|
|
d7d081ffb1 | ||
|
|
840facd1cc | ||
|
|
f67f829dfc | ||
|
|
0152187aa8 | ||
|
|
68c992962b | ||
|
|
514fa4321d | ||
|
|
313e047d1f | ||
|
|
62ad99e252 | ||
|
|
8785bb2875 | ||
|
|
7be93b38c2 |
2
.github/ISSUE_TEMPLATE/Custom.md
vendored
2
.github/ISSUE_TEMPLATE/Custom.md
vendored
@@ -11,6 +11,8 @@ about: 提交问题前,请先阅读文档和搜索issue
|
||||
|
||||
* 系统版本
|
||||
|
||||
## 错误的url
|
||||
|
||||
## 错误日志
|
||||
<!-- 请提供详细的错误日志 -->
|
||||
|
||||
|
||||
5
.github/stale.yml
vendored
5
.github/stale.yml
vendored
@@ -1,13 +1,14 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 7
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
daysUntilClose: 1000
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- bug
|
||||
- adaptation
|
||||
- new features
|
||||
- suggest
|
||||
- pending
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: wontfix
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
@@ -16,4 +17,4 @@ markComment: >
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
closeComment: false
|
||||
|
||||
@@ -15,6 +15,9 @@ android {
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
debug{
|
||||
debuggable true
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
|
||||
@@ -12,7 +12,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
/**
|
||||
* AES加密
|
||||
*
|
||||
* @author lyy
|
||||
* author lyy
|
||||
*/
|
||||
public class AESEncryption {
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,9 @@ android {
|
||||
versionName rootProject.ext.versionName
|
||||
}
|
||||
buildTypes {
|
||||
debug{
|
||||
debuggable true
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
@@ -24,9 +27,13 @@ dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
testImplementation 'junit:junit:4.12'
|
||||
// implementation "androidx.appcompat:appcompat:${rootProject.ext.XAppcompatVersion}"
|
||||
api project(':AriaAnnotations')
|
||||
api project(path: ':AriaAnnotations')
|
||||
api project(path: ':PublicComponent')
|
||||
api project(path: ':HttpComponent')
|
||||
}
|
||||
|
||||
apply from: 'bintray-release.gradle'
|
||||
//apply from: 'bintray-release.gradle'
|
||||
ext{
|
||||
PUBLISH_ARTIFACT_ID = 'core'
|
||||
}
|
||||
apply from: '../gradle/mavenCentral-release.gradle'
|
||||
@@ -18,11 +18,10 @@ package com.arialyy.aria.core.common;
|
||||
import com.arialyy.annotations.TaskEnum;
|
||||
import com.arialyy.aria.core.download.DownloadGroupTaskListener;
|
||||
import com.arialyy.aria.core.download.DownloadTaskListener;
|
||||
import com.arialyy.aria.core.scheduler.TaskInternalListenerInterface;
|
||||
import com.arialyy.aria.core.scheduler.M3U8PeerTaskListener;
|
||||
import com.arialyy.aria.core.scheduler.SubTaskListener;
|
||||
import com.arialyy.aria.core.scheduler.TaskInternalListenerInterface;
|
||||
import com.arialyy.aria.core.upload.UploadTaskListener;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -81,7 +80,8 @@ public class ProxyHelper {
|
||||
return result;
|
||||
}
|
||||
result = checkProxyTypeByInterface(clazz);
|
||||
if (result != null) {
|
||||
if (result != null && !result.isEmpty()) {
|
||||
mProxyCache.put(clazz.getName(), result);
|
||||
return result;
|
||||
}
|
||||
result = checkProxyTypeByProxyClass(clazz);
|
||||
|
||||
@@ -35,7 +35,7 @@ public class SFtpOption extends BaseOption {
|
||||
|
||||
public SFtpOption() {
|
||||
super();
|
||||
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_M3U8);
|
||||
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_SFTP);
|
||||
}
|
||||
|
||||
public SFtpOption charSet(String charSet) {
|
||||
|
||||
@@ -110,7 +110,12 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
|
||||
if (TextUtils.isEmpty(filePath)) {
|
||||
ALog.e(TAG, "下载失败,文件保存路径为null");
|
||||
return false;
|
||||
} else if (!filePath.startsWith("/")) {
|
||||
}
|
||||
if (!FileUtil.canWrite(new File(filePath).getParent())){
|
||||
ALog.e(TAG, String.format("路径【%s】不可写", filePath));
|
||||
return false;
|
||||
}
|
||||
if (!filePath.startsWith("/")) {
|
||||
ALog.e(TAG, String.format("下载失败,文件保存路径【%s】错误", filePath));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.arialyy.aria.core.inf.IOptionConstant;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -62,33 +63,41 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
|
||||
* @return {@code true} 合法
|
||||
*/
|
||||
private boolean checkDirPath() {
|
||||
if (TextUtils.isEmpty(mWrapper.getDirPathTemp())) {
|
||||
String dirPath = mWrapper.getDirPathTemp();
|
||||
|
||||
if (TextUtils.isEmpty(dirPath)) {
|
||||
ALog.e(TAG, "文件夹路径不能为null");
|
||||
return false;
|
||||
} else if (!mWrapper.getDirPathTemp().startsWith("/")) {
|
||||
ALog.e(TAG, String.format("文件夹路径【%s】错误", mWrapper.getDirPathTemp()));
|
||||
}
|
||||
File file = new File(dirPath);
|
||||
if (!FileUtil.canWrite(file.getParent()) && !FileUtil.canWrite(dirPath)) {
|
||||
ALog.e(TAG, String.format("路径【%s】不可写", dirPath));
|
||||
return false;
|
||||
}
|
||||
File file = new File(mWrapper.getDirPathTemp());
|
||||
if (!dirPath.startsWith("/")) {
|
||||
ALog.e(TAG, String.format("文件夹路径【%s】错误", dirPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.isFile()) {
|
||||
ALog.e(TAG, String.format("路径【%s】是文件,请设置文件夹路径", mWrapper.getDirPathTemp()));
|
||||
ALog.e(TAG, String.format("路径【%s】是文件,请设置文件夹路径", dirPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查路径冲突
|
||||
if (mWrapper.isNewTask() && !CheckUtil.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(),
|
||||
mWrapper.getDirPathTemp())) {
|
||||
dirPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(mEntity.getDirPath()) || !mEntity.getDirPath()
|
||||
.equals(mWrapper.getDirPathTemp())) {
|
||||
.equals(dirPath)) {
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
needModifyPath = true;
|
||||
mEntity.setDirPath(mWrapper.getDirPathTemp());
|
||||
ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", mWrapper.getDirPathTemp()));
|
||||
mEntity.setDirPath(dirPath);
|
||||
ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", dirPath));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -123,8 +132,9 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
|
||||
* @return false 任务不再执行,true 任务继续执行
|
||||
*/
|
||||
private boolean checkGroupHash(boolean isIgnoreTaskOccupy, String groupHash) {
|
||||
DownloadGroupEntity dge = DbEntity.findFirst(DownloadGroupEntity.class, "groupHash=?", groupHash);
|
||||
if (dge != null && dge.getGroupHash().equals(mEntity.getGroupHash())){
|
||||
DownloadGroupEntity dge =
|
||||
DbEntity.findFirst(DownloadGroupEntity.class, "groupHash=?", groupHash);
|
||||
if (dge != null && dge.getGroupHash().equals(mEntity.getGroupHash())) {
|
||||
mEntity.rowID = dge.rowID;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -45,32 +45,34 @@ public class CheckFtpDirEntityUtil implements ICheckEntityUtil {
|
||||
* @return {@code true} 合法
|
||||
*/
|
||||
private boolean checkDirPath() {
|
||||
if (TextUtils.isEmpty(mWrapper.getDirPathTemp())) {
|
||||
String dirPath = mWrapper.getDirPathTemp();
|
||||
if (TextUtils.isEmpty(dirPath)) {
|
||||
ALog.e(TAG, "文件夹路径不能为null");
|
||||
return false;
|
||||
} else if (!mWrapper.getDirPathTemp().startsWith("/")) {
|
||||
ALog.e(TAG, String.format("文件夹路径【%s】错误", mWrapper.getDirPathTemp()));
|
||||
}
|
||||
if (!dirPath.startsWith("/")) {
|
||||
ALog.e(TAG, String.format("文件夹路径【%s】错误", dirPath));
|
||||
return false;
|
||||
}
|
||||
File file = new File(mWrapper.getDirPathTemp());
|
||||
File file = new File(dirPath);
|
||||
if (file.isFile()) {
|
||||
ALog.e(TAG, String.format("路径【%s】是文件,请设置文件夹路径", mWrapper.getDirPathTemp()));
|
||||
ALog.e(TAG, String.format("路径【%s】是文件,请设置文件夹路径", dirPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查路径冲突
|
||||
if (mWrapper.isNewTask() && !CheckUtil.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(),
|
||||
mWrapper.getDirPathTemp())) {
|
||||
dirPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(mEntity.getDirPath()) || !mEntity.getDirPath()
|
||||
.equals(mWrapper.getDirPathTemp())) {
|
||||
.equals(dirPath)) {
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
mEntity.setDirPath(mWrapper.getDirPathTemp());
|
||||
ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", mWrapper.getDirPathTemp()));
|
||||
mEntity.setDirPath(dirPath);
|
||||
ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", dirPath));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.arialyy.aria.core.task.DownloadGroupTask;
|
||||
|
||||
/**
|
||||
* @author ChenFei(chenfei0928 @ gmail.com)
|
||||
* @date 2020-07-07 14:12
|
||||
* Date: 2020-07-07 14:12
|
||||
*/
|
||||
public interface DownloadGroupTaskListener extends NormalTaskListenerInterface<DownloadGroupTask> {
|
||||
}
|
||||
|
||||
@@ -111,8 +111,8 @@ public class DownloadReceiver extends AbsReceiver {
|
||||
/**
|
||||
* 加载组合任务,用于任务停止、删除等操作
|
||||
*
|
||||
* @param taskId 任务id,可从{@link AbsBuilderTarget#create()}、{@link AbsBuilderTarget#add()}、{@link
|
||||
* * AbsEntity#getId()}读取任务id
|
||||
* @param taskId 任务id,可从{@link AbsBuilderTarget#create}、{@link AbsBuilderTarget#add}、{@link
|
||||
* AbsEntity#getId}读取任务id
|
||||
*/
|
||||
|
||||
public GroupNormalTarget loadGroup(long taskId) {
|
||||
@@ -175,6 +175,7 @@ public class DownloadReceiver extends AbsReceiver {
|
||||
return;
|
||||
}
|
||||
if (obj instanceof TaskInternalListenerInterface){
|
||||
ProxyHelper.getInstance().checkProxyType(obj.getClass());
|
||||
if (obj instanceof DownloadTaskListener){
|
||||
TaskSchedulers.getInstance().register(obj, TaskEnum.DOWNLOAD);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ import com.arialyy.aria.core.scheduler.NormalTaskListenerInterface;
|
||||
import com.arialyy.aria.core.task.DownloadTask;
|
||||
|
||||
/**
|
||||
* @author ChenFei(chenfei0928 @ gmail.com)
|
||||
* @date 2020-07-07 14:12
|
||||
* @author ChenFei(chenfei0928@gmail.com)
|
||||
* Date: 2020-07-07 14:12
|
||||
*/
|
||||
public interface DownloadTaskListener extends NormalTaskListenerInterface<DownloadTask> {
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ import com.arialyy.aria.core.common.AbsNormalTarget;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author aria
|
||||
* @Date 2019-09-05
|
||||
* @author aria
|
||||
* Date: 2019-09-05
|
||||
*/
|
||||
public class DTargetFactory {
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
|
||||
/**
|
||||
* @Author aria
|
||||
* @Date 2019-09-06
|
||||
* @author aria
|
||||
* Date: 2019-09-06
|
||||
*/
|
||||
public class TcpBuilderTarget extends AbsBuilderTarget<TcpBuilderTarget> {
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ import com.arialyy.aria.util.ALog;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* @Author aria
|
||||
* @Date 2019-09-06
|
||||
* @author aria
|
||||
* Date: 2019-09-06
|
||||
*/
|
||||
public class TcpDelegate extends BaseOption {
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.arialyy.aria.core.download.tcp;
|
||||
/**
|
||||
* tcp任务配置
|
||||
*
|
||||
* @Author aria
|
||||
* @Date 2019-09-06
|
||||
* @author aria
|
||||
* Date: 2019-09-06
|
||||
*/
|
||||
public class TcpTaskConfig {
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.arialyy.aria.core.scheduler;
|
||||
* 直接实现监听器回调接口的基类,不对外部直接开放,仅作为内部监听器的父接口使用
|
||||
*
|
||||
* @author ChenFei(chenfei0928 @ gmail.com)
|
||||
* @date 2020-07-07 15:18
|
||||
* Date: 2020-07-07 15:18
|
||||
*/
|
||||
public interface TaskInternalListenerInterface {
|
||||
}
|
||||
|
||||
@@ -272,6 +272,7 @@ public class UploadReceiver extends AbsReceiver {
|
||||
return;
|
||||
}
|
||||
if (obj instanceof TaskInternalListenerInterface){
|
||||
ProxyHelper.getInstance().checkProxyType(obj.getClass());
|
||||
if (obj instanceof UploadTaskListener){
|
||||
TaskSchedulers.getInstance().register(obj, TaskEnum.UPLOAD);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import com.arialyy.aria.core.task.UploadTask;
|
||||
* 上传任务接口
|
||||
*
|
||||
* @author ChenFei(chenfei0928 @ gmail.com)
|
||||
* @date 2020-07-07 13:23
|
||||
* Date: 2020-07-07 13:23
|
||||
*/
|
||||
public interface UploadTaskListener extends NormalTaskListenerInterface<UploadTask> {
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ import com.arialyy.aria.core.common.AbsBuilderTarget;
|
||||
import com.arialyy.aria.core.common.AbsNormalTarget;
|
||||
|
||||
/**
|
||||
* @Author aria
|
||||
* @Date 2019-09-05
|
||||
* @author aria
|
||||
* Date: 2019-09-05
|
||||
*/
|
||||
public class UTargetFactory {
|
||||
|
||||
|
||||
@@ -11,4 +11,9 @@ dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
}
|
||||
|
||||
apply from: 'bintray-release.gradle'
|
||||
//apply from: 'bintray-release.gradle'
|
||||
|
||||
ext{
|
||||
PUBLISH_ARTIFACT_ID = 'annotations'
|
||||
}
|
||||
apply from: '../gradle/mavenCentral-release.gradle'
|
||||
@@ -15,4 +15,8 @@ dependencies {
|
||||
implementation project(':AriaAnnotations')
|
||||
}
|
||||
|
||||
apply from: 'bintray-release.gradle'
|
||||
//apply from: 'bintray-release.gradle'
|
||||
ext{
|
||||
PUBLISH_ARTIFACT_ID = 'compiler'
|
||||
}
|
||||
apply from: '../gradle/mavenCentral-release.gradle'
|
||||
15
DEV_LOG.md
15
DEV_LOG.md
@@ -1,4 +1,19 @@
|
||||
## 开发日志
|
||||
+ v_3.8.16 (2021/4/18)
|
||||
- 修复单线程下载时,文件已经完成,重复下载回调下载失败的问题
|
||||
- 修复一个重新下载文件时,同名路径文件没有被被删除的问题
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/807
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/811
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/851
|
||||
- 修复组合任务在获取子任务信息的过程中,手动停止或删除,没有回调的问题
|
||||
+ v_3.8.15 (2020/11/9)
|
||||
- 修复不支持断点的连接下载失败问题,https://github.com/AriaLyy/Aria/issues/771
|
||||
- 修复iv不存在时,索引文件异常的问题,https://github.com/AriaLyy/Aria/issues/780
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/799
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/798
|
||||
+ v_3.8.14 (2020/9/23)
|
||||
- 修复spi机制的兼容问题,https://github.com/AriaLyy/Aria/issues/743
|
||||
- 增加路径不可以写的判断,下载时,如果路径不可写,将执行失败回调 https://github.com/AriaLyy/Aria/issues/750
|
||||
+ v_3.8.12 (2020/8/15)
|
||||
- 修复一个正则表达式导致的文件名保存号异常问题 https://github.com/AriaLyy/Aria/issues/715
|
||||
- 修复一个匿名内部类中的内存溢出的问题 https://github.com/AriaLyy/Aria/issues/705
|
||||
|
||||
@@ -15,6 +15,9 @@ android {
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug{
|
||||
debuggable true
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
@@ -32,4 +35,8 @@ dependencies {
|
||||
implementation project(path: ':PublicComponent')
|
||||
}
|
||||
|
||||
apply from: 'bintray-release.gradle'
|
||||
//apply from: 'bintray-release.gradle'
|
||||
ext{
|
||||
PUBLISH_ARTIFACT_ID = 'ftp'
|
||||
}
|
||||
apply from: '../gradle/mavenCentral-release.gradle'
|
||||
@@ -27,6 +27,7 @@ import aria.apache.commons.net.ftp.FTPSClient;
|
||||
import com.arialyy.aria.core.AriaConfig;
|
||||
import com.arialyy.aria.core.FtpUrlEntity;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.core.common.FtpConnectionMode;
|
||||
import com.arialyy.aria.core.loader.IInfoTask;
|
||||
import com.arialyy.aria.core.loader.ILoaderVisitor;
|
||||
@@ -55,7 +56,8 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
|
||||
private int mConnectTimeOut;
|
||||
protected long mSize = 0;
|
||||
protected String charSet = "UTF-8";
|
||||
protected Callback callback;
|
||||
private Callback callback;
|
||||
private boolean isStop = false, isCancel = false;
|
||||
|
||||
public AbsFtpInfoTask(TASK_WRAPPER taskWrapper) {
|
||||
mTaskWrapper = taskWrapper;
|
||||
@@ -81,6 +83,14 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
|
||||
protected abstract void handelFileInfo(FTPClient client, FTPFile[] files,
|
||||
String convertedRemotePath) throws IOException;
|
||||
|
||||
@Override public void stop() {
|
||||
isStop = true;
|
||||
}
|
||||
|
||||
@Override public void cancel() {
|
||||
isCancel = true;
|
||||
}
|
||||
|
||||
@Override public void setCallback(Callback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
@@ -101,10 +111,10 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
|
||||
handelFileInfo(client, files, convertedRemotePath);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
failDownload(client, "FTP错误信息", e, true);
|
||||
handleFail(client, "FTP错误信息", e, true);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
failDownload(client, "FTP错误信息", e, true);
|
||||
handleFail(client, "FTP错误信息", e, true);
|
||||
} finally {
|
||||
closeClient(client);
|
||||
}
|
||||
@@ -146,7 +156,7 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
|
||||
}
|
||||
|
||||
if (client == null) {
|
||||
failDownload(client, String.format("链接失败, url: %s", mTaskOption.getUrlEntity().url), null,
|
||||
handleFail(client, String.format("链接失败, url: %s", mTaskOption.getUrlEntity().url), null,
|
||||
true);
|
||||
return null;
|
||||
}
|
||||
@@ -168,14 +178,14 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
|
||||
}
|
||||
|
||||
if (!loginSuccess) {
|
||||
failDownload(client, "登录失败", null, false);
|
||||
handleFail(client, "登录失败", null, false);
|
||||
client.disconnect();
|
||||
return null;
|
||||
}
|
||||
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||
failDownload(client, String.format("无法连接到ftp服务器,filePath: %s, url: %s", mEntity.getKey(),
|
||||
handleFail(client, String.format("无法连接到ftp服务器,filePath: %s, url: %s", mEntity.getKey(),
|
||||
mTaskOption.getUrlEntity().url), null, true);
|
||||
client.disconnect();
|
||||
return null;
|
||||
@@ -299,7 +309,7 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
|
||||
for (FTPFile file : files) {
|
||||
if (file.isFile()) {
|
||||
size += file.getSize();
|
||||
handleFile(path + file.getName(), file);
|
||||
handleFile(client, path + file.getName(), file);
|
||||
} else {
|
||||
String remotePath = CommonUtil.convertFtpChar(charSet, path + file.getName());
|
||||
size += getFileSize(client.listFiles(remotePath), client, path + file.getName());
|
||||
@@ -314,10 +324,13 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
|
||||
* @param remotePath ftp服务器文件夹路径
|
||||
* @param ftpFile ftp服务器上对应的文件
|
||||
*/
|
||||
protected void handleFile(String remotePath, FTPFile ftpFile) {
|
||||
protected void handleFile(FTPClient client, String remotePath, FTPFile ftpFile) {
|
||||
}
|
||||
|
||||
protected void failDownload(FTPClient client, String msg, Exception e, boolean needRetry) {
|
||||
protected void handleFail(FTPClient client, String msg, Exception e, boolean needRetry) {
|
||||
if (isStop || isCancel) {
|
||||
return;
|
||||
}
|
||||
if (callback != null) {
|
||||
if (client == null) {
|
||||
msg = "创建ftp客户端失败";
|
||||
@@ -332,6 +345,10 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
|
||||
}
|
||||
}
|
||||
|
||||
protected void onSucceed(CompleteInfo info){
|
||||
callback.onSucceed(mEntity.getKey(), info);
|
||||
}
|
||||
|
||||
@Override public void accept(ILoaderVisitor visitor) {
|
||||
visitor.addComponent(this);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ import java.net.UnknownHostException;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-18
|
||||
* @author lyy
|
||||
* Date: 2019-09-18
|
||||
*/
|
||||
public abstract class BaseFtpThreadTaskAdapter extends AbsThreadTaskAdapter {
|
||||
|
||||
|
||||
@@ -38,10 +38,10 @@ final class FtpDFileInfoTask extends AbsFtpInfoTask<DownloadEntity, DTaskWrapper
|
||||
super(taskEntity);
|
||||
}
|
||||
|
||||
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
|
||||
super.handleFile(remotePath, ftpFile);
|
||||
@Override protected void handleFile(FTPClient client, String remotePath, FTPFile ftpFile) {
|
||||
super.handleFile(client, remotePath, ftpFile);
|
||||
if (!FileUtil.checkMemorySpace(mEntity.getFilePath(), ftpFile.getSize())) {
|
||||
callback.onFail(mEntity, new AriaFTPException(
|
||||
handleFail(client, "内存空间不足", new AriaFTPException(
|
||||
String.format("获取ftp文件信息失败,内存空间不足, filePath: %s", mEntity.getFilePath())),
|
||||
false);
|
||||
}
|
||||
@@ -72,7 +72,7 @@ final class FtpDFileInfoTask extends AbsFtpInfoTask<DownloadEntity, DTaskWrapper
|
||||
}
|
||||
closeClient(client);
|
||||
|
||||
failDownload(client,
|
||||
handleFail(client,
|
||||
String.format("文件不存在,url: %s, remotePath:%s", mTaskOption.getUrlEntity().url,
|
||||
getRemotePath()), null, false);
|
||||
return;
|
||||
@@ -90,7 +90,7 @@ final class FtpDFileInfoTask extends AbsFtpInfoTask<DownloadEntity, DTaskWrapper
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||
closeClient(client);
|
||||
failDownload(client, "获取文件信息错误,url: " + mTaskOption.getUrlEntity().url, null, true);
|
||||
handleFail(client, "获取文件信息错误,url: " + mTaskOption.getUrlEntity().url, null, true);
|
||||
return;
|
||||
}
|
||||
mTaskWrapper.setCode(reply);
|
||||
@@ -112,6 +112,6 @@ final class FtpDFileInfoTask extends AbsFtpInfoTask<DownloadEntity, DTaskWrapper
|
||||
mTaskWrapper.setNewTask(true);
|
||||
}
|
||||
mEntity.setFileSize(mSize);
|
||||
callback.onSucceed(mEntity.getUrl(), new CompleteInfo(code, mTaskWrapper));
|
||||
onSucceed(new CompleteInfo(code, mTaskWrapper));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
|
||||
|
||||
@Override public void run() {
|
||||
if (mTaskWrapper.getEntity().getFileSize() > 1 && checkSubOption()) {
|
||||
callback.onSucceed(mEntity.getKey(), new CompleteInfo(200, mTaskWrapper));
|
||||
onSucceed(new CompleteInfo(200, mTaskWrapper));
|
||||
} else {
|
||||
super.run();
|
||||
}
|
||||
@@ -80,7 +80,7 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
|
||||
}
|
||||
closeClient(client);
|
||||
|
||||
failDownload(client,
|
||||
handleFail(client,
|
||||
String.format("文件不存在,url: %s, remotePath:%s", mTaskOption.getUrlEntity().url,
|
||||
getRemotePath()), null, false);
|
||||
return;
|
||||
@@ -98,7 +98,7 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||
closeClient(client);
|
||||
failDownload(client, "获取文件信息错误,url: " + mTaskOption.getUrlEntity().url, null, true);
|
||||
handleFail(client, "获取文件信息错误,url: " + mTaskOption.getUrlEntity().url, null, true);
|
||||
return;
|
||||
}
|
||||
mTaskWrapper.setCode(reply);
|
||||
@@ -127,8 +127,8 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
|
||||
return mTaskOption.getUrlEntity().remotePath;
|
||||
}
|
||||
|
||||
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
|
||||
super.handleFile(remotePath, ftpFile);
|
||||
@Override protected void handleFile(FTPClient client, String remotePath, FTPFile ftpFile) {
|
||||
super.handleFile(client, remotePath, ftpFile);
|
||||
addEntity(remotePath, ftpFile);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
|
||||
for (DTaskWrapper wrapper : mTaskWrapper.getSubTaskWrapper()) {
|
||||
cloneInfo(wrapper);
|
||||
}
|
||||
callback.onSucceed(mEntity.getKey(), new CompleteInfo(code, mTaskWrapper));
|
||||
onSucceed(new CompleteInfo(code, mTaskWrapper));
|
||||
}
|
||||
|
||||
private void cloneInfo(DTaskWrapper subWrapper) {
|
||||
@@ -234,8 +234,8 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failDownload(FTPClient client, String msg, Exception e, boolean needRetry) {
|
||||
super.failDownload(client, msg, e, needRetry);
|
||||
protected void handleFail(FTPClient client, String msg, Exception e, boolean needRetry) {
|
||||
super.handleFail(client, msg, e, needRetry);
|
||||
DeleteDGRecord.getInstance().deleteRecord(mTaskWrapper.getEntity(), true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ import com.arialyy.aria.core.loader.NormalThreadStateManager;
|
||||
import com.arialyy.aria.ftp.FtpTaskOption;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-19
|
||||
* @author lyy
|
||||
* Date: 2019-09-19
|
||||
*/
|
||||
public final class FtpDLoaderUtil extends AbsNormalLoaderUtil {
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ import com.arialyy.aria.util.RecordUtil;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-19
|
||||
* @author lyy
|
||||
* Date: 2019-09-19
|
||||
*/
|
||||
final class FtpDRecordHandler extends RecordHandler {
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-18
|
||||
* @author lyy
|
||||
* Date: 2019-09-18
|
||||
*/
|
||||
final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
|
||||
|
||||
@@ -19,13 +19,14 @@ import android.os.Handler;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.group.AbsSubDLoadUtil;
|
||||
import com.arialyy.aria.core.group.SubRecordHandler;
|
||||
import com.arialyy.aria.core.loader.GroupSubThreadStateManager;
|
||||
import com.arialyy.aria.core.loader.LoaderStructure;
|
||||
import com.arialyy.aria.core.loader.NormalTTBuilder;
|
||||
import com.arialyy.aria.core.loader.SubLoader;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-28
|
||||
* @author lyy
|
||||
* Date: 2019-09-28
|
||||
*/
|
||||
final class FtpSubDLoaderUtil extends AbsSubDLoadUtil {
|
||||
/**
|
||||
@@ -48,6 +49,7 @@ final class FtpSubDLoaderUtil extends AbsSubDLoadUtil {
|
||||
@Override protected LoaderStructure buildLoaderStructure() {
|
||||
LoaderStructure structure = new LoaderStructure();
|
||||
structure.addComponent(new SubRecordHandler(getWrapper()))
|
||||
.addComponent(new GroupSubThreadStateManager(getSchedulers(),getKey()))
|
||||
.addComponent(new NormalTTBuilder(getWrapper(), new FtpDTTBuilderAdapter()))
|
||||
.addComponent(new FtpDFileInfoTask(getWrapper()));
|
||||
structure.accept(getLoader());
|
||||
|
||||
@@ -60,7 +60,7 @@ final class FtpUFileInfoTask extends AbsFtpInfoTask<UploadEntity, UTaskWrapper>
|
||||
return;
|
||||
}
|
||||
|
||||
handleFile(getRemotePath(), files.length == 0 ? null : files[0]);
|
||||
handleFile(client, getRemotePath(), files.length == 0 ? null : files[0]);
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||
//服务器上没有该文件路径,表示该任务为新的上传任务
|
||||
@@ -133,8 +133,8 @@ final class FtpUFileInfoTask extends AbsFtpInfoTask<UploadEntity, UTaskWrapper>
|
||||
* @param remotePath ftp服务器文件夹路径
|
||||
* @param ftpFile ftp服务器上对应的文件
|
||||
*/
|
||||
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
|
||||
super.handleFile(remotePath, ftpFile);
|
||||
@Override protected void handleFile(FTPClient client,String remotePath, FTPFile ftpFile) {
|
||||
super.handleFile(client, remotePath, ftpFile);
|
||||
this.ftpFile = ftpFile;
|
||||
if (ftpFile != null && ftpFile.getSize() == mEntity.getFileSize()) {
|
||||
isComplete = true;
|
||||
@@ -145,6 +145,6 @@ final class FtpUFileInfoTask extends AbsFtpInfoTask<UploadEntity, UTaskWrapper>
|
||||
super.onPreComplete(code);
|
||||
CompleteInfo info = new CompleteInfo(isComplete ? CODE_COMPLETE : code, mTaskWrapper);
|
||||
info.obj = ftpFile;
|
||||
callback.onSucceed(mEntity.getKey(), info);
|
||||
onSucceed(info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,13 +23,14 @@ import com.arialyy.aria.core.loader.AbsNormalTTBuilderAdapter;
|
||||
import com.arialyy.aria.core.loader.LoaderStructure;
|
||||
import com.arialyy.aria.core.loader.NormalTTBuilder;
|
||||
import com.arialyy.aria.core.loader.NormalThreadStateManager;
|
||||
import com.arialyy.aria.core.loader.UploadThreadStateManager;
|
||||
import com.arialyy.aria.core.task.IThreadTaskAdapter;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.ftp.FtpTaskOption;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-19
|
||||
* @author lyy
|
||||
* Date: 2019-09-19
|
||||
*/
|
||||
public final class FtpULoaderUtil extends AbsNormalLoaderUtil {
|
||||
|
||||
@@ -44,7 +45,8 @@ public final class FtpULoaderUtil extends AbsNormalLoaderUtil {
|
||||
@Override public LoaderStructure BuildLoaderStructure() {
|
||||
LoaderStructure structure = new LoaderStructure();
|
||||
structure.addComponent(new FtpURecordHandler((UTaskWrapper) getTaskWrapper()))
|
||||
.addComponent(new NormalThreadStateManager(getListener()))
|
||||
// .addComponent(new NormalThreadStateManager(getListener()))
|
||||
.addComponent(new UploadThreadStateManager(getListener()))
|
||||
.addComponent(new FtpUFileInfoTask((UTaskWrapper) getTaskWrapper()))
|
||||
.addComponent(new NormalTTBuilder(getTaskWrapper(), new AbsNormalTTBuilderAdapter() {
|
||||
@Override public IThreadTaskAdapter getAdapter(SubThreadConfig config) {
|
||||
|
||||
2
FtpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
2
FtpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -14,6 +14,9 @@ android {
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug{
|
||||
debuggable true
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
@@ -31,4 +34,8 @@ dependencies {
|
||||
implementation project(path: ':PublicComponent')
|
||||
}
|
||||
|
||||
apply from: 'bintray-release.gradle'
|
||||
//apply from: 'bintray-release.gradle'
|
||||
ext{
|
||||
PUBLISH_ARTIFACT_ID = 'http'
|
||||
}
|
||||
apply from: '../gradle/mavenCentral-release.gradle'
|
||||
@@ -20,8 +20,8 @@ import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.task.AbsThreadTaskAdapter;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-22
|
||||
* @author lyy
|
||||
* Date: 2019-09-22
|
||||
*/
|
||||
public abstract class BaseHttpThreadTaskAdapter extends AbsThreadTaskAdapter {
|
||||
protected HttpTaskOption mTaskOption;
|
||||
|
||||
@@ -48,8 +48,6 @@ public final class ConnectionHelp {
|
||||
|
||||
/**
|
||||
* 处理url参数
|
||||
*
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public static URL handleUrl(String url, HttpTaskOption taskDelegate)
|
||||
throws MalformedURLException {
|
||||
@@ -127,8 +125,6 @@ public final class ConnectionHelp {
|
||||
|
||||
/**
|
||||
* 设置头部参数
|
||||
*
|
||||
* @throws ProtocolException
|
||||
*/
|
||||
public static HttpURLConnection setConnectParam(HttpTaskOption delegate, HttpURLConnection conn) {
|
||||
if (delegate.getRequestEnum() == RequestEnum.POST) {
|
||||
|
||||
@@ -28,8 +28,8 @@ import com.arialyy.aria.util.RecordUtil;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-23
|
||||
* @author lyy
|
||||
* Date: 2019-09-23
|
||||
*/
|
||||
public final class HttpRecordHandler extends RecordHandler {
|
||||
public HttpRecordHandler(AbsTaskWrapper wrapper) {
|
||||
|
||||
@@ -64,6 +64,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
private int mConnectTimeOut;
|
||||
private Callback callback;
|
||||
private HttpTaskOption taskOption;
|
||||
private boolean isStop = false, isCancel = false;
|
||||
|
||||
HttpDFileInfoTask(DTaskWrapper taskWrapper) {
|
||||
this.mTaskWrapper = taskWrapper;
|
||||
@@ -81,7 +82,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
conn = ConnectionHelp.handleConnection(url, taskOption);
|
||||
ConnectionHelp.setConnectParam(taskOption, conn);
|
||||
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
|
||||
if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()){
|
||||
if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()) {
|
||||
ALog.d(TAG, "head请求");
|
||||
conn.setRequestMethod("HEAD");
|
||||
}
|
||||
@@ -111,6 +112,14 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override public void stop() {
|
||||
isStop = true;
|
||||
}
|
||||
|
||||
@Override public void cancel() {
|
||||
isCancel = true;
|
||||
}
|
||||
|
||||
private void handleConnect(HttpURLConnection conn) throws IOException {
|
||||
if (taskOption.getRequestEnum() == RequestEnum.POST) {
|
||||
Map<String, String> params = taskOption.getParams();
|
||||
@@ -232,7 +241,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
|| code == HttpURLConnection.HTTP_CREATED // 201 跳转
|
||||
|| code == 307) {
|
||||
handleUrlReTurn(conn, conn.getHeaderField("Location"));
|
||||
}else if (code == 416){ // 处理0k长度的文件的情况
|
||||
} else if (code == 416) { // 处理0k长度的文件的情况
|
||||
ALog.w(TAG, "文件长度为0,不支持断点");
|
||||
mTaskWrapper.setSupportBP(false);
|
||||
mTaskWrapper.setNewTask(true);
|
||||
@@ -245,12 +254,13 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
String.format("任务下载失败,errorCode:%s, errorMsg: %s, url: %s", code,
|
||||
conn.getResponseMessage(), mEntity.getUrl())), !CheckUtil.httpIsBadRequest(code));
|
||||
}
|
||||
if (isStop || isCancel) {
|
||||
return;
|
||||
}
|
||||
if (end) {
|
||||
taskOption.setChunked(isChunked);
|
||||
if (callback != null) {
|
||||
CompleteInfo info = new CompleteInfo(code, mTaskWrapper);
|
||||
callback.onSucceed(mEntity.getUrl(), info);
|
||||
}
|
||||
CompleteInfo info = new CompleteInfo(code, mTaskWrapper);
|
||||
callback.onSucceed(mEntity.getUrl(), info);
|
||||
mEntity.update();
|
||||
}
|
||||
}
|
||||
@@ -343,7 +353,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
ConnectionHelp.setConnectParam(taskOption, conn);
|
||||
conn.setRequestProperty("Cookie", cookies);
|
||||
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
|
||||
if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()){
|
||||
if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()) {
|
||||
conn.setRequestMethod("HEAD");
|
||||
}
|
||||
conn.setConnectTimeout(mConnectTimeOut);
|
||||
@@ -367,6 +377,9 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
}
|
||||
|
||||
private void failDownload(AriaHTTPException e, boolean needRetry) {
|
||||
if (isStop || isCancel) {
|
||||
return;
|
||||
}
|
||||
if (callback != null) {
|
||||
callback.onFail(mEntity, e, needRetry);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.core.download.DGTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.listener.DownloadGroupListener;
|
||||
import com.arialyy.aria.core.loader.IInfoTask;
|
||||
import com.arialyy.aria.core.loader.ILoaderVisitor;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
@@ -44,7 +43,20 @@ public final class HttpDGInfoTask implements IInfoTask {
|
||||
private boolean getLenComplete = false;
|
||||
private AtomicInteger count = new AtomicInteger();
|
||||
private AtomicInteger failCount = new AtomicInteger();
|
||||
private DownloadGroupListener listener;
|
||||
private boolean isStop = false, isCancel = false;
|
||||
|
||||
public interface DGInfoCallback extends Callback {
|
||||
|
||||
/**
|
||||
* 子任务失败
|
||||
*/
|
||||
void onSubFail(DownloadEntity subEntity, AriaHTTPException e, boolean needRetry);
|
||||
|
||||
/**
|
||||
* 组合任务停止
|
||||
*/
|
||||
void onStop(long len);
|
||||
}
|
||||
|
||||
/**
|
||||
* 子任务回调
|
||||
@@ -60,15 +72,32 @@ public final class HttpDGInfoTask implements IInfoTask {
|
||||
ALog.e(TAG, String.format("获取文件信息失败,url:%s", ((DownloadEntity) entity).getUrl()));
|
||||
count.getAndIncrement();
|
||||
failCount.getAndIncrement();
|
||||
listener.onSubFail((DownloadEntity) entity, new AriaHTTPException(
|
||||
String.format("子任务获取文件长度失败,url:%s", ((DownloadEntity) entity).getUrl())));
|
||||
((DGInfoCallback) callback).onSubFail((DownloadEntity) entity, new AriaHTTPException(
|
||||
String.format("子任务获取文件长度失败,url:%s", ((DownloadEntity) entity).getUrl())), needRetry);
|
||||
checkGetSizeComplete(count.get(), failCount.get());
|
||||
}
|
||||
};
|
||||
|
||||
HttpDGInfoTask(DGTaskWrapper wrapper, DownloadGroupListener listener) {
|
||||
HttpDGInfoTask(DGTaskWrapper wrapper) {
|
||||
this.wrapper = wrapper;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止
|
||||
*/
|
||||
@Override
|
||||
public void stop() {
|
||||
isStop = true;
|
||||
if (mPool != null) {
|
||||
mPool.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void cancel() {
|
||||
isCancel = true;
|
||||
if (mPool != null) {
|
||||
mPool.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
@@ -76,7 +105,7 @@ public final class HttpDGInfoTask implements IInfoTask {
|
||||
if (mPool != null && !getLenComplete) {
|
||||
ALog.d(TAG, "获取长度未完成的情况下,停止组合任务");
|
||||
mPool.shutdown();
|
||||
listener.onStop(0);
|
||||
((DGInfoCallback)callback).onStop(0);
|
||||
return;
|
||||
}
|
||||
// 处理组合任务大小未知的情况
|
||||
@@ -131,6 +160,11 @@ public final class HttpDGInfoTask implements IInfoTask {
|
||||
* 检查组合任务大小是否获取完成,获取完成后取消阻塞,并设置组合任务大小
|
||||
*/
|
||||
private void checkGetSizeComplete(int count, int failCount) {
|
||||
if (isStop || isCancel) {
|
||||
ALog.w(TAG, "任务已停止或已取消,isStop = " + isStop + ", isCancel = " + isCancel);
|
||||
notifyLock();
|
||||
return;
|
||||
}
|
||||
if (failCount == wrapper.getSubTaskWrapper().size()) {
|
||||
callback.onFail(wrapper.getEntity(), new AriaHTTPException("获取子任务长度失败"), false);
|
||||
notifyLock();
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.arialyy.aria.core.listener.DownloadGroupListener;
|
||||
import com.arialyy.aria.core.loader.IInfoTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.exception.AriaHTTPException;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
@@ -64,7 +65,17 @@ final class HttpDGLoader extends AbsGroupLoader {
|
||||
|
||||
@Override public void addComponent(IInfoTask infoTask) {
|
||||
mInfoTask = infoTask;
|
||||
mInfoTask.setCallback(new IInfoTask.Callback() {
|
||||
mInfoTask.setCallback(new HttpDGInfoTask.DGInfoCallback() {
|
||||
|
||||
@Override
|
||||
public void onSubFail(DownloadEntity subEntity, AriaHTTPException e, boolean needRetry) {
|
||||
getState().countFailNum(subEntity.getKey());
|
||||
}
|
||||
|
||||
@Override public void onStop(long len) {
|
||||
getListener().onStop(len);
|
||||
}
|
||||
|
||||
@Override public void onSucceed(String key, CompleteInfo info) {
|
||||
startSub();
|
||||
}
|
||||
|
||||
@@ -38,8 +38,7 @@ public final class HttpDGLoaderUtil extends AbsGroupLoaderUtil {
|
||||
|
||||
@Override protected LoaderStructure buildLoaderStructure() {
|
||||
LoaderStructure structure = new LoaderStructure();
|
||||
structure.addComponent(new HttpDGInfoTask((DGTaskWrapper) getTaskWrapper(),
|
||||
(DownloadGroupListener) getListener()));
|
||||
structure.addComponent(new HttpDGInfoTask((DGTaskWrapper) getTaskWrapper()));
|
||||
structure.accept(getLoader());
|
||||
return structure;
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ import com.arialyy.aria.http.HttpRecordHandler;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-21
|
||||
* @author lyy
|
||||
* Date: 2019-09-21
|
||||
*/
|
||||
public final class HttpDLoaderUtil extends AbsNormalLoaderUtil {
|
||||
|
||||
|
||||
@@ -35,10 +35,13 @@ final class HttpDTTBuilderAdapter extends AbsNormalTTBuilderAdapter {
|
||||
BufferedRandomAccessFile file = null;
|
||||
try {
|
||||
if (totalThreadNum > 1 && !record.isBlock) {
|
||||
file = new BufferedRandomAccessFile(new File(getTempFile().getPath()), "rwd", 8192);
|
||||
file = new BufferedRandomAccessFile(getTempFile().getPath(), "rwd", 8192);
|
||||
//设置文件长度
|
||||
file.setLength(getEntity().getFileSize());
|
||||
}
|
||||
if (getTempFile().exists()) {
|
||||
FileUtil.deleteFile(getTempFile());
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -25,8 +25,8 @@ import com.arialyy.aria.core.loader.NormalTTBuilder;
|
||||
import com.arialyy.aria.core.loader.SubLoader;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-28
|
||||
* @author lyy
|
||||
* Date: 2019-09-28
|
||||
*/
|
||||
final class HttpSubDLoaderUtil extends AbsSubDLoadUtil {
|
||||
/**
|
||||
|
||||
@@ -23,14 +23,15 @@ import com.arialyy.aria.core.loader.AbsNormalTTBuilderAdapter;
|
||||
import com.arialyy.aria.core.loader.LoaderStructure;
|
||||
import com.arialyy.aria.core.loader.NormalTTBuilder;
|
||||
import com.arialyy.aria.core.loader.NormalThreadStateManager;
|
||||
import com.arialyy.aria.core.loader.UploadThreadStateManager;
|
||||
import com.arialyy.aria.core.task.IThreadTaskAdapter;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.http.HttpRecordHandler;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-19
|
||||
* @author lyy
|
||||
* Date: 2019-09-19
|
||||
*/
|
||||
public final class HttpULoaderUtil extends AbsNormalLoaderUtil {
|
||||
|
||||
@@ -45,7 +46,8 @@ public final class HttpULoaderUtil extends AbsNormalLoaderUtil {
|
||||
@Override public LoaderStructure BuildLoaderStructure() {
|
||||
LoaderStructure structure = new LoaderStructure();
|
||||
structure.addComponent(new HttpRecordHandler(getTaskWrapper()))
|
||||
.addComponent(new NormalThreadStateManager(getListener()))
|
||||
// .addComponent(new NormalThreadStateManager(getListener()))
|
||||
.addComponent(new UploadThreadStateManager(getListener()))
|
||||
.addComponent(new NormalTTBuilder(getTaskWrapper(), new AbsNormalTTBuilderAdapter() {
|
||||
@Override public IThreadTaskAdapter getAdapter(SubThreadConfig config) {
|
||||
return new HttpUThreadTaskAdapter(config);
|
||||
|
||||
@@ -102,7 +102,7 @@ final class HttpUThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
|
||||
}
|
||||
|
||||
uploadFile(writer, mTaskOption.getAttachment(), uploadFile);
|
||||
getEntity().setResponseStr(finish(writer));
|
||||
finish(writer);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(new AriaHTTPException(
|
||||
@@ -214,10 +214,12 @@ final class HttpUThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
|
||||
}
|
||||
reader.close();
|
||||
mHttpConn.disconnect();
|
||||
getEntity().setResponseStr(response.toString());
|
||||
complete();
|
||||
} else {
|
||||
String msg = "response msg: " + mHttpConn.getResponseMessage() + ",code: " + status;
|
||||
ALog.e(TAG, msg);
|
||||
getEntity().setResponseStr(response.toString());
|
||||
fail(new AriaHTTPException(msg), false);
|
||||
response.append(status);
|
||||
}
|
||||
|
||||
2
HttpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
2
HttpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -15,6 +15,9 @@ android {
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug{
|
||||
debuggable true
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
@@ -33,4 +36,8 @@ dependencies {
|
||||
implementation project(path: ':PublicComponent')
|
||||
}
|
||||
|
||||
apply from: 'bintray-release.gradle'
|
||||
//apply from: 'bintray-release.gradle'
|
||||
ext{
|
||||
PUBLISH_ARTIFACT_ID = 'm3u8'
|
||||
}
|
||||
apply from: '../gradle/mavenCentral-release.gradle'
|
||||
@@ -95,9 +95,21 @@ public abstract class BaseM3U8Loader extends AbsNormalLoader<DTaskWrapper> {
|
||||
i++;
|
||||
} else if (line.startsWith("#EXT-X-KEY")) {
|
||||
M3U8Entity m3U8Entity = getEntity().getM3U8Entity();
|
||||
String keyInfo = String.format("#EXT-X-KEY:METHOD=%s,URI=\"%s\",IV=%s\r\n", m3U8Entity.method,
|
||||
m3U8Entity.keyPath, m3U8Entity.iv);
|
||||
bytes = keyInfo.getBytes(Charset.forName("UTF-8"));
|
||||
StringBuilder sb = new StringBuilder("#EXT-X-KEY:");
|
||||
sb.append("METHOD=").append(m3U8Entity.method);
|
||||
sb.append(",URI=\"").append(m3U8Entity.keyPath).append("\"");
|
||||
if (!TextUtils.isEmpty(m3U8Entity.iv)) {
|
||||
sb.append(",IV=").append(m3U8Entity.iv);
|
||||
}
|
||||
if (!TextUtils.isEmpty(m3U8Entity.keyFormat)) {
|
||||
sb.append(",KEYFORMAT=\"").append(m3U8Entity.keyFormat).append("\"");
|
||||
sb.append(",KEYFORMATVERSIONS=\"")
|
||||
.append(TextUtils.isEmpty(m3U8Entity.keyFormatVersion) ? "1"
|
||||
: m3U8Entity.keyFormatVersion)
|
||||
.append("\"");
|
||||
}
|
||||
sb.append("\r\n");
|
||||
bytes = sb.toString().getBytes(Charset.forName("UTF-8"));
|
||||
} else {
|
||||
bytes = line.concat("\r\n").getBytes(Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
@@ -7,11 +7,8 @@ public final class IdGenerator {
|
||||
* <p>
|
||||
* 主要就是三部分: 时间戳,进程id,序列号 时间戳41,id10位,序列号12位
|
||||
*
|
||||
* @author chiwei
|
||||
* @param args
|
||||
* @since JDK 1.6
|
||||
*/
|
||||
|
||||
private static volatile IdGenerator INSTANCE = null;
|
||||
|
||||
private final static long beginTs = 1483200000000L;
|
||||
|
||||
@@ -115,6 +115,14 @@ final public class M3U8InfoTask implements IInfoTask {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override public void stop() {
|
||||
this.isStop = true;
|
||||
}
|
||||
|
||||
@Override public void cancel() {
|
||||
this.isStop = true;
|
||||
}
|
||||
|
||||
private void handleConnect(String tsListUrl, HttpURLConnection conn) throws IOException {
|
||||
int code = conn.getResponseCode();
|
||||
if (code == HttpURLConnection.HTTP_OK) {
|
||||
@@ -205,8 +213,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
||||
}
|
||||
CompleteInfo info = new CompleteInfo();
|
||||
info.obj = extInf;
|
||||
|
||||
mCallback.onSucceed(mEntity.getKey(), info);
|
||||
onSucceed(info);
|
||||
if (fos != null) {
|
||||
fos.close();
|
||||
}
|
||||
@@ -223,6 +230,13 @@ final public class M3U8InfoTask implements IInfoTask {
|
||||
}
|
||||
}
|
||||
|
||||
private void onSucceed(CompleteInfo info) {
|
||||
if (isStop) {
|
||||
return;
|
||||
}
|
||||
mCallback.onSucceed(mEntity.getKey(), info);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加切片信息到索引文件中
|
||||
* 直播下载的索引只记录头部信息,不记录EXTINF中的信息,该信息在onGetPeer的方法中添加。
|
||||
@@ -362,6 +376,9 @@ final public class M3U8InfoTask implements IInfoTask {
|
||||
}
|
||||
|
||||
private void failDownload(String errorInfo, boolean needRetry) {
|
||||
if (isStop) {
|
||||
return;
|
||||
}
|
||||
mCallback.onFail(mEntity, new AriaM3U8Exception(errorInfo), needRetry);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-24
|
||||
* @author lyy
|
||||
* Date: 2019-09-24
|
||||
*/
|
||||
final class VodRecordHandler extends RecordHandler {
|
||||
private M3U8TaskOption mOption;
|
||||
|
||||
2
M3U8Component/src/main/resources/META-INF/MANIFEST.MF
Normal file
2
M3U8Component/src/main/resources/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -15,6 +15,9 @@ android {
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug{
|
||||
debuggable true
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
@@ -32,4 +35,8 @@ dependencies {
|
||||
testImplementation 'junit:junit:4.12'
|
||||
}
|
||||
|
||||
apply from: 'bintray-release.gradle'
|
||||
//apply from: 'bintray-release.gradle'
|
||||
ext{
|
||||
PUBLISH_ARTIFACT_ID = 'public'
|
||||
}
|
||||
apply from: '../gradle/mavenCentral-release.gradle'
|
||||
@@ -157,7 +157,7 @@ public class AriaConfig {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isNetworkAvailable() {
|
||||
public boolean isNetworkAvailable() {
|
||||
// 获取手机所有连接管理对象(包括对wi-fi,net等连接的管理)
|
||||
ConnectivityManager connectivityManager =
|
||||
(ConnectivityManager) getAPP().getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
@@ -38,8 +38,8 @@ import java.util.Map;
|
||||
/**
|
||||
* 任务配置参数
|
||||
*
|
||||
* @Author lyy
|
||||
* @Date 2019-09-10
|
||||
* @author lyy
|
||||
* Date: 2019-09-10
|
||||
*/
|
||||
public class TaskOptionParams {
|
||||
|
||||
|
||||
@@ -234,6 +234,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable,
|
||||
}
|
||||
|
||||
@Override public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(this.rowID);
|
||||
dest.writeLong(this.speed);
|
||||
dest.writeString(this.convertSpeed);
|
||||
dest.writeInt(this.failNum);
|
||||
@@ -249,6 +250,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable,
|
||||
}
|
||||
|
||||
protected AbsEntity(Parcel in) {
|
||||
this.rowID = in.readLong();
|
||||
this.speed = in.readLong();
|
||||
this.convertSpeed = in.readString();
|
||||
this.failNum = in.readInt();
|
||||
|
||||
@@ -29,8 +29,8 @@ import java.io.IOException;
|
||||
/**
|
||||
* 任务记录帮助类,用于处理统一的逻辑
|
||||
*
|
||||
* @Author lyy
|
||||
* @Date 2019-09-19
|
||||
* @author lyy
|
||||
* Date: 2019-09-19
|
||||
*/
|
||||
public class RecordHelper {
|
||||
private String TAG = CommonUtil.getClassName(getClass());
|
||||
@@ -76,7 +76,7 @@ public class RecordHelper {
|
||||
tr.endLocation = endL;
|
||||
}
|
||||
}
|
||||
mWrapper.setNewTask(false);
|
||||
//mWrapper.setNewTask(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,8 +125,8 @@ public class RecordHelper {
|
||||
continue;
|
||||
}
|
||||
|
||||
long realLocation =
|
||||
tr.threadId * normalRectLen + blockFileLen; //正常情况下,该线程的startLocation的位置
|
||||
//正常情况下,该线程的startLocation的位置
|
||||
long realLocation = tr.threadId * normalRectLen + blockFileLen;
|
||||
/*
|
||||
* 检查记录文件
|
||||
*/
|
||||
@@ -147,7 +147,7 @@ public class RecordHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
mWrapper.setNewTask(false);
|
||||
//mWrapper.setNewTask(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,7 +190,7 @@ public class RecordHelper {
|
||||
tr.isComplete = false;
|
||||
}
|
||||
}
|
||||
mWrapper.setNewTask(false);
|
||||
//mWrapper.setNewTask(false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.arialyy.aria.util.CommonUtil;
|
||||
* Created by lyy on 2015/12/25.
|
||||
* 下载实体
|
||||
*/
|
||||
public class DownloadEntity extends AbsNormalEntity implements Parcelable {
|
||||
public class DownloadEntity extends AbsNormalEntity implements Parcelable, Cloneable {
|
||||
@Unique private String downloadPath; //保存路径
|
||||
|
||||
/**
|
||||
|
||||
@@ -217,14 +217,24 @@ public abstract class AbsGroupLoader implements ILoaderVisitor, ILoader {
|
||||
|
||||
@Override public void cancel() {
|
||||
isCancel = true;
|
||||
if (mInfoTask != null){
|
||||
mInfoTask.cancel();
|
||||
}
|
||||
closeTimer();
|
||||
mSubQueue.removeAllTask();
|
||||
mListener.onCancel();
|
||||
}
|
||||
|
||||
@Override public void stop() {
|
||||
if (mInfoTask != null){
|
||||
mInfoTask.stop();
|
||||
}
|
||||
isStop = true;
|
||||
mSubQueue.stopAllTask();
|
||||
if (mSubQueue.getExecSize() == 0) {
|
||||
mListener.onStop(mGTWrapper.getEntity().getCurrentProgress());
|
||||
} else {
|
||||
mSubQueue.stopAllTask();
|
||||
}
|
||||
closeTimer();
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ public final class GroupRunState {
|
||||
* 停止的任务数
|
||||
*/
|
||||
private AtomicInteger mStopNum = new AtomicInteger();
|
||||
;
|
||||
|
||||
/**
|
||||
* 当前进度
|
||||
|
||||
@@ -182,7 +182,7 @@ final class SimpleSchedulers implements Handler.Callback {
|
||||
Log.d(TAG,
|
||||
String.format("handleComplete, size = %s, completeNum = %s, failNum = %s, stopNum = %s",
|
||||
mGState.getSubSize(), mGState.getCompleteNum(), mGState.getFailNum(),
|
||||
mGState.getSubSize()));
|
||||
mGState.getStopNum()));
|
||||
|
||||
TaskRecord record = loader.getRecord();
|
||||
if (record != null && record.isBlock) {
|
||||
|
||||
@@ -43,7 +43,7 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
|
||||
/**
|
||||
* 最大执行任务数
|
||||
*/
|
||||
private int mExecSize;
|
||||
private int mMaxExecSize;
|
||||
|
||||
/**
|
||||
* 是否停止任务任务
|
||||
@@ -51,7 +51,7 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
|
||||
private boolean isStopAll = false;
|
||||
|
||||
private SimpleSubQueue() {
|
||||
mExecSize = Configuration.getInstance().dGroupCfg.getSubMaxTaskNum();
|
||||
mMaxExecSize = Configuration.getInstance().dGroupCfg.getSubMaxTaskNum();
|
||||
}
|
||||
|
||||
static SimpleSubQueue newInstance() {
|
||||
@@ -73,6 +73,10 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
|
||||
return mCache.size();
|
||||
}
|
||||
|
||||
public int getExecSize(){
|
||||
return mExec.size();
|
||||
}
|
||||
|
||||
boolean isStopAll() {
|
||||
return isStopAll;
|
||||
}
|
||||
@@ -82,7 +86,7 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
|
||||
}
|
||||
|
||||
@Override public void startTask(AbsSubDLoadUtil fileer) {
|
||||
if (mExec.size() < mExecSize) {
|
||||
if (mExec.size() < mMaxExecSize) {
|
||||
mCache.remove(fileer.getKey());
|
||||
mExec.put(fileer.getKey(), fileer);
|
||||
ALog.d(TAG,
|
||||
@@ -102,6 +106,7 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
|
||||
@Override public void stopAllTask() {
|
||||
isStopAll = true;
|
||||
ALog.d(TAG, "停止组合任务");
|
||||
mCache.clear();
|
||||
Set<String> keys = mExec.keySet();
|
||||
for (String key : keys) {
|
||||
AbsSubDLoadUtil loader = mExec.get(key);
|
||||
@@ -117,12 +122,12 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
|
||||
ALog.e(TAG, String.format("修改组合任务子任务队列数失败,num: %s", num));
|
||||
return;
|
||||
}
|
||||
if (num == mExecSize) {
|
||||
ALog.i(TAG, String.format("忽略此次修改,oldSize: %s, num: %s", mExecSize, num));
|
||||
if (num == mMaxExecSize) {
|
||||
ALog.i(TAG, String.format("忽略此次修改,oldSize: %s, num: %s", mMaxExecSize, num));
|
||||
return;
|
||||
}
|
||||
int oldSize = mExecSize;
|
||||
mExecSize = num;
|
||||
int oldSize = mMaxExecSize;
|
||||
mMaxExecSize = num;
|
||||
int diff = Math.abs(oldSize - num);
|
||||
|
||||
if (oldSize < num) { // 处理队列变小的情况,该情况下将停止队尾任务,并将这些任务添加到缓存队列中
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.arialyy.aria.core.inf;
|
||||
/**
|
||||
* 事件处理对象
|
||||
*
|
||||
* @Author lyy
|
||||
* @Date 2019-09-10
|
||||
* @author lyy
|
||||
* Date: 2019-09-10
|
||||
*/
|
||||
public interface IEventHandler {
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
package com.arialyy.aria.core.inf;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-10
|
||||
* @author lyy
|
||||
* Date: 2019-09-10
|
||||
*/
|
||||
public interface IOptionConstant {
|
||||
// ftp 任务设置常量
|
||||
|
||||
@@ -229,6 +229,9 @@ public abstract class AbsNormalLoader<T extends AbsTaskWrapper> implements ILoad
|
||||
ALog.d(TAG, String.format("任务【%s】正在删除,删除任务失败", mTaskWrapper.getKey()));
|
||||
return;
|
||||
}
|
||||
if (mInfoTask != null){
|
||||
mInfoTask.cancel();
|
||||
}
|
||||
closeTimer();
|
||||
isCancel = true;
|
||||
onCancel();
|
||||
@@ -262,6 +265,9 @@ public abstract class AbsNormalLoader<T extends AbsTaskWrapper> implements ILoad
|
||||
if (isStop) {
|
||||
return;
|
||||
}
|
||||
if (mInfoTask != null){
|
||||
mInfoTask.stop();
|
||||
}
|
||||
closeTimer();
|
||||
isStop = true;
|
||||
onStop();
|
||||
|
||||
@@ -34,6 +34,16 @@ public interface IInfoTask extends ILoaderComponent {
|
||||
*/
|
||||
void setCallback(Callback callback);
|
||||
|
||||
/**
|
||||
* 任务停止
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* 任务取消
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
interface Callback {
|
||||
/**
|
||||
* 处理完成
|
||||
|
||||
@@ -21,8 +21,8 @@ import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-18
|
||||
* @author lyy
|
||||
* Date: 2019-09-18
|
||||
*/
|
||||
public interface ILoaderAdapter {
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-18
|
||||
* @author lyy
|
||||
* Date: 2019-09-18
|
||||
*/
|
||||
public interface IRecordHandler extends ILoaderComponent {
|
||||
|
||||
|
||||
@@ -70,12 +70,9 @@ public final class NormalTTBuilder implements IThreadTaskBuilder {
|
||||
private List<IThreadTask> handleNoSupportBP() {
|
||||
List<IThreadTask> list = new ArrayList<>();
|
||||
mStartThreadNum = 1;
|
||||
|
||||
mRecord.isBlock = false;
|
||||
mRecord.update();
|
||||
IThreadTask task = createSingThreadTask(mRecord.threadRecords.get(0), 1);
|
||||
if (task == null) {
|
||||
ALog.e(TAG, "创建线程任务失败");
|
||||
return null;
|
||||
}
|
||||
list.add(task);
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -105,16 +105,16 @@ public class NormalThreadStateManager implements IThreadStateManager {
|
||||
// mergerSFtp();
|
||||
// mListener.onComplete();
|
||||
//} else
|
||||
|
||||
if (mTaskRecord.isBlock) {
|
||||
if (mTaskRecord.isBlock || mTaskRecord.threadNum == 1) {
|
||||
if (mergeFile()) {
|
||||
mListener.onComplete();
|
||||
} else {
|
||||
mListener.onFail(false, null);
|
||||
}
|
||||
} else {
|
||||
mListener.onComplete();
|
||||
quitLooper();
|
||||
break;
|
||||
}
|
||||
mListener.onComplete();
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
@@ -248,8 +248,19 @@ public class NormalThreadStateManager implements IThreadStateManager {
|
||||
*/
|
||||
private boolean mergeFile() {
|
||||
if (mTaskRecord.threadNum == 1) {
|
||||
File targetFile = new File(mTaskRecord.filePath);
|
||||
if (targetFile.exists()){
|
||||
//没有获得文件长度:不支持断点续传
|
||||
if (mTaskRecord.fileLength == 0 && targetFile.length() != 0) {
|
||||
return true;
|
||||
}
|
||||
if (targetFile.length() != 0 && targetFile.length() == mTaskRecord.fileLength) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
FileUtil.deleteFile(targetFile);
|
||||
File partFile = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, 0));
|
||||
return partFile.renameTo(new File(mTaskRecord.filePath));
|
||||
return partFile.renameTo(targetFile);
|
||||
}
|
||||
|
||||
List<String> partPath = new ArrayList<>();
|
||||
|
||||
@@ -182,6 +182,9 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
|
||||
return;
|
||||
}
|
||||
isStop = true;
|
||||
if (infoTask != null){
|
||||
infoTask.stop();
|
||||
}
|
||||
for (IThreadTask iThreadTask : mTask) {
|
||||
iThreadTask.stop();
|
||||
}
|
||||
@@ -203,6 +206,9 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
|
||||
return;
|
||||
}
|
||||
isCancel = true;
|
||||
if (infoTask != null){
|
||||
infoTask.cancel();
|
||||
}
|
||||
for (IThreadTask iThreadTask : mTask) {
|
||||
iThreadTask.cancel();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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.core.loader;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.inf.IThreadStateManager;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 线程任务管理器,用于处理多线程下载时任务的状态回调
|
||||
*/
|
||||
public class UploadThreadStateManager implements IThreadStateManager {
|
||||
private final String TAG = CommonUtil.getClassName(this);
|
||||
|
||||
/**
|
||||
* 任务状态回调
|
||||
*/
|
||||
private IEventListener mListener;
|
||||
private int mThreadNum; // 启动的线程总数
|
||||
private AtomicInteger mCancelNum = new AtomicInteger(0); // 已经取消的线程的数
|
||||
private AtomicInteger mStopNum = new AtomicInteger(0); // 已经停止的线程数
|
||||
private AtomicInteger mFailNum = new AtomicInteger(0); // 失败的线程数
|
||||
private AtomicInteger mCompleteNum = new AtomicInteger(0); // 完成的线程数
|
||||
private long mProgress; //当前总进度
|
||||
private TaskRecord mTaskRecord; // 任务记录
|
||||
private Looper mLooper;
|
||||
|
||||
/**
|
||||
* @param listener 任务事件
|
||||
*/
|
||||
public UploadThreadStateManager(IEventListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override public void setLooper(TaskRecord taskRecord, Looper looper) {
|
||||
mTaskRecord = taskRecord;
|
||||
mThreadNum = mTaskRecord.threadNum;
|
||||
mLooper = looper;
|
||||
}
|
||||
|
||||
private void checkLooper() {
|
||||
if (mTaskRecord == null) {
|
||||
throw new NullPointerException("任务记录为空");
|
||||
}
|
||||
if (mLooper == null) {
|
||||
throw new NullPointerException("Looper为空");
|
||||
}
|
||||
}
|
||||
|
||||
private Handler.Callback callback = new Handler.Callback() {
|
||||
@Override public boolean handleMessage(Message msg) {
|
||||
checkLooper();
|
||||
switch (msg.what) {
|
||||
case STATE_STOP:
|
||||
mStopNum.getAndIncrement();
|
||||
if (isStop()) {
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_CANCEL:
|
||||
mCancelNum.getAndIncrement();
|
||||
if (isCancel()) {
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_FAIL:
|
||||
mFailNum.getAndIncrement();
|
||||
if (isFail()) {
|
||||
Bundle b = msg.getData();
|
||||
mListener.onFail(b.getBoolean(DATA_RETRY, false),
|
||||
(AriaException) b.getSerializable(DATA_ERROR_INFO));
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_COMPLETE:
|
||||
mCompleteNum.getAndIncrement();
|
||||
if (isComplete()) {
|
||||
ALog.d(TAG, "isComplete, completeNum = " + mCompleteNum);
|
||||
//上传文件不需要合并文件
|
||||
mListener.onComplete();
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_RUNNING:
|
||||
Bundle b = msg.getData();
|
||||
if (b != null) {
|
||||
long len = b.getLong(IThreadStateManager.DATA_ADD_LEN, 0);
|
||||
mProgress += len;
|
||||
}
|
||||
|
||||
break;
|
||||
case STATE_UPDATE_PROGRESS:
|
||||
if (msg.obj == null) {
|
||||
mProgress = updateBlockProgress();
|
||||
} else if (msg.obj instanceof Long) {
|
||||
mProgress = (long) msg.obj;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@Override public void updateCurrentProgress(long currentProgress) {
|
||||
mProgress = currentProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出looper循环
|
||||
*/
|
||||
private void quitLooper() {
|
||||
mLooper.quit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前任务下载进度
|
||||
*
|
||||
* @return 当前任务下载进度
|
||||
*/
|
||||
@Override
|
||||
public long getCurrentProgress() {
|
||||
return mProgress;
|
||||
}
|
||||
|
||||
@Override public Handler.Callback getHandlerCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经停止
|
||||
*/
|
||||
public boolean isStop() {
|
||||
//ALog.d(TAG,
|
||||
// String.format("isStop; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s", mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mStopNum.get() == mThreadNum || mStopNum.get() + mCompleteNum.get() == mThreadNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经失败
|
||||
*/
|
||||
@Override
|
||||
public boolean isFail() {
|
||||
//ALog.d(TAG,
|
||||
// String.format("isFail; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s", mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mCompleteNum.get() != mThreadNum
|
||||
&& (mFailNum.get() == mThreadNum || mFailNum.get() + mCompleteNum.get() == mThreadNum);
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经完成
|
||||
*/
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
//ALog.d(TAG,
|
||||
// String.format("isComplete; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s",
|
||||
// mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mCompleteNum.get() == mThreadNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经取消
|
||||
*/
|
||||
public boolean isCancel() {
|
||||
//ALog.d(TAG, String.format("isCancel; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s",
|
||||
// mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mCancelNum.get() == mThreadNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新分块任务s的真实进度
|
||||
*/
|
||||
private long updateBlockProgress() {
|
||||
long size = 0;
|
||||
for (int i = 0, len = mTaskRecord.threadRecords.size(); i < len; i++) {
|
||||
File temp = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, i));
|
||||
if (temp.exists()) {
|
||||
size += temp.length();
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并sftp的分块
|
||||
*/
|
||||
private boolean mergerSFtp() {
|
||||
if (mTaskRecord.threadNum == 1) {
|
||||
File partFile = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, 0));
|
||||
return partFile.renameTo(new File(mTaskRecord.filePath));
|
||||
}
|
||||
|
||||
List<String> partPath = new ArrayList<>();
|
||||
for (int i = 0, len = mTaskRecord.threadNum; i < len; i++) {
|
||||
partPath.add(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, i));
|
||||
}
|
||||
FileUtil.mergeSFtpFile(mTaskRecord.filePath, partPath, mTaskRecord.fileLength);
|
||||
for (String pp : partPath) {
|
||||
FileUtil.deleteFile(pp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并文件
|
||||
*
|
||||
* @return {@code true} 合并成功,{@code false}合并失败
|
||||
*/
|
||||
private boolean mergeFile() {
|
||||
if (mTaskRecord.threadNum == 1) {
|
||||
File targetFile = new File(mTaskRecord.filePath);
|
||||
if (targetFile.exists() && targetFile.length() == mTaskRecord.fileLength){
|
||||
return true;
|
||||
}
|
||||
FileUtil.deleteFile(targetFile);
|
||||
File partFile = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, 0));
|
||||
return partFile.renameTo(targetFile);
|
||||
}
|
||||
|
||||
List<String> partPath = new ArrayList<>();
|
||||
for (int i = 0, len = mTaskRecord.threadNum; i < len; i++) {
|
||||
partPath.add(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, i));
|
||||
}
|
||||
boolean isSuccess = FileUtil.mergeFile(mTaskRecord.filePath, partPath);
|
||||
if (isSuccess) {
|
||||
for (String pp : partPath) {
|
||||
FileUtil.deleteFile(pp);
|
||||
}
|
||||
File targetFile = new File(mTaskRecord.filePath);
|
||||
if (targetFile.exists() && targetFile.length() > mTaskRecord.fileLength) {
|
||||
ALog.e(TAG, String.format("任务【%s】分块文件合并失败,下载长度超出文件真实长度,downloadLen: %s,fileSize: %s",
|
||||
targetFile.getName(), targetFile.length(), mTaskRecord.fileLength));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
ALog.e(TAG, "合并失败");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void accept(ILoaderVisitor visitor) {
|
||||
visitor.addComponent(this);
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,8 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-10-7
|
||||
* @author lyy
|
||||
* Date: 2019-10-7
|
||||
* 处理器的动态代理
|
||||
*/
|
||||
public class ProxyHandler implements InvocationHandler {
|
||||
|
||||
@@ -24,8 +24,8 @@ import com.arialyy.aria.util.BandwidthLimiter;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-18
|
||||
* @author lyy
|
||||
* Date: 2019-09-18
|
||||
*/
|
||||
public abstract class AbsThreadTaskAdapter implements IThreadTaskAdapter {
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.arialyy.aria.core.task;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-18
|
||||
* @author lyy
|
||||
* Date: 2019-09-18
|
||||
*/
|
||||
public interface IThreadTask extends Callable<IThreadTask> {
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.arialyy.aria.core.task;
|
||||
/**
|
||||
* 线程适配器
|
||||
*
|
||||
* @Author lyy
|
||||
* @Date 2019-09-18
|
||||
* @author lyy
|
||||
* Date: 2019-09-18
|
||||
*/
|
||||
public interface IThreadTaskAdapter {
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ import com.arialyy.aria.exception.AriaException;
|
||||
/**
|
||||
* 线程任务观察者
|
||||
*
|
||||
* @Author lyy
|
||||
* @Date 2019-09-18
|
||||
* @author lyy
|
||||
* Date: 2019-09-18
|
||||
*/
|
||||
public interface IThreadTaskObserver {
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
File blockFile = mConfig.tempFile;
|
||||
if (!blockFile.exists() || blockFile.length() != mRecord.blockLen) {
|
||||
ALog.i(TAG,
|
||||
String.format("分块【%s】错误,blockFileLen: %s, threadRect: %s; 即将重新下载该分块,开始位置:%s,结束位置:%s",
|
||||
String.format("分块【%s】错误,blockFileLen: %s, threadRect: %s; 即将重新下载该分块, 开始位置:%s,结束位置:%s",
|
||||
blockFile.getName(), blockFile.length(), mRecord.blockLen, mRecord.startLocation,
|
||||
mRecord.endLocation));
|
||||
if (blockFile.exists()) {
|
||||
@@ -310,7 +310,8 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
}
|
||||
|
||||
@Override public synchronized void updateCompleteState() {
|
||||
ALog.i(TAG, String.format("任务【%s】线程__%s__完成", getTaskWrapper().getKey(), mRecord.threadId));
|
||||
ALog.i(TAG, String.format("任务【%s】线程__%s__完成, blockSize = %s", getTaskWrapper().getKey(),
|
||||
mRecord.threadId, mConfig.tempFile.length()));
|
||||
writeConfig(true, mRecord.endLocation);
|
||||
// 进度发送不是实时的,发送完成任务前,需要更新一次进度
|
||||
sendRunningState();
|
||||
@@ -420,7 +421,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
* 重试ts分片
|
||||
*/
|
||||
private void retryM3U8Peer(boolean needRetry) {
|
||||
if (mConfig.ignoreFailure){
|
||||
if (mConfig.ignoreFailure) {
|
||||
ALog.d(TAG, "忽略失败的切片");
|
||||
sendFailMsg(null, false);
|
||||
return;
|
||||
@@ -431,9 +432,10 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
sendFailMsg(null, false);
|
||||
return;
|
||||
}
|
||||
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(
|
||||
AriaConfig.getInstance().getAPP())
|
||||
|| isNotNetRetry) && !isBreak()) {
|
||||
if (mFailTimes < RETRY_NUM
|
||||
&& needRetry
|
||||
&& (NetUtils.isConnected(AriaConfig.getInstance().getAPP()) || isNotNetRetry)
|
||||
&& !isBreak()) {
|
||||
ALog.w(TAG, String.format("ts切片【%s】第%s重试", getFileName(), String.valueOf(mFailTimes)));
|
||||
mFailTimes++;
|
||||
FileUtil.deleteFile(mConfig.tempFile);
|
||||
@@ -455,15 +457,19 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
sendFailMsg(null, false);
|
||||
return;
|
||||
}
|
||||
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(
|
||||
AriaConfig.getInstance().getAPP()) || isNotNetRetry) && !isBreak()) {
|
||||
if (mFailTimes < RETRY_NUM
|
||||
&& needRetry
|
||||
&& (NetUtils.isConnected(AriaConfig.getInstance().getAPP()) || isNotNetRetry)
|
||||
&& !isBreak()) {
|
||||
ALog.w(TAG, String.format("分块【%s】第%s次重试", getFileName(), String.valueOf(mFailTimes)));
|
||||
mFailTimes++;
|
||||
handleBlockRecord();
|
||||
ThreadTaskManager.getInstance().retryThread(this);
|
||||
return;
|
||||
}
|
||||
ALog.e(TAG, String.format("任务【%s】执行失败", getFileName()));
|
||||
ALog.e(TAG,
|
||||
String.format("重试分开【%s】失败,failTimes = %s, needRetry = %s, isBreak = %s",
|
||||
getFileName(), mFailTimes, needRetry, isBreak()));
|
||||
sendFailMsg(null, needRetry);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,7 +32,7 @@ import java.util.ServiceLoader;
|
||||
* 参考{@link ServiceLoader}
|
||||
*/
|
||||
public class AriaServiceLoader<S> {
|
||||
|
||||
private static final String TAG = "AriaServiceLoader";
|
||||
private static final String PREFIX = "META-INF/services/";
|
||||
|
||||
// The class or interface representing the service being loaded
|
||||
@@ -177,6 +177,10 @@ public class AriaServiceLoader<S> {
|
||||
}
|
||||
|
||||
private S loadService(String serviceName) {
|
||||
if (pending == null){
|
||||
ALog.e(TAG, "pending为空");
|
||||
return null;
|
||||
}
|
||||
for (String s : pending) {
|
||||
if (s.equals(serviceName)) {
|
||||
Class<?> c = null;
|
||||
|
||||
@@ -24,16 +24,18 @@ import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.exception.AriaComponentException;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 组件工具,用于跨组件创建对应的工具类
|
||||
*
|
||||
* @Author lyy
|
||||
* @Date 2019-09-23
|
||||
* @author lyy
|
||||
* Date: 2019-09-23
|
||||
*/
|
||||
public class ComponentUtil {
|
||||
public static final int COMPONENT_TYPE_HTTP = 1;
|
||||
@@ -43,12 +45,9 @@ public class ComponentUtil {
|
||||
|
||||
private String TAG = CommonUtil.getClassName(getClass());
|
||||
private static volatile ComponentUtil INSTANCE = null;
|
||||
private AriaServiceLoader<IUtil> utilLoader;
|
||||
private AriaServiceLoader<IEventListener> listenerLoader;
|
||||
|
||||
private ComponentUtil() {
|
||||
utilLoader = AriaServiceLoader.load(IUtil.class);
|
||||
listenerLoader = AriaServiceLoader.load(IEventListener.class);
|
||||
|
||||
}
|
||||
|
||||
public static ComponentUtil getInstance() {
|
||||
@@ -105,7 +104,8 @@ public class ComponentUtil {
|
||||
*
|
||||
* @return 返回任务工具
|
||||
*/
|
||||
public synchronized IUtil buildUtil(AbsTaskWrapper wrapper, IEventListener listener) {
|
||||
public synchronized <T extends IUtil> T buildUtil(AbsTaskWrapper wrapper,
|
||||
IEventListener listener) {
|
||||
int requestType = wrapper.getRequestType();
|
||||
String className = null;
|
||||
switch (requestType) {
|
||||
@@ -140,11 +140,30 @@ public class ComponentUtil {
|
||||
className = "com.arialyy.aria.sftp.upload.SFtpULoaderUtil";
|
||||
break;
|
||||
}
|
||||
IUtil util = utilLoader.getService(className);
|
||||
if (util == null) {
|
||||
throw new AriaComponentException("加载工具异常,请求类型:" + wrapper.getRequestType());
|
||||
if (className == null) {
|
||||
ALog.e(TAG, "不识别的类名:" + className);
|
||||
return null;
|
||||
}
|
||||
return util.setParams(wrapper, listener);
|
||||
T util = null;
|
||||
try {
|
||||
Class<T> clazz = (Class<T>) getClass().getClassLoader().loadClass(className);
|
||||
Constructor<T> con = clazz.getConstructor();
|
||||
util = con.newInstance();
|
||||
Method method =
|
||||
CommonUtil.getMethod(clazz, "setParams", AbsTaskWrapper.class, IEventListener.class);
|
||||
method.invoke(util, wrapper, listener);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return util;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,7 +172,7 @@ public class ComponentUtil {
|
||||
* @param wrapperType 任务类型{@link ITaskWrapper}
|
||||
* @return 返回事件监听,如果创建失败返回null
|
||||
*/
|
||||
public synchronized IEventListener buildListener(int wrapperType, AbsTask task,
|
||||
public synchronized <T extends IEventListener> T buildListener(int wrapperType, AbsTask task,
|
||||
Handler outHandler) {
|
||||
String className = null, errorStr = "请添加FTP插件";
|
||||
switch (wrapperType) {
|
||||
@@ -180,12 +199,26 @@ public class ComponentUtil {
|
||||
if (className == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
IEventListener listener = listenerLoader.getService(className);
|
||||
if (listener == null) {
|
||||
throw new AriaComponentException(errorStr);
|
||||
T listener = null;
|
||||
try {
|
||||
Class<T> clazz = (Class<T>) getClass().getClassLoader().loadClass(className);
|
||||
Constructor<T> con = clazz.getConstructor();
|
||||
listener = con.newInstance();
|
||||
Method method =
|
||||
CommonUtil.getMethod(clazz, "setParams", AbsTask.class, Handler.class);
|
||||
method.invoke(listener, task, outHandler);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalArgumentException(errorStr);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return listener.setParams(task, outHandler);
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.os.StatFs;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.os.storage.StorageVolume;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.AriaConfig;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
@@ -322,6 +323,7 @@ public class FileUtil {
|
||||
* @return {@code true} 合并成功,{@code false}合并失败
|
||||
*/
|
||||
public static boolean mergeFile(String targetPath, List<String> subPaths) {
|
||||
Log.d(TAG, "开始合并文件");
|
||||
File file = new File(targetPath);
|
||||
FileOutputStream fos = null;
|
||||
FileChannel foc = null;
|
||||
@@ -691,7 +693,7 @@ public class FileUtil {
|
||||
return list;
|
||||
}
|
||||
|
||||
private static boolean canWrite(String dirPath) {
|
||||
public static boolean canWrite(String dirPath) {
|
||||
File dir = new File(dirPath);
|
||||
if (dir.canWrite()) {
|
||||
return true;
|
||||
|
||||
@@ -61,7 +61,7 @@ public class NetUtils {
|
||||
return true;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
return AriaConfig.getInstance().isConnectedNet();
|
||||
return AriaConfig.getInstance().isNetworkAvailable();
|
||||
}
|
||||
ConnectivityManager cm =
|
||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
2
PublicComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
2
PublicComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
53
README.md
53
README.md
@@ -45,19 +45,27 @@ Aria有以下特点:
|
||||
|
||||
## 引入库
|
||||
[](https://github.com/AriaLyy/Aria/blob/master/LICENSE)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
|
||||
|
||||
```java
|
||||
implementation 'com.arialyy.aria:core:3.8.12'
|
||||
annotationProcessor 'com.arialyy.aria:compiler:3.8.12'
|
||||
implementation 'com.arialyy.aria:ftpComponent:3.8.12' # 如果需要使用ftp,请增加该组件
|
||||
implementation 'com.arialyy.aria:sftpComponent:3.8.12' # 如果需要使用ftp,请增加该组件
|
||||
implementation 'com.arialyy.aria:m3u8Component:3.8.12' # 如果需要使用m3u8下载功能,请增加该组件
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'me.laoyuyu.aria:core:3.8.16'
|
||||
annotationProcessor 'me.laoyuyu.aria:compiler:3.8.16'
|
||||
implementation 'me.laoyuyu.aria:ftp:3.8.16' # 如果需要使用ftp,请增加该组件
|
||||
implementation 'me.laoyuyu.aria:sftp:3.8.16' # 如果需要使用ftp,请增加该组件
|
||||
implementation 'me.laoyuyu.aria:m3u8:3.8.16' # 如果需要使用m3u8下载功能,请增加该组件
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
如果你使用的是kotlin,请使用kotlin官方提供的方法配置apt,[kotlin kapt官方配置传送门](https://www.kotlincn.net/docs/reference/kapt.html)
|
||||
@@ -138,22 +146,14 @@ protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
|
||||
### 版本日志
|
||||
+ v_3.8.12 (2020/8/15)
|
||||
- 修复一个正则表达式导致的文件名保存号异常问题 https://github.com/AriaLyy/Aria/issues/715
|
||||
- 修复一个匿名内部类中的内存溢出的问题 https://github.com/AriaLyy/Aria/issues/705
|
||||
- 修复同一个url地址的任务提示路径冲突的问题
|
||||
- 修复m3u8任务地址错误时,无法删除实体的问题 https://github.com/AriaLyy/Aria/issues/712
|
||||
- 修复m3u8gzip的问题,https://github.com/AriaLyy/Aria/issues/639
|
||||
- 修复http表单上传,本地md5和上传的服务的的文件md5不一致的问题 https://github.com/AriaLyy/Aria/issues/730
|
||||
- 修复0kb的文件不可下载的问题 https://github.com/AriaLyy/Aria/issues/711
|
||||
- 修复加密的m3u8下载,并且使用索引模式时,key的uri没有使用双引号的问题 https://github.com/AriaLyy/Aria/issues/731
|
||||
- 修复删除m3u8索引文件后,下载完成回调无法触发的问题
|
||||
- 修复删除加密的m3u8文件时,key没有被删除的问题 https://github.com/AriaLyy/Aria/issues/735#issuecomment-673958845
|
||||
- 增加m3u8密钥下载地址转换器增加ts列表的url地址 https://github.com/AriaLyy/Aria/issues/718
|
||||
- 增加现在http文件下载将使用HEAD请求获取文件大小,配置文件增加 <useHeadRequest value="true"/>。慎用,并不是所有服务器都支持head请求
|
||||
- 增加允许不使用apt直接通过实现监听器来回调下载进度更新,该功能由[chenfei0928](https://github.com/chenfei0928)提交,感谢他的pr。如果注解不生效,只需要实现`DownloadListener`接口便可
|
||||
- 增加m3u8使用`ignoreFailureTs`后将不会自动重试失败的切片 https://github.com/AriaLyy/Aria/issues/662
|
||||
|
||||
+ v_3.8.16
|
||||
- 修复单线程下载时,文件已经完成,重复下载回调下载失败的问题
|
||||
- 修复一个重新下载文件时,同名路径文件没有被被删除的问题
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/807
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/811
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/851
|
||||
- 修复组合任务在获取子任务信息的过程中,手动停止或删除,没有回调的问题
|
||||
|
||||
[更多版本记录](https://github.com/AriaLyy/Aria/blob/master/DEV_LOG.md)
|
||||
|
||||
## 混淆配置
|
||||
@@ -181,6 +181,7 @@ protected void onCreate(Bundle savedInstanceState) {
|
||||
## 其他
|
||||
有任何问题,可以在[issues](https://github.com/AriaLyy/Aria/issues)给我留言反馈。</br>
|
||||
在提交问题前,希望你已经查看过[wiki](https://aria.laoyuyu.me/aria_doc/)或搜索过[issues](https://github.com/AriaLyy/Aria/issues)。</br>
|
||||
[我的博客](https://www.laoyuyu.me)
|
||||
|
||||
## 捐赠
|
||||
Aria是作业利用业余时间开发的一个项目,如果你喜欢我写的软件,可以考虑给我捐赠以支持我的工作</br>
|
||||
|
||||
@@ -15,6 +15,9 @@ android {
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug{
|
||||
debuggable true
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
@@ -34,4 +37,8 @@ dependencies {
|
||||
implementation project(path: ':PublicComponent')
|
||||
}
|
||||
|
||||
apply from: 'bintray-release.gradle'
|
||||
//apply from: 'bintray-release.gradle'
|
||||
ext{
|
||||
PUBLISH_ARTIFACT_ID = 'sftp'
|
||||
}
|
||||
apply from: '../gradle/mavenCentral-release.gradle'
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.arialyy.aria.sftp;
|
||||
|
||||
import com.arialyy.aria.core.FtpUrlEntity;
|
||||
import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.core.loader.IInfoTask;
|
||||
import com.arialyy.aria.core.loader.ILoaderVisitor;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
@@ -32,9 +33,10 @@ import java.io.UnsupportedEncodingException;
|
||||
*/
|
||||
public abstract class AbsSFtpInfoTask<WP extends AbsTaskWrapper> implements IInfoTask {
|
||||
protected String TAG = CommonUtil.getClassName(this);
|
||||
protected Callback callback;
|
||||
private Callback callback;
|
||||
private WP wrapper;
|
||||
private SFtpTaskOption option;
|
||||
private boolean isStop = false, isCancel = false;
|
||||
|
||||
public AbsSFtpInfoTask(WP wp) {
|
||||
this.wrapper = wp;
|
||||
@@ -44,6 +46,28 @@ public abstract class AbsSFtpInfoTask<WP extends AbsTaskWrapper> implements IInf
|
||||
protected abstract void getFileInfo(Session session)
|
||||
throws JSchException, UnsupportedEncodingException, SftpException;
|
||||
|
||||
@Override public void stop() {
|
||||
isStop = true;
|
||||
}
|
||||
|
||||
@Override public void cancel() {
|
||||
isCancel = true;
|
||||
}
|
||||
|
||||
protected void handleFail(AriaException e, boolean needRetry) {
|
||||
if (isStop || isCancel){
|
||||
return;
|
||||
}
|
||||
callback.onFail(getWrapper().getEntity(), e, needRetry);
|
||||
}
|
||||
|
||||
protected void onSucceed(CompleteInfo info){
|
||||
if (isStop || isCancel){
|
||||
return;
|
||||
}
|
||||
callback.onSucceed(getWrapper().getKey(), info);
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
try {
|
||||
FtpUrlEntity entity = option.getUrlEntity();
|
||||
|
||||
@@ -39,7 +39,7 @@ final class SFtpDInfoTask extends AbsSFtpInfoTask<DTaskWrapper> {
|
||||
}
|
||||
|
||||
@Override protected void getFileInfo(Session session) throws JSchException,
|
||||
UnsupportedEncodingException, SftpException {
|
||||
UnsupportedEncodingException {
|
||||
SFtpTaskOption option = (SFtpTaskOption) getWrapper().getTaskOption();
|
||||
ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
|
||||
channel.connect(1000);
|
||||
@@ -60,10 +60,9 @@ final class SFtpDInfoTask extends AbsSFtpInfoTask<DTaskWrapper> {
|
||||
getWrapper().getEntity().setFileSize(attr.getSize());
|
||||
CompleteInfo info = new CompleteInfo();
|
||||
info.code = 200;
|
||||
callback.onSucceed(getWrapper().getKey(), info);
|
||||
onSucceed(info);
|
||||
} else {
|
||||
callback.onFail(getWrapper().getEntity(),
|
||||
new AriaSFTPException(String.format("文件不存在,remotePath:%s", remotePath)), false);
|
||||
handleFail(new AriaSFTPException(String.format("文件不存在,remotePath:%s", remotePath)), false);
|
||||
}
|
||||
channel.disconnect();
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ import com.arialyy.aria.util.RecordUtil;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-19
|
||||
* @author lyy
|
||||
* Date: 2019-09-19
|
||||
*/
|
||||
final class SFtpDRecordHandler extends RecordHandler {
|
||||
|
||||
|
||||
@@ -64,6 +64,6 @@ final class SFtpUInfoTask extends AbsSFtpInfoTask<UTaskWrapper> {
|
||||
info.code = isComplete ? ISCOMPLETE : 200;
|
||||
info.obj = attr;
|
||||
channel.disconnect();
|
||||
callback.onSucceed(getWrapper().getKey(), info);
|
||||
onSucceed(info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.arialyy.aria.core.loader.AbsNormalLoaderUtil;
|
||||
import com.arialyy.aria.core.loader.LoaderStructure;
|
||||
import com.arialyy.aria.core.loader.NormalTTBuilder;
|
||||
import com.arialyy.aria.core.loader.NormalThreadStateManager;
|
||||
import com.arialyy.aria.core.loader.UploadThreadStateManager;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.sftp.SFtpTaskOption;
|
||||
|
||||
@@ -41,7 +42,8 @@ public class SFtpULoaderUtil extends AbsNormalLoaderUtil {
|
||||
@Override public LoaderStructure BuildLoaderStructure() {
|
||||
LoaderStructure structure = new LoaderStructure();
|
||||
structure.addComponent(new SFtpURecordHandler((UTaskWrapper) getTaskWrapper()))
|
||||
.addComponent(new NormalThreadStateManager(getListener()))
|
||||
// .addComponent(new NormalThreadStateManager(getListener()))
|
||||
.addComponent(new UploadThreadStateManager(getListener()))
|
||||
.addComponent(new SFtpUInfoTask((UTaskWrapper) getTaskWrapper()))
|
||||
.addComponent(new NormalTTBuilder(getTaskWrapper(), new SFtpUTTBuilderAdapter(
|
||||
(UTaskWrapper) getTaskWrapper())));
|
||||
|
||||
@@ -63,14 +63,14 @@ final class SFtpURecordHandler extends RecordHandler {
|
||||
+ ftpAttrs.getSize()
|
||||
+ "】"
|
||||
+ "尝试从位置:"
|
||||
+ (ftpAttrs.getSize() - 1)
|
||||
+ ftpAttrs.getSize()
|
||||
+ "开始上传");
|
||||
getWrapper().setNewTask(false);
|
||||
|
||||
// 修改记录
|
||||
ThreadRecord threadRecord = record.threadRecords.get(0);
|
||||
//修改本地保存的停止地址为服务器上对应文件的大小
|
||||
threadRecord.startLocation = ftpAttrs.getSize() - 1;
|
||||
threadRecord.startLocation = ftpAttrs.getSize();
|
||||
}
|
||||
} else {
|
||||
ALog.d(TAG, "SFTP服务器上不存在该文件");
|
||||
|
||||
2
SFtpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
2
SFtpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -30,9 +30,14 @@ android {
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
debuggable true
|
||||
minifyEnabled false //混淆
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
zipAlignEnabled true
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
@@ -43,16 +48,12 @@ android {
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/services/javax.annotation.processing.Processor'
|
||||
merge 'META-INF/services/com.arialyy.aria.core.inf.IUtil'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
// sourceSets {
|
||||
// main.kotlin.srcDirs += 'src/main/kotlin'
|
||||
// main.java.srcDirs += 'src/main/java'
|
||||
// }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -61,6 +62,7 @@ dependencies {
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
|
||||
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'com.google.android.material:material:1.0.0'
|
||||
@@ -70,16 +72,23 @@ dependencies {
|
||||
implementation 'com.github.bumptech.glide:glide:3.7.0'
|
||||
implementation 'com.pddstudio:highlightjs-android:1.5.0'
|
||||
implementation 'org.greenrobot:eventbus:3.1.1'
|
||||
implementation project(':AppFrame')
|
||||
|
||||
// aria
|
||||
kapt project(':AriaCompiler')
|
||||
implementation project(':Aria')
|
||||
implementation project(':AppFrame')
|
||||
implementation project(':M3U8Component')
|
||||
implementation project(':FtpComponent')
|
||||
implementation project(path: ':AriaAnnotations')
|
||||
implementation project(path: ':SFtpComponent')
|
||||
|
||||
|
||||
// implementation 'com.arialyy.aria:core:3.8.12'
|
||||
// kapt 'com.arialyy.aria:compiler:3.8.12'
|
||||
// implementation 'com.arialyy.aria:ftpComponent:3.8.12' // 如果需要使用ftp,请增加该组件
|
||||
// implementation 'com.arialyy.aria:sftpComponent:3.8.12' // 如果需要使用ftp,请增加该组件
|
||||
// implementation 'com.arialyy.aria:m3u8Component:3.8.12' // 如果需要使用m3u8下载功能,请增加该组件
|
||||
|
||||
debugImplementation 'com.amitshekhar.android:debug-db:1.0.6'
|
||||
}
|
||||
repositories {
|
||||
|
||||
135
app/proguard-rules.pro
vendored
Normal file
135
app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
################################### 混淆配置 start ###########################################
|
||||
#指定代码的压缩级别
|
||||
-optimizationpasses 1
|
||||
#包明不混合大小写
|
||||
-dontusemixedcaseclassnames
|
||||
#不去忽略非公共的库类
|
||||
-dontskipnonpubliclibraryclasses
|
||||
#优化 不优化输入的类文件
|
||||
-dontoptimize
|
||||
#预校验
|
||||
-dontpreverify
|
||||
#混淆时是否记录日志
|
||||
-verbose
|
||||
# 混淆时所采用的算法
|
||||
#-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
|
||||
-optimizations !code/simplification/cast,!field/*,!class/merging/*
|
||||
#-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
|
||||
#忽略警告
|
||||
#-ignorewarning
|
||||
################################### 混淆配置 end ############################################
|
||||
|
||||
|
||||
################## 记录生成的日志数据,gradle build时在本项目根目录输出 #################
|
||||
####### 输出文件夹 build/outputs/mapping
|
||||
#apk 包内所有 class 的内部结构
|
||||
-dump build/outputs/mapping/class_files.txt
|
||||
#未混淆的类和成员
|
||||
-printseeds build/outputs/mapping/kpa_seeds.txt
|
||||
#列出从 apk 中删除的代码
|
||||
-printusage build/outputs/mapping/kpa_unused.txt
|
||||
#混淆前后的映射
|
||||
-printmapping build/outputs/mapping/kpa_mapping.txt
|
||||
################## 记录生成的日志数据,gradle build时 在本项目根目录输出-end #################
|
||||
|
||||
################## 常用属性配置-start ##################
|
||||
# 保护注解
|
||||
-keepattributes *Annotation*
|
||||
# 保护support v4 包
|
||||
-dontwarn android.support.v4.app.**
|
||||
-keep class android.support.v4.app.**{ *; }
|
||||
# 保护andorid x
|
||||
-keep class com.google.android.material.** {*;}
|
||||
-keep class androidx.** {*;}
|
||||
-keep public class * extends androidx.**
|
||||
-keep interface androidx.** {*;}
|
||||
-dontwarn com.google.android.material.**
|
||||
-dontnote com.google.android.material.**
|
||||
-dontwarn androidx.**
|
||||
# 保护一些奇葩的问题
|
||||
-dontwarn org.xmlpull.v1.XmlPullParser
|
||||
-dontwarn org.xmlpull.v1.XmlSerializer
|
||||
-keep class org.xmlpull.v1.* {*;}
|
||||
|
||||
# 保护JS接口
|
||||
-keepclassmembers class * {
|
||||
@android.webkit.JavascriptInterface <methods>;
|
||||
}
|
||||
##保持 native 方法不被混淆
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
##保持 Parcelable 不被混淆
|
||||
-keep class * implements android.os.Parcelable {
|
||||
public static final android.os.Parcelable$Creator *;
|
||||
}
|
||||
##保持 Serializable 不被混淆
|
||||
-keepnames class * implements java.io.Serializable
|
||||
#
|
||||
#保持 Serializable 不被混淆并且enum 类也不被混淆
|
||||
-keepclassmembers class * implements java.io.Serializable {
|
||||
static final long serialVersionUID;
|
||||
private static final java.io.ObjectStreamField[] serialPersistentFields;
|
||||
private void writeObject(java.io.ObjectOutputStream);
|
||||
private void readObject(java.io.ObjectInputStream);
|
||||
java.lang.Object writeReplace();
|
||||
java.lang.Object readResolve();
|
||||
}
|
||||
#避免混淆泛型 如果混淆报错建议关掉
|
||||
#–keepattributes Signature
|
||||
# webview + js
|
||||
-keepattributes *JavascriptInterface*
|
||||
|
||||
################## 常用属性配置-end ##################
|
||||
|
||||
################## kotlin-start ##################
|
||||
-keep class kotlin.** { *; }
|
||||
-keep class kotlin.Metadata { *; }
|
||||
-dontwarn kotlin.**
|
||||
-keepclassmembers class **$WhenMappings {
|
||||
<fields>;
|
||||
}
|
||||
-keepclassmembers class kotlin.Metadata {
|
||||
public <methods>;
|
||||
}
|
||||
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
|
||||
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
|
||||
}
|
||||
################## kotlin-end ##################
|
||||
|
||||
-dontwarn com.arialyy.aria.**
|
||||
-keep class com.arialyy.aria.**{*;}
|
||||
-keep class **$$DownloadListenerProxy{ *; }
|
||||
-keep class **$$UploadListenerProxy{ *; }
|
||||
-keep class **$$DownloadGroupListenerProxy{ *; }
|
||||
-keep class **$$DGSubListenerProxy{ *; }
|
||||
-keepclasseswithmembernames class * {
|
||||
@Download.* <methods>;
|
||||
@Upload.* <methods>;
|
||||
@DownloadGroup.* <methods>;
|
||||
}
|
||||
-keep class com.arialyy.aria.ftp.download.FtpDLoaderUtil{*;}
|
||||
-adaptresourcefilenames **.IUtil
|
||||
-adaptresourcefilecontents **.IUtil
|
||||
@@ -44,7 +44,7 @@
|
||||
3、从3.4.1开始,如果线程数为1,文件初始化时将不再预占用对应长度的空间,下载多少byte,则占多大的空间;
|
||||
对于采用多线程的任务或旧任务,依然采用原来的文件空间占用方式;
|
||||
-->
|
||||
<threadNum value="3"/>
|
||||
<threadNum value="1"/>
|
||||
|
||||
<!--设置下载队列最大任务数, 默认为2-->
|
||||
<maxTaskNum value="1"/>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user