package zeus.plugin; import android.content.res.AssetManager; import android.text.TextUtils; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; /** * 插件的工具类,用到的工具静态方法在这里,包括zip、file、路径配置等等 * <p/> * Created by huangjian on 2016/6/21. */ public class PluginUtil { private final static int BYTE_IN_SIZE = 4096; private static final int BUF_SIZE = 8192; private static final int CPU_AMR = 1; private static final int CPU_X86 = 2; private static final int CPU_MIPS = 3; private static String mInsidePluginPath = null; //start========================获取插件相关目录的方法====================== /** * 获取某个插件的安装目录 * * @param plugId 插件id * @return 插件的安装目录 */ public static String getPlugDir(String plugId) { return getInsidePluginPath() + plugId + "/"; } /** * 获取插件模块的目录 * * @return 插件模块的目录 */ public static String getInsidePluginPath() { if (mInsidePluginPath != null) { return mInsidePluginPath; } return mInsidePluginPath = PluginManager.mBaseContext.getFilesDir().getPath() + "/plugins/"; } /** * 获取安装后的某个插件文件路径 * * @param pluginName 插件id * @return 安装后的某个插件文件路径 */ public static String getAPKPath(String pluginName) { return getAPKPath(pluginName, getInstalledPathInfo(pluginName)); } public static String getAPKPath(String pluginName, String pathifo){ return PluginUtil.getPlugDir(pluginName)+ pathifo + PluginConfig.PLUGIN_SUFF; } /** * 获取安装前某个插件文件的路径 * * @param pluginName 插件id * @return 安装前某个插件文件的路径 */ public static String getZipPath(String pluginName) { return getPlugDir(pluginName) + pluginName; } /** * 获取dex优化后的文件地址 * * @param apkName apk的名称 * @return dex优化后的文件地址 */ public static String getDexCacheFilePath(String apkName) { return getDexCacheParentDirectPath() + apkName + ".dex"; } /** * 优化后的odex/opt文件的文件夹路径 * * @return 优化后的odex/opt文件的文件夹路径 */ public static String getDexCacheParentDirectPath() { return getInsidePluginPath() + "dalvik-cache/"; } /** * 获取某个插件安装后so文件存放目录 * * @param pluginName 插件id * @return 某个插件安装后so文件存放目录 */ public static String getLibFileInside(String pluginName) { return getInsidePluginPath() + pluginName + "/" + getInstalledPathInfo(pluginName) + "/" + getLibFile(getCpuArchitecture()); } //end========================获取插件相关目录的方法======================end /** * 是否是插件或者补丁 * * @param pluginId 插件id * @return 是否是插件或者补丁 */ public static boolean iszeusPlugin(String pluginId) { return !TextUtils.isEmpty(pluginId) && (pluginId.startsWith(PluginConfig.EXP_PLUG_PREFIX) || isHotFix(pluginId)); } /** * 是否是插件 * * @param pluginId 插件id * @return 是否是插件或者补丁 */ public static boolean isPlugin(String pluginId) { return !TextUtils.isEmpty(pluginId) && pluginId.startsWith(PluginConfig.EXP_PLUG_PREFIX); } /** * 是否是不带so文件的插件 * * @param pluginId 插件id * @return 是否是插件或者补丁 */ public static boolean isPluginWithoutSoFile(String pluginId) { return !TextUtils.isEmpty(pluginId) && pluginId.startsWith(PluginConfig.EXP_PLUG_NO_SO_PREFIX); } /** * 是否是不带so文件的补丁 * * @param pluginId 插件id * @return 是否是不带so文件的补丁 */ public static boolean isHotfixWithoutSoFile(String pluginId) { return !TextUtils.isEmpty(pluginId) && (pluginId.startsWith(PluginConfig.EXP_PLUG_HOT_FIX_NO_SO_PREFIX) || pluginId.startsWith(PluginConfig.EXP_PLUG_HOT_FIX_NO_RES_SO_PREFIX)); } /** * 是否是不带资源文件的补丁 * * @param pluginId 插件id * @return ture表明是不带资源文件的补丁 */ public static boolean isHotfixWithoutResFile(String pluginId) { return !TextUtils.isEmpty(pluginId) && (pluginId.startsWith(PluginConfig.EXP_PLUG_HOT_FIX_NO_RES_PREFIX) || pluginId.startsWith(PluginConfig.EXP_PLUG_HOT_FIX_NO_RES_SO_PREFIX)); } /** * 是否是不带so和资源文件的补丁 * * @param pluginId 插件id * @return ture表明是不带so和资源文件的补丁 */ public static boolean isHotfixWithoutSoAndResFile(String pluginId) { return !TextUtils.isEmpty(pluginId) && pluginId.startsWith(PluginConfig.EXP_PLUG_HOT_FIX_NO_RES_SO_PREFIX); } /** * 是否是补丁文件 * * @param pluginId 插件id * @return 是否是补丁文件 */ public static boolean isHotFix(String pluginId) { return !TextUtils.isEmpty(pluginId) && pluginId.startsWith(PluginConfig.EXP_PLUG_HOT_FIX_PREFIX); } /** * 关闭流 * * @param closeable closeable */ public static void close(Closeable closeable) { try { if (closeable != null) closeable.close(); } catch (Throwable e) { e.printStackTrace(); } } //start========================获取cpu类型的方法========================start /** * 获取cpu类型和架构 * * @return 返回CPU的指令集类型,仅支持arm,x86和mips这三种,arm中不区分armv6,armv7和neon,有需要自行添加. */ public static int getCpuArchitecture() { try { InputStream is = new FileInputStream("/proc/cpuinfo"); InputStreamReader ir = new InputStreamReader(is); BufferedReader br = new BufferedReader(ir); try { String nameProcessor = "Processor"; String nameModel = "model name"; while (true) { String line = br.readLine(); String[] pair; if (line == null) { break; } pair = line.split(":"); if (pair.length != 2) continue; String key = pair[0].trim(); String val = pair[1].trim(); if (key.compareTo(nameProcessor) == 0) { if (val.contains("ARM")) { return CPU_AMR; } } if (key.compareToIgnoreCase(nameModel) == 0) { if (val.contains("Intel")) { return CPU_X86; } } if (key.compareToIgnoreCase(nameProcessor) == 0) { if (val.contains("MIPS")) { return CPU_MIPS; } } } } finally { close(br); close(ir); close(is); } } catch (Exception e) { e.printStackTrace(); } return CPU_AMR; } /** * 获取当前应当执行的so文件的存放文件夹 */ public static String getLibFile(int cpuType) { switch (cpuType) { case CPU_AMR: return "lib/armeabi"; case CPU_X86: return "lib/x86/"; case CPU_MIPS: return "lib/mips/"; default: return "lib/armeabi/"; } } //end========================获取cpu类型的方法========================end //start========================文件相关的方法========================start /** * 创建文件夹 * * @param dirPath 文件夹路径 * @return 是否成功 */ public static boolean createDir(String dirPath) { File file = new File(dirPath); return !file.exists() && file.mkdirs(); } /** * 删除文件夹 * * @param file 文件对象 */ public static void deleteDirectory(File file) { if (!file.isDirectory()) { return; } File[] paths = file.listFiles(); for (File pathF : paths) { if (pathF.isDirectory()) { deleteDirectory(pathF); } else { deleteFile(pathF); } } deleteFile(file); } /** * 为防止创建一个正在被删除的文件夹,所以在删除前先重命名该文件夹 * 可以解决很多快速创建删除而产生的0字节大小文件问题 * * @param file 文件对象 * @return 是否成功 */ public static boolean deleteFile(File file) { File to = new File(file.getAbsolutePath() + System.currentTimeMillis()); file.renameTo(to); return to.delete(); } /** * 重命名 * * @param filePathName 原始文件路径 * @param newPathName 新的文件路径 * @return 是否成功 */ public static boolean rename(String filePathName, String newPathName) { if (TextUtils.isEmpty(filePathName)) return false; if (TextUtils.isEmpty(newPathName)) return false; delete(newPathName); File file = new File(filePathName); File newFile = new File(newPathName); if (!file.exists()) { return false; } File parentFile = newFile.getParentFile(); if (!parentFile.exists()) { parentFile.mkdirs(); } return file.renameTo(newFile); } /** * 创建目录,整个路径上的目录都会创建 * * @param path 路径 * @return 文件 */ public static File createDirWithFile(String path) { File file = new File(path); if (!path.endsWith("/")) { file = file.getParentFile(); } if (!file.exists()) { file.mkdirs(); } return file; } /** * 删除文件 */ public static boolean delete(String filePathName) { if (TextUtils.isEmpty(filePathName)) return false; File file = new File(filePathName); return file.isFile() && file.exists() && file.delete(); } /** * 文件是否存在 * * @param filePathName 文件路径 * @return 文件是否存在 */ public static boolean exists(String filePathName) { if (TextUtils.isEmpty(filePathName)) return false; File file = new File(filePathName); return (!file.isDirectory() && file.exists()); } //end========================文件相关的方法======================== //start========================压缩解压相关方法======================== /** * 读取zip文件中某个文件为字符串 * * @param zipFile 压缩文件 * @param fileNameReg 需要获取的文件名 * @return 获取的字符串 */ public static String readZipFileString(String zipFile, String fileNameReg) { String result = null; byte[] buffer = new byte[BUF_SIZE]; InputStream in = null; ZipInputStream zipIn = null; ByteArrayOutputStream bos = null; try { File file = new File(zipFile); if (!file.exists()) return null; in = new FileInputStream(file); zipIn = new ZipInputStream(in); ZipEntry entry; while (null != (entry = zipIn.getNextEntry())) { String zipName = entry.getName(); if (zipName.equals(fileNameReg)) { int bytes; int count = 0; bos = new ByteArrayOutputStream(); while ((bytes = zipIn.read(buffer, 0, BUF_SIZE)) != -1) { bos.write(buffer, 0, bytes); count += bytes; } if (count > 0) { result = bos.toString(); break; } } } } catch (Exception e) { e.printStackTrace(); } finally { try { close(in); close(zipIn); close(bos); } catch (Exception e2) { e2.printStackTrace(); } } return result; } /** * 将压缩文件中的某个文件夹拷贝到指定文件夹中 * * @param zipFile 压缩文件 * @param toDir 指定一个存放解压缩文件的文件夹,或者直接指定文件名方法自动识别 * @param fileNameReg 需要解压的文件夹路径如:res/drawable-hdpi/ * @return 是否成功 */ public static boolean unzipFile(String zipFile, String toDir, String fileNameReg) { boolean result = false; byte[] buffer = new byte[BUF_SIZE]; InputStream in = null; ZipInputStream zipIn = null; try { File file = new File(zipFile); in = new FileInputStream(file); zipIn = new ZipInputStream(in); ZipEntry entry; while (null != (entry = zipIn.getNextEntry())) { String zipName = entry.getName(); if (zipName.startsWith(fileNameReg)) { String relName = toDir + zipName; File unzipFile = new File(toDir); if (unzipFile.isDirectory()) { createDirWithFile(relName); unzipFile = new File(relName); } FileOutputStream out = new FileOutputStream(unzipFile); int bytes; while ((bytes = zipIn.read(buffer, 0, BUF_SIZE)) != -1) { out.write(buffer, 0, bytes); } close(out); } } result = true; } catch (Exception e) { e.printStackTrace(); result = false; } finally { close(in); close(zipIn); } return result; } /** * 复制assets下文件到一个路径下 * @param assetsFileName 要复制的assets的文件名 * @param filePath 复制后的文件的绝对路径 * @return true表示成功了 */ public static boolean copyAssetsFile(String assetsFileName, String filePath){ FileOutputStream out = null; InputStream in = null; try { AssetManager am = PluginManager.mBaseResources.getAssets(); in = am.open(assetsFileName); PluginUtil.createDirWithFile(filePath); out = new FileOutputStream(filePath, false); byte[] temp = new byte[2048]; int len; while ((len = in.read(temp)) > 0) { out.write(temp, 0, len); } } catch (Exception e) { e.printStackTrace(); return false; } finally { close(in); close(out); } return true; } //end========================压缩解压相关方法======================== /** * 获取某个插件的安装的随机路径信息 * * @param pluginId 插件id * @return 某个插件的安装的随机路径信息 */ public static String getInstalledPathInfo(String pluginId) { String result = null; String libFileInfoPath = getPlugDir(pluginId) + PluginConfig.PLUGIN_INSTALLED_INFO_PATH; BufferedInputStream bis = null; ByteArrayOutputStream baos = null; try { if (!exists(libFileInfoPath)) return null; bis = new BufferedInputStream(new FileInputStream(libFileInfoPath)); baos = new ByteArrayOutputStream(); byte[] buffer = new byte[BYTE_IN_SIZE]; int length; while ((length = bis.read(buffer, 0, BYTE_IN_SIZE)) > -1) { baos.write(buffer, 0, length); } result = new String(baos.toByteArray(), "UTF-8"); } catch (Exception e) { e.printStackTrace(); } finally { close(bis); close(baos); } return result; } /** * 保存某个插件的安装随机路径信息 * * @param pluginId 插件id * @param installedPathInfo 插件的安装随机路径信息 * @return 是否成功 */ public static boolean writePathInfo(String pluginId, String installedPathInfo) { String infoPath = PluginUtil.getPlugDir(pluginId) + PluginConfig.PLUGIN_INSTALLED_INFO_PATH; File file = new File(infoPath); FileOutputStream out = null; try { if (!file.exists()) { file.createNewFile(); } out = new FileOutputStream(file); out.write(installedPathInfo.getBytes()); } catch (Exception e) { e.printStackTrace(); return false; } finally { close(out); } return true; } //start========================反射相关方法======================== /** * 反射的方式设置某个类的成员变量的值 * * @param paramClass 类对象 * @param paramString 域的名称 * @param newClass 新的对象 */ public static void setField(Object paramClass, String paramString, Object newClass) { if (paramClass == null || TextUtils.isEmpty(paramString)) return; Field field = null; Class cl = paramClass.getClass(); for (; field == null && cl != null; ) { try { field = cl.getDeclaredField(paramString); if (field != null) { field.setAccessible(true); } } catch (Throwable ignored) { } if (field == null) { cl = cl.getSuperclass(); } } if (field != null) { try { field.set(paramClass, newClass); } catch (Throwable e) { e.printStackTrace(); } } else { System.err.print(paramString + " is not found in " + paramClass.getClass().getName()); } } /** * 反射的方式获取某个类的方法 * * @param cl 类的class * @param name 方法名称 * @param parameterTypes 方法对应的输入参数类型 * @return 方法 */ public static Method getMethod(Class cl, String name, Class... parameterTypes) { Method method = null; for (; method == null && cl != null; ) { try { method = cl.getDeclaredMethod(name, parameterTypes); if (method != null) { method.setAccessible(true); } } catch (Exception ignored) { } if (method == null) { cl = cl.getSuperclass(); } } return method; } /** * 反射的方式获取某个类的某个成员变量值 * * @param paramClass 类对象 * @param paramString field的名字 * @return field对应的值 */ public static Object getField(Object paramClass, String paramString) { if (paramClass == null) return null; Field field = null; Object object = null; Class cl = paramClass.getClass(); for (; field == null && cl != null; ) { try { field = cl.getDeclaredField(paramString); if (field != null) { field.setAccessible(true); } } catch (Exception ignored) { } if (field == null) { cl = cl.getSuperclass(); } } try { if (field != null) object = field.get(paramClass); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } return object; } //end========================反射相关方法======================== }