环境准备
- 一个刷好magisk面具的手机,然后安装个lsposed框架
- Android Studio + Jadx + bilibili.apk(测试版本7.69.0)
插件开发
1.默认配置
新建一个AS工程,添加依赖
1
| compileOnly 'de.robv.android.xposed:api:82'
|
在settings.gradle里面添加 xposed 依赖
1 2 3 4 5 6 7
| dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { maven { url 'https://api.xposed.info/' } } }
|
然后在AndroidManifest.xml里面添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <application <!-- 是否为Xposed模块 --> <meta-data android:name="xposedmodule" android:value="true"/> <meta-data android:name="xposeddescription" android:value="去除bilibili一些烦人的东西" /> <meta-data android:name="xposedminversion" android:value="54"/> <meta-data android:name="xposedscope" android:resource="@array/xposedscope"/> </application>
|
在arrays.xml里面添加作用域,就是作用包名
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="xposedscope" > <item>tv.danmaku.bili</item> </string-array> </resources>
|
新建一个xposed_init文件, app/src/main/assets/xposed_init,在里面指定一个MainHook入口文件,例如com.user.knock.bilib.hook.HookInit
2.Hook方法 findAndHookMethod
主要是XposedHelpers.findAndHookMethod来注册需要hook的方法,这里的方法和参数需要正确对应才会生效,需要的当前实例和方法参数都可以通过MethodHookParam来获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class HookInit : IXposedHookLoadPackage, IXposedHookZygoteInit { @Throws(Throwable::class) override fun handleLoadPackage(loadPackageParam: LoadPackageParam) { XposedHelpers.findAndHookMethod(Application::class.java, "attach", Context::class.java, object : XC_MethodHook() { @Throws(Throwable::class) override fun afterHookedMethod(param: MethodHookParam) } })
} }
|
我们的逻辑就在XC_MethodHook里面写的, 现在可以什么都不写,直接安装到手机里面,在lsposed模块里面能看到我们写的模块
3.一些调试踩坑
安装的时候,关掉AS的部署优化,不生效的话,可以多加一些log或重启一次手机来验证
反解bilibili apk
通常的思路是我们得找到我们需要去掉的功能关键代码,例如我需要关掉这个广告,我这里的思路是
先找id,通过id定位代码,在代码里面定位具体的view,然后通过反解apk查找对应的逻辑,通过hook方法修改对应的逻辑
1.找view的id
这里推荐一个开发助手,可以简单抓一下布局的id,这个简单的原理可以通过 获得一些信息
1
| adb shell dumpsys activity top
|
例如这里我们就找到了这个R.id.ad_tint_frame的id,接下来我们就是jadx里面找个id,有时候id不是一样的,可以搜索ad_tint_frame
这里我们重要的是拿到这个id值,在app里面通过这个id值,查到对应的view,就可以操作了
2.查找view
查找view,我们一般先获取到当前的activity,然后find一个安卓的根布局,然后通过根布局查找我们的view。
打开对应的页面,获取当前页面的activity,这个方法很多,看activity或类似的topactivity工具即可。
去看对应的代码,hook onCreat方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| XposedHelpers.findAndHookMethod("com.bilibili.ship.theseus.detail.UnitedBizDetailsActivity", lpparam.classLoader, "onCreate", Bundle::class.java, object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam?) { super.beforeHookedMethod(param) }
@SuppressLint("ResourceType") override fun afterHookedMethod(param: MethodHookParam?) { super.afterHookedMethod(param) val curActivity = param?.thisObject as? Activity Toast.makeText( context, "UnitedBizDetailsActivity show curActivity=$curActivity", Toast.LENGTH_SHORT ).show() val rootLayout = curActivity?.findViewById<View>(R.id.content) rootLayout?.post { rootLayout.postDelayed({ hookRemoveView(rootLayout, 2131296637, context) }, 500) } } })
|
在hook里面,我们可以delay 久一点,保证这个view 已经被加载了,这里主要是做测试,具体的时间我们可以再仔细调节,因为view的加载时机还是很多的。
3.优化hook逻辑
在hook的代码里面,我们获取到对应具体实例类,然后去看对应的类里面能不能做通用的hook逻辑,因为如果是简单hook gone的话,不是很通用,我们也不能hook 其他一些创建的逻辑,给null值话,会触发很多nep,我们也很难取做兼容逻辑。
在代码里面打印这个view实例
然后去看这个实例的一些逻辑
比如有个构造的逻辑,那么我在这个构造的逻辑里面获取这个view的引用,就可以了
在构造的时候,获取引用,置为gone之后,业务还有其他地方掉show的逻辑,我们可以添加一个addOnAttachStateChangeListener,在onViewAttachedToWindow的时候,再gone一次。保证view的不可见。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| XposedHelpers.findAndHookConstructor("com.bilibili.ad.adview.video detail.upper.AdUpperRootFrameLayout", lpparam.classLoader, Context::class.java, AttributeSet::class.java, Int::class.javaPrimitiveType, object : XC_MethodHook() { @Throws(Throwable::class) override fun beforeHookedMethod(param: MethodHookParam) { super.beforeHookedMethod(param) }
@Throws(Throwable::class) override fun afterHookedMethod(param: MethodHookParam) { super.afterHookedMethod(param) val frameLayout = param.thisObject as? ViewGroup frameLayout?.visibility = View.GONE frameLayout?.addOnAttachStateChangeListener(object :OnAttachStateChangeListener{ override fun onViewAttachedToWindow(p0: View) { p0.visibility = View.GONE (p0?.parent as? View)?.visibility = View.GONE } override fun onViewDetachedFromWindow(p0: View) {
} }) } })
|
最后多点几个,测试ok