![](https://img.haomeiwen.com/i7522223/9028d68c579474bf.jpg)
了解系统启动activity的过程,先检查Activity是否注册,然后再去生成该Activity。我们在检查时用一个已经注册的Activity(桩,StubActivity和ViewStub类似)来给系统检查,检查通过后再替换成插件的Activity。
plugin(插件项目,可以独立运行)
不用做特殊处理。
debug下项目生成为plugin.apk。放到sdcard中提供主项目去hook。
app(主项目)中的代码:
HookedInstrumentation:自己实现Instrumentation,做一些替换工作,Hook掉系统持有的对象。
PluginApp:插件app实体类
PluginManager:负责加载插件的类和资源
ReflectUtil:反射工具类
StubActivity:桩,用来躲过项目清单文件对插件activity的检测
清单文件权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
注册桩:
<activity android:name=".StubActivity"/>
MainActivty的代码:
public class MainActivity extends Activity implements View.OnClickListener {
// https://zhuanlan.zhihu.com/p/33017826
public static final String TAG = "MainActivity";
private String mPluginPackageName = "com.george.plugin";
private String mPluginClassName = "com.george.plugin.MainActivity";
//读写权限
private static String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
//请求状态码
private static int REQUEST_PERMISSION_CODE = 1;
private PluginManager mPluginManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
initPlugin();
}
private void initPlugin() {
// !! must first
ReflectUtil.init();
mPluginManager = PluginManager.getInstance(getApplicationContext());
mPluginManager.hookInstrumentation();
mPluginManager.hookCurrentActivityInstrumentation(this);
}
private void initData() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_PERMISSION_CODE);
}
}
}
private void initView() {
(findViewById(R.id.tv_launch)).setOnClickListener(this);
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
// !!! 不要在此Hook,看源码发现mInstrumentaion会在此方法后初始化
}
@Override
public void onClick(View view) {
if (Constants.DEBUG) Log.e(TAG, "click view id: " + view.getId());
if (view.getId() == R.id.tv_launch) {
// TODO launch plugin app
if (mPluginManager.loadPlugin(Constants.PLUGIN_PATH)) {
Intent intent = new Intent();
intent.setClassName(mPluginPackageName, mPluginClassName);
startActivity(intent);
}
}
}
}
运行主项目,点击hook,跳转到插件plugin的activity中。
代码地址
网友评论