本项目旨在实现像web开发一样开发Android,代码写好发布之后就能让用户立即看到,而不是必须每次打包apk -> 更新 -> 安装,实现方式是Activity和资源文件的动态替换。
WandFix是一个可以使用注解来注入实现类对象的库,基于java APT+反射+classloader,因此不需要使用new来初始化对象。另外它还可以动态加载指定.apk .dex .jar .class文件,使用注入设置优先级的方式来选择注入class类的来源,因此利用此种方法,该项目还可以使得被注解的类获得热修复的能力!
使用 WandFix 只需要对变量名添加注解即可实现对象的注入。而热修复功能的实现既是用对象注入的这种途径,通过更换热修复包替换实现类,来达到每次注入的对象都为最后改动过的,实现热修复的目的。当然,如果您不想使用热修复功能,只是想方便的注入对象,直接添加注解也是可以的,因为如果它在热修复包中没有找到对应的实现类的话,会尝试从项目本地来加载对应的类,保证程序的稳定。
本项目Demo效果预览:(2019年4月12日17:23:29 更新: 针对使用这个项目进行实际的项目开发,我还写了一个简单的项目,它或许是使用本项目开发的一个比较好的示例。传送门)
优点:
在项目根目录的build.gradle添加:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
然后在:app:添加依赖:
annotationProcessor 'com.github.miqt.WandFix:wand-compiler:v1.3.6'
compile 'com.github.miqt.WandFix:wand:v1.3.6'
activity动态代理就是把一个activity的全部事情,都交给一个代理类去处理,而这个代理本质上也是一个类,一个对象,因此我们只要使用DexClassloader一替换,即变成了动态代理。
先新建一个activity,继承ProxyActivity,然后添加@BindProxy
注解
//绑定代理类
@BindProxy(clazz = TextActivityProxy.class)
//必须继承 ProxyActivity
public class TextActivity extends ProxyActivity {
//这里什么都不用写
}
然后新建一个class 继承 ActivityProxy 实现代理方法
//每个代理类都要设置
@AddToFixPatch
public class TextActivityProxy extends ActivityProxy {
public TextActivityProxy(ProxyActivity acty) {
super(acty);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
mActy.setContentView(R.layout.activity_hello);
...
}
...
}
直接startActivity(new Intent(this,TextActivity.class));
启动这个activity,代理就生效了,后来如果改动代理类,可以直接通过打包热修复包下发下去。
public class MainActivity extends AppCompatActivity implements Wand.MotorListener {
@InjectObject(
//指向类的全名
value = "com.miqt.demo.presenter.AppPresenterImpl",
//设置双亲委托
//项目开发中建议使用PROJECT,优先应用本地类库。
//项目发布时,应修改为NEVER,优先应用热修复包中的类库。
level = ParentalEntrustmentLevel.NEVER)
AppPresenter ap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//可以在application中初始化一次即可
Wand.get().init(this).listener(this);
}
public void getStr(View view) {
//使用注解注入对象必须要调用这一行
ClassInstall.inject(this);
//或者带参数的构造方法
//Map<String, Object[]> pramHouse=new HashMap<>();
//pramHouse.put("com.miqt.demo.presenter.AppPresenterImpl",new Object[]{"hello"});
//ClassInstall.inject(this,pramHouse);
//也可以不使用注解注入的方式初始化对象
//ap= ObjectFactory.make("com.miqt.demo.presenter.AppPresenterImpl"/*,构造参数*/);
//ap= ObjectFactory.make(AppPresenterImpl.class/*,构造参数*/);
String str = ap.getStr();
Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
}
}
//先根据apk插件文件路径创建PluginResources
//需要文件读写权限才行
PluginResources manager = new PluginResources(context, pluginApkPath);
//颜色资源加载
int id=manager.getId("text_color", "color");
int color = manager.getResources().getColor(id, context.getTheme());
textView.setTextColor(color);
//布局加载
View main_layout=manager.getLayout("activity_main");
如果项目设置了混淆,需要将以下代码复制到混淆配置文件中:
-keep class com.miqt.wand.**{*;}
-keep class * {@com.miqt.wand.anno.InjectObject <fields>;}
-keep @com.miqt.wand.anno.AddToFixPatch class * {*;}
-keep @com.miqt.wand.anno.BindProxy class * {*;}
千里之行,始于足下,欢迎提出问题和宝贵意见。
具体更多用法请移步Wiki
如果您觉得这个项目还不错,就点个star吧( ̄▽ ̄)~*
Sign in for post a comment
Comments ( 0 )