Android(安卓)热修复案例
16lz
2021-12-04
1.MainActivity
import android.app.Activity;import android.os.Bundle;import android.os.Environment;import android.view.View;import android.widget.TextView;import android.widget.Toast;import com.xinrui.hotfix.utils.FixBug;import com.xinrui.hotfix.utils.HotFix;public class MainActivity extends Activity implements View.OnClickListener{ private TextView fix_txt,show_txt; private FixBug mFixMe; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } public void init(){ fix_txt=(TextView)findViewById(R.id.fixtxt); show_txt=(TextView)findViewById(R.id.show); fix_txt.setOnClickListener(this); show_txt.setOnClickListener(this); mFixMe = new FixBug(MainActivity.this); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.fixtxt: checkFix(); break; case R.id.show: mFixMe.showWhat(); break; } } private void checkFix(){ try { String dexPath = Environment.getExternalStorageDirectory() + "/classes2.dex"; HotFix.fixDexFile(MainActivity.this, dexPath); Toast.makeText(MainActivity.this, "修复成功", Toast.LENGTH_SHORT).show(); } catch (Exception e) { Toast.makeText(MainActivity.this, "修复失败" + e.getMessage(), Toast.LENGTH_SHORT).show(); e.printStackTrace(); } }}
2.activity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/fixtxt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="25sp" android:text="修复" android:layout_marginTop="100px" android:layout_centerHorizontal="true" android:layout_alignParentTop="true"/> <TextView android:id="@+id/notgril" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Not Gril!" android:layout_centerInParent="true" android:visibility="gone"/> <ImageView android:id="@+id/gril" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:visibility="gone"/> <TextView android:id="@+id/show" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="显示" android:textSize="25sp" android:layout_marginBottom="100px" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true"/></RelativeLayout>
3.HotFix类
import java.io.File;import java.lang.reflect.Array;import java.lang.reflect.Field;import android.content.Context;import dalvik.system.DexClassLoader;import dalvik.system.PathClassLoader;/** * 作者:created by yufenfen on 2019/3/21:12:13 * 邮箱: ybyj1314@126.com */public class HotFix { /** * 修复指定的类 * * @param context 上下文对象 * @param fixDexFilePath 修复的dex文件路径 */ public static void fixDexFile(Context context, String fixDexFilePath) { if (fixDexFilePath != null && new File(fixDexFilePath).exists()) { try { injectDexToClassLoader(context, fixDexFilePath); } catch (Exception e) { e.printStackTrace(); } } } /** * @param context * @param fixDexFilePath 修复文件的路径 * @throws ClassNotFoundException * @throws NoSuchFieldException * @throws IllegalAccessException */ private static void injectDexToClassLoader(Context context, String fixDexFilePath) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { //读取 baseElements PathClassLoader pathClassLoader = (PathClassLoader) context.getClassLoader(); Object basePathList = getPathList(pathClassLoader); Object baseElements = getDexElements(basePathList); //读取 fixElements String baseDexAbsolutePath = context.getDir("dex", 0).getAbsolutePath(); DexClassLoader fixDexClassLoader = new DexClassLoader( fixDexFilePath, baseDexAbsolutePath, fixDexFilePath, context.getClassLoader()); Object fixPathList = getPathList(fixDexClassLoader); Object fixElements = getDexElements(fixPathList); //合并两份Elements Object newElements = combineArray(baseElements, fixElements); //一定要重新获取,不要用basePathList,会报错 Object basePathList2 = getPathList(pathClassLoader); //新的dexElements对象重新设置回去 setField(basePathList2, basePathList2.getClass(), "dexElements", newElements); } /** * 通过反射先获取到pathList对象 * * @param obj * @return * @throws ClassNotFoundException * @throws NoSuchFieldException * @throws IllegalAccessException */ private static Object getPathList(Object obj) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { return getField(obj, Class.forName("dalvik.system.BaseDexClassLoader"), "pathList"); } /** * 从上面获取到的PathList对象中,进一步反射获得dexElements对象 * * @param obj * @return * @throws NoSuchFieldException * @throws IllegalAccessException */ private static Object getDexElements(Object obj) throws NoSuchFieldException, IllegalAccessException { return getField(obj, obj.getClass(), "dexElements"); } private static Object getField(Object obj, Class cls, String str) throws NoSuchFieldException, IllegalAccessException { Field declaredField = cls.getDeclaredField(str); declaredField.setAccessible(true);//设置为可访问 return declaredField.get(obj); } private static void setField(Object obj, Class cls, String str, Object obj2) throws NoSuchFieldException, IllegalAccessException { Field declaredField = cls.getDeclaredField(str); declaredField.setAccessible(true);//设置为可访问 declaredField.set(obj, obj2); } /** * 合拼dexElements ,并确保 fixElements 在 baseElements 之前 * * @param baseElements * @param fixElements * @return */ private static Object combineArray(Object baseElements, Object fixElements) { Class componentType = fixElements.getClass().getComponentType(); int length = Array.getLength(fixElements); int length2 = Array.getLength(baseElements) + length; Object newInstance = Array.newInstance(componentType, length2); for (int i = 0; i < length2; i++) { if (i < length) { Array.set(newInstance, i, Array.get(fixElements, i)); } else { Array.set(newInstance, i, Array.get(baseElements, i - length)); } } return newInstance; }}
4.FixBug 类
import android.app.Activity;import android.content.Context;import android.util.Log;import android.view.View;import android.widget.ImageView;import android.widget.TextView;import com.xinrui.hotfix.R;public class FixBug { private final String TAG = "FixBug"; private ImageView mBelle; private TextView mNotShow; private Context mContext; //false: bug, true: fix private boolean fix = false; public FixBug(Activity context) { mContext = context; mBelle = (ImageView) context.findViewById(R.id.gril); mNotShow = (TextView) context.findViewById(R.id.notgril); } public void showWhat() { if (fix) { fixBug(); Log.d(TAG, "fix bug!"); } else { mBelle.setVisibility(View.GONE); mNotShow.setVisibility(View.VISIBLE); Log.d(TAG, "this is a bug!"); } } private void fixBug() { try { mBelle.setVisibility(View.VISIBLE); mNotShow.setVisibility(View.GONE); mBelle.setBackgroundResource(R.drawable.timg); } catch (Exception e) { e.printStackTrace(); } }}
更多相关文章
- Android(安卓)获取手机信号
- Android获取SDK的版本信息
- 获取android联系人信息
- android版本更新代码
- android java获取当前时间的总结
- Android(安卓)获取网络图片
- Android(安卓)圆角矩形ImageView
- android 版本号比较大小
- Android(安卓)图片加载缓存