An Android Gradle plugin to inject method call at the beginning and end of methods in Android application at compile time using the ASM library.
Build and tested for AGP version: 8.2.2
.
Apply Gradle plugin to Android application
plugins {
id("com.android.application") version <version>
id("io.github.aleksrychkov.methodhook") version <version>
}
Create methodhook_activity.conf
file to instruct plugin what and where to inject calls. You can
place it adjacent to
application's build.gradle[.kts] file
activity {
superClass = "android.app.Activity"
methods = [
"onCreate"
]
packageId = "org.example"
beginMethodWith = "org.example.MethodHook.start"
endMethodWith = "org.example.MethodHook.end"
}
Add plugin's configuration to an Android application's build.gradle[.kts]
file. In addConfig
method specify a path
to
a created methodhook_activity.conf
file previously
// build.gradle.kts
plugins {
id("com.android.application") version <version>
id("io.github.aleksrychkov.methodhook") version <version>
}
android { … }
androidMethodHook {
configs {
create("debug") {
addConfig("./methodhook_activity.conf")
}
}
}
Create a class with two static methods to be injected by the plugin
package org.example
object MethodHook {
@JvmStatic
fun start(runtimeClazz: String, clazz: String, method: String) {
println("MethodHook::start::$runtimeClazz::$clazz::$method")
}
@JvmStatic
fun end(runtimeClazz: String, clazz: String, method: String) {
println("MethodHook::end::$runtimeClazz::$clazz::$method")
}
}
Build project's debug
buildType.
Now, onCreate(savedInstanceState: Bundle?)
method of all activities defined in org.example
package should be
instructed with MethodHook::start
and MethodHook::end
calls.
For a practical example of how to configure and use this plugin, refer to the examples.
A config file specifies which methods in your classes the plugin will modify to inject method calls.
The files are defined in Typesafe config format.
You can create as many files as you need, for example, we can create a config file for each Android
app component
./methodhook_activity.conf
./methodhook_service.conf
./methodhook_broadcast_receiver.conf
./methodhook_content_provider.conf
You can define multiple configs inside one file. Start a config with a name
activity {
superClass = "android.app.Activity"
methods = [
"onCreate"
]
packageId = "org.example"
beginMethodWith = "org.example.MethodHook.start"
endMethodWith = "org.example.MethodHook.end"
}
frgament {
exactClass = "org.example.SomeFragment"
methods = [
"onResume"
]
beginMethodWith = "org.example.MethodHook.start"
endMethodWith = "org.example.MethodHook.end"
}
Each config supports following options:
superClass
: Specifies the parent class (canonical name) for which the plugin should target methods in its subclasses, e.g.android.app.Activity
. Must not be defined along withexactClass
.exactClass
: Specifies the exact class (canonical name) for which the plugin should target methods,e.g. org.example.SomeClass
. Must not be defined along withsuperClass
.methods
: Specifies an array of methods (identified by their names) where the plugin will inject additional code, e.g.onCreate
.beginMethodWith
: Specifies a reference to a method to be injected at the beginning of instructed methods, e.g.org.example.MethodHook.start
.endMethodWith
: Specifies a reference to a method to be injected at the end of instructed methods, e.g.org.example.MethodHook.end
.packageId
: Specifies the package name that identifies the group of classes where the plugin will target methods for injection, e.g.org.example
.
Not required, if not defined, the config will be applied to all files in your project, including third-party libraries
Important
- Each config must have either
superClass
orexactClass
option, but not both. - Do not duplicate configs with same
superClass
orexactClass
option. - Each config must have
methods
option. - Each config must have at least one of the options (or both):
beginMethodWith
,endMethodWith
. - Bear in mind that, a class, targeted by the plugin, must be associated with only one config. Otherwise, you will get an error.
In order to apply plugin to application, add androidMethodHook
configuration to the
application's build.gradle[.kts]
file
// build.gradle.kts
plugins {
id("com.android.application") version <version>
id("io.github.aleksrychkov.methodhook") version <version>
}
android {
buildTypes {
debug { … }
release { … }
}
}
androidMethodHook {
forceLogging = true
configs {
create("debug") {
addConfig("./methodhook_activity_debug.conf")
}
create("release") {
addConfig("./methodhook_activity_release.conf")
}
}
}
The androidMethodHook
configuration supports next options:
forceLogging
: Enables info logs of the plugin. Same as if executing gradle command with--info
flag, e.g../gradlew assembleDebug --info
. Default value isfalse
.configs
: Creates plugin's config for specific build variant. The name of config must be the same as name of build variant, e.g. buildType:debug
, or if you have productFlavor nameddemo
:demoDebug
. You can have separate sets of config for different build variants.addConfig
: Adds relative path to a config file.
Plugin allows to inject a single method call to the beginning or the end of a target method.
Injected method must be public static void
and have three String
arguments.
Create a separate method to be injected at the beginning and end of the target method
@file:Suppress("UNUSED_PARAMETER")
package org.example
object MethodHook {
@JvmStatic
fun start(runtimeClazz: String, clazz: String, method: String) {
// some logic to be executed at the beginning of a [method]
}
@JvmStatic
fun end(runtimeClazz: String, clazz: String, method: String) {
// some logic to be executed at the end of a [method]
}
}
package org.example;
public class MethodHook {
public static void start(String runtimeClazz, String clazz, String method) {
// some logic to be executed at the beginning of a [method]
}
public static void end(String runtimeClazz, String clazz, String method) {
// some logic to be executed at the end of a [method]
}
}
- first argument is a runtime class,
this.getClass().getName()
, e.g.org.example.MainActivity
. - second argument is an actual class where method was called, e.g.
org.example.AbstractActivity
. - third argument is a method name, arguments, return type, e.g.
onCreate(Bundle)->void
.
Specify created methods in config
activity {
…
beginMethodWith = "org.example.MethodHook.start"
endMethodWith = "org.example.MethodHook.end"
}
Copyright Aleksandr Rychkov
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.