This commit is contained in:
2022-02-09 02:02:43 +08:00
parent acff94d32b
commit 8dedc9f555
70 changed files with 745 additions and 790 deletions

3
.idea/compiler.xml generated
View File

@@ -2,7 +2,8 @@
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="1.8">
<module name="YukiHookAPI.app" target="11" />
<module name="YukiHookAPI.app_demo" target="11" />
<module name="YukiHookAPI.module_demo" target="11" />
<module name="YukiHookAPI.yukihookapi-yaya" target="11" />
</bytecodeTargetLevel>
</component>

3
.idea/gradle.xml generated
View File

@@ -10,7 +10,8 @@
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/app_demo" />
<option value="$PROJECT_DIR$/module_demo" />
<option value="$PROJECT_DIR$/yukihookapi" />
<option value="$PROJECT_DIR$/yukihookapi-ksp-xposed" />
</set>

3
.idea/misc.xml generated
View File

@@ -4,6 +4,9 @@
<option name="filePathToZoomLevelMap">
<map>
<entry key="app/src/main/res/layout/activity_main.xml" value="0.4169230769230769" />
<entry key="app_demo/src/main/res/layout/activity_main.xml" value="0.4375" />
<entry key="demo/src/main/res/layout/activity_main.xml" value="0.4375" />
<entry key="module_demo/src/main/res/layout/activity_main.xml" value="0.4375" />
</map>
</option>
</component>

View File

@@ -1,24 +0,0 @@
package com.highcapable.yukihookapi
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.highcapable.yukihookapi", appContext.packageName)
}
}

View File

@@ -1 +0,0 @@
com.highcapable.yukihookapi.demo.hook.inject.MainInjecter_YukiHookXposedInit

View File

@@ -1,52 +0,0 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/7.
*/
@file:Suppress("unused")
package com.highcapable.yukihookapi.demo
import android.app.Application
import android.content.Context
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.demo.hook.MainHooker
import com.highcapable.yukihookapi.demo.hook.SecondHooker
class App : Application() {
override fun attachBaseContext(base: Context?) {
////
// 装载你的 Hook 框架的代码
////
// 方式 1
YukiHookAPI.encase(base) {
// Your code here.
}
// 方式 2
YukiHookAPI.encase(base, MainHooker(), SecondHooker())
super.attachBaseContext(base)
}
}

View File

@@ -1,55 +0,0 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/8.
*/
package com.highcapable.yukihookapi.demo
import androidx.annotation.Keep
// for test
@Keep
class InjectLucky {
// for test
@Keep
private var string = "没有"
// for test
@Keep
constructor() {
string = "原始数据"
}
// for test
@Keep
constructor(string: String = "原始数据复写") {
this.string = string
}
// for test
@Keep
fun getString() = string
}

View File

@@ -1,46 +0,0 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/8.
*/
package com.highcapable.yukihookapi.demo
import androidx.annotation.Keep
// for test
@Keep
class InjectNoParamTest {
@Keep
private var test = "没有"
init {
test = "没修改的变量"
}
// for test
@Keep
fun getString() = test
}

View File

@@ -1,39 +0,0 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/3.
*/
package com.highcapable.yukihookapi.demo
import androidx.annotation.Keep
// for test
@Keep
class InjectTestName(private val string: String) {
// for test
@Keep
fun getString() = string
}

View File

@@ -1,111 +0,0 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/1/29.
*/
@file:Suppress("SameParameterValue")
package com.highcapable.yukihookapi.demo
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.annotation.Keep
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.highcapable.yukihookapi.hook.factory.modulePrefs
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
@Keep
class MainActivity : AppCompatActivity() {
@Keep
private var a = "没更改的变量"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// for test
findViewById<Button>(R.id.main_button).setOnClickListener {
modulePrefs.apply {
putString("data", "这是存储的数据")
putBoolean("test_key", true)
putString("test_key_name", "存储数据成功,包名:$packageName")
}
Toast.makeText(this, "存储完成", Toast.LENGTH_SHORT).show()
}
// for test
AlertDialog.Builder(this)
.setTitle("Hook 方法返回值测试")
.setMessage(test() + "\n变量:$a\n模块数据:${xptest()}\n模块是否已激活:${YukiHookModuleStatus.isActive()}")
.setPositiveButton("下一个") { _, _ ->
AlertDialog.Builder(this)
.setTitle("Hook 方法参数测试")
.setMessage(test("这是没有更改的文字") + "\n${a(content = "这是原文")}\n模块是否已激活:${YukiHookModuleStatus.isActive()}")
.setPositiveButton("下一个") { _, _ ->
AlertDialog.Builder(this)
.setTitle("Hook 构造方法测试(stub)")
.setMessage(InjectTest("文字未更改").getString() + "\n模块是否已激活:${YukiHookModuleStatus.isActive()}")
.setPositiveButton("下一个") { _, _ ->
AlertDialog.Builder(this)
.setTitle("Hook 构造方法测试(多个)")
.setMessage(InjectLucky().getString() + "\n" + InjectLucky(string = "没更改的文字").getString() + "\n模块是否已激活:${YukiHookModuleStatus.isActive()}")
.setPositiveButton("下一个") { _, _ ->
AlertDialog.Builder(this)
.setTitle("Hook 构造方法测试(无参)")
.setMessage(InjectNoParamTest().getString() + "\n模块是否已激活:${YukiHookModuleStatus.isActive()}")
.setPositiveButton("下一个") { _, _ ->
AlertDialog.Builder(this)
.setTitle("Hook 构造方法测试(名称)")
.setMessage(InjectTestName("文字没更改").getString() + "\n模块是否已激活:${YukiHookModuleStatus.isActive()}")
.setPositiveButton("完成") { _, _ -> toast() }
.show()
}.show()
}.show()
}.show()
}.show()
}.show()
}
// for test
@Keep
private fun toast() = Toast.makeText(this, "我弹出来了,没有 Hook", Toast.LENGTH_SHORT).show()
// for test
@Keep
private fun a(content1: String = "前缀", content: String) = "$content1${content}_后面加了一段文字"
// for test
@Keep
private fun test() = "正常显示的一行文字"
// for test
@Keep
private fun xptest() = "这里是正常的文字"
// for test
@Keep
private fun test(string: String) = string
}

View File

@@ -1,100 +0,0 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/2.
*/
@file:Suppress("unused")
package com.highcapable.yukihookapi.demo.hook
import com.highcapable.yukihookapi.demo.BuildConfig
import com.highcapable.yukihookapi.demo.InjectTest
import com.highcapable.yukihookapi.demo.MainActivity
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.type.BundleClass
import com.highcapable.yukihookapi.hook.type.StringType
import com.highcapable.yukihookapi.hook.type.UnitType
// for test
class MainHooker : YukiBaseHooker() {
override fun onHook() =
loadApp(name = BuildConfig.APPLICATION_ID) {
MainActivity::class.java.hook {
injectMember {
method {
name = "onCreate"
param(BundleClass)
}
beforeHook {
field {
name = "a"
type = StringType
}.set(instance, "这段文字被修改成功了")
}
}
injectMember {
method {
name = "toast"
returnType = UnitType
}
intercept()
}
injectMember {
method {
name = "a"
param(StringType, StringType)
returnType = StringType
}
beforeHook {
args(index = 0).set("改了前面的")
args(index = 1).set("改了后面的")
}
}
injectMember {
method {
name = "test"
returnType = StringType
}
replaceTo("这段文字已被 Hook 成功")
}
injectMember {
method {
name = "test"
param(StringType)
returnType = StringType
}
beforeHook { args().set("方法参数已被 Hook 成功") }
}
}
InjectTest::class.java.hook {
injectMember {
constructor { param(StringType) }
beforeHook { args().set("构造方法已被 Hook 成功") }
}
}
loadHooker(hooker = TestChildHooker())
}
}

View File

@@ -1,66 +0,0 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/3.
*/
package com.highcapable.yukihookapi.demo.hook
import android.app.AlertDialog
import android.widget.Toast
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.findMethod
import com.highcapable.yukihookapi.hook.type.ActivityClass
import com.highcapable.yukihookapi.hook.type.BundleClass
// for test
class SecondHooker : YukiBaseHooker() {
override fun onHook() =
loadApp(name = "com.android.browser") {
ActivityClass.hook {
injectMember {
method {
name = "onCreate"
param(BundleClass)
}
afterHook {
AlertDialog.Builder(instance())
.setCancelable(false)
.setTitle("测试 Hook")
.setMessage("Hook 已成功")
.setPositiveButton("OK") { _, _ ->
Toast.makeText(instance(), "Hook Success", Toast.LENGTH_SHORT).show()
}.show()
}
}
injectMember {
member = hookClass.findMethod(name = "onStart")
afterHook {
Toast.makeText(instance(), "手动 Hook", Toast.LENGTH_SHORT).show()
}
}
}
}
}

View File

@@ -1,43 +0,0 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/4.
*/
package com.highcapable.yukihookapi.demo.hook
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.type.StringType
// for test
class TestChildHooker : YukiBaseHooker() {
override fun onHook() =
findClass(name = "$packageName.InjectTestName").hook {
injectMember {
constructor { param(StringType) }
beforeHook { args().set("构造方法已被 Hook 成功 [2]") }
}
}
}

View File

@@ -1,187 +0,0 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/4.
*/
@file:Suppress("unused")
package com.highcapable.yukihookapi.demo.hook.inject
import android.app.AlertDialog
import android.widget.Toast
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.demo.*
import com.highcapable.yukihookapi.hook.factory.encase
import com.highcapable.yukihookapi.hook.factory.findMethod
import com.highcapable.yukihookapi.hook.type.ActivityClass
import com.highcapable.yukihookapi.hook.type.BundleClass
import com.highcapable.yukihookapi.hook.type.StringType
import com.highcapable.yukihookapi.hook.type.UnitType
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
// for test
@InjectYukiHookWithXposed
class MainInjecter : YukiHookXposedInitProxy {
override fun onHook() {
// 设置模式
YukiHookAPI.configs {
debugTag = "YukiSuki"
isDebug = true
}
// 方案 1
// encase(MainHooker(), SecondHooker())
// 方案 2
encase {
loadApp(name = BuildConfig.APPLICATION_ID) {
MainActivity::class.java.hook {
injectMember {
method {
name = "onCreate"
param(BundleClass)
}
beforeHook {
field {
name = "a"
type = StringType
}.set(instance, "这段文字被修改成功了")
}
}
injectMember {
method {
name = "xptest"
returnType = StringType
}
replaceTo(prefs.getString(key = "data", default = "获取 Hook没数据"))
}
injectMember {
method {
name = "toast"
returnType = UnitType
}
intercept()
}
injectMember {
method {
name = "a"
param(StringType, StringType)
returnType = StringType
}
beforeHook {
args(index = 0).set("✌️改了前面的")
args(index = 1).set("✌️改了后面的")
}
}
injectMember {
method {
name = "test"
returnType = StringType
}
replaceTo("这段文字已被 Hook 成功")
}
injectMember {
method {
name = "test"
param(StringType)
returnType = StringType
}
beforeHook { args().set("方法参数已被 Hook 成功") }
}
}
InjectLucky::class.java.hook {
injectMember {
allConstructors()
afterHook {
field {
name = "string"
type = StringType
}.set(instance, "内容被改掉了")
}
}
}
InjectTest::class.java.hook {
injectMember {
constructor { param(StringType) }
beforeHook { args().set("构造方法已被 Hook 成功") }
}
}
InjectNoParamTest::class.java.hook {
injectMember {
constructor()
afterHook {
field {
name = "test"
type = StringType
}.set(instance, "内容被改掉了")
}
}
}
findClass(name = "$packageName.InjectTestName").hook {
injectMember {
constructor { param(StringType) }
beforeHook { args().set("构造方法已被 Hook 成功 [2]") }
}
}
}
loadApp(name = "com.android.browser") {
ActivityClass.hook {
injectMember {
method {
name = "onCreate"
param(BundleClass)
}
afterHook {
AlertDialog.Builder(instance())
.setCancelable(false)
.setTitle("测试 Hook")
.setMessage(
"Hook 已成功\n" +
"test_key:${prefs.getBoolean("test_key")}\n" +
"test_key_name:${prefs.getString("test_key_name", "默认值")}"
)
.setPositiveButton("OK") { _, _ ->
Toast.makeText(instance(), "Hook Success", Toast.LENGTH_SHORT).show()
}.show()
}
}
injectMember {
member = hookClass.findMethod(name = "onStart")
afterHook {
Toast.makeText(instance(), "手动 Hook", Toast.LENGTH_SHORT).show()
}
}.failures {
onConductFailure { _, _ -> }
onHookingFailure {}
onAllFailure {}
ignoredConductFailure()
ignoredHookingFailure()
ignoredAllFailure()
}
}
}
}
}
}

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity"
tools:ignore="HardcodedText">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="Hello World!" />
<Button
android:id="@+id/main_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="存储模块数据" />
</LinearLayout>

View File

@@ -1,3 +0,0 @@
<resources>
<string name="app_name">YukiHookAPI</string>
</resources>

View File

@@ -1,17 +0,0 @@
package com.highcapable.yukihookapi
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

54
app_demo/build.gradle Normal file
View File

@@ -0,0 +1,54 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
signingConfigs {
debug {
storeFile file('../keystore/public')
storePassword '123456'
keyAlias 'public'
keyPassword '123456'
v1SigningEnabled true
v2SigningEnabled true
}
}
compileSdk 31
defaultConfig {
applicationId "com.highcapable.yukihookapi.app_demo"
minSdk 22
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.highcapable.yukihookapi.app_demo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Default">
<activity
android:name=".ui.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,62 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/9.
*/
@file:Suppress("SameParameterValue")
package com.highcapable.yukihookapi.app_demo.ui
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.highcapable.yukihookapi.app_demo.R
import com.highcapable.yukihookapi.app_demo.utils.Main
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<TextView>(R.id.app_demo_first_text).text = getFirstText()
findViewById<TextView>(R.id.app_demo_second_text).text = secondText
findViewById<TextView>(R.id.app_demo_third_text).text = Main("Feel real").getString()
findViewById<TextView>(R.id.app_demo_fourth_text).text = getRegularText("Have fun day")
findViewById<TextView>(R.id.app_demo_fifth_text).text = getDataText()
findViewById<Button>(R.id.app_demo_button).setOnClickListener { toast() }
}
private val secondText = "This is a miracle"
private fun getFirstText() = "Hello World!"
private fun getRegularText(string: String) = string
private fun getDataText() = "No data found"
private fun toast() = Toast.makeText(this, "Nothing to show", Toast.LENGTH_SHORT).show()
}

View File

@@ -23,17 +23,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/3.
* This file is Created by fankes on 2022/2/9.
*/
package com.highcapable.yukihookapi.demo
package com.highcapable.yukihookapi.app_demo.utils
import androidx.annotation.Keep
class Main(private val string: String) {
// for test
@Keep
class InjectTest(private val string: String) {
// for test
@Keep
fun getString() = string
}

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:ignore="HardcodedText">
<TextView
android:id="@+id/app_demo_first_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:text="sample"
android:textSize="20sp" />
<TextView
android:id="@+id/app_demo_second_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:text="sample"
android:textSize="20sp" />
<TextView
android:id="@+id/app_demo_third_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:text="sample"
android:textSize="20sp" />
<TextView
android:id="@+id/app_demo_fourth_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:text="sample"
android:textSize="20sp" />
<TextView
android:id="@+id/app_demo_fifth_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:text="sample"
android:textSize="20sp" />
<Button
android:id="@+id/app_demo_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click Me!"
android:textAllCaps="false" />
</LinearLayout>

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 982 B

After

Width:  |  Height:  |  Size: 982 B

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.YukiHookAPI" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<style name="Theme.Default" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">YukiHookAppDemo</string>
</resources>

View File

@@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.YukiHookAPI" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<style name="Theme.Default" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>

1
module_demo/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -19,7 +19,7 @@ android {
compileSdk 31
defaultConfig {
applicationId "com.highcapable.yukihookapi.demo"
applicationId "com.highcapable.yukihookapi.module_demo"
minSdk 22
targetSdk 31
versionCode 1
@@ -55,12 +55,12 @@ dependencies {
compileOnly 'de.robv.android.xposed:api:82'
// Implementation API
implementation project(':yukihookapi')
// Implementation Processor
ksp project(':yukihookapi-ksp-xposed')
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation project(path: ':yukihookapi')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

41
module_demo/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,41 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-dontwarn
-ignorewarnings
-optimizationpasses 10
-dontusemixedcaseclassnames
-dontoptimize
-verbose
-overloadaggressively
-repackageclasses i
-allowaccessmodification
-adaptclassstrings
-adaptresourcefilenames
-adaptresourcefilecontents
# -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
-renamesourcefileattribute P
-keepattributes SourceFile,LineNumberTable

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.highcapable.yukihookapi.demo">
package="com.highcapable.yukihookapi.module_demo">
<application
android:allowBackup="true"
@@ -8,25 +8,25 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.YukiHookAPI">
android:theme="@style/Theme.Default">
<!-- 是否是xposed模块 -->
<!-- 设置为 Xposed 模块 -->
<meta-data
android:name="xposedmodule"
android:value="true" />
<!-- 模块描述 -->
<!-- 设置你的模块描述 -->
<meta-data
android:name="xposeddescription"
android:value="YukiHookAPI Xposed Module Test" />
<!-- 最低xposed版本号 -->
<!-- 最低 Xposed 版本号 -->
<meta-data
android:name="xposedminversion"
android:value="93" />
<activity
android:name=".MainActivity"
android:name=".ui.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@@ -0,0 +1 @@
com.highcapable.yukihookapi.module_demo.hook.MainHook_YukiHookXposedInit

View File

@@ -0,0 +1,133 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/9.
*/
@file:Suppress("unused")
package com.highcapable.yukihookapi.module_demo.hook
import android.app.AlertDialog
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.type.BundleClass
import com.highcapable.yukihookapi.hook.type.StringType
import com.highcapable.yukihookapi.hook.type.UnitType
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
@InjectYukiHookWithXposed
class MainHook : YukiHookXposedInitProxy {
override fun onHook() {
// 配置 YuKiHookAPI
YukiHookAPI.configs {
// 全局调试用的 TAG
debugTag = "YukiHookAPI"
// 是否开启全局调试日志输出功能
isDebug = true
}
// 开始你的 Hook
YukiHookAPI.encase {
// 装载需要 Hook 的 APP
loadApp(name = "com.highcapable.yukihookapi.app_demo") {
// 得到需要 Hook 的 Class
findClass(name = "$packageName.ui.MainActivity").hook {
// 注入要 Hook 的方法
injectMember {
method {
name = "getFirstText"
returnType = StringType
}
// 执行替换 Hook
replaceTo(any = "Hello YukiHookAPI!")
}
// 注入要 Hook 的方法
injectMember {
method {
name = "onCreate"
param(BundleClass)
}
// 在方法执行之前拦截
beforeHook {
field {
name = "secondText"
type = StringType
}.set(instance, "I am hook result")
}
}
// 注入要 Hook 的方法
injectMember {
method {
name = "getRegularText"
param(StringType)
returnType = StringType
}
// 在方法执行之前拦截
beforeHook {
// 设置 0 号 param
args().set("I am hook method param")
}
}
// 注入要 Hook 的方法
injectMember {
method {
name = "toast"
returnType = UnitType
}
// 拦截整个方法
replaceUnit {
AlertDialog.Builder(instance())
.setTitle("Hooked")
.setMessage("I am hook your toast showing")
.setPositiveButton("OK", null)
.show()
}
}
// 注入要 Hook 的方法
injectMember {
method {
name = "getDataText"
returnType = StringType
}
// 执行替换 Hook
replaceTo(prefs.getString(key = "test_data", default = "Test data is nothing"))
}
}
// 得到需要 Hook 的 Class
findClass(name = "$packageName.utils.Main").hook {
// 注入要 Hook 的方法
injectMember {
constructor { param(StringType) }
// 在方法执行之前拦截
beforeHook {
// 设置 0 号 param
args().set("I am hook constructor param")
}
}
}
}
}
}
}

View File

@@ -0,0 +1,58 @@
/**
* MIT License
*
* Copyright (C) 2022 HighCapable
*
* This file is part of YukiHookAPI.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/1/29.
*/
@file:Suppress("SetTextI18n")
package com.highcapable.yukihookapi.module_demo.ui
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.highcapable.yukihookapi.hook.factory.modulePrefs
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
import com.highcapable.yukihookapi.module_demo.R
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<TextView>(R.id.module_demo_text).text = "Module is Active -> ${YukiHookModuleStatus.isActive()}"
findViewById<EditText>(R.id.module_demo_edit_text).also {
it.setText(modulePrefs.getString(key = "test_data"))
findViewById<Button>(R.id.module_demo_button).setOnClickListener { _ ->
if (it.text.toString().isNotEmpty()) {
modulePrefs.putString(key = "test_data", value = it.text.toString())
Toast.makeText(applicationContext, "Saved", Toast.LENGTH_SHORT).show()
} else Toast.makeText(applicationContext, "Please enter the text", Toast.LENGTH_SHORT).show()
}
}
}
}

View File

@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:ignore="HardcodedText">
<TextView
android:id="@+id/module_demo_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:text="sample"
android:textSize="20sp" />
<EditText
android:id="@+id/module_demo_edit_text"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:hint="Please enter the text"
android:singleLine="true"
android:textSize="20sp"
tools:ignore="Autofill,LabelFor,TextFields" />
<Button
android:id="@+id/module_demo_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Save Test Data"
android:textAllCaps="false" />
</LinearLayout>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Default" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">YukiHookModuleDemo</string>
</resources>

View File

@@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Default" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -1,4 +1,5 @@
rootProject.name = "YukiHookAPI"
include ':app'
include ':app_demo'
include ':module_demo'
include ':yukihookapi'
include ':yukihookapi-ksp-xposed'

View File

@@ -174,8 +174,8 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
if (modulePackageName.isNotBlank()) logger.warn(message = "You set the customize module package name to \"$modulePackageName\",please check for yourself if it is correct")
val realPackageName =
modulePackageName.ifBlank {
if (packageName.contains(".hook."))
packageName.split(".hook.")[0]
if (packageName.contains(".hook.") || packageName.endsWith(".hook"))
packageName.split(".hook")[0]
else error(msg = "YukiHookAPI cannot identify your App's package name,please refer to the wiki https://github.com/fankes/YukiHookAPI/wiki to fix the package name or manually configure the package name")
}
codeGenerator.createNewFile(