From 1468a398cf9244508c67829e892f497b4a213482 Mon Sep 17 00:00:00 2001 From: gedoor Date: Thu, 29 Jul 2021 23:44:36 +0800 Subject: [PATCH] to kotlin --- app/src/main/java/io/legado/app/App.kt | 3 +- .../io/legado/app/help/http/HttpHelper.kt | 3 +- .../app/help/http/cronet/CronetHelper.kt | 4 +- .../app/help/http/cronet/CronetLoader.kt | 472 ++++++++---------- 4 files changed, 224 insertions(+), 258 deletions(-) diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index 0f277f010..24bfe161d 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -25,9 +25,8 @@ class App : MultiDexApplication() { CrashHandler(this) if (AppConfig.isCronet) { //预下载Cronet so - CronetLoader.getInstance(this).preDownload() + CronetLoader.preDownload() } - LanguageUtils.setConfiguration(this) createNotificationChannels() applyDayNight(this) diff --git a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt index 828531205..a77ebb17e 100644 --- a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt +++ b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt @@ -8,7 +8,6 @@ import okhttp3.ConnectionSpec import okhttp3.Credentials import okhttp3.Interceptor import okhttp3.OkHttpClient -import splitties.init.appCtx import java.net.InetSocketAddress import java.net.Proxy import java.util.concurrent.ConcurrentHashMap @@ -45,7 +44,7 @@ val okHttpClient: OkHttpClient by lazy { .build() chain.proceed(request) }) - if (AppConfig.isCronet && CronetLoader.getInstance(appCtx).install()) { + if (AppConfig.isCronet && CronetLoader.install()) { builder.addInterceptor(CronetInterceptor()) } diff --git a/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt b/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt index 60994332f..777e91292 100644 --- a/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt +++ b/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt @@ -19,11 +19,11 @@ import java.util.concurrent.Executors val executor: Executor by lazy { Executors.newSingleThreadExecutor() } val cronetEngine: ExperimentalCronetEngine by lazy { - CronetLoader.getInstance(appCtx).preDownload() + CronetLoader.preDownload() val builder = ExperimentalCronetEngine.Builder(appCtx) //设置自定义so库加载 - .setLibraryLoader(CronetLoader.getInstance(appCtx)) + .setLibraryLoader(CronetLoader) //设置缓存路径 .setStoragePath(appCtx.externalCacheDir?.absolutePath) //设置缓存模式 diff --git a/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt b/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt index 46372cb52..1f505d99f 100644 --- a/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt +++ b/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt @@ -1,219 +1,182 @@ -package io.legado.app.help.http.cronet; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.os.Build; -import android.text.TextUtils; -import android.util.Log; - -import org.chromium.net.CronetEngine; -import org.chromium.net.impl.ImplVersion; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.Field; -import java.math.BigInteger; -import java.net.HttpURLConnection; -import java.net.URL; -import java.security.MessageDigest; -import java.util.Objects; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -public class CronetLoader extends CronetEngine.Builder.LibraryLoader { +package io.legado.app.help.http.cronet + +import android.annotation.SuppressLint +import android.content.Context +import android.content.pm.ApplicationInfo +import android.os.Build +import android.text.TextUtils +import android.util.Log +import org.chromium.net.CronetEngine +import org.chromium.net.impl.ImplVersion +import splitties.init.appCtx +import java.io.* +import java.math.BigInteger +import java.net.HttpURLConnection +import java.net.URL +import java.security.MessageDigest +import java.util.* +import java.util.concurrent.Executor +import java.util.concurrent.Executors + +object CronetLoader : CronetEngine.Builder.LibraryLoader() { //https://storage.googleapis.com/chromium-cronet/android/92.0.4515.127/Release/cronet/libs/arm64-v8a/libcronet.92.0.4515.127.so //https://cdn.jsdelivr.net/gh/ag2s20150909/cronet-repo@92.0.4515.127/cronet/92.0.4515.127/arm64-v8a/libcronet.92.0.4515.127.so.js - private final String soName = "libcronet." + ImplVersion.getCronetVersion() + ".so"; - private final String soUrl; - private final String md5Url; - private final File soFile; - private final File downloadFile; - private String CPU_ABI; - private String md5; - private static final String TAG = "CronetLoader"; - - private static CronetLoader instance; - - public static CronetLoader getInstance(Context context) { - if (instance == null) { - synchronized (CronetLoader.class) { - if (instance == null) { - instance = new CronetLoader(context); - } - } - } - return instance; - } - - - CronetLoader(Context context) { - Context mContext = context.getApplicationContext(); - soUrl = "https://storage.googleapis.com/chromium-cronet/android/" + private const val TAG = "CronetLoader" + private val soName = "libcronet." + ImplVersion.getCronetVersion() + ".so" + private val soUrl: String + private val md5Url: String + private val soFile: File + private val downloadFile: File + private var cpuAbi: String? = null + private var md5: String? = null + var download = false + private var executor: Executor = Executors.newSingleThreadExecutor() + + + init { + soUrl = ("https://storage.googleapis.com/chromium-cronet/android/" + ImplVersion.getCronetVersion() + "/Release/cronet/libs/" - + getCpuAbi(mContext) + "/" + soName; - md5Url = "https://cdn.jsdelivr.net/gh/ag2s20150909/cronet-repo@" + + + getCpuAbi(appCtx) + "/" + soName) + md5Url = ("https://cdn.jsdelivr.net/gh/ag2s20150909/cronet-repo@" + ImplVersion.getCronetVersion() + "/cronet/" + ImplVersion.getCronetVersion() + "/" - + getCpuAbi(mContext) + "/" + soName + ".js"; - File dir = mContext.getDir("lib", Context.MODE_PRIVATE); - soFile = new File(dir + "/" + getCpuAbi(mContext), soName); - - downloadFile = new File(mContext.getCacheDir() + "/so_download", soName); - Log.e(TAG, "soName+:" + soName); - Log.e(TAG, "destSuccessFile:" + soFile); - Log.e(TAG, "tempFile:" + downloadFile); - Log.e(TAG, "soUrl:" + soUrl); - - + + getCpuAbi(appCtx) + "/" + soName + ".js") + val dir = appCtx.getDir("lib", Context.MODE_PRIVATE) + soFile = File(dir.toString() + "/" + getCpuAbi(appCtx), soName) + downloadFile = File(appCtx.cacheDir.toString() + "/so_download", soName) + Log.e(TAG, "soName+:$soName") + Log.e(TAG, "destSuccessFile:$soFile") + Log.e(TAG, "tempFile:$downloadFile") + Log.e(TAG, "soUrl:$soUrl") } - public boolean install() { - return soFile.exists(); + fun install(): Boolean { + return soFile.exists() } - public void preDownload() { - new Thread(() -> { - md5 = getUrlMd5(md5Url); - if (soFile.exists() && Objects.equals(md5, getFileMD5(soFile))) { - Log.e(TAG, "So 库已存在"); + fun preDownload() { + Thread { + md5 = getUrlMd5(md5Url) + if (soFile.exists() && md5 == getFileMD5(soFile)) { + Log.e(TAG, "So 库已存在") } else { - download(soUrl, md5, downloadFile, soFile); + download(soUrl, md5, downloadFile, soFile) } - - Log.e(TAG, soName); - }).start(); - + Log.e(TAG, soName) + }.start() } @SuppressLint("UnsafeDynamicallyLoadedCode") - @Override - public void loadLibrary(String libName) { - Log.e(TAG, "libName:" + libName); - long start = System.currentTimeMillis(); + override fun loadLibrary(libName: String) { + Log.e(TAG, "libName:$libName") + val start = System.currentTimeMillis() + @Suppress("SameParameterValue") try { //非cronet的so调用系统方法加载 if (!libName.contains("cronet")) { - System.loadLibrary(libName); - return; + System.loadLibrary(libName) + return } //以下逻辑为cronet加载,优先加载本地,否则从远程加载 //首先调用系统行为进行加载 - System.loadLibrary(libName); - Log.i(TAG, "load from system"); - - } catch (Throwable e) { + System.loadLibrary(libName) + Log.i(TAG, "load from system") + } catch (e: Throwable) { //如果找不到,则从远程下载 - - //删除历史文件 - deleteHistoryFile(Objects.requireNonNull(soFile.getParentFile()), soFile); - md5 = getUrlMd5(md5Url); - Log.i(TAG, "soMD5:" + md5); - - - if (md5 == null || md5.length() != 32 || soUrl.length() == 0) { + deleteHistoryFile(Objects.requireNonNull(soFile.parentFile), soFile) + md5 = getUrlMd5(md5Url) + Log.i(TAG, "soMD5:$md5") + if (md5 == null || md5!!.length != 32 || soUrl.isEmpty()) { //如果md5或下载的url为空,则调用系统行为进行加载 - System.loadLibrary(libName); - return; + System.loadLibrary(libName) + return } - - - if (!soFile.exists() || !soFile.isFile()) { - //noinspection ResultOfMethodCallIgnored - soFile.delete(); - download(soUrl, md5, downloadFile, soFile); + if (!soFile.exists() || !soFile.isFile) { + soFile.delete() + download(soUrl, md5, downloadFile, soFile) //如果文件不存在或不是文件,则调用系统行为进行加载 - System.loadLibrary(libName); - return; + System.loadLibrary(libName) + return } - if (soFile.exists()) { //如果文件存在,则校验md5值 - String fileMD5 = getFileMD5(soFile); - if (fileMD5 != null && fileMD5.equalsIgnoreCase(md5)) { + val fileMD5 = getFileMD5(soFile) + if (fileMD5 != null && fileMD5.equals(md5, ignoreCase = true)) { //md5值一样,则加载 - System.load(soFile.getAbsolutePath()); - Log.e(TAG, "load from:" + soFile); - return; + System.load(soFile.absolutePath) + Log.e(TAG, "load from:$soFile") + return } //md5不一样则删除 - //noinspection ResultOfMethodCallIgnored - soFile.delete(); - + soFile.delete() } //不存在则下载 - download(soUrl, md5, downloadFile, soFile); + download(soUrl, md5, downloadFile, soFile) //使用系统加载方法 - System.loadLibrary(libName); + System.loadLibrary(libName) } finally { - Log.e(TAG, "time:" + (System.currentTimeMillis() - start)); + Log.e(TAG, "time:" + (System.currentTimeMillis() - start)) } } - @SuppressLint("DiscouragedPrivateApi") - private String getCpuAbi(Context context) { - if (CPU_ABI != null) { - return CPU_ABI; + private fun getCpuAbi(context: Context): String? { + if (cpuAbi != null) { + return cpuAbi } // 5.0以上Application才有primaryCpuAbi字段 try { - ApplicationInfo appInfo = context.getApplicationInfo(); - Field abiField = ApplicationInfo.class.getDeclaredField("primaryCpuAbi"); - abiField.setAccessible(true); - CPU_ABI = (String) abiField.get(appInfo); - } catch (Exception e) { - e.printStackTrace(); + val appInfo = context.applicationInfo + val abiField = ApplicationInfo::class.java.getDeclaredField("primaryCpuAbi") + abiField.isAccessible = true + cpuAbi = abiField[appInfo] as String + } catch (e: Exception) { + e.printStackTrace() } - if (TextUtils.isEmpty(CPU_ABI)) { - CPU_ABI = Build.SUPPORTED_ABIS[0]; + if (TextUtils.isEmpty(cpuAbi)) { + cpuAbi = Build.SUPPORTED_ABIS[0] } //貌似只有这个过时了的API能获取当前APP使用的ABI - return CPU_ABI; + return cpuAbi } - - private String getUrlMd5(String url) { - if (md5 != null && md5.length() == 32) { - return md5; + @Suppress("SameParameterValue") + private fun getUrlMd5(url: String): String? { + if (md5 != null && md5!!.length == 32) { + return md5 } - InputStream inputStream; - OutputStream outputStream; - try { - outputStream = new ByteArrayOutputStream(); - HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); - inputStream = connection.getInputStream(); - byte[] buffer = new byte[1024]; - int read; - while ((read = inputStream.read(buffer)) != -1) { - outputStream.write(buffer, 0, read); - outputStream.flush(); + val inputStream: InputStream + val outputStream: OutputStream + return try { + outputStream = ByteArrayOutputStream() + val connection = URL(url).openConnection() as HttpURLConnection + inputStream = connection.inputStream + val buffer = ByteArray(1024) + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + outputStream.write(buffer, 0, read) + outputStream.flush() } - return outputStream.toString(); - - } catch (IOException e) { - return null; + outputStream.toString() + } catch (e: IOException) { + null } } /** * 删除历史文件 */ - private static void deleteHistoryFile(File dir, File currentFile) { - File[] files = dir.listFiles(); - if (files != null && files.length > 0) { - for (File f : files) { - if (f.exists() && (currentFile == null || !f.getAbsolutePath().equals(currentFile.getAbsolutePath()))) { - boolean delete = f.delete(); - Log.e(TAG, "delete file: " + f + " result: " + delete); + private fun deleteHistoryFile(dir: File, currentFile: File?) { + val files = dir.listFiles() + @Suppress("SameParameterValue") + if (files != null && files.isNotEmpty()) { + for (f in files) { + if (f.exists() && (currentFile == null || f.absolutePath != currentFile.absolutePath)) { + val delete = f.delete() + Log.e(TAG, "delete file: $f result: $delete") if (!delete) { - f.deleteOnExit(); + f.deleteOnExit() } } } @@ -223,158 +186,163 @@ public class CronetLoader extends CronetEngine.Builder.LibraryLoader { /** * 下载文件 */ - private static boolean downloadFileIfNotExist(String url, File destFile) { - InputStream inputStream = null; - OutputStream outputStream = null; + private fun downloadFileIfNotExist(url: String, destFile: File): Boolean { + var inputStream: InputStream? = null + var outputStream: OutputStream? = null try { - HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); - inputStream = connection.getInputStream(); + val connection = URL(url).openConnection() as HttpURLConnection + inputStream = connection.inputStream if (destFile.exists()) { - return true; + return true } - destFile.getParentFile().mkdirs(); - destFile.createNewFile(); - outputStream = new FileOutputStream(destFile); - byte[] buffer = new byte[32768]; - int read; - while ((read = inputStream.read(buffer)) != -1) { - outputStream.write(buffer, 0, read); - outputStream.flush(); + destFile.parentFile!!.mkdirs() + destFile.createNewFile() + outputStream = FileOutputStream(destFile) + val buffer = ByteArray(32768) + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + outputStream.write(buffer, 0, read) + outputStream.flush() } - return true; - } catch (Throwable e) { - e.printStackTrace(); + return true + } catch (e: Throwable) { + e.printStackTrace() if (destFile.exists() && !destFile.delete()) { - destFile.deleteOnExit(); + destFile.deleteOnExit() } } finally { if (inputStream != null) { try { - inputStream.close(); - } catch (IOException e) { - e.printStackTrace(); + inputStream.close() + } catch (e: IOException) { + e.printStackTrace() } } if (outputStream != null) { try { - outputStream.close(); - } catch (IOException e) { - e.printStackTrace(); + outputStream.close() + } catch (e: IOException) { + e.printStackTrace() } } } - return false; + return false } - static boolean download = false; - static Executor executor = Executors.newSingleThreadExecutor(); - /** * 下载并拷贝文件 */ - private static synchronized void download(final String url, final String md5, final File downloadTempFile, final File destSuccessFile) { + @Suppress("SameParameterValue") + @Synchronized + private fun download( + url: String, + md5: String?, + downloadTempFile: File, + destSuccessFile: File + ) { if (download) { - return; + return } - download = true; - executor.execute(() -> { - boolean result = downloadFileIfNotExist(url, downloadTempFile); - Log.e(TAG, "download result:" + result); + download = true + executor.execute { + val result = downloadFileIfNotExist(url, downloadTempFile) + Log.e(TAG, "download result:$result") //文件md5再次校验 - String fileMD5 = getFileMD5(downloadTempFile); - if (md5 != null && !md5.equalsIgnoreCase(fileMD5)) { - boolean delete = downloadTempFile.delete(); + val fileMD5 = getFileMD5(downloadTempFile) + if (md5 != null && !md5.equals(fileMD5, ignoreCase = true)) { + val delete = downloadTempFile.delete() if (!delete) { - downloadTempFile.deleteOnExit(); + downloadTempFile.deleteOnExit() } - download = false; - return; + download = false + return@execute } - Log.e(TAG, "download success, copy to " + destSuccessFile); + Log.e(TAG, "download success, copy to $destSuccessFile") //下载成功拷贝文件 - copyFile(downloadTempFile, destSuccessFile); - File parentFile = downloadTempFile.getParentFile(); - deleteHistoryFile(parentFile, null); - }); - + copyFile(downloadTempFile, destSuccessFile) + val parentFile = downloadTempFile.parentFile + @Suppress("SameParameterValue") + deleteHistoryFile(parentFile!!, null) + } } - /** * 拷贝文件 */ - private static boolean copyFile(File source, File dest) { - if (source == null || !source.exists() || !source.isFile() || dest == null) { - return false; + private fun copyFile(source: File?, dest: File?): Boolean { + if (source == null || !source.exists() || !source.isFile || dest == null) { + return false } - if (source.getAbsolutePath().equals(dest.getAbsolutePath())) { - return true; + if (source.absolutePath == dest.absolutePath) { + return true } - FileInputStream is = null; - FileOutputStream os = null; - File parent = dest.getParentFile(); - if (parent != null && (!parent.exists())) { - boolean mkdirs = parent.mkdirs(); + var fileInputStream: FileInputStream? = null + var os: FileOutputStream? = null + val parent = dest.parentFile + if (parent != null && !parent.exists()) { + val mkdirs = parent.mkdirs() if (!mkdirs) { - mkdirs = parent.mkdirs(); + parent.mkdirs() } } try { - is = new FileInputStream(source); - os = new FileOutputStream(dest, false); - - byte[] buffer = new byte[1024 * 512]; - int length; - while ((length = is.read(buffer)) > 0) { - os.write(buffer, 0, length); + fileInputStream = FileInputStream(source) + os = FileOutputStream(dest, false) + val buffer = ByteArray(1024 * 512) + var length: Int + while (fileInputStream.read(buffer).also { length = it } > 0) { + os.write(buffer, 0, length) } - return true; - } catch (Exception e) { - e.printStackTrace(); + return true + } catch (e: Exception) { + e.printStackTrace() } finally { - if (is != null) { + if (fileInputStream != null) { try { - is.close(); - } catch (Exception e) { - e.printStackTrace(); + fileInputStream.close() + } catch (e: Exception) { + e.printStackTrace() } } if (os != null) { try { - os.close(); - } catch (Exception e) { - e.printStackTrace(); + os.close() + } catch (e: Exception) { + e.printStackTrace() } } } - return false; + return false } /** * 获得文件md5 */ - private static String getFileMD5(File file) { - FileInputStream fileInputStream = null; + private fun getFileMD5(file: File): String? { + var fileInputStream: FileInputStream? = null try { - fileInputStream = new FileInputStream(file); - MessageDigest md5 = MessageDigest.getInstance("MD5"); - byte[] buffer = new byte[1024]; - int numRead = 0; - while ((numRead = fileInputStream.read(buffer)) > 0) { - md5.update(buffer, 0, numRead); + fileInputStream = FileInputStream(file) + val md5 = MessageDigest.getInstance("MD5") + val buffer = ByteArray(1024) + var numRead: Int + while (fileInputStream.read(buffer).also { numRead = it } > 0) { + md5.update(buffer, 0, numRead) } - return String.format("%032x", new BigInteger(1, md5.digest())).toLowerCase(); - } catch (Exception | OutOfMemoryError e) { - e.printStackTrace(); + return String.format("%032x", BigInteger(1, md5.digest())).lowercase() + } catch (e: Exception) { + e.printStackTrace() + } catch (e: OutOfMemoryError) { + e.printStackTrace() } finally { if (fileInputStream != null) { try { - fileInputStream.close(); - } catch (Exception e) { - e.printStackTrace(); + fileInputStream.close() + } catch (e: Exception) { + e.printStackTrace() } } } - return null; + return null } -} + +} \ No newline at end of file