直接上代码

package com.enjoy.patch;

import android.content.Context;
import android.os.Build;
import android.util.Log; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List; public class EnjoyFix { private static final String TAG = "EnjoyFix"; private static File initHack(Context context) { File hackDir = context.getDir("hack", Context.MODE_PRIVATE);
File hackFile = new File(hackDir, "hack.jar");
if (!hackFile.exists()) {
BufferedInputStream is = null;
BufferedOutputStream os = null;
try {
is = new BufferedInputStream(context.getAssets().open("hack" +
".jar"));
os = new BufferedOutputStream(new FileOutputStream(hackFile));
byte[] buffer = new byte[4096];
int len;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (os != null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return hackFile; } public static void installPatch(Context context, File patch) {
File hackFile = initHack(context);
ClassLoader classLoader = context.getClassLoader();
List<File> files = new ArrayList<>();
if (patch.exists()) {
files.add(patch);
}
files.add(hackFile);
File dexOptDir = context.getCacheDir();
try {
Log.i("TAG","Build.VERSION.SDK_INT"+Build.VERSION.SDK_INT);
//23 6.0及以上
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
V23.install(classLoader, files, dexOptDir);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
V19.install(classLoader, files, dexOptDir); //4.4以上
} else { // >= 14
V14.install(classLoader, files, dexOptDir);
}
} catch (Exception e) {
e.printStackTrace();
}
} private static final class V23 { private static void install(ClassLoader loader, List<File> additionalClassPathEntries,
File optimizedDirectory)
throws IllegalArgumentException, IllegalAccessException,
NoSuchFieldException, InvocationTargetException, NoSuchMethodException,
IOException {
//找到 pathList
Field pathListField = SharedReflectUtils.findField(loader, "pathList");
Object dexPathList = pathListField.get(loader); ArrayList<IOException> suppressedExceptions = new ArrayList<>();
// 从 pathList找到 makePathElements 方法并执行
// 得到补丁创建的 Element[]
Object[] objects = makePathElements(dexPathList,
new ArrayList<>(additionalClassPathEntries), optimizedDirectory,
suppressedExceptions); //将原本的 dexElements 与 makePathElements生成的数组合并
SharedReflectUtils.expandFieldArray(dexPathList, "dexElements", objects);
if (suppressedExceptions.size() > 0) {
for (IOException e : suppressedExceptions) {
Log.w(TAG, "Exception in makePathElement", e);
throw e;
} }
} /**
* 把dex转化为Element数组
*/
private static Object[] makePathElements(
Object dexPathList, ArrayList<File> files, File optimizedDirectory,
ArrayList<IOException> suppressedExceptions)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
//通过阅读android6、7、8、9源码,都存在makePathElements方法
Method makePathElements = SharedReflectUtils.findMethod(dexPathList, "makePathElements",
List.class, File.class,
List.class);
return (Object[]) makePathElements.invoke(dexPathList, files, optimizedDirectory,
suppressedExceptions);
}
} private static final class V19 { private static void install(ClassLoader loader, List<File> additionalClassPathEntries,
File optimizedDirectory)
throws IllegalArgumentException, IllegalAccessException,
NoSuchFieldException, InvocationTargetException, NoSuchMethodException,
IOException {
Field pathListField = SharedReflectUtils.findField(loader, "pathList");
Object dexPathList = pathListField.get(loader);
ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
SharedReflectUtils.expandFieldArray(dexPathList, "dexElements",
makeDexElements(dexPathList,
new ArrayList<File>(additionalClassPathEntries), optimizedDirectory,
suppressedExceptions));
if (suppressedExceptions.size() > 0) {
for (IOException e : suppressedExceptions) {
Log.w(TAG, "Exception in makeDexElement", e);
throw e;
}
}
} private static Object[] makeDexElements(
Object dexPathList, ArrayList<File> files, File optimizedDirectory,
ArrayList<IOException> suppressedExceptions)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Method makeDexElements = SharedReflectUtils.findMethod(dexPathList, "makeDexElements",
ArrayList.class, File.class,
ArrayList.class); return (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory,
suppressedExceptions);
}
} /**
* 14, 15, 16, 17, 18.
*/
private static final class V14 { private static void install(ClassLoader loader, List<File> additionalClassPathEntries,
File optimizedDirectory)
throws IllegalArgumentException, IllegalAccessException,
NoSuchFieldException, InvocationTargetException, NoSuchMethodException { Field pathListField = SharedReflectUtils.findField(loader, "pathList");
Object dexPathList = pathListField.get(loader); SharedReflectUtils.expandFieldArray(dexPathList, "dexElements",
makeDexElements(dexPathList,
new ArrayList<File>(additionalClassPathEntries), optimizedDirectory));
} private static Object[] makeDexElements(
Object dexPathList, ArrayList<File> files, File optimizedDirectory)
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
Method makeDexElements =
SharedReflectUtils.findMethod(dexPathList, "makeDexElements", ArrayList.class,
File.class);
return (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory);
}
} }
---------------------------------------------------------------------------------------------------------------------------------
package com.enjoy.patch;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays; /**
* 反射工具类
*/
public class SharedReflectUtils { /**
* 从 instance 到其父类 找 name 属性
*
* @param instance
* @param name
* @return
* @throws NoSuchFieldException
*/
public static Field findField(Object instance, String name) throws NoSuchFieldException {
for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
try {
//查找当前类的 属性(不包括父类)
Field field = clazz.getDeclaredField(name); if (!field.isAccessible()) {
field.setAccessible(true);
}
return field;
} catch (NoSuchFieldException e) {
// ignore and search next
}
}
throw new NoSuchFieldException("Field " + name + " not found in " + instance.getClass());
} /**
* 从 instance 到其父类 找 name 方法
*
* @param instance
* @param name
* @return
* @throws NoSuchFieldException
*/
public static Method findMethod(Object instance, String name, Class<?>... parameterTypes)
throws NoSuchMethodException {
for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
try {
Method method = clazz.getDeclaredMethod(name, parameterTypes); if (!method.isAccessible()) {
method.setAccessible(true);
} return method;
} catch (NoSuchMethodException e) {
// ignore and search next
}
}
throw new NoSuchMethodException("Method "
+ name
+ " with parameters "
+ Arrays.asList(parameterTypes)
+ " not found in " + instance.getClass());
} /**
* @param instance
* @param fieldName
* @param fixs 补丁的Element数组
* @throws NoSuchFieldException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static void expandFieldArray(Object instance, String fieldName, Object[] fixs)
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
//拿到 classloader中的dexelements 数组
Field jlrField = findField(instance, fieldName);
//old Element[]
Object[] old = (Object[]) jlrField.get(instance); //合并后的数组
Object[] newElements = (Object[]) Array.newInstance(old.getClass().getComponentType(),
old.length + fixs.length); // 先拷贝新数组
System.arraycopy(fixs, 0, newElements, 0, fixs.length);
System.arraycopy(old, 0, newElements, fixs.length, old.length); //修改 classLoader中 pathList的 dexelements
jlrField.set(instance, newElements);
} }

Android为TV端助力之QQ空间热更新技术的更多相关文章

  1. Android为TV端助力 计算每个目录剩余空间丶总空间以及SD卡剩余空间

    ublic class MemorySpaceCheck { /** * 计算剩余空间 * @param path * @return */ public static String getAvail ...

  2. Android为TV端助力 转载:RecyclerView分页加载

    package com.android.ryane.pulltoloaddata_recyclerview; import android.os.Handler;import android.os.L ...

  3. Android为TV端助力(转载)

    作者地址http://www.jianshu.com/u/63915ef020e2 针对Android Tv的自定义RecyclerView 作者 wenju_song 关注 2016.12.09 1 ...

  4. Android为TV端助力 关于4.0之后不能直接获取SD卡外部存储路径的问题

    Environment.getExternalStorageDirectory()是Android 2.x时代的产物,那时Android主流设备只有很小的内置存储器,然后都会外置一张sd卡,那时这个方 ...

  5. Android为TV端助力 转载:Android绘图Canvas十八般武器之Shader详解及实战篇(上)

    前言 Android中绘图离不开的就是Canvas了,Canvas是一个庞大的知识体系,有Java层的,也有jni层深入到Framework.Canvas有许多的知识内容,构建了一个武器库一般,所谓十 ...

  6. Android为TV端助力 布局、绘制、内存泄露、响应速度、listview和bitmap、线程优化以及一些优化的建议!

    1.布局优化 首先删除布局中无用的控件和层级,其次有选择地使用性能较低的viewgroup,比如布局中既可以使用RelativeLayout和LinearLayout,那我们就采用LinearLayo ...

  7. Android为TV端助力 不需要Socket的跨进程推送消息AIDL!

    上篇介绍了跨进程实时通讯http://www.cnblogs.com/xiaoxiaing/p/5818161.html 但是他有个缺点就是服务端无法推送消息给客户端,今天这篇文章主要说的就是服务器推 ...

  8. Android为TV端助力之Webview与JS双向交互

    package com.hhzt.iptv.adservice; import android.app.Activity;import android.graphics.Bitmap;import a ...

  9. Android为TV端助力之WebView开发踩坑一

    在Android清单配置文件里面 自定义application时,在4.4系统上面不能加上一个属性,见下图 否则界面将不会显示任何数据,在更高或者更低的系统上面没有测试!

随机推荐

  1. Mac Mini 2014 更换SSD 升级SSD

    将自己的Mac Mini 2014版升级成固态硬盘 亲自动手, 还算顺利, 参考网络教程, 并改进了里面的关键步骤, 下面是原文链接 Mac Mini 2014 升级成SSD Mac Mini 拆机图 ...

  2. IIS调优--增加并发处理能力

    一个ASP.NET项目在部署到生产环境时,当用户并发量达到200左右时,IIS出现了明显的请求排队现象,发送的请求都进入等待,无法及时响应,系统基本处于不可用状态.因经验不足,花了很多时间精力解决这个 ...

  3. Android Studio的下载、安装与配置

    1 下载 下载地址:http://www.android-studio.org/index.php ☟这里下载的是3.1.2版本 2 安装与配置 2.1 初步安装 默认就可以,点击红框内按钮依次进行安 ...

  4. 支付宝小程序开发——rich-text富文本组件支持html代码

    前言: 与微信小程序不同,支付宝小程序的富文本组件并不能直接支持html代码,如: 如上,支付宝小程序的富文本组件只支持数组类型,html代码需要使用 mini-html-parser 转换,具体用法 ...

  5. libmodbus学习笔记

    libmodbus功能: a fast and portable Modbus library 库下载地址https://libmodbus.org 使用指南1)包含头文件#include <m ...

  6. matlab学习笔记13_3创建函数句柄

    一起来学matlab-matlab学习笔记13函数 13_3 创建函数句柄 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献 https://ww2.mathworks.cn/help ...

  7. SAP翔子_ABAP_DEMO篇索引

    序号 描述 SAP翔子_ABAP_DEMO篇1 ABAP DEMO篇1 单层反查BOM SAP翔子_ABAP_DEMO篇2 ABAP DEMO篇2 删除工艺路线 SAP翔子_ABAP_DEMO篇3 A ...

  8. Session丢失的原因及解决办法

    Asp.net 默认配置下,Session莫名丢失的原因及解决办法: 正常操作情况下Session会无故丢失.因为程序是在不停的被操作,排除Session超时的可能.另外,Session超时时间被设定 ...

  9. [ ceph ] 基本概念、原理、架构介绍

    1. Ceph 架构 1.1 Ceph 接口 Ceph 支持三种接口: Object:有原生的API,而且也兼容 Swift 和 S3 的 API Block:支持精简配置.快照.克隆 File:Po ...

  10. find命令实例

    按时间查找也有参数 -atime 访问时间 -ctime 改变状态的时间 -mtime修改的时间. 这里的时间是以24小时为单位的. 查找最近30分钟修改的当前目录下的.php文件 find . -n ...