Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -1182,9 +1182,12 @@ import moe.ouom.wekit.hooks.core.annotation.HookItem
)
class DexCacheCleaner : BaseClickableFunctionHookItem() {

// 如果重写noSwitchWidget为true时将永远不会调用entry 此时可不重写entry方法来触发功能 通过onClick触发
/*
override fun entry(classLoader: ClassLoader) {
// 可点击功能不需要 Hook,只需实现 onClick
}
*/

override fun onClick() {
// 清理缓存
Expand All @@ -1195,6 +1198,8 @@ class DexCacheCleaner : BaseClickableFunctionHookItem() {

WeLogger.i("DexCacheCleaner", "DEX 缓存已清理")
}

override fun noSwitchWidget(): Boolean = true
}
```

Expand Down Expand Up @@ -1653,6 +1658,8 @@ class AutoGrabRedPacketConfigDialog(context: Context) : BaseRikkaDialog(context,
| **点击处理** | 点击切换开关 | **`onClick(Context)` 必须重写** |
| **主要用途** | 主要用于 Hook 功能 | 主要用于需要点击交互的功能 |

**如果重写noSwitchWidget为true将不会调用entry 请手动在onClick实现**

### 功能放置位置

根据功能类型放置到对应的包中:
Expand Down Expand Up @@ -2210,6 +2217,7 @@ class MyPacketInterceptor : IWePkgInterceptor {

**步骤 2: 注册拦截器**

请确保该项目未重写noSwitchWidget为true 否则不会触发 `entry()` 方法
在 Hook 入口点(通常是 `entry()` 方法)中注册拦截器:

```kotlin
Expand Down
94 changes: 94 additions & 0 deletions SCRIPT_API_DOCUMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# 脚本 API 文档

## Beta 状态警告

**重要提醒:此 API 目前处于 Beta 测试阶段,在后续更新中可能出现不兼容的更改,使用时请密切关注相关更新通知。**
## 目录

1. [钩子函数](#钩子函数)
- [onRequest](#onrequest)
- [onResponse](#onresponse)
2. [WEKit 对象](#wekit-对象)
- [概述](#概述)
- [WEKit Log 函数](#wekit-log-函数)

## 钩子函数

### onRequest

当请求即将发出时触发此函数。

```javascript
function onRequest(data) {
// data 对象包含以下字段:
const {uri,cgiId,jsonData} = data;

// 示例:修改请求数据
if (data.cgiId === '111') {
data.jsonData.newField = 'newValue';
}
}
```

### onResponse

当请求收到响应时触发此函数。

```javascript
function onResponse(data) {
// data 对象包含以下字段:
const {uri,cgiId,jsonData} = data;

// 示例:修改响应数据
if (data.cgiId === 'some_cgi_id') {
data.jsonData.newField = 'newValue';
}
}
```

## 数据对象说明

每个钩子函数接收一个 `data` 参数,该参数是一个对象,包含以下字段:

| 字段名 | 类型 | 描述 |
|----------|--------|------------------------------|
| uri | string | 请求的目标 URI 地址 |
| cgiId | string | 请求的 CGI ID,用于识别请求类型 |
| jsonData | object | 请求或响应的数据体(JSON 格式) |

## WEKit 对象

### 概述

`wekit` 是一个特殊的全局对象,是软件为脚本环境设计的api,提供了与底层系统交互的各种功能接口。该对象在脚本执行环境中自动可用,无需额外导入或初始化。

### WEKit Log 函数

`wekit.log` 是 `wekit` 对象提供的日志输出函数,专门用于在脚本执行过程中打印调试信息。所有通过此函数输出的日志都会被收集并可在脚本日志查看器中查看。

#### 使用方法

```javascript
wekit.log(message);
```

#### 示例

```javascript
function onRequest(data) {
wekit.log('请求发起:', data.uri);
wekit.log('CGI ID:', data.cgiId);
wekit.log('原始数据:', JSON.stringify(data.jsonData));

// 修改数据...
}
```

### 注意事项

1. 日志输出将显示在脚本日志查看器中
2. 当 API 发生变更时,请及时更新相关脚本代码

### 后续更新计划

我们可能在稳定版本中提供更加完善和一致的日志功能接口,届时会提供更详细的文档和更稳定的 API 设计。
26 changes: 24 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ android {
)
resources {
merges += "META-INF/xposed/*"
merges += "org/mozilla/javascript/**" // 合并 Mozila Rhino 所有资源
excludes += "**"
}
}
Expand Down Expand Up @@ -588,8 +589,26 @@ tasks.register("protectSensitiveCode") {
val d8Name = if (System.getProperty("os.name").lowercase().contains("win")) "d8.bat" else "d8"
val d8Path = "${android.sdkDirectory}/build-tools/${android.buildToolsVersion}/$d8Name"

project.exec {
commandLine(d8Path, "--release", "--min-api", "26", "--output", tempDir.absolutePath, *classFiles.map { it.absolutePath }.toTypedArray())
// 生成参数文件
val argsFile = tempDir.resolve("d8-args.txt")
// 写入并确保执行后删除
try {
argsFile.printWriter().use { writer ->
writer.println("--release")
writer.println("--min-api")
writer.println("26")
writer.println("--output")
writer.println(tempDir.absolutePath)
classFiles.forEach { writer.println(it.absolutePath) }
}

project.exec {
commandLine(d8Path, "@${argsFile.absolutePath}")
}
} finally {
if (!argsFile.delete() && argsFile.exists()) {
argsFile.deleteOnExit()
}
}

val dexFile = File(tempDir, "classes.dex")
Expand Down Expand Up @@ -943,6 +962,9 @@ dependencies {
implementation(libs.hutool.core)
implementation(libs.nanohttpd)

// Mozila Rhino
implementation("io.apisense:rhino-android:1.3.0")

compileOnly(libs.lombok)
annotationProcessor(libs.lombok)

Expand Down
10 changes: 10 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@
public static com.tencent.mmkv.MMKV defaultMMKV();
}

# ==========================================================
# Mozila Rhino
# ==========================================================
-keep class javax.script.** { *; }
-keep class com.sun.script.javascript.** { *; }
-keep class org.mozilla.javascript.** { *; }
-dontwarn org.mozilla.javascript.**
-dontwarn sun.reflect.CallerSensitive


# ==========================================================
# 忽略警告
# ==========================================================
Expand Down
7 changes: 3 additions & 4 deletions app/src/main/java/moe/ouom/wekit/core/model/BaseHookItem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,13 @@ abstract class BaseHookItem {
/**
* 在 loadHook 前执行一次
* 返回 true 表示继续执行 loadHook
* 返回 false 表示由 initOnce 自行处理 loadHook 事件
* 返回 false 表示不执行 entry 的事件 不可重写
*/
open fun initOnce(): Boolean = true

fun initOnce(): Boolean = true
/**
* Hook 入口方法
*/
abstract fun entry(classLoader: ClassLoader)
open fun entry(classLoader: ClassLoader) {}

/**
* 卸载 Hook
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import moe.ouom.wekit.hooks.core.annotation.HookItem

@HookItem(path = "开发者选项/清除适配信息", desc = "点击清除适配信息")
class DexCacheCleaner : BaseClickableFunctionHookItem() {
override fun entry(classLoader: ClassLoader) {}


override fun onClick(context: Context?) {
context?.let {
MaterialDialog(it)
Expand All @@ -25,7 +24,5 @@ class DexCacheCleaner : BaseClickableFunctionHookItem() {
}
}

override fun noSwitchWidget(): Boolean {
return true
}
override fun noSwitchWidget(): Boolean = true
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import moe.ouom.wekit.util.log.WeLogger

@HookItem(path = "开发者选项/发包调试", desc = "发送自定义数据包到微信服务器")
class WePacketDebugger : BaseClickableFunctionHookItem() {
override fun entry(classLoader: ClassLoader) {}

override fun onClick(context: Context?) {
context?.let {
Expand Down Expand Up @@ -96,7 +95,5 @@ class WePacketDebugger : BaseClickableFunctionHookItem() {
}
}

override fun noSwitchWidget(): Boolean {
return true
}
override fun noSwitchWidget(): Boolean = true
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import moe.ouom.wekit.util.log.WeLogger

@HookItem(path = "娱乐功能/清空资料信息", desc = "点击清空你之前所选择的微信地区和性别等资料信息")
class WeProfileCleaner : BaseClickableFunctionHookItem() {
override fun entry(classLoader: ClassLoader) {}

override fun onClick(context: Context?) {
context?.let {
Expand Down Expand Up @@ -54,7 +53,5 @@ class WeProfileCleaner : BaseClickableFunctionHookItem() {
}
}

override fun noSwitchWidget(): Boolean {
return true
}
override fun noSwitchWidget(): Boolean = true
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import moe.ouom.wekit.util.log.WeLogger

@HookItem(path = "娱乐功能/设置微信昵称", desc = "通过发包来更灵活的设置微信昵称")
class WeProfileNameSetter : BaseClickableFunctionHookItem() {
override fun entry(classLoader: ClassLoader) {}

override fun onClick(context: Context?) {
context?.let {
Expand Down Expand Up @@ -65,7 +64,5 @@ class WeProfileNameSetter : BaseClickableFunctionHookItem() {
return input.replace("\"", "\\\"")
}

override fun noSwitchWidget(): Boolean {
return true
}
override fun noSwitchWidget(): Boolean = true
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import moe.ouom.wekit.util.log.WeLogger
@HookItem(path = "开发者选项/分裂群组", desc = "让群聊一分为二")
class WeSplitChatroomMaker : BaseClickableFunctionHookItem() {

override fun entry(classLoader: ClassLoader) {}

override fun onClick(context: Context?) {
context ?: return

Expand Down Expand Up @@ -132,7 +130,5 @@ class WeSplitChatroomMaker : BaseClickableFunctionHookItem() {
}
}

override fun noSwitchWidget(): Boolean {
return true
}
override fun noSwitchWidget(): Boolean = true
}
32 changes: 4 additions & 28 deletions app/src/main/java/moe/ouom/wekit/hooks/item/fix/CrashLogViewer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import com.afollestad.materialdialogs.list.listItems
import moe.ouom.wekit.core.model.BaseClickableFunctionHookItem
import moe.ouom.wekit.hooks.core.annotation.HookItem
import moe.ouom.wekit.ui.CommonContextWrapper
import moe.ouom.wekit.util.Initiator.loadClass
import moe.ouom.wekit.util.common.Toasts.showToast
import moe.ouom.wekit.util.common.Utils.formatFileSize
import moe.ouom.wekit.util.crash.CrashLogManager
Expand All @@ -34,32 +33,9 @@ import java.util.Locale
class CrashLogViewer : BaseClickableFunctionHookItem() {

private var crashLogManager: CrashLogManager? = null
private var appContext: Context? = null

override fun entry(classLoader: ClassLoader) {
try {
// 获取 Application Context
val activityThreadClass = loadClass("android.app.ActivityThread")
val currentApplicationMethod = activityThreadClass.getMethod("currentApplication")
appContext = currentApplicationMethod.invoke(null) as? Context

if (appContext == null) {
WeLogger.e("CrashLogViewer", "Failed to get application context")
return
}

// 初始化崩溃日志管理器
crashLogManager = CrashLogManager(appContext!!)

WeLogger.i("CrashLogViewer", "Crash log viewer initialized")
} catch (e: Throwable) {
WeLogger.e("[CrashLogViewer] Failed to initialize crash log viewer", e)
}
}

override fun onClick(context: Context?) {
val ctx = context ?: appContext
if (ctx == null) {
if (context == null) {
WeLogger.e("CrashLogViewer", "Context is null")
return
}
Expand All @@ -68,15 +44,15 @@ class CrashLogViewer : BaseClickableFunctionHookItem() {
if (crashLogManager == null) {
WeLogger.i("CrashLogViewer", "Lazy initializing CrashLogManager")
try {
crashLogManager = CrashLogManager(ctx)
crashLogManager = CrashLogManager(context)
} catch (e: Throwable) {
WeLogger.e("[CrashLogViewer] Failed to initialize CrashLogManager", e)
showToast(ctx, "初始化失败: ${e.message}")
showToast(context, "初始化失败: ${e.message}")
return
}
}

showCrashLogList(ctx)
showCrashLogList(context)
}

/**
Expand Down
Loading