diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml index c0f43a2..e75312f 100644 --- a/.idea/assetWizardSettings.xml +++ b/.idea/assetWizardSettings.xml @@ -14,8 +14,8 @@ diff --git a/app/src/main/assets/updatelog.fy b/app/src/main/assets/updatelog.fy index 2deae15..b02b6df 100644 --- a/app/src/main/assets/updatelog.fy +++ b/app/src/main/assets/updatelog.fy @@ -1,5 +1,13 @@ +2021.05.16 +风月读书v2.0.0 +更新内容: +1、优化第三方书源(之前beta版本导入的第三方书源需要重新导入) +2、修复已知bug +3、新增崩溃日志记录 +4、关于界面新增崩溃日志分享 + 2021.05.15 -风月读书v1.9.8-beta +风月读书v1.9.9-beta 更新内容: 1、修复搜索闪退的bug diff --git a/app/src/main/java/xyz/fycz/myreader/application/CrashHandler.java b/app/src/main/java/xyz/fycz/myreader/application/CrashHandler.java index 277d1d7..e9c2ecb 100644 --- a/app/src/main/java/xyz/fycz/myreader/application/CrashHandler.java +++ b/app/src/main/java/xyz/fycz/myreader/application/CrashHandler.java @@ -18,6 +18,8 @@ import androidx.annotation.NonNull; import org.jetbrains.annotations.NotNull; +import java.io.File; +import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.net.InetAddress; @@ -29,9 +31,14 @@ import java.util.Date; import java.util.List; import java.util.Locale; +import io.reactivex.Observable; +import io.reactivex.ObservableSource; +import io.reactivex.functions.Function; import xyz.fycz.myreader.common.APPCONST; +import xyz.fycz.myreader.common.URLCONST; import xyz.fycz.myreader.ui.activity.SplashActivity; import xyz.fycz.myreader.util.utils.FileUtils; +import xyz.fycz.myreader.util.utils.OkHttpUtils; /** * @author fengyue @@ -40,6 +47,7 @@ import xyz.fycz.myreader.util.utils.FileUtils; public final class CrashHandler implements Thread.UncaughtExceptionHandler { private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + /** * 注册 Crash 监听 */ @@ -62,14 +70,11 @@ public final class CrashHandler implements Thread.UncaughtExceptionHandler { @SuppressLint("ApplySharedPref") @Override public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) { - saveCrashLog(throwable); - // 不去触发系统的崩溃处理(com.android.internal.os.RuntimeInit$KillApplicationHandler) if (mNextHandler != null && !mNextHandler.getClass().getName().startsWith("com.android.internal.os")) { mNextHandler.uncaughtException(thread, throwable); } - // 杀死进程(这个事应该是系统干的,但是它会多弹出一个崩溃对话框,所以需要我们自己手动杀死进程) android.os.Process.killProcess(android.os.Process.myPid()); System.exit(10); @@ -135,7 +140,8 @@ public final class CrashHandler implements Thread.UncaughtExceptionHandler { String time = formatter.format(new Date()); String fileName = "crash-" + time + "-" + timestamp + ".log"; String path = APPCONST.LOG_DIR + fileName; - FileUtils.writeText(mPhoneInfo + "\n\n" + mStackTrace, FileUtils.getFile(path)); + File file = FileUtils.getFile(path); + FileUtils.writeText(mPhoneInfo + "\n\n" + mStackTrace, file); } /** diff --git a/app/src/main/java/xyz/fycz/myreader/common/URLCONST.java b/app/src/main/java/xyz/fycz/myreader/common/URLCONST.java index 2aeacbd..2a307c1 100644 --- a/app/src/main/java/xyz/fycz/myreader/common/URLCONST.java +++ b/app/src/main/java/xyz/fycz/myreader/common/URLCONST.java @@ -21,6 +21,7 @@ public class URLCONST { public static final String FY_READER_URL = "https://fyreader.fycz.tk"; public static final String AD_URL = FY_READER_URL + "/ad"; + public static final String LOG_UPLOAD_URL = FY_READER_URL + "/logUpload"; public static final String DONATE = "https://gitee.com/fengyuecanzhu/Donate/raw/master"; diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/AboutActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/AboutActivity.java index c6bd143..979a87b 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/AboutActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/AboutActivity.java @@ -8,15 +8,27 @@ import android.net.Uri; import androidx.appcompat.widget.Toolbar; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +import io.reactivex.Observable; +import io.reactivex.ObservableOnSubscribe; import xyz.fycz.myreader.R; import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.base.BaseActivity; +import xyz.fycz.myreader.base.observer.MyObserver; +import xyz.fycz.myreader.common.APPCONST; import xyz.fycz.myreader.common.URLCONST; import xyz.fycz.myreader.databinding.ActivityAboutBinding; import xyz.fycz.myreader.ui.dialog.DialogCreator; import xyz.fycz.myreader.util.ShareUtils; import xyz.fycz.myreader.util.SharedPreUtils; import xyz.fycz.myreader.util.ToastUtils; +import xyz.fycz.myreader.util.ZipUtils; +import xyz.fycz.myreader.util.utils.FileUtils; +import xyz.fycz.myreader.util.utils.OkHttpUtils; +import xyz.fycz.myreader.util.utils.RxUtils; /** * @author fengyue @@ -61,8 +73,9 @@ public class AboutActivity extends BaseActivity { SharedPreUtils.getInstance().getString(getString(R.string.downloadLink), URLCONST.LAN_ZOUS_URL))); binding.il.vwUpdate.setOnClickListener(v -> App.checkVersionByServer(this, true)); binding.il.vwUpdateLog.setOnClickListener(v -> DialogCreator.createAssetTipDialog(this, "更新日志", "updatelog.fy")); + binding.il.vwShareLog.setOnClickListener(v -> shareCrashLog()); binding.il.vwQq.setOnClickListener(v -> { - if (!App.joinQQGroup(this,"8PIOnHFuH6A38hgxvD_Rp2Bu-Ke1ToBn")){ + if (!App.joinQQGroup(this, "8PIOnHFuH6A38hgxvD_Rp2Bu-Ke1ToBn")) { //数据 ClipData mClipData = ClipData.newPlainText("Label", "1085028304"); //把数据设置到剪切板上 @@ -73,7 +86,6 @@ public class AboutActivity extends BaseActivity { }); binding.il.vwGit.setOnClickListener(v -> openIntent(Intent.ACTION_VIEW, getString(R.string.this_github_url))); binding.il.vwDisclaimer.setOnClickListener(v -> DialogCreator.createAssetTipDialog(this, "免责声明", "disclaimer.fy")); - } void openIntent(String intentName, String address) { @@ -87,4 +99,65 @@ public class AboutActivity extends BaseActivity { } + private void updateCrashLog() { + File logDir = new File(APPCONST.LOG_DIR); + if (!logDir.exists() || logDir.listFiles() == null || logDir.listFiles().length == 0) { + ToastUtils.showWarring("没有日志文件"); + return; + } + Observable.create((ObservableOnSubscribe) emitter -> { + String time = String.valueOf(System.currentTimeMillis()); + String fileName = "log-" + time + ".zip"; + String logZip = FileUtils.getCachePath() + File.separator + fileName; + File zipFile = FileUtils.getFile(logZip); + if (ZipUtils.zipFile(logDir, zipFile)) { + emitter.onNext(OkHttpUtils.upload(URLCONST.LOG_UPLOAD_URL, logZip, fileName)); + } else { + emitter.onError(new Throwable("日志文件压缩失败")); + } + emitter.onComplete(); + }).compose(RxUtils::toSimpleSingle).subscribe(new MyObserver() { + @Override + public void onNext(@NotNull String s) { + ToastUtils.showInfo(s); + } + + @Override + public void onError(Throwable e) { + ToastUtils.showError(e.getLocalizedMessage()); + } + + }); + } + + private void shareCrashLog() { + File logDir = new File(APPCONST.LOG_DIR); + if (!logDir.exists() || logDir.listFiles() == null || logDir.listFiles().length == 0) { + ToastUtils.showWarring("没有日志文件"); + return; + } + Observable.create((ObservableOnSubscribe) emitter -> { + String time = String.valueOf(System.currentTimeMillis()); + String fileName = "log-" + time + ".zip"; + String logZip = FileUtils.getCachePath() + File.separator + fileName; + File zipFile = FileUtils.getFile(logZip); + if (ZipUtils.zipFile(logDir, zipFile)) { + emitter.onNext(zipFile); + } else { + emitter.onError(new Throwable("日志文件压缩失败")); + } + emitter.onComplete(); + }).compose(RxUtils::toSimpleSingle).subscribe(new MyObserver() { + @Override + public void onNext(@NotNull File file) { + ShareUtils.share(AboutActivity.this, file, file.getName(), "application/x-zip-compressed"); + } + + @Override + public void onError(Throwable e) { + ToastUtils.showError(e.getLocalizedMessage()); + } + + }); + } } diff --git a/app/src/main/java/xyz/fycz/myreader/util/OpenFileHelper.java b/app/src/main/java/xyz/fycz/myreader/util/OpenFileHelper.java index 0d2a31f..7ad0752 100644 --- a/app/src/main/java/xyz/fycz/myreader/util/OpenFileHelper.java +++ b/app/src/main/java/xyz/fycz/myreader/util/OpenFileHelper.java @@ -6,9 +6,8 @@ import android.content.Intent; import java.io.File; - public class OpenFileHelper { - private final static String[][] MIME_MapTable={ + private final static String[][] MIME_MapTable = { //{后缀名,MIME类型} {".3gp", "video/3gpp"}, {".apk", "application/vnd.android.package-archive"}, @@ -80,23 +79,24 @@ public class OpenFileHelper { /** * 打开文件 + * * @param file */ - public static void openFile(Context context,File file){ + public static void openFile(Context context, File file) { Intent intent = new Intent(); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - //设置intent的Action属性 + //设置intent的Action属性 intent.setAction(Intent.ACTION_VIEW); - //获取文件file的MIME类型 + //获取文件file的MIME类型 String type = getMIMEType(file); - //设置intent的data和Type属性。 - intent.setDataAndType(/*uri*/UriFileUtil.getUriForFile(context,file), type); - //跳转 + //设置intent的data和Type属性。 + intent.setDataAndType(/*uri*/UriFileUtil.getUriForFile(context, file), type); + //跳转 try { context.startActivity(intent); //这里最好try一下,有可能会报错。 比如说你的MIME类型是打开邮箱,但是你手机里面没装邮箱客户端,就会报错。 - }catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); ToastUtils.showError("没有安装相应的文件读取工具或者文件错误"); } @@ -104,26 +104,26 @@ public class OpenFileHelper { } - /** * 根据文件后缀名获得对应的MIME类型。 + * * @param file */ private static String getMIMEType(File file) { - String type="*/*"; + String type = "*/*"; String fName = file.getName(); //获取后缀名前的分隔符"."在fName中的位置。 int dotIndex = fName.lastIndexOf("."); - if(dotIndex < 0){ + if (dotIndex < 0) { return type; } -/* 获取文件的后缀名*/ - String end=fName.substring(dotIndex,fName.length()).toLowerCase(); - if(end=="")return type; -//在MIME和文件类型的匹配表中找到对应的MIME类型。 - for(int i=0;i read finish", bodyStr); return bodyStr; } } @@ -180,7 +183,7 @@ public class OkHttpUtils { String content = jsonObj.getString("content"); Document doc = Jsoup.parse(content); content = doc.text(); - Log.d("Http: UpdateInfo", content); + Log.d("Http -> UpdateInfo", content); return content; } } @@ -322,4 +325,31 @@ public class OkHttpUtils { this.content = content; } } + + + public static String upload(String url, String filePath, String fileName) throws IOException { + OkHttpClient client = getOkHttpClient(); + RequestBody requestBody = new MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart("file", fileName, + RequestBody.create(MediaType.parse("multipart/form-data"), new File(filePath))) + .build(); + + Request request = new Request.Builder() + .header("Authorization", "Client-ID " + UUID.randomUUID()) + .url(url) + .post(requestBody) + .build(); + + Response response = client.newCall(request).execute(); + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + ResponseBody body = response.body(); + if (body == null) { + return ""; + } else { + String bodyStr = new String(body.bytes(), StandardCharsets.UTF_8); + Log.d("Http -> upload finish", bodyStr); + return bodyStr; + } + } } diff --git a/app/src/main/res/drawable/ic___.xml b/app/src/main/res/drawable/ic___.xml deleted file mode 100644 index 5800208..0000000 --- a/app/src/main/res/drawable/ic___.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_upload.xml b/app/src/main/res/drawable/ic_upload.xml new file mode 100644 index 0000000..85fedb8 --- /dev/null +++ b/app/src/main/res/drawable/ic_upload.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/layout_about_content.xml b/app/src/main/res/layout/layout_about_content.xml index 14be276..8dbab40 100644 --- a/app/src/main/res/layout/layout_about_content.xml +++ b/app/src/main/res/layout/layout_about_content.xml @@ -279,6 +279,42 @@ + + + + + + + + + + + 分享软件 更新日志 GitHub + 分享崩溃日志 邮箱:fy@fycz.xyz https://github.com/fengyuecanzhu/FYReader 检查更新