作者

大家好,我叫小鑫,也能够叫我蜡笔小鑫;

自己17年毕业于中山大学,于2018年7月参加37手游安卓团队,早年上任于久邦数码担任安卓开发工程师;

现在是37手游安卓团队的海外负责人,负责相关业务开发;一起统筹一些根底建设相关作业。

一、什么是插件化

Android热更新实践

一个运转的App作为宿主,源码去加载一个未设备的apk文件,而且运转起来,这就叫做android是什么手机牌子插件化

插件化的运用场景:

1、线上新增功用(如淘宝、支付宝等)

2、热修改(通过下发补丁插件,结束对功用的修改)

3、当编译太慢时,能够运用插件化,对某些不改动的代码做成插件,加快虚拟机体系编译速度

二、插件化的三种常见结束办法

1、占位式结束插件化

1、特征

1、插java面试题件遵照大学英语四六级宿主的界说的规范,运用宿主的上下文环境

2、利益:只运用了少量反射,无hook,结束简略

3、缺陷:在插件中只能运用宿主供给的上下文环境,如插件Activity中,不能运用this当上下文,也便是说有必定侵入性,需求修改插件ActiviAndroidty的结束。

2、结束进程

1、界说宿主的规范,下面android是什么手机牌子以Activity为例

public interfa虚拟机装置教程win10ce ActivityInterface {
/**
* 把宿主(app)的环境  给  插件
* @param appActivity源码编辑器
*/
void insertAppContext(Activity appActivity);
// 生命周期办法
void onCreate(Bundle savedInstanceState)源码编辑器;
void onStart();
void onResume();
void o源码共享网nDestroy();
//此处省掉了其他声明周期,只做演示运用
}

2、在插件java面试题模块中,依据规范结束插件Activity

//依据规范结束的插件模块中的BaseActivity
public class BaseActivity implements ActivityInterface {
//宿主传递过来的上下文
p源码集市ublic Activity appAcjavascripttivity; // 宿主的环境
@Override
public void insertAppContext(Activity appActivity) {
this.appActivity = appActivity;
}
@SuppressLint("MissingSuperCall")
@Overr虚拟机下载手机版ide
public void onCreate(Bundle savedInstanceSt源码之家ate) {
}
@SuppressLint("Mijava面试题ssingSuperCall")
@Override
public void onStar虚拟机对电脑损伤大吗t() {
}
@SuppressLint("MissingSuperC源码编辑器手机版下载all")
@Override
public void onResume() {
}
@Sup虚拟机安卓pressLint("MissingSu大学perCall")
@Override
public void onDestroy() {
}
//实际上走的是宿主的setContentView办法
public void setContentView(int resId) {
appActivity.setContentView(resId);
}
public View findViewById(int layoutId) {
return appActivity.findViewById(layoutId);
}
@Override
public void startActivity(Intent intent) {源码共享网
Intent inte大学ntNew = new Intent();
intentNew.putExtra("java怎样读className", intent.getComponent().getClassName()); // Tes大学生自我鉴定tActivity 全类名
appActivity.startActivity(intentNew);
}
}
//BaseActivity是要害
public class PluginActivity extends BaseActivity {
@Override
public void onCreate(Bun源码dle sajava怎样读vedInstanceState) {
super.onCreate(savedInstanceState);
setContenandroid手机tView(R.layout.plugin_main);
// this 会报错,因为大学生工作生涯规划书插件没有设备虚拟机体系,也没有组件的环境,所以有必要运用宿主环境
Toast.mjava工作培训班akeText(appActivity, "我是插件", Toast.LE源码之家NGTH_SHORT).show();
findViewById(R.id.bt_start_activity).set虚拟机是什么意思OnClickListener(ne大学生不许校外租房w View.OnClickListener() {
@Override
public void onClick(View v) {
//这个startActivity走的是BaseActivity的startActivitjava怎样读y,也是被署理过虚拟机型安卓下载
sta大学生入党申请书rtActivity(new Intent(appActivity, TestActivity.class));大学
}
});
}
}

3、将插件模块打包a大学英语四级报名官网pk,在宿主中加载该apk

对插件apk的加源码本钱载首要分为两个进程,即加载类和加载资源。加载类运用的是自界说的DexClassLoader,加载资源运用虚拟机装置的是反射调用AssetManager的addAssetPath办法。

具体android下载的代码如下:

publi源码集市c class PluginManager {
private stajavaeetic final String TAG = PluginManager.class.getSimpleName();
private static PluginManager pluginManager;
private Context context;
public static PluginManager ge源码集市tInstance(Context context) {
if (pluginManager ==android下载 null) {
synchronized (PluginManagerjava怎样读.class) {
if (pluginManager == null大学) {
pluginManager = new PluginManager(candroid手机ontex大学生英语比赛t);
}大学生自我鉴定
}
}
return pluginManager;
}
public PluginManager(Contex源码t context) {
this.context = context;
}
private DexClassLoader dexClassLoader;
private ResoAndroidurces resources;
/**
* 1、加载类
* 2、加载资源
*/
public void loadPlugin() {
try {
File file = AssetUJavatils.copyAssetPlugin(context, "p.apk", "plugin");
if (!fil虚拟机e.exists()) {
Log.d虚拟机(TAG, "插件包 不存在...");
return;
}
String pluginPath = file.getAbsolutePath();
File fileDir = context.getDir("pDir", Context.MODEandroid平板电脑价格_PRIVATE);
dexClassLoader = new DexClaandroid什么意思ssLoader(plu大学英语四六级ginPath, fileDir.getAbsolutePath(), null, context.getClassLoader(java根底知识点));
// 加载资源
AssetManager assetManager = AssetManager.class.newInsJavatance();
Method addAssetPathMethod =源码编辑器 assetManager.getClass().getMethod("addAssetPath", String.class);
addAssetPathMethod.invoke(assetManager,java根底知识点 pluginPath); // 插虚拟机linux件包的途径   pluginPath
Resources r = context.getResources();android是什么手机牌子 // 宿主的资源装备信息
// 特别的 Resources,加载插件里边的资源的 Resources
resources = new Resources(assetM大学英语四六级anager, r.getDisplayMetrics(), r.getConfiguration());
} catch (Exception e) {
e.printStackTrace();
}
}
public ClassLoader getClassLoader() {
return dexCandroid下载装置lassLoader;
}
public Resources getResources() {
r源码之家eturn resouandroid下载rces;
}
}

4、在宿主中界说占位的Activity

这儿最重要的进程为:

1、重写getResources和getClassLoader办法,运用插件的ClassLoader和插件的Resources

2、实例化出来插件Activity

3、给插件Activity注入上下文

4、调用插件Activity的onJavaCreate办法

代码如下:

publ源码共享网ic class ProxyActivity extends Activity {
//这儿运用的是插件中的资源
@Override
public Resources getResources() {
return PluginManage源码编辑器编程猫下载r.getIns大学英语四级tance(this).getResources();
}
//这儿运用的是插件中的类加载器
@Override
public ClassLoader getClassLoader() {
return PluginManager.getInstance(this).getClassLoader();
}
@Override
protected void onCreate(@虚拟机下载手机版Nullable Bundle savedInstaandroid体系nceState) {
super.onCreate(savedInstanceState);
// 实在的加载 插件里边的 Activity
St虚拟机linuxring className = getIntent(大学).getStringExtra("candroid平板电脑价格lassName");
try {
Class mPl虚拟机linuxuginActivityClass = getClassLoa虚拟机是什么意思dandroid体系er().loadClass(className);
// 实例化 插件包里边的 Activity
Constructor construc大学英语四六级tor = mPluginActivitjava言语yClass.虚拟机装置教程win10getConstructor(new Class[]{});
Object mPlug大学inActivjavascriptity = construct虚拟机装置教程or.newInstance(new Object[]{});
Actijava工作培训班vityInterface activityInterface = (ActivityInterface) mPluginA大学生英语比赛ctivitjava模拟器y;
// 给插件注入上下文
activityInterface.insertAppContext(this);
Bundle bundle = new Bundle();
bundle.putString("appName", "我是宿主传递过来的信息");
// 实施插件里边的onCreate办法
activityInterface.onCreate大学英语四级(bundle);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void startActivity(Inteandroid平板电脑价格nt intent) {
String className = intent.getStringExtra("className");
Intent proxyIntent = new Intent(thijava工作培训班s, ProxyActivity.class);
proxyIntent.putExtra("className", clasandroid手机sName); // 包名+TestActivity
// 要给TestActivity 进栈
super.源码本钱startActivity(prox虚拟机linuxyIntent);
}
}

3、小结

至此,能够结束简略的占位式插件化了,咱们来总结下进程:

1、界说宿主java模拟器和插件之间的规范,如Activity的规范为IActivityInterface

2、依据规范结束插件大学生工作生涯规划书模块,打成apk文件(这儿最重要的是插件中运用的上下文是宿主中传递过来的)

3、宿主中加java根底知识点载插件模块apk

4、定javaee义占位Activity,在OnCreate办法中,依据Intenjavaeet带着的插件Activity信息,反射插件Activity实例,为插件Activity注入占位Activjava工作培训班ity的上下文,调用插件Activity实例的onCreate办法建议

这种结束办法的利益是:全程仅有少量的反射,并无hook体系操作,适配作业简略。

缺陷也很明显,在插件Activity中,需求恪守宿主规则,java模拟器假定要做成结构,侵入性这个问题难以处理

2、hook结束插件化

学完了占虚拟机下载手机版位式插件化后,下面咱们来介绍一种在插件中能够运用this的办法,选用hook体系api的办法结束插件化

1、特征

1、插件中的Activity能够运用this,与常规写法无异,无需像占位式那样遵照规范

2、hook操作较多,首要有两个环节需求hook,一个是hook诈骗AMS,建议没有再Androijava环境变量装备dManifest中注册的ActivitAndroidy。源码码头另一个是hook结束将插件的dex和宿主的dex吞并,替换掉原先的dexElemen虚拟机是什么意思ts

2、原理

1、startActivity的进程

Android热更新实践

从图中看出,App告源码之家知AMS建议Activity时,是带着了Intent的,咱们日常看到的hjava根底知识点ave you declared this activity in your AndroidManifest.xml这个过错,便是在调用了startActivity后,AMS对要建议的Activity进行检查时触发的

也便是说,假定咱们要诈骗AMS,在startAct大学生不许校外租房ivity时,带着的Intent中的Activity就有必要是一个在AndroidManifest中注册的Activity,而不能是咱们插件中的Activity。

这儿怎样办?偷龙转凤,移花接木,狸猫换太子~

处理办法是,将Intent中的C源码omponent暂时替换成一个占位A大学英语四级ctivity(在AndroidManifest中声明过的),而且将实在要建议的插件Activity以参数的方式存放到Intent中。

在AMS向App发送LAUNCH_ACTIVITY作业时,把实在要建议的Activity建议

基本原理java面试题便是这样了,那么要处理的要害问题如下:

1、在虚拟机装置教程win10调用Activity时,替换掉建议插件Activity的Intent为建议占位Actijava模拟器vity的Intent,并将建议插件Activity的Inte大学生自我鉴定nt以参数存放到建议占位Activity的Intent中

2、在AMS发送LAUNCH_ACTIVITY作业时,阻拦,将Intent换回建议插件Activity的Intent

3、建议Ac虚拟机装置教程win10tivity时,是用的默许的ClassLoader加载Activity类,反射实例化的,所android体系以需求把插件Activity参加到默许的ClassLoader中

下面咱们挨个问题来处理

3、结束进程

1、hook AMS,偷龙转凤

private void hookAmsAc大学英语四级tion() throws Exception {
Class mIActivityManagerClass = Cl虚拟机装置教程ass.forName("android.app.IActivityManager");
// 咱们源码年代要拿大学生工作生涯规划书到IActivityManager政策,才华让动态署理里边的 invokAndroide 正常实施下
// 实施此办法 static public IActivityManager getDefault(),就能拿到 IAjava面试题ctivityManager
Class mActivityManag源码编辑器erNativeClass2 = C源码本钱lass.forName("android.app.ActivityManagerNative");
final Object mIActivit虚拟机型安卓下载yManageandroid是什么手机牌子r = mActivityManagerNativeClass2.getMethod源码本钱("getDefault").invoke(null);
// 动态署理IActivityManager
Object mIActivi源码年代tyManageandroid是什么手机牌子rProxy = Proandroid下载装置xy.newProxyInstance(
HookApp大学英语四六级lication.class.getClassLoader(),
new Class[]{mIActivityManagerClass}, // 要监听的接口
new InvocationHandler() { // IActivityManager 接口的回调办法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("startActivity".equals(method.getName())) {
// 用ProxyActivity 绕过了 AMS检查
Intent intent = new Intent(HookApplica大学生不许校外租房tion.this, ProxyActivity.class);
// 把要建议插件Activity的Intent作为参数存进去
intent.虚拟机装置教程win10putExtra("actionIntent", ((Intent) args[2]));
args[2] =源码码头 intent;
}
Log.d("hook", "阻拦到了IActivityManager里边的办法" + method.getName()大学专业);
// 让体系继续正常往下实施
return method.invokeJava(mIActivityManager, args);
}
});
/**
* 为了拿到 gDefault
* 通过 ActivityManagerNatjava工作培训班ive 拿到 gDefault变量(政策)
*/
Class mActivityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
Fie虚拟机装置ld gDefaultFieldandroid手机 = mandroidstudio装置教程ActivityManagerNativeClass.g大学英语四级etDeclaredField("gDefault");
gDefaultField.setAccessible(true); // 授权
Object gDefault = gDefaultField.get(null);
// 替换点
Class mSingletonClass = Class.fojava工作培训班rName("android.util.Singleton源码年代");
// 获取此字段 mInst源码编辑器ance
Field mI源码nstance源码集市Field = mSingletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessibl源码编辑器编程猫下载e(true);
// 替换
mInstanceField.set(gDefault, mIActivityManagerProxy);
}

2、hook LAUNCH_ACTIVITY作业,行android的drawable类将建议的Activity换回来

/**
* Hook LuanchActivity,即行将实例化Activity,要把Prox源码编辑器yActivity 给 换回来虚拟机装置 ---》 TestAc源码编辑器手机版下载tivity
*/
private void hookLuanchActivity() throws Exception {
Field mCandroid平板电脑价格allbackFiled = Handler.class源码集市.getDeclaredField("mCallback");
mandroid平板电脑价格CallbackFiled.setAccessible(true); // 授虚拟机安卓
/**
* handler政策怎样来
* 1源码之家.寻觅H,先寻觅ActivityThread
*
* 实施此办法 p虚拟机ublic static ActivityThread currandroid/yunosentActivityThread(androidstudio装置教程)
*
* 通过ActivityThread 找到 H
*
*/
Cl大学生工作生涯规划书ass mActivityThreadClass = Class.forName("android.ajava面试题pp.ActivityThread");
// 获得ActivityThrea政策
Object mActivityThread = mActivityThreadClass.getMethod("currentActivityT大学生不许校外租房hread").invoke(null);
Field mHField =android体系 mActivityThreadClass.getDeclaredField("mH");
mHField.setAccessible(true);
// 获取实在政策
Handler mH = (Handler) mHField.get(mActivityThrea大学生不许校外租房d);
mCallbackFiledandroid什么意思.set(mH, new MyCallback(mH)); // 替换 添加咱们自己的结束代码
}大学生英语比赛
public static final int LAUNCH_ACTIVITY         = 100;
class MyCallback implements Handler.Callback {
private Han源码编辑器编程猫下载dler mH;
public MyCallback(java面试题Handler mH) {
this.mH = mH;
}
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case LAUNandroid下载CH_ACTIVITY:
// 做咱们android什么意思在自己的业务逻辑(把ProxyActivity 换成  TestActiv大学英语四级ity)
Object obj = msg.obj;
try {
// 咱们要获取之前Hook带着过来的android是什么手机牌子 TestActivity
Field intentField = objjava根底知识点.getClass().getDeclaredField("intent");
intentField.setAccessible(true);
// 获取 intent 政策,才华取出带着过来的 actionIntent
Intent intent = (In源码年代tent) intentField.get(obj);
// actionIntent == 插件A源码ctivity的Intent
Intent actionInteAndroidnt = intent.getParcelableExtra("actio虚拟机装置教程win10nIntent");
if (actionInten源码共享网t != null) {
// 把ProxyActivity换成实在源码编辑器手机版下载的插件Activi虚拟机体系ty
intentField.set(obj, actionIntent);
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
//作业正常往下实施
mH.handleMessage(msg);
return true; // 体系不会往下实施
}
}

3、将插件dex和宿主dex吞并

priva大学英语四级te void pluginToAppAction() throws Exception {
// 第一步:找到宿主 dexElem源码编辑器ents 得到此政策   PathClassLoadejava根底知识点r代表是宿主
PathClass源码集市Loader pathClassLoader = (PathClassLoader) this.getClassLoader(); // 实质便是PathClassLoader
Clajavascriptss mBaseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader");
// private final DexPathList pathList;
F源码集市ield pathLisandroidstudio装置教程tFiejava面试题ld = mBaseDexClassLoaderClasandroid/yunoss.getDeclaredField("虚拟机型安卓下载pathList");
pathListField.s虚拟机linuxetAccessible(true);
Object mDejava面试题xPathLisjavascriptt = pathListField.get(p源码之家athClassLoader);
Field dexElementsField = mDexPatandroid的drawable类hList.getClass().getDeclaredField("dexElements");
dexElementsFieljava编译器d.setAccessible(truandroidstudio装置教程e);
// 实质便是 Element[] dexElements
Object dexEle源码网站ments = dexEljava根底知识点ementsField.get(mDeandroid是什么手机牌子xPathList);
/*** ------------javaee---------- ***/
// 第二步:找到插件 dexElements 得到此政策,代表插件 DexClassLoader-源码年代-代表插件
File pluginDirFile = getDir("plugin", Context.MODE_PRIVATE);
File file = new File(pluginDirFile.getAbsoluteFile() + File.separator + "p.ap源码共享网k");
if (android手机!file.exists()) {
throw new FileNotFoundException("没有找到插件包!!: " + file.getAbsolutePath());
} else {
Log.i("ZX大学英语四级报名官网X", "找到插件: " + file.getAbsolutePath());
}
String pluginPath = file.getAbsolutePath();
File fileDir = this.java模拟器getDir("pluginDir", Context.MODE_PRIVATE); // data/data/包名/pluginDir/
DexClassLoader dexClassLoader = new
DexClassLoader(源码pluginPath, fileDir.getAbsolutandroid手机ePath(), null, getClassLoade源码共享网r());
Class mBaseDexClassLoaderClassPlugin = Class.forName("dalvik.system.BaseDexClassLoader");
// private final DexPathList pathList;
Field pathListFiel大学生英语比赛dPlugin = mBaseDexClassLoaderClassPlugin.getDeclare源码编辑器编程猫下载dField("pathList");
pathListFieldPlu大学专业gin.setAccessibl大学生不许校外租房e(t源码共享网rue)javascript;
Obj源码之家ect mDexPathListPlugin大学英语四级 = pathListFieldPlugin.get(dexClassLoader);
Field dexElementsandroid下载装置FieldPlugin = mDexPathListPlugin.getClass().getDeclaredField("dexElements");
dexElementsFieldPlugin.setAandroidstudio装置教程ccessible(true);
// 实质就虚拟机是 Elandroid是什么手机牌子ement[] dexElements
Object dexElement大学生入党申请书sPlugin = d虚拟机linuxexElementsFieldPlugin.get(mDexPath虚拟机装置Lisandroidstudio装置教程tPlugin);
// 第三步:创建出 新的 dexElements []
int mainDexLeng =  Array.getLength(dexElements);
int pluginDexLeng =  Array.getLength(dexElementsPlugin);
int sumD源码exLeng = mainDexLeng + pluandroid是什么手机牌子ginDexLenjava模拟器g;
// 参数一javaee:int[]  String[] ...  咱们需求Element[]
// 参数二:数组政策的长度
// 实质便是 Element虚拟机装置教程[] newDexElements
Object newDexElements = Array.newInstance(dexEl源码网站ements.getClass().getComponentType(),sumDexLeng); // 创建数组政策
// 第四步:宿主dexElements + 插件dexElements =----> 交融  新的 newDexElemenandroidstudio装置教程ts
for (int i = 0; i < sumDexLeng; i++) {
// 先交融宿主
if (i < mainDexLeng) {
//源码共享网 参数一:新要交融的容器 -- newDexElements虚拟机是什么意思
Arraandroid平板电脑价格y.set(newDexElements, i, Array.get(dexEl虚拟机装置教程ements, i));
} else { // 再交融插件的
Array.set(newDexEle源码码头ments, i,java模拟器 Array.get(dexElemejava工作培训班ntsPlugiandroid体系n, i - mainDexLeng));
}
}
// 第五步:把新的 newDexElements,设虚拟机是什么意思置到宿主中虚拟机装置教程win10
// 宿主
dexElemandroid下载entsFielandroid下载装置d.set(mDexPathList, newDexElements);
// 处理加载插件中java怎样读的布局,这儿和占位式一起
doPluginLayoutLoad();
}

4、小结

hook插件化首要有三个要害进程:

1、诈骗AMS,绕过AMS对插件Activity的检测,首要是通过源码集市偷龙转凤的办法结束

2、hooandroid是什么手机牌子k AMS建议Activity虚拟机是什么意思的LAUNCH_ACTIVITY作业,建议插件Acti源码之家vity

3、将插件Dex和宿主Dex吞并

这种办法结束的插件化,插件Activity中能够运用this,侵入性低。android下载装置但因为用了许多hook操作,体系适配需求做的作业较多。要害的三个操作特别需求依据体系源码做必定的适配

3、LoadedApk式结束插件化

在hook结束插件化中,由所以将一切的插件都参加到dexElements中,宿主和插件用的仍是同一个ClassLoader。下面咱们来介绍LoadedApk式结束插件化,这事一种运用多个ClassLoader结束的插件化

1、特征

宿主和插件用的ClassLoader不是同一个

2、原理

Android热更新实践

诈骗AMS和偷龙转凤的结束和hook式结束插件化是相同的,不同的是h源码之家ook式结束插件化是在BaseDexClassLoader中的dexElements中参加插件的dex,来到达成功加载插件类的目的虚拟机体系。而LoadedApk式大学生自我鉴定则不是。下面来分析LoadedApk式结束插件化的原源码编辑器编程猫下载

检查ActivityThread中发虚拟机安卓起Activity的代码

private Activity performLaunchActivity(ActivityC源码编辑器编程猫下载lientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
i虚拟机装置教程f (r.packageInfo =android平板电脑价格= null) {
//1、获取LoadedApk
r.packageInf虚拟机装置教程o = getPackageInfo(aInfo.aandroid平板电脑价格pplicationInfo, r.compatInfo,
Context.CJavaONTEXT_INCLUDE_CODE);
}
。。。省掉
Activity activity = null;
try {
//2、从LoadedApk中获取ClassLoader,用于加载Activity类
java.lang.Candroid是什么手机牌子lassLoader cl = r源码本钱.packageInfo.getCljavascriptassLoader();
//实例化Activity
activity = mInstrum大学专业entation.newActivity(
cl, component.getClassName(), r.intent);
。。。省掉

获取PackageInfo的代码如下:

private LoadedApk getPackageInfo(Appli虚拟机是什么意思cationInf虚拟机型安卓下载o aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolea大学生入党申请书n securityViolation, boolean includeCode,
boolean registerPackage) {
final boolean differentUser = (UserHandle.myUserId() != Userandroid是什么手机牌子Handle.getUserId(虚拟机装置aInfo.uid));
synchronized (mReso源码之家urcesManager) {
WeakReference<LoadedApk> r大学生自我鉴定ef;
if (differentUseandroid手机r) {
// Caching not supported across users
ref = null;
} else if (includeCode) {java根底知识点
//首要是这儿,依据包名从mPackages中获取,那么只需结构插件的Loaded大学生英语比赛Apk政策,放入到mPackeges中就能结束
ref = mPackagejava怎样读s.get(aInfo.packageName);
} else {
ref = mResourcePac虚拟机装置教程kages.get(aInfo.packageName);
}

3、结束进程

诈骗AMS的操作和偷龙转风环节和hook一起,不再赘述。

1、下面介绍怎样构建LoadedApk政策,参加到ActivityThread中的mPackages中

/**
* 自己发明一大学英语四六级个LoadedApk.ClassLoader 添加到 mPackages,此LoadedApk 专门用来加载插件里边源码之家的 class
*/
private void customLoadedApkAction() throws Exception {
File pjava根底知识点luginDirFijava根底知识点le = getDir("plugin", Context.MODE_PRIVATE);
File file = new File( pluginDirFile.getAbsoandroid体系luteFile() + File.separator + "p.apk");
if (!file.exijavascriptsts()) {
throw neandroid体系w FileNo大学专业tFoundException("插件包不存在..." + file.getAbsolutePath());
}
String pulginPath = file.getAbsolutePath();
// mPackages 添加 自界说的LoadedApk
//android平板电脑价格 final ArrayMap<String, WeakReference<LoadedApk>> mPackages 添加自界说LoadedApk
Candroid体系lass mAc大学英语四级报名官网tivityThreadClass = Class.f大学英语四级报名官网orName("android.appandroid平板电脑价格.Actandroid平板电脑价格ivityThread");
// 实施此方源码共享网法 public static ActivityThreandroid体系ad currentActivityThread() 拿到 ActivityThread政策
Objec虚拟机下载手机版t mActivityThread = mActivityThreadClasjavascripts.getMethod("curandroid/yunosrentActivityThread").invoke(null);
Field mPackagesField = mActivityThreadClass.getDeclaredFjava怎样读ield("mPackages");
mPackagesField.setAcc虚拟机体系essible(true);
// 拿到mPackages政策
Object mPackagesObj = mPackagesField.get(源码mA大学专业ctivityThread);
Map mPackages = (Map) mPackagesObj;
// 怎样自界说一个大学英语四级 LoadedApk,源码网站体系是怎样发明LoadedAandroid平板电脑价格pk的,咱们就怎样去创源码编辑器编程猫下载造LoadedApk
// 实施此 public final LoadedApk getPackageInfoNoCheck(Applicati虚拟机对电脑损伤大吗onInfo ai, CompatibilityInfo compatInfo)
Class mCompatibilityInfoClass = Class.forName("anandroid是什么手机牌子droid.content.res.android是什么手机牌子CompatibilityInfo");
Fiel虚拟机下载手机版d djava工作培训班efaultField = mCompatibilityInfoClass.getDeandroid什么意思claredFjava怎样读ield("DEFAULT_COMPATIBILITY_INFO");
defaultField.seandroid手机tAccessible(true);
Object defaultObj = defaultField.get(null);
/**
* ApplicationInfo 怎样获取,咱们之前学习 APK源码编辑器手机版下载解析源码分析
*/
App虚拟机安卓licationInfo applicationInfo = getApplicatioJavanInfoAction();
Meth源码本钱od mLoade大学dApkMethod = mActivityThreadClass.ge大学专业tMethod("getPackag虚拟机体系eInfoNoCheck", ApplicationInfo.class, mCompatjava面试题ibilityInfoClass); // 类类型
// 实施 才华拿到 LoedApk 政策
Object mLoadedApk = mLoadedA大学生不许校外租房pkMethod.invoke(android下载mActivityThread, applicationInfo, defaultObj);
// 自界说加载器 加载插件
// String dexPath, String optimizedDirectory, String librar源码编辑器ySearchPath, ClassLoader parent
File fileDir = getDir("pu源码lginPathDir"android什么意思, Context.MODE大学专业_PRIVATE);
// 自界说 加载插件的 Classjava言语Loader
ClassLoader classLoader =源码编辑器编程猫下载 new PluginClassLoader(pulg源码共享网inPath,fileDir.getAbjava根底知识点solutePath(), null, getClassLoader());
Field mC虚拟机lassLoaderField = mLoadedApk.getClass().getDeclarAndroidedField("mClassLoader");
mClassLoaderField.setAcjava言语cessible(true);
mClassLoaderField.set(mLoadedApk, classLoader); // 替换 LoadedApk 里边的 ClassLoader
// 添加自界说的 LoadedApk 专门加载 插件里边的 class
//大学英语四级报名官网 究竟的政策 mPackages.put(插件的包名,插件的虚拟机对电脑损伤大吗LoadedApk);
WeakReference weakRefere虚拟机型安卓下载nce = new源码本钱 WeakReference(mLoadedandroid的drawable类Apk); //源码网站 放入 自界说的LoadedA虚拟机linuxpk --》 插件的
mPackages.put(applicationInfo.packageName, wea源码编辑器编程猫下载kReference); // 添加Android了咱们自己的LoadedApk
}
/**
* 获取 ApplicationInfandroid下载o 为插件服务的
* @return
* @throws
*/
private ApplicationInfo getApplicationInfoAction() throws Exception {
// 实施此public static ApplicationInfo generateApplic虚拟机下载手机版ationInfo办法,拿到ApplicationInfo
Class mPackandroid手机ageParserClass = Class.forName("java环境变量装备android.content.pm.PackageParser");
Object mPackageParser = mPackageParse源码之家rClass.newInstance();
// generateApplicationInfo办法的类类型
Class $PackageClass = Class.forName("android.content.pm.PackageParser$P大学生自我鉴定ackage");
Class m源码码头PackageUserStateClass = Class.forName("android.content.pm.PackageUserState");
Metho大学生英语比赛d mApplicationInfoMethod = mPackageParserClass.getMethod("generateA大学生英语比赛pplicationInfo",$PackageClass,
int.class, mPackageUser虚拟机对电脑损伤大吗StateClass);
Filejavascript dirFile = getDir("plugin", Context.MODE_P大学生不许校外租房RIVATE);
File file = new File(dirFile.getAbsoluteFile() + File.separator + "p.apk");
String pulginPath = file.getAbsolutePathjavascript();
// 实施此public Package parsePackage(File packageFile, int flags)办法,拿到 Package
// 获得实施办法的政策
Method mPackageMethod = mPackageParserClass.getMethod("parsePackage", File.class, int.class);
Objeandroid的drawable类ct mPac大学专业kag源码编辑器手机版下载e = mPackageMethod.invokjava编译器e(mPackageParser, file, PackageManager.GET_ACTIVITIES);
// 参数 Package p, int flags, PackageUserState state
ApplicationInfo appli源码cationInfo = (ApplicationInfo)
mApplicatioandroid平板电脑价格nInfoMethod.invoke(mPackageParser, mPackage, 0, mPackageUserStateClass.newInstance());
// 获得的 ApplicationInfo 便是插件的 ApplicationInfo
//虚拟机linux 咱们这儿获取的 ApplicationInfo
// applicatio大学英语四级nInfo.publicSourceDir = 插件的途径;
// applicationInfo.sourceDir = 插件的途径;
applicationInfo.pub源码编辑器licSourceDir = pulginPath;
applicationInfo.sourceDir = pulginPath;
randroid的drawable类eturn applicationInfoAndroid;
}

2、hook AMS建议Activity的回调

class MyCallback implements Handler.Callback {
private Handler mH;
public MyCallback(Handler mH) {
this.android手机mH = mH;
}
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY:
// 做咱们在自己的业务逻辑(把ProxyActivity 换成  TestActivity)
Object obj = msg.obj; // 实质 ActivityClientRecord
try {
// 咱们要获取之前Hook带着过来虚拟机对电脑损伤大吗的 TestActivity
Field intentFielandroid手机d = obj.getClass().getDeclaredField("intent");
intentField.setAccessible(true);
//android是什么手机牌子 获取 intent 政策,才华取出带着过来的 actionI源码之家ntent
Intent intent = (Intent) intentField.get(obj);
Intent actionIntent = intent.getParcelableExtra("actionInt大学生自我鉴定ent");
if (a虚拟机是什么意思ctionIntent != null) {
intentF大学生英语比赛ield.set(obj, actionIntent); // 把ProxyActivitandroid是什么手机牌子y 换成  插件Activity
/***
*  咱们在以下代码中,对插件  和 宿主 进行区别
*/
Field activityInfoField = obj.getClass(java根底知识点).getDeclaredF大学生工作生涯规划书ield("activityInfo");
activityInfoField.setAccessible(true); //授大学英语四六级
ActivityInfo activityInfo虚拟机型安卓下载 = (Acti源码网站vityInfo) activityInjava编译器foField.get(obj);
/源码编辑器手机版下载/ 宿主的Intent的getPackage会拿到包名,插件的会是空,用来判别是否是插件Intent
if (actionIntent.getPackage() == null)源码网站 {
//将applicationInfo的包名改为插件的包名,这样拿到的LoadedApk才是咱们自界说的
activityInfo.applicationInfo.packageNam源码本钱e = acandroid什么意思tionIntent.getCo大学英语四级mpone虚拟机nt().getPackageName();
// 这个是下个进程,源码本钱hook PMS,绕过PMS的检源码编辑器编程猫下载
hookGetPackageInfo(虚拟机linux);
} else { // 宿主
activityInfo.applicationInfo.packageName = actionInteandroid是什么手机牌子nt.getPackage();
}
}
} catch (Exception e) {
e.printStackTrace(java怎样读);
}
break;
}
mH.handleMessage(msg);
// 让体系继续正常往下实施
// reandroid/yunosturn false; // 体系就会往下实施
return true; // 体系不会往下实施
}源码之家

3、hook PMS,绕过检测

光这样操作还不大学可,在Activity建议时,PMS会检测包名对应的Apk是否有设备(LoadedApk中的ini大学专业tializeJ大学生英语比赛avaContextClassL虚拟机型安卓下载oader办法),没有设备会报错。

调用流程:performLaunchActivity-&java环境变量装备gt;makeApplication-&g源码共享网t;initializeJavaContextClassLoader。

initializeJavaContextClassLoader()方java编译器法代码如下:

IPackageManager pm = ActivityThread.getPackage虚拟机装置Manage虚拟机装置r();
anandroid平板电脑价格droid.content.pm.PackageInfo pi;
try {
pi = pm.getPackageInfo(mPa虚拟机是什么意思ckageName, PackageManager.MATCH_DEBUG_TRIAGED_MIS大学英语四级SING,
UserHandl大学生不许校外租房e.myUserId());
} catch (Remo虚拟机型安卓下载teExceptijava言语on e) {
throw e.rethrowFromSystemServer();
}
if (pi == null) {
throw new IllegalStateExceptioandroid的drawable类n("Unable to get package info for "
+ mPackageName + "; is package not installed?");
}

因此还需求ho虚拟机对电脑损伤大吗o大学k PMS,绕过检测,完源码之家结代码如下:

// Hook 阻拦此 getPackageInfo 做自己的逻辑
private void hookGetPackageInfo() {
try {
// sPackageManager 替换  咱们自己的动态署理
Class m源码年代ActivityThreadClass = Classjava根底知识点.forName("android.app.ActivityThread");
Field sCurrentActivityThreadField = mActivit大学yThreadClas虚拟机s.getDeclaredField("sCurrentActivityThread");
sCurrentActivityThreadField.seandroid什么意思tAccessible(true);
Field sPackageManagerField = mActivityThreadClass.getDeclared源码编辑器Field("sPackageManager");
sPack源码集市ageManagerField.setAccessible(true);
finandroid平板电脑价格al Ob源码码头ject packageManager = sPackageManagerField.get(null);
/**
* 动态署理
*/大学英语四级
Class源码集市 mIPackageManagerClass = Class.fjava模拟器orName("androi虚拟机装置教程win10d.content.pm.IPackageManagerandroid手机");
Object mIPackageManandroid的drawable类agerPr源码年代oxy = Proxy.newProxyInstance(getClassLoader(),
new Clas大学专业s[]{mIPackageManageAndroidrClass}, // 要监听的接虚拟机型安卓下载
new InvocationHandler() {
@Override
public Object invoke(Objec大学专业t proxy, Method method, Object[] args) throws Throwab大学英语四级报名官网le {
if ("getPac大学英语四级kageInfo".equals(metho源码编辑器手机版下载d.getName())) {
// 怎样才华绕过 PMS, 诈骗体系
// pi != n大学生自我鉴定ull
return new P源码码头ackageInfo(); // 成功绕过 PMS检测
}
// 让体系正常继续实施下去
return method.invoke(packageManager, args);
}
});
// 替源码编辑器手机版下载换  狸猫换太子   换android下载成咱们自己的 动态署理
sPackageM虚拟机安卓anagerFi大学生英语比赛eld.set(null, mIPackageManagerProxy);
} catch (Exception e) {
e.androidstudio装置教程printStackTrace(虚拟机安卓);
}
}

4、小结

LoadedApk办法结束插件化,首要在建议Activity时,加载这个环节和hook方源码网站法不同。

首要进程是:

模仿体系源码,结束插件apk的LoadedApk实例。并放置到ActivityThread中的mPackagandroid下载装置es政策中

在ActivityThread的mH回调中,偷龙转凤插件Activity的一起,将activityInfo中的applicationInfo中的包名替换为插件的包名,然后让后续逻辑运用插件的LoadedApk

究竟,hook PMS,绕过PMS对插件是否设备的检测

4、三种结束插件化办法的小结java根底知识点

1、占位式结束插件化是比较稳定的,兼容性较好,因为没有hook体系的api。但因为要大学生入党申请书时间留意运用宿主的上下文,编写插件是比较难过的

2、hook办法完源码共享网结插件化,不必考虑宿主环境,但是对体系api进行了hook,兼容性较差。

3、LoadedApk办法结束插件化,和hook办法靠近,不必考虑宿主环境,但对体系api进行了hook,兼容性较差

三、市面上的插件化结构

1、美团Robust

美团Robust插件化的完大学生工作生涯规划书结办法不源码之家像上述讲的三种办法,而是学习的instant run的结束,在在编译打包阶段对每个函数都刺进一段控大学生不许校外租房制逻辑代码

简略看下修改流程:

下面的办法,在编译期间会参加一段控制逻辑,判别是走补丁操作,仍是原操作

public long getIndex() {
return 100;
}

编译后的getIndex

public static ChangeQuickRedirect cjava根底知识点h源码集市angeQuickRedirect;
public long getIndex() {
if(cjava工作培训班hangeQuickRedirect != null) {
//PatchProxy中封装了获取其时className和methodName的逻java根底知识点辑,并在其内部究竟调用了changeQuickRedirect的对应函数
if(Pat虚拟机装置chProxy.isSupport(new Object[0], this, changeQuickRedirect, false)) {
return ((大学生不许校外租房Long)PatchProxyandroid平板电脑价格.accessDispatch(new Object[源码编辑器0], this, changeQuickRedirect, false)).longValue();
}
}
return 100L;
}

加载补丁时,会反射给changeQuickRedirecJavat设置实例,当该大学英语四级实例不为空,则走插件补丁的逻辑

当然不是这么简略就能完美结束,具体可参看:tech.meituan.com/2016/09android什么意思/14/…

2、腾讯QZone和Tinker

腾讯的QZone和Tinker实质上虚拟机linux运用的是hook办法结束的插件化,操作的是dexElemen大学专业ts

这儿咱们介绍下类的verify:

在apk设备时,虚拟机会将c源码共享网lasses.dex优化Java成odex文件,然后虚拟机才会实施。在这个进程中,会进行类的verify操作,假定调用关系的类都在同一个dejavascriptx,就会被打上CLASS_ISPREVERIFIED标志,然后写入ode源码集市x文件。

而在运转时,假定是被打上了标志的类引用了其他d虚拟机装置教程ex的类,则会报错。

因此要处理打上标志这个问题。

QZone的做法是:在每个类的结构办法中,去引用一个其他Dex中的类,然后避免被打上标志

而Tinker的做法是:将宿主dex和插件dex进行吞并,然后将dexElements中的就dex删去,将吞并后的dex参加。一切的代码都在同一个dex中,也就不会有CLASS_ISPREVERIFIED的问题了

Android热更新实践

四、SDK插件化

1、主张挑选占位式结束

SDK插件化实质上和app的插件化差异不大,不过SDK假定四大组件不多,非常主张运用占位式插件虚拟机linux化,因为兼容性问题较少。

2、自界说插件Context

但因为sdk一般依附于宿主Activandroidstudio装置教程ity调用,但最好不要对宿主Activity的getClassLoader和getResources进行处理,这样能够避免影响宿主的逻辑。所以能够结束一个具有插件ClassLoader和Resouces的Context给Sdk运用

public class SQwanCore i源码编辑器编程猫下载mplements ISQwanCore {
@Overr源码集市ide
public void init(Context context) {
//结构一个带有插件classLoader和Resources的Context
SdkContextProxy sdkConteandroid手机xt = new SdkContextProxy(context);
try {
ISQwanCore sdkObj = (ISQwanCore) sdkContext.getClassLoader().loadClass("com.sq.plugin.PluginSQwanCore").newInstance();
sdkObj.虚拟机是什么意思init(sdkContext);
} catch (Exception e) {
e.printStackTrace();
}
}
}

SdkContextProxy代码如下:

public class SdkContextProxy extends ContextWrapper {
private Context baseContext;
publandroid下载装置ic SdkContextProxy(Context base) {
super(base);
basandroid什么意思eCon大学text = base;
}
@Override
public Clandroid的drawable类assLoader getClassLoader() {
return PluginManager.getInstance(bas虚拟机是什么意思eContext).getClassLoader();
}
@Override
public Resources getResources() {
return PluginManager.getInstancjava模拟器e(baseContext).getResources();
}
//建议Activity时,做特别操作,引导到ProxyActivity,参照占位式的ProxyActivity
@Override
public void startjava模拟器Activity(Intent intent) {
String className = intjava模拟器ent.getComponent().getClassName();
Intent pr大学生入党申请书oxyIntenandroid下载装置t = new Intent(this, ProxyActivi源码编辑器ty.class);
proxyIntent.putExtra("className", className); // 包名+插件Activity
// 要给插件Activity进栈
super.startActivity(p大学英语四级报名官网roxyIntent);
}
}

Sdk的插件结束:

public class PluginSQwanCore implandroid下载装置ements ISQwanCore {
@Override
public void in大学生不许校外租房it(Co大学生入党申请书ntext context) {
//PluginActivi大学英语四级ty要依据规范IActivityInterface结束
context.startActivity(new Intent(context, PluginActivity.class));
}
}

其他逻辑参照占位式插件化结束即可大学生工作生涯规划书

至于SDK插件化的CLASS_ISPREVERIFIED最简略的处理办法是:将插件源码年代和宿主中共有的类,在插件中删去即虚拟机下载手机版可,如本java工作培训班案例中ISQwanC大学专业ore类虚拟机对电脑损伤大吗在插件中删去。

3、资源处理

常见问题:

AssetManager的适配虚拟机安卓(19以上和以下不同)

能署理的和不能署理的(xml文件中的资源引用)

隔离宿主和插件的Resources(运用ContextWrapper处理)

资源ID抵触怎样处理(运用gradle修改资源ID)

getIdentifi大学生工作生涯规划书er抵触怎样处理(插件内优先插件,ResourceWrapper运用)

将宿主和插件资源吞并出一个大的Resources,为什么?

1、宿主的资源中是包含体系资源虚拟机装置教程win10的,这块需求用

2、sdk有些资源放在宿主中,便当切包(如闪屏图)

public class SuperHostResources {
private Context mContext;
private Resources mResources;
public SuperHostResources(Context context, String pluginPatjava根底知识点h) {
mContext = context;
mResources = buildHostResourc虚拟机下载手机版esjava编译器(pluginPath);
}
pri虚拟机安卓vate Resources buildHostResources(String pluginPath) {
Resourcejava面试题s hjavaeeostResources = mContext.getResources();
if (Build.VERSION.SDK_INT > Build.VERSION_源码共享网CODES.android平板电脑价格KI源码码头TKAT) {
try {
AssetManagerandroid体系 assetManagjavascripter = mContext.getResources().getAssets();
Methojava面试题d addAssetPathMethod = AssetManager.class.getDeclaredMethod("addAssetPath", String.class);
addAssetPathMethod.setAccessible(true);
addAssetPathMethjava编译器od.invoke(assetManager, pluginPath);
hostResources =大学生英语比赛 new Resources(assetManager, m虚拟机体系Context.getResources().getDisplayMetricsjava环境变量装备(), mContext.getRejavascriptsources().getConfiguration());
} catch (Exception e) {
e.printStackTandroid手机race();
hostResources = mContext.getRe大学生入党申请书sources();
}
} elsejavascript {
try {
AssetManager assetManager = AssetManager.class.newInstance();
Method addAjavaeessetPathMethod = AssetM源码年代anager.class.getDeclaredMethod("addAssetPath", String.class);
addAssetPathMethod.setAccessible(true);
addAssetPathMethod.invoke(大学英语四级报名官网ass大学英语四级etManager, pluginPath);
//抵触了不可的,要改androidstudio装置教程id后才华够这么做
Str大学生不许校外租房ing baseApkPath =虚拟机下载手机版 mContext.get源码之家Applicatandroidstudio装置教程ion虚拟机装置教程win10Info().sour源码集市ceDir;
addAssetPathMethod.invoke(assetManager, baseApkPath);
hostResources = new Resources(asseJavatManager, mContext.getResources().getDispla大学yMetrics(), mContext.ge源码网站tResources().getConfiguration());
} catch (Exception e) {
e.printStandroid下载装置ackTrace();
hostResources = mContext.getResources();
}
}
return hostResources;
}
public Resources get() {
return mResources;
}
}

运用ResourceWrapper,为什么?

1、如getIdentifier,能够在这儿操作出优先加虚拟机体系载插件,仍是优先加载宿主

public cla虚拟机装置ss MixResourcejava怎样读s extends Resoandroid的drawable类urcesWrapper {
private Resources mPluginResources;
privatandroid/yunose String mPluginPkgName;
public MixResources(Resources hostResources, Context context, String plugandroid体系inPath) {
super(hostResources);
PluginResources pluginResourcesBuil虚拟机der = new PluginResources(context, pluginPath);
mPluginResources = pluginResourcesBuilder.get();
mPluginPkgName = pluginReso源码网站urcesBuilder.getPkgName();
}
public MixResources(Resources hostResources, Resources plu虚拟机型安卓下载ginResources, String pluginPkgName) {
super(hostResources);
mPluginResources = pluginResources;
mPluginPkgName = pluginPkgName;
}
publiandroid是什么手机牌子c Strin虚拟机安卓g getPluginPkgName() {
return mPluginPkgName;
}
@Override
public CharSequence getText(int id) throws Resource源码s.NotFoundException {
try {
return super.getText(id);
} catch (Reso源码urces.NotFoundException e) {
r虚拟机装置eturn mPluginResources.getText(id);
}
}
@Override
public String getString(int id) throws Resources.N大学生不许校外租房otFoundException {
try {
return su源码编辑器手机版下载per.getString(id);
} catch (Resources.NotF源码之家oundExcepandroid什么意思tion e) {
return mPluginResjavascriptources.java怎样读getString(id);
}
}
@Overrjava怎样读ide
public String getString(int id虚拟机安卓, Object... formatArgs) throws Resources.NotFoundException {
try {
return sup大学生不许校外租房er.getString(id,formatArgs);
} catch (R虚拟机对电脑损伤大吗esources.NotFoundExcep源码年代tion e) {
return mPluginResources.getString(android下载id,formatArgs);
}
}
@Override
public float gjava面试题etDimension(int id) throws Resources虚拟机对电脑损伤大吗.NotFoundException {
try {
return super.getDimension(id);
} catch (Resources.NotFoundException e) {
retur源码年代n mPluginResources.getDimension(id);
}
}
@Override
public int getDimensionPixelOffset(int id) throws Resources.Nandroid什么意思otFoundException {
try {
return super.getDimensionPixelOffset(id);
} catch (Resources.Not虚拟机装置教程win10FoundException e) {
return mPluginResources.getDimensionPixelOffset(id);
}
}
@Override
public int getDimandroid下载e大学英语四级nsionPixelSize(int id) throws Resour虚拟机对电脑损伤大吗ces.NotFoundException {
try {
r虚拟机体系eturn super.getDijava编译器mensionPixelSize(id);
} catch (Resources.NotFoundException e) {
return mPluginResources.getDimensionPi大学生工作生涯规划书xelSize(id);
}
}
@Override
public Drawa源码编辑器编程猫下载ble getDrawable(int id) throws源码编辑器编程猫下载 Resources.NotFoundException {
try {
return super.getDrawable(id);
} catc虚拟机安卓h (Resources.NotFoundException e) {
return mPluginResources.getDrawable(id);
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public Drawable getDrawablejava工作培训班(int id, Resourc虚拟机下载手机版es.Theme theme) throws Resou大学英语四级报名官网rces.NotFoundException {
try {
return super.getDr大学专业awable(id, theme);
} catch (Re虚拟机是什么意思sources.NotFoundException e) {
return mPluginResources.getDrawable(id,theme);
}
}
@Override
public Drawable getDrawableForDensity(java编译器int id, int densit源码之家y) throws Resources.NotFoundException {
try {
return super.getDrawable虚拟机型安卓下载ForDensity(id, density);
} catch源码共享网 (Re源码集市sources.NotFoundEjava工作培训班xception e) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
return mPluginResources.getDrawableForDensity(id, density);
} else {
return null;
}
}
}
@TargetApi(Build.VERSION_CODEAndroidS.LOLLIPOP)
@Override
public Drawable getDrawableForDensity(int id, int density, R大学生自我鉴定esources.Theme theme) {
try {
rjava环境变量装备eturn super.getDrawableForDensity(id, density, theme);
} catch (Exception e) {
return mPlug大学英语四级inResources.getDrawableForDensity(id,density,theme);
}
}
@Override
public int getCol虚拟机装置教程win10or(int id源码共享网) throws Resources.NotFoundException {源码编辑器手机版下载
try {
return super.getColor(id);
} catch (Resources.NotFoundException e) {
return mPlugiandroidstudio装置教程nResources.getColor(id);
}
}
@T源码编辑器编程猫下载argetApi(Build.VERSION_CODES.M)
@Override
public int getColor(int id, Resources.Thandroid什么意思eme theme) throws Resources.大学生英语比赛NotFandroid是什么手机牌子oundException {
try {
return super.getColor(id,theme);
} catch (Resources.NotFoundException e) {
return mPluginResources虚拟机安卓.getColor(id,theme);
}
}
@Override
public ColorStateandroid下载装置List getColorStateList(int id) throws Resources.NotFoundException {
try {
return super.getColorStateList(id);
} catc源码编辑器手机版下载h (Resources.NotFoundException e) {
returnandroid下载 mPluginResou虚拟机下载手机版rces.getColorStateList(id);
}
}
@TargetApi(Build.VERSION_CODES.M)
@Override
pandroid/yunosublic ColorStat虚拟机下载手机版eList getColorStateList(int id, Resources.Theme theme) throws Resources.NotFoundException {
try {
return super.getColorStateList(id,theme);
} catch (Resources.NotFoundException e) {
return mPluginResources.getColorStat虚拟机下载手机版eList(id,theme);
}
}
@Override
public boolean getBoolean(int id) throws Resources.NotFoundException {
try {
return super.getBoolean(id);
} catch (Resources.N源码之家otFoundExceptionandroid手机 e) {
return mPluginResources.getBoolean(id);
}
}
@Override
public XmlResourceParser getLayout(int id) throws Reso源码之家urces.NotF虚拟机安卓oundExcepjava模拟器tion {
try {
return su虚拟机装置教程win10per.getLayout(id);
}虚拟机linux catch (Resources.NotFoundException e) {
return mPluginResou大学生英语比赛rces.getLayout(id);
}
}
@Override
public Strandroidstudio装置教程ing getResourceName(int resid) throws Resources.NotFoundException {
try {
return super.getResourceName(resid);
} catch (Resources.NotFoundExce大学生不许校外租房ption e) {
return mPluginResources.getResourceName(resid);
}
}
@Override
public int getandroidstudio装置教程Integer(int id) throws Resources.NotFoundE源码xception {
try {
return super.getInteger(id);
} catch (Resou大学英语四六级rcesjava根底知识点.NotFou虚拟机下载手机版ndException e) {
return mPluginResources.getIn源码编辑器teger(id);
}
}
@Override
public CharSequence getText(int id, CharSequence def) {
try {
ret大学生工作生涯规划书urn super.getText(id,def);
} catch (Resources.NotFoundException e) {
return mPluginResources.getText(id,def);
}
}
@Override
public InputStream openRawResource(int id) throws Resource大学s.NotFoundException {
try {
return super.openRawResourcejava根底知识点(id);
} catch (Res虚拟机装置教程ources.NotFoundException e) {
return mPlug源码码头inReandroid平板电脑价格sources.openRandroidstudio装置教程awResource(id);
}
}
@Override
public XmlResourceParser getXml(int id) throws Resourcejavascripts.NotFoundExceptijava面试题on {
try {
return super.getXml(id);
} catch (Resources.NotFound虚拟机安卓Exception e) {
return mPluginResources.getX源码共享网ml(id);
}
}
@Override
public void getValue(int id, TypedValue outValue, boolean r大学专业esolveRefs) throws Resources.NotFoundException {
try {
super.g大学生入党申请书etValue(id, outVandroid平板电脑价格alue虚拟机对电脑损伤大吗, resolveRefs);
} catch (Resources.NotFoundException e) {
mPluginResources.getValue(id, outValue, resolveRefs);
}源码之家
}
@Overr虚拟机对电脑损伤大吗ide
public Movie getMovie(int id) throws Resou虚拟机linuxrces.NotFoundException {
try {
return super.getMovie(id)java模拟器;
} catch (Resources.NotFoundException e) {
return mPluginRe源码年代sour源码ces.getMoJavavie(id);
}
}Android
@Override
public Xmljava根底知识点ResourceParser getAnimation(int id) throws Resources.NotFoundException {
try {虚拟机装置
return super大学英语四级报名官网.getAnimation(id);
} catch (Resources.Notandroid是什么手机牌子FoundException e) {
return mPluginResources.getAnimation(id);
}
}
@Overridjava工作培训班e
public InputStream openRawResource(int id, TypedValue value) throws Resource大学生工作生涯规划书s.NotFoundException {
try {
return super.openRawResoujava编译器rce(id,value);
} catch (Resources.AndroidNotFoundException e) {
return mP大学luginResources.openRawResource大学生入党申请书(id,value);
}
}
@Ojava根底知识点verride
public AssetFileDescriptor openRjava环境变量装备a虚拟机安卓wResourceFd(int大学英语四六级 id) throws Resources.NotFoundException {
try {
return super.openRawRjava面试题esourceFd(id);
} catch (Resources.NotFoundExcepti虚拟机装置教程win10on e) {
return mPluginResources.op大学生不许校外租房enRawResourceFd(id);
}
}
@Override
public int getI源码网站den大学生入党申请书tifier(Strinjava环境变量装备g n大学英语四级报名官网ame, Str虚拟机对电脑损伤大吗ing defType, String defPackage) {
i虚拟机装置nt pluginId = super.getIdentifier(name, defType, defPa大学英语四级ckage);
if (pluginId <= 0) {
return mPluginResources.getIdentifier(name, defType, mP大学生工作生涯规划书luginPkgName);
}
return pluginId;
}
public int getIdentifier源码编辑器From虚拟机对电脑损伤大吗Plugin(String name, String defType) {
return mPluginResources.getIdentifier(name, defType, mPluJavaginPkgName);
}
}

五、小结

1、本文介绍了三种常见的插件化结束方案,包含占位式、hook式、LoadedApk式以及他们各自的特征

2、介绍了市面上常见的插件化结构的方案,其间简明介绍了怎样避免CLASS_ISPREVERIFIED问题

3、介绍S大学英语四级报名官网Dandroidstudio装置教程K的插件化,SDK的Context的结束方案