前言
消失大半年,其中一个原因是工作了,大部分时间在给公司做开发,业余时间在写外包赚米,另一个原因就是拖延症犯了,越拖越想拖
过年放了半个月假,稍微有点时间做点自己一直以来就很想做的事——给NGA去广告,当然,JS教程也会安排上的
正文
开发环境配置
首先新建一个新的新项目,我为了方便选了 Settings Activity
作为模板
当然,你乐意的话完全可以不创建 Activity
然后设置项目名称以及语言,推荐使用 Kotlin
浅浅用了下感觉还是很方便的,虽然依旧不如 C#
优雅
完成以后需要等待 Gradle Sync
一次,视网络情况可能会比较久
前天弄了半天一直Build失败,然后换了最新的 Android Studio,最后发现是我 Gradle 全局配置被 Android Studio 自动配置了一个根本不通的 proxy,删掉以后就正常了
然后需要在模块级 build.gradle
中添加 Xposed 库
compileOnly 'de.robv.android.xposed:api:82'
接着在 setting.gradle
中添加仓库链接,不然默认仓库中是没有这个库的
maven { url "https://api.xposed.info/" }
然后要创建 assets
文件夹
接着创建 xposed_init 声明文件,xposed_init 文件内容就是 Xposed Hook 入口函数类,根据实际情况修改
然后编辑 AndroidManifest.xml
添加 meta
信息
- xposedmodule
标记此 app 是一个 Xposed 模块,必须为 true - xposeddescription
模块描述信息,显示在 Xposed 模块管理器中 - xposedminversion
兼容的最低 Xposed API 版本,与引用的库版本一致即可 - xposedscope
说明该模块推荐对哪些 app 启用,是一个包名数组,内容如下图
接着创建 Xposed 入口类,类名和 xposed_init
里面写的保持一致
package com.chrxw.purenga
//import 省略
class XposedInit : IXposedHookLoadPackage, IXposedHookZygoteInit {
override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) {
}
@Throws(Throwable::class)
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
}
}
到此准备工作就做完了
核心代码
篇幅所限本文只贴出核心代码,完整代码参考 开源仓库
首先分析APP启动逻辑,我使用 GDA
来逆向,先找启动入口
定位到 gov.pianzong.androidnga.activity.LoadingActivity
,
逻辑挺好看的,调用 finishPage
或者 goHome
应该就能自动关闭广告了,不过这个方法是实例方法,需要想办法获取 LoadingActivity
实例
用交叉引用找不到别的地方引用,不过无伤大雅,用字符串搜索可以在 com.donews.nga.interfaces.ActivityLifecycleImpl
类中的 toForeGround
静态方法方法里判断了参数是否为 LodingActivity
,而且这个类是一个静态类,这就非常方便了
然后发现一个控制切屏广告的方法,如果前后台的时间戳满足条件就显示广告,也一起处理掉
上代码
try {
// 获取ActivityLifecycleImpl类
val clsLifeCycle =
XposedHelpers.findClass("com.donews.nga.interfaces.ActivityLifecycleImpl", mClassLoader)
// 获取LoadingActivity类
val clsLoadingActivity =
XposedHelpers.findClass("gov.pianzong.androidnga.activity.LoadingActivity", mClassLoader)
// Hook toForeGround 方法
XposedHelpers.findAndHookMethod(
clsLifeCycle,
"toForeGround",
Activity::class.java,
object : XC_MethodHook() {
@Throws(Throwable::class)
override fun beforeHookedMethod(param: MethodHookParam?) {
super.beforeHookedMethod(param)
Log.i("Before")
val activity = param?.args?.get(0) as Activity
if (activity.javaClass == clsLoadingActivity) {
Log.i("跳过启动页")
XposedHelpers.setBooleanField(activity, "canJump", true)
XposedHelpers.setBooleanField(activity, "isADShow", true)
XposedHelpers.callMethod(activity, "goHome")
}
Log.i(activity.toString())
}
}
)
// 获取SPUtil类
val clsSPUtil = XposedHelpers.findClass("com.donews.nga.common.utils.SPUtil", mClassLoader)
// 修改时间戳实现切屏无广告
XposedHelpers.findAndHookMethod(
clsSPUtil,
"getInt",
String::class.java,
Int::class.java,
object : XC_MethodHook() {
@Throws(Throwable::class)
override fun afterHookedMethod(param: MethodHookParam) {
when (param.args[0] as String) {
"AD_FORGROUND_TIME" -> {
Log.i("FG " + param.result.toString())
param.result = 0
}
"AD_BACKGROUND_TIME" -> {
Log.i("BG " + param.result.toString())
param.result = 0
}
else -> {
Log.i(param.args[0].toString() + " " + param.result.toString())
}
}
}
}
)
} catch (e: Exception) {
Log.e(e)
}
原理很简单,先获取 ActivityLifecycleImpl
和 ActivityLifecycleImpl
类的类型,因为 ActivityLifecycleImpl
是静态类,所以可以用类型直接 Hook toForeGround
方法,在方法执行前后执行 Hook 代码,判断传入的 activity
参数是否为 LoadingActivity
类,如果是的话先修改 canJump
和 isADShow
字段为 true
,然后调用 goHome
方法就完成了关闭开屏广告的操作。
然后获取静态类 SPUtil
并 Hook 它的 getInt
方法,判断传入的参数是否为 AD_FORGROUND_TIME
和 AD_BACKGROUND_TIME
, 如果是的话就修改返回值为 0
,这样切屏回来的时候就不会展示广告了(当然,你乐意的话可以让"AD_FORGROUND_TIME"-"AD_BACKGROUND_TIME" >= 1800,这样的效果就是100%显示切屏广告了)
最后编译一下就可以了,除了第一次打开APP会有个从黑屏切到主界面的过程,开屏广告和切屏广告已经被屏蔽了
本文链接:https://blog.chrxw.com/archives/2023/01/19/1710.html
转载请保留本文链接,谢谢