parent
0fdf222a78
commit
2b8635e45a
|
|
@ -103,7 +103,7 @@ dependencies {
|
|||
// https://mvnrepository.com/artifact/com.github.bumptech.glide/glide
|
||||
implementation("com.github.bumptech.glide:glide:4.13.2")
|
||||
// implementation("com.luozm.captcha:captcha:1.1.2")
|
||||
|
||||
implementation("com.aliyun.dpa:oss-android-sdk:2.9.19")
|
||||
}
|
||||
|
||||
tasks.getByName("clean", type = Delete::class) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import android.widget.ImageView
|
|||
import android.widget.LinearLayout
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
|
|
@ -27,6 +28,15 @@ import com.afollestad.materialdialogs.MaterialDialog
|
|||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.afollestad.materialdialogs.customview.getCustomView
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.alibaba.sdk.android.oss.ClientException
|
||||
import com.alibaba.sdk.android.oss.OSSClient
|
||||
import com.alibaba.sdk.android.oss.ServiceException
|
||||
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback
|
||||
import com.alibaba.sdk.android.oss.callback.OSSProgressCallback
|
||||
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider
|
||||
import com.alibaba.sdk.android.oss.internal.OSSAsyncTask
|
||||
import com.alibaba.sdk.android.oss.model.PutObjectRequest
|
||||
import com.alibaba.sdk.android.oss.model.PutObjectResult
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
|
|
@ -52,8 +62,10 @@ import com.yingmao.clash.net.http.NetService
|
|||
import com.yingmao.clash.net.http.entity.AppVersionCheckRsp
|
||||
import com.yingmao.clash.net.http.entity.GetActivityRsp
|
||||
import com.yingmao.clash.net.http.entity.HeartBeatRsp
|
||||
import com.yingmao.clash.net.http.entity.ParamData
|
||||
import com.yingmao.clash.net.http.entity.PhDownloadUrlRsp
|
||||
import com.yingmao.clash.net.http.entity.SubscriptionRsp
|
||||
import com.yingmao.clash.net.http.entity.UploadParamData
|
||||
import com.yingmao.clash.net.http.entity.VipSignRsp
|
||||
import com.yingmao.clash.remote.Remote
|
||||
import com.yingmao.clash.service.ClashManager
|
||||
|
|
@ -65,6 +77,8 @@ import com.yingmao.clash.service.remote.IProfileManager
|
|||
import com.yingmao.clash.service.remote.wrap
|
||||
import com.yingmao.clash.util.AESUtil
|
||||
import com.yingmao.clash.util.CommonUtils
|
||||
import com.yingmao.clash.util.DataUtils
|
||||
import com.yingmao.clash.util.DataUtils.getAllFilePath
|
||||
import com.yingmao.clash.util.Utils
|
||||
import com.yingmao.clash.view.RxToast
|
||||
import com.yingmao.clash.view.adapter.MainVPAdapter
|
||||
|
|
@ -74,6 +88,7 @@ import com.yingmao.clash.view.dialog.DialogAppVersion
|
|||
import com.yingmao.clash.view.dialog.DialogBandChoose
|
||||
import com.yingmao.clash.view.dialog.DialogNotice
|
||||
import com.yingmao.clash.view.dialog.RxDialogShapeLoading
|
||||
import com.yingmao.clash.view.permissions.PermissionX
|
||||
import com.yingmao.clash.vm.MainAtyVM
|
||||
import com.yingmao.clash.webview.BZYWebViewKeFu
|
||||
import com.yingmao.clash.webview.BZYWebViewNormal
|
||||
|
|
@ -87,6 +102,7 @@ import okhttp3.RequestBody
|
|||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.Timer
|
||||
import java.util.TimerTask
|
||||
import java.util.UUID
|
||||
|
|
@ -249,7 +265,7 @@ class NewMainActivity : BaseActivity() {
|
|||
startLog()
|
||||
// showBindAccount()
|
||||
firstEntry()
|
||||
|
||||
checkPermission()
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -543,7 +559,32 @@ class NewMainActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
android.util.Log.i("levelData", "data:::${data}")
|
||||
} else if (httpStatus.reqType == HttpReqType.UploadParameters) {
|
||||
val upLoadData = httpStatus.rsp as UploadParamData
|
||||
if (upLoadData.code == 1000) {
|
||||
val directory: File? = this.getExternalFilesDir("CrashLog")
|
||||
//多文件上传
|
||||
if (directory != null) {
|
||||
val allFilePath = getAllFilePath(directory.path)
|
||||
if (upLoadData.data != null) {
|
||||
if (allFilePath.isNotEmpty()) {
|
||||
val username =
|
||||
MMKV.defaultMMKV()
|
||||
.decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")!!
|
||||
val nowTime = SimpleDateFormat(
|
||||
"yyyyMMddkkmmss",
|
||||
Locale.getDefault()
|
||||
).format(Date())
|
||||
uploadForAliOss(
|
||||
upLoadData.data,
|
||||
allFilePath,
|
||||
"app/errlog/" + username + "_" + nowTime + ".txt"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1086,4 +1127,89 @@ class NewMainActivity : BaseActivity() {
|
|||
super.onDestroy()
|
||||
stopUploadTimer()
|
||||
}
|
||||
|
||||
private fun uploadForAliOss(data: ParamData, filePath: List<String>, dirStr: String) {
|
||||
val endpoint = "oss-cn-hongkong.aliyuncs.com"
|
||||
val accessKeyId = data.credentials?.accessKeyId
|
||||
val accessKeySecret = data.credentials?.accessKeySecret
|
||||
// 从STS服务获取的安全令牌(SecurityToken)。
|
||||
val securityToken = data.credentials?.securityToken
|
||||
val credentialProvider =
|
||||
OSSStsTokenCredentialProvider(accessKeyId, accessKeySecret, securityToken)
|
||||
val oss = OSSClient(applicationContext, endpoint, credentialProvider)
|
||||
|
||||
android.util.Log.i("uploadForAliOss", "filePath::::${filePath[0]}")
|
||||
val put = PutObjectRequest("yingmao", dirStr, filePath[0])
|
||||
// 异步上传时可以设置进度回调。
|
||||
put.progressCallback =
|
||||
OSSProgressCallback { request, currentSize, totalSize ->
|
||||
android.util.Log.d(
|
||||
"PutObject",
|
||||
"currentSize: $currentSize totalSize: $totalSize"
|
||||
)
|
||||
}
|
||||
|
||||
val task: OSSAsyncTask<*> = oss.asyncPutObject(put,
|
||||
object : OSSCompletedCallback<PutObjectRequest?, PutObjectResult> {
|
||||
override fun onSuccess(request: PutObjectRequest?, result: PutObjectResult) {
|
||||
if (result.statusCode == 200) {
|
||||
//删除文件
|
||||
DataUtils.deleteFile(filePath[0])
|
||||
}
|
||||
android.util.Log.d("PutObjectRequest", "$request")
|
||||
android.util.Log.d("PutObjectResult", "$result")
|
||||
android.util.Log.d("PutObject", "UploadSuccess")
|
||||
android.util.Log.d("ETag", result.eTag)
|
||||
android.util.Log.d("RequestId", result.requestId)
|
||||
}
|
||||
|
||||
override fun onFailure(
|
||||
request: PutObjectRequest?,
|
||||
clientExcepion: ClientException,
|
||||
serviceException: ServiceException
|
||||
) {
|
||||
// 请求异常。
|
||||
if (clientExcepion != null) {
|
||||
// 本地异常,如网络异常等。
|
||||
clientExcepion.printStackTrace()
|
||||
}
|
||||
if (serviceException != null) {
|
||||
// 服务异常。
|
||||
android.util.Log.e("ErrorCode", serviceException.errorCode)
|
||||
android.util.Log.e("RequestId", serviceException.requestId)
|
||||
android.util.Log.e("HostId", serviceException.hostId)
|
||||
android.util.Log.e("RawMessage", serviceException.rawMessage)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun checkPermission() {
|
||||
PermissionX.request(
|
||||
this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
) { allGranted, deniedList ->
|
||||
if (allGranted) {
|
||||
android.util.Log.i("checkPermission", "checkPermission::所有申请的权限都已通过")
|
||||
val directory: File? = this.getExternalFilesDir("CrashLog")
|
||||
if (directory != null) {
|
||||
val allFilePath = getAllFilePath(directory.path)
|
||||
if (allFilePath.isNotEmpty()) {
|
||||
mainAtyVM.getUploadParameters()
|
||||
} else {
|
||||
android.util.Log.i("checkPermission", "allFilePath is empty")
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, "You denied $deniedList", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ import com.yingmao.clash.common.compat.currentProcessName
|
|||
import com.yingmao.clash.common.log.Log
|
||||
import com.yingmao.clash.entity.CheckLoginRsp
|
||||
import com.yingmao.clash.entity.UserData
|
||||
import com.yingmao.clash.util.CrashCatchHandler
|
||||
|
||||
import com.yingmao.clash.util.clashDir
|
||||
import java.io.File
|
||||
|
|
@ -68,6 +69,11 @@ class MainApplication : Application() {
|
|||
val MMKVRootDir = MMKV.initialize(this)
|
||||
Logger.i("MMKV_ROOT_DIR:$MMKVRootDir")
|
||||
updateNotificationChannels()
|
||||
/*
|
||||
* 错误日志上传捕获
|
||||
* */
|
||||
val crashCatchHandler: CrashCatchHandler = CrashCatchHandler.getInstance() //获得单例
|
||||
crashCatchHandler.init(applicationContext) //初始化,传入context
|
||||
}
|
||||
|
||||
private fun extractGeoFiles() {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import com.yingmao.clash.net.http.entity.AppVersionCheckRsp
|
|||
import com.yingmao.clash.net.http.entity.GetActivityRsp
|
||||
import com.yingmao.clash.net.http.entity.LoginRsp2
|
||||
import com.yingmao.clash.net.http.entity.SendSmsRsp
|
||||
import com.yingmao.clash.net.http.entity.UploadParamData
|
||||
import com.yingmao.clash.net.http.entity.VipSignRsp
|
||||
import okhttp3.RequestBody
|
||||
import retrofit2.Call
|
||||
|
|
@ -489,4 +490,16 @@ interface HttpApi {
|
|||
BZYConstants.MMKV_KEY_TOKEN
|
||||
).toString()
|
||||
): GetActivityRsp
|
||||
|
||||
//获取阿里云上传数据
|
||||
@Headers(
|
||||
"User-Agent: Octopus_Android"
|
||||
)
|
||||
@POST("/netbarcloud/vpn/getOssAssumeRoleToken")
|
||||
suspend fun getUploadParameters(
|
||||
@QueryMap params: Map<String, String>,
|
||||
@Header("token") string: String = MMKV.defaultMMKV().decodeString(
|
||||
BZYConstants.MMKV_KEY_TOKEN
|
||||
).toString()
|
||||
): UploadParamData
|
||||
}
|
||||
|
|
@ -46,6 +46,6 @@ enum class HttpReqType(type: Int) {
|
|||
Get_Node_Other(42),
|
||||
GetActivity(43),
|
||||
GetRuningNotice(44),
|
||||
unionPay(45)
|
||||
|
||||
unionPay(45),
|
||||
UploadParameters(46)
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.yingmao.clash.net.http.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class UploadParamData (
|
||||
@SerializedName("code") val code: Int,
|
||||
@SerializedName("message") val message: String,
|
||||
@SerializedName("data") val data: ParamData?
|
||||
)
|
||||
data class ParamData(
|
||||
val requestId:String?,
|
||||
val credentials:Credentials?,
|
||||
val assumedRoleUser:AssumedRoleUser?
|
||||
)
|
||||
|
||||
data class AssumedRoleUser(
|
||||
val arn:String,
|
||||
val assumedRoleId:String
|
||||
)
|
||||
data class Credentials(
|
||||
val securityToken:String,
|
||||
val accessKeySecret:String,
|
||||
val accessKeyId:String
|
||||
)
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
package com.yingmao.clash.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.lang.reflect.Field;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CrashCatchHandler implements UncaughtExceptionHandler {
|
||||
private final static String FILE_TYPE = "CrashLog";
|
||||
public static final String TAG = "CrashHandler";
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static final CrashCatchHandler INSTANCE = new CrashCatchHandler();// 单例模式
|
||||
private Context context;
|
||||
private UncaughtExceptionHandler defaultHandler;// 系统默认的UncaughtException处理类
|
||||
private final Map<String, String> infoMap = new HashMap<String, String>(); // 用来存储设备信息和异常信息
|
||||
|
||||
/**
|
||||
* 私有构造方法,保证只有一个CrashHandler实例
|
||||
*/
|
||||
private CrashCatchHandler() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取CrashHandler,单例模式
|
||||
*/
|
||||
public static CrashCatchHandler getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
public void init(Context context) {
|
||||
this.context = context;
|
||||
defaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 获取系统默认的UncaughtException处理器
|
||||
Thread.setDefaultUncaughtExceptionHandler(this);// 设置当前CrashHandler为程序的默认处理器
|
||||
}
|
||||
|
||||
/**
|
||||
* 当UncaughtException发生时会转入该函数来处理
|
||||
*/
|
||||
@Override
|
||||
public void uncaughtException(@NonNull Thread thread, @NonNull Throwable ex) {
|
||||
try {
|
||||
if (!handleException(ex) && defaultHandler != null) {
|
||||
// 如果用户没有处理则让系统默认的异常处理器来处理
|
||||
defaultHandler.uncaughtException(thread, ex);
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "exception : ", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 杀死进程
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(1);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
|
||||
*
|
||||
* @return 如果处理了该异常信息, 返回true;否则返回false.
|
||||
*/
|
||||
private boolean handleException(Throwable ex) throws IOException {
|
||||
if (ex == null) {
|
||||
return false;
|
||||
}
|
||||
// 使用Toast显示异常信息
|
||||
new Thread() {
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
Toast.makeText(context, "程序异常停止,请稍后重启应用!", Toast.LENGTH_SHORT).show();
|
||||
Looper.loop();
|
||||
}
|
||||
}.start();
|
||||
|
||||
collectDeviceInfo(context);// 收集设备参数信息
|
||||
saveCrashInfoToFile(ex);// 保存日志文件
|
||||
//上传错误文件
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集设备信息
|
||||
*/
|
||||
public void collectDeviceInfo(Context context) {
|
||||
// 使用包管理器获取信息
|
||||
PackageManager pm = context.getPackageManager();
|
||||
SimpleDateFormat nowTime = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒E", Locale.getDefault());
|
||||
String nowTimeStr = nowTime.format(System.currentTimeMillis());
|
||||
|
||||
|
||||
try {
|
||||
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
|
||||
if (pi != null) {
|
||||
// TODO 在这里得到包的信息
|
||||
String versionName = pi.versionName == null ? "" : pi.versionName;// 版本名;若versionName==null,则="null";否则=versionName
|
||||
String versionCode = pi.versionCode + "";// 版本号
|
||||
infoMap.put("versionName", versionName);
|
||||
infoMap.put("versionCode", versionCode);
|
||||
infoMap.put("当前时间", String.valueOf(nowTimeStr));
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.e(TAG, "an NameNotFoundException occured when collect package info");
|
||||
}
|
||||
|
||||
// 使用反射获取获取系统的硬件信息
|
||||
Field[] fields = Build.class.getDeclaredFields();// 获得某个类的所有申明的字段,即包括public、private和proteced,
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);// 暴力反射 ,获取私有的信息;类中的成员变量为private,故必须进行此操作
|
||||
try {
|
||||
infoMap.put(field.getName(), Objects.requireNonNull(field.get(null)).toString());
|
||||
Log.d(TAG, field.getName() + " : " + field.get(null));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(TAG, "an IllegalArgumentException occured when collect reflect field info", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(TAG, "an IllegalAccessException occured when collect reflect field info", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存错误信息到文件中
|
||||
*/
|
||||
private void saveCrashInfoToFile(Throwable ex) throws IOException {
|
||||
// 字符串流
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
// 获得设备信息
|
||||
for (Map.Entry<String, String> entry : infoMap.entrySet()) {// 遍历map中的值
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
stringBuffer.append(key).append("=").append(value).append("\n");
|
||||
}
|
||||
// 获得错误信息
|
||||
Writer writer = new StringWriter();// 这个writer下面还会用到,所以需要它的实例
|
||||
PrintWriter printWriter = new PrintWriter(writer);// 输出错误栈信息需要用到PrintWriter
|
||||
ex.printStackTrace(printWriter);
|
||||
Throwable cause = ex.getCause();
|
||||
while (cause != null) {// 循环,把所有的cause都输出到printWriter中
|
||||
cause.printStackTrace(printWriter);
|
||||
cause = ex.getCause();
|
||||
}
|
||||
printWriter.close();
|
||||
String result = writer.toString();
|
||||
stringBuffer.append(result);
|
||||
stringBuffer.append("\n");
|
||||
stringBuffer.append("==============================================================================================================");
|
||||
File directory = context.getExternalFilesDir(FILE_TYPE);
|
||||
if (directory != null) {
|
||||
if (!directory.isDirectory()) {
|
||||
directory.delete();
|
||||
}
|
||||
if (!directory.exists()) {
|
||||
directory.mkdirs();
|
||||
}
|
||||
}
|
||||
File file = new File(directory, new SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(new Date()) + ".txt");
|
||||
if (!file.isFile()) {
|
||||
file.delete();
|
||||
}
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(file, true);
|
||||
fos.write(stringBuffer.toString().getBytes());
|
||||
fos.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "an FileNotFoundException when write to sdcard", e);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "an IOException when write to sdcard", e);
|
||||
}
|
||||
file.getPath();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
package com.yingmao.clash.util
|
||||
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.alibaba.sdk.android.oss.ClientException
|
||||
import com.alibaba.sdk.android.oss.OSSClient
|
||||
import com.alibaba.sdk.android.oss.ServiceException
|
||||
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback
|
||||
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider
|
||||
import com.alibaba.sdk.android.oss.internal.OSSAsyncTask
|
||||
import com.alibaba.sdk.android.oss.model.PutObjectRequest
|
||||
import com.alibaba.sdk.android.oss.model.PutObjectResult
|
||||
import com.yingmao.clash.net.http.entity.ParamData
|
||||
import java.io.File
|
||||
|
||||
object DataUtils {
|
||||
/** 删除文件,可以是文件或文件夹
|
||||
* @param delFile 要删除的文件夹或文件名
|
||||
* @return 删除成功返回true,否则返回false
|
||||
*/
|
||||
fun deleteFile(delFile: String): Boolean {
|
||||
val file = File(delFile)
|
||||
if (!file.exists()) {
|
||||
Log.e(
|
||||
"--Method--",
|
||||
"删除文件失败:\" + delFile + \"不存在!"
|
||||
)
|
||||
return false
|
||||
} else {
|
||||
return if (file.isFile) deleteSingleFile(delFile)
|
||||
else deleteDirectory(delFile)
|
||||
}
|
||||
}
|
||||
|
||||
/** 删除单个文件
|
||||
* @param 要删除的文件的文件名
|
||||
* @return 单个文件删除成功返回true,否则返回false
|
||||
*/
|
||||
private fun deleteSingleFile(filePath: String): Boolean {
|
||||
val file = File(filePath)
|
||||
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
|
||||
if (file.exists() && file.isFile) {
|
||||
if (file.delete()) {
|
||||
Log.e(
|
||||
"--Method--",
|
||||
"Copy_Delete.deleteSingleFile: 删除单个文件" + `filePath` + "成功!"
|
||||
)
|
||||
return true
|
||||
} else {
|
||||
Log.e(
|
||||
"--Method--",
|
||||
"删除单个文件" + `filePath` + "失败!",
|
||||
)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
Log.e(
|
||||
"--Method--",
|
||||
"删除单个文件失败:" + `filePath` + "不存在!",
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/** 删除目录及目录下的文件
|
||||
* @param filePath 要删除的目录的文件路径
|
||||
* @return 目录删除成功返回true,否则返回false
|
||||
*/
|
||||
private fun deleteDirectory(filePath: String): Boolean {
|
||||
// 如果dir不以文件分隔符结尾,自动添加文件分隔符
|
||||
var filePath = filePath
|
||||
if (!filePath.endsWith(File.separator)) filePath = filePath + File.separator
|
||||
val dirFile = File(filePath)
|
||||
// 如果dir对应的文件不存在,或者不是一个目录,则退出
|
||||
if ((!dirFile.exists()) || (!dirFile.isDirectory)) {
|
||||
Log.e(
|
||||
"--Method--",
|
||||
"删除目录失败:" + filePath + "不存在!"
|
||||
)
|
||||
return false
|
||||
}
|
||||
var flag = true
|
||||
// 删除文件夹中的所有文件包括子目录
|
||||
val files = dirFile.listFiles()
|
||||
for (file in files) {
|
||||
// 删除子文件
|
||||
if (file.isFile) {
|
||||
flag = deleteSingleFile(file.absolutePath)
|
||||
if (!flag) break
|
||||
} else if (file.isDirectory) {
|
||||
flag = deleteDirectory(
|
||||
file
|
||||
.absolutePath
|
||||
)
|
||||
if (!flag) break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
Log.e(
|
||||
"--Method--",
|
||||
"删除目录失败"
|
||||
)
|
||||
return false
|
||||
}
|
||||
// 删除当前目录
|
||||
if (dirFile.delete()) {
|
||||
Log.e("--Method--", "Copy_Delete.deleteDirectory: 删除目录" + filePath + "成功!")
|
||||
return true
|
||||
} else {
|
||||
Log.e(
|
||||
"--Method--",
|
||||
"删除目录:" + filePath + "失败!"
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllFilePath(folderPath: String): MutableList<String> {
|
||||
val fileList =mutableListOf<String>()
|
||||
val file = File(folderPath)
|
||||
val tempList = file.listFiles()
|
||||
if (tempList != null) {
|
||||
for (i in tempList.indices) {
|
||||
if (tempList[i].isFile) {
|
||||
Log.i("dirpath","文 件:" + tempList[i].name)
|
||||
val fileName = folderPath+"/"+tempList[i].name
|
||||
Log.i("getAllFilePath","fileName:" +fileName)
|
||||
if (fileName.endsWith(".txt")) { // 根据自己的需要进行类型筛选
|
||||
fileList.add(fileName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fileList
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.yingmao.clash.view.permissions
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.fragment.app.Fragment
|
||||
typealias PermissionCallback = (Boolean, List<String>) -> Unit
|
||||
class InvisibleFragment : Fragment() {
|
||||
private var callback: ((Boolean, List<String>) -> Unit)? = null
|
||||
fun requestNow(cb: (Boolean, List<String>) -> Unit, vararg permissions: String) {
|
||||
callback = cb
|
||||
requestPermissions(permissions, 1)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>, grantResults: IntArray
|
||||
) {
|
||||
if (requestCode == 1) {
|
||||
val deniedList = ArrayList<String>()
|
||||
for ((index, result) in grantResults.withIndex()) {
|
||||
if (result != PackageManager.PERMISSION_GRANTED) {
|
||||
deniedList.add(permissions[index])
|
||||
}
|
||||
}
|
||||
val allGranted = deniedList.isEmpty()
|
||||
callback?.let { it(allGranted, deniedList) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.yingmao.clash.view.permissions
|
||||
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
|
||||
object PermissionX {
|
||||
private const val TAG = "InvisibleFragment"
|
||||
fun request(activity: FragmentActivity, vararg permissions: String, callback:
|
||||
PermissionCallback) {
|
||||
val fragmentManager = activity.supportFragmentManager
|
||||
val existedFragment = fragmentManager.findFragmentByTag(TAG)
|
||||
val fragment = if (existedFragment != null) {
|
||||
existedFragment as InvisibleFragment
|
||||
} else {
|
||||
val invisibleFragment = InvisibleFragment()
|
||||
fragmentManager.beginTransaction().add(invisibleFragment, TAG).commitNow()
|
||||
invisibleFragment
|
||||
}
|
||||
fragment.requestNow(callback, *permissions)
|
||||
}
|
||||
}
|
||||
|
|
@ -179,4 +179,16 @@ class MainAtyVM : PublicViewMode() {
|
|||
)
|
||||
doAsync(HttpReqType.GetActivity) { httpApi.getActivity(params) }
|
||||
}
|
||||
|
||||
fun getUploadParameters() {
|
||||
val httpApi = NetService.instances.createHttps(HttpApi::class.java)
|
||||
val username =
|
||||
MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")!!
|
||||
val phToken = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_PH_TOKEN, "")!!
|
||||
val params = hashMapOf(
|
||||
"phoneNumber" to username,
|
||||
"phToken" to phToken,
|
||||
)
|
||||
doAsync(HttpReqType.UploadParameters) { httpApi.getUploadParameters(params) }
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,8 @@
|
|||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent" >
|
||||
</androidx.viewpager2.widget.ViewPager2>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_slider"
|
||||
|
|
|
|||
Loading…
Reference in New Issue