简介
QEdge 是一个基于 Xposed 框架的 QQ 扩展模块,允许开发者通过编写脚本扩展 QQ 的功能。脚本引擎基于 Modern BeanShell(3.0.0 lambda 分支),支持 Lambda、var 类型推断等现代 Java 语法特性。
脚本目录位于 QQ 数据目录下的 QEdge/plugin 文件夹中。
开发环境说明
脚本运行于 Modern BeanShell 环境(3.0.0 lambda 分支),实现了 Java 8~10 的多数常用语法糖。它是脚本解释器而非完整的 Java 编译器,编写时请遵循以下规范:
- 属性访问:推荐使用成员符
. 直接访问对象属性(如 msgData.msg),无需调用 Getter 方法。
- 方法访问:无需强制类型转换即可自动调用对应签名的方法和字段。
- 全局作用域:所有 API 方法在脚本任意位置均可直接调用,无需传递。
- 语法支持:支持 Lambda 表达式、方法引用、
var 类型推断、增强 for、自动装箱及流式 API 等现代语法;暂不支持 switch 表达式、record、模式匹配等 Java 10+ 之后的新特性。
- 线程模型:事件回调默认在 IO 线程执行。操作 UI 需切换至主线程。
脚本必须文件
| 文件名称 |
说明 |
是否必需 |
| main.java |
脚本执行入口 |
是 |
| desc.txt |
脚本描述文件 |
否 |
| info.prop |
配置文件 |
是 |
info.prop 配置项
| 配置项 |
说明 |
示例 |
| id |
脚本唯一标识符 |
example_123456 |
| pluginName |
脚本名称 |
示例脚本 |
| author |
作者 |
Developer |
| versionCode |
版本号 |
1.0 |
全局变量
| 变量名 |
类型 |
描述 |
| context |
android.content.Context |
宿主 App 全局上下文 |
| pluginId |
String |
当前加载脚本 ID |
| pluginPath |
String |
当前加载脚本的文件夹绝对路径 |
| myUin |
String |
当前登录的 QQ 号 |
| classLoader |
ClassLoader |
QQ 宿主类加载器 |
核心数据结构
MsgData (消息对象)
用于 onMsg 回调中。
| 字段 |
类型 |
描述 |
| type |
int |
聊天类型 (1:好友/私聊, 2:群聊, 100:陌生人) |
| msgType |
int |
消息类型 |
| peerUin |
String |
群号或好友QQ号 |
| peerUid |
String |
群号或好友UID |
| userUin |
String |
发送者QQ号 |
| userUid |
String |
发送者UID |
| time |
long |
发送时间戳 (秒) |
| msgId |
long |
消息ID |
| msg |
String |
文本消息内容 |
| path |
String |
文件/视频/语音保存路径 |
| atList |
List<String> |
消息中艾特的QQ号列表 |
| atMap |
Map<String, String> |
艾特映射表 |
FriendInfo (好友信息)
| 字段 |
类型 |
描述 |
| uin |
String |
QQ号 |
| uid |
String |
UID |
| name |
String |
昵称 |
| remark |
String |
备注 |
GroupInfo (群信息)
| 字段 |
类型 |
描述 |
| group |
String |
群号 |
| groupName |
String |
群名称 |
| groupOwner |
String |
群主QQ号 |
MemberInfo (群成员信息)
| 字段 |
类型 |
描述 |
| uin |
String |
成员QQ号 |
| uinName |
String |
群名片/昵称 |
| role |
String |
角色 (OWNER/ADMIN/MEMBER) |
ForbidInfo (禁言信息)
| 字段 |
类型 |
描述 |
| user |
String |
被禁言成员QQ号 |
| userName |
String |
被禁言成员昵称 |
| time |
long |
剩余禁言时长 (秒) |
BlackUser (群黑名单信息)
| 字段 |
类型 |
描述 |
| uin |
String |
QQ号 |
| name |
String |
昵称 |
| time |
long |
拉黑时间 |
| op_uin |
String |
操作者 |
JointGroup (共同群信息)
| 字段 |
类型 |
描述 |
| qun |
String |
群号 |
| joinTime |
long |
进群时间 |
消息相关方法
sendMsg - 发送消息
void sendMsg(String peerUin, String msg, int chatType)
发送文本消息。
| 参数 |
类型 |
说明 |
| peerUin |
String |
好友QQ号或群号 |
| msg |
String |
消息内容 |
| chatType |
int |
聊天类型 (1好友/2群聊/100陌生人) |
支持格式:
艾特:[atUin=QQ号](QQ号为0时表示艾特全体)
图片:[pic=图片链接或绝对路径]
sendPic - 发送图片
void sendPic(String peerUin, String path, int chatType)
sendPtt - 发送语音
void sendPtt(String peerUin, String path, int chatType)
sendCard - 发送卡片
void sendCard(String peerUin, String data, int chatType)
sendFile - 发送文件
void sendFile(String peerUin, String path, int chatType)
sendVideo - 发送视频
void sendVideo(String peerUin, String path, int chatType)
sendBubbleVideo - 发送泡泡消息视频
void sendBubbleVideo(String peerUin, String path, int chatType)
sendPai - 拍一拍
void sendPai(String toUin, String peerUin, int chatType)
void sendPai(String toUin, String peerUin)
recallMsg - 撤回消息
void recallMsg(int chatType, String peerUin, long msgId)
sendMusic - 发送音乐卡片
void sendMusic(String platform, String peerUin, String title, String desc, String jumpUrl, String musicUrl, String imgUrl, int chatType)
| 参数 |
类型 |
说明 |
| platform |
String |
qq,wy,mg,kw(已废弃,自测),kg,mg,bd |
快捷消息方法
| 方法 |
返回值 |
参数 |
说明 |
| sendPrivateMsg |
void |
String uin, String msg |
发送私聊文本消息 |
| sendGroupMsg |
void |
String qun, String msg |
发送群文本消息 |
| sendPrivatePic |
void |
String uin, String path |
发送私聊图片 |
| sendGroupPic |
void |
String qun, String path |
发送群图片 |
| sendPrivatePtt |
void |
String uin, String path |
发送私聊语音 |
| sendGroupPtt |
void |
String qun, String path |
发送群语音 |
| sendPrivateCard |
void |
String uin, String data |
发送私聊卡片 |
| sendGroupCard |
void |
String qun, String data |
发送群卡片 |
| sendPrivateVideo |
void |
String uin, String path |
发送私聊视频 |
| sendGroupVideo |
void |
String qun, String path |
发送群视频 |
| sendPrivateFile |
void |
String uin, String path |
发送私聊文件 |
| sendGroupFile |
void |
String qun, String path |
发送群文件 |
| recallPrivateMsg |
void |
String uin, long msgId |
撤回私聊消息 |
| recallGroupMsg |
void |
String qun, long msgId |
撤回群消息 |
| addLocalGrayTipMsg |
void |
String peerUin, String jsonStr, long busiId, int chatType |
添加本地灰条提示消息 |
| sendReplyMsg |
void |
String peerUin, long replyMsgId, String msg, int chatType |
发送引用回复消息 |
| sendPrivateReplyMsg |
void |
String uin, long replyMsgId, String msg |
发送私聊引用回复 |
| sendGroupReplyMsg |
void |
String qun, long replyMsgId, String msg |
发送群引用回复 |
平台音乐卡片
| 方法 |
返回值 |
参数 |
说明 |
| qqsendTroopMusic |
void |
String qun, String title, String desc, String detailUrl, String audio, String img |
发送QQ音乐群卡片 |
| qqsendFriendMusic |
void |
String uin, String title, String desc, String detailUrl, String audio, String img |
发送QQ音乐好友卡片 |
| wysendTroopMusic |
void |
String qun, String title, String desc, String detailUrl, String audio, String img |
发送网易云音乐群卡片 |
| wysendFriendMusic |
void |
String uin, String title, String desc, String detailUrl, String audio, String img |
发送网易云音乐好友卡片 |
| kgsendTroopMusic |
void |
String qun, String title, String desc, String detailUrl, String audio, String img |
发送酷狗音乐群卡片 |
| kgsendFriendMusic |
void |
String uin, String title, String desc, String detailUrl, String audio, String img |
发送酷狗音乐好友卡片 |
| kwsendTroopMusic |
void |
String qun, String title, String desc, String detailUrl, String audio, String img |
发送酷我音乐群卡片 |
| kwsendFriendMusic |
void |
String uin, String title, String desc, String detailUrl, String audio, String img |
发送酷我音乐好友卡片 |
| bdsendTroopMusic |
void |
String qun, String title, String desc, String detailUrl, String audio, String img |
发送百度音乐群卡片 |
| bdsendFriendMusic |
void |
String uin, String title, String desc, String detailUrl, String audio, String img |
发送百度音乐好友卡片 |
| mgsendTroopMusic |
void |
String qun, String title, String desc, String detailUrl, String audio, String img |
发送咪咕音乐群卡片 |
| mgsendFriendMusic |
void |
String uin, String title, String desc, String detailUrl, String audio, String img |
发送咪咕音乐好友卡片 |
好友相关方法
getAllFriend - 获取好友列表
List<FriendInfo> getAllFriend()
getJointGroupList - 获取好友共同群列表
List<JointGroup> getJointGroupList()
isFriend - 判断好友
boolean isFriend(String uin)
sendZan - 点赞
void sendZan(String uin, int num)
getCurrentUin - 获取当前QQ号
String getCurrentUin()
getCurrentUid - 获取当前UID
String getCurrentUid()
getCurrentName - 获取当前昵称
String getCurrentName()
群管理方法
getGroupList - 获取群列表
List<GroupInfo> getGroupList()
getGroupInfo - 获取群信息
Object getGroupInfo(String group)
获取指定群的详细信息对象。
getGroupMemberList - 获取群成员列表
List<MemberInfo> getGroupMemberList(String group)
getForbidInfo - 获取禁言列表
List<ForbidInfo> getForbidInfo(String group)
getGroupBlackList - 获取群拉黑名单列表
List<BlackUser> getGroupBlackList(String group)
shutUp - 禁言成员
void shutUp(String group, String uin, long time)
传 0 为解禁。
shutUpAll - 全员禁言
void shutUpAll(String group, boolean enable)
setMemberTitle - 设置群头衔
void setMemberTitle(String group, String uin, String title)
kickGroup - 踢出群成员
void kickGroup(String group, String uin, boolean block)
setGroupAdmin - 设置管理员
void setGroupAdmin(String group, String uin, boolean enable)
clockIn - 群打卡
void clockIn(String group)
changeGroupName - 更换群名
void changeGroupName(String group, String name)
getAbnormalUserList - 获取群内异常用户列表
List<String> getAbnormalUserList(String group)
setGroupLocation - 设置群地点
void setGroupLocation(String group, String location)
setGroupShortcutBar - 设置群快捷栏
void setGroupShortcutBar(String group, String desc, String link, String name, String cover)
Cookie与Token
| 方法 |
返回值 |
说明 |
| getSkey() |
String |
获取skey |
| getRealSkey() |
String |
获取RealSkey(鬼知道是什么玩意) |
| getPskey(String url) |
String |
获取指定域名的pskey |
| getPt4Token(String url) |
String |
获取Pt4Token |
| getStweb() |
String |
获取stweb |
| getGTK(String url) |
String |
根据URL获取GTK |
| getGtk(String skey) |
String |
根据skey计算GTK |
| getBkn(String key) |
long |
计算Bkn |
| getGroupRKey() |
String |
群聊图片RKey |
| getFriendRKey() |
String |
私聊图片RKey |
数据存储
数据保存在 plugin/脚本ID/config/ 下的 JSON 文件中。
写入数据
| 方法 |
说明 |
| putString(configName, key, value) |
写入字符串 |
| putInt(configName, key, value) |
写入整数 |
| putLong(configName, key, value) |
写入长整数 |
| putBoolean(configName, key, value) |
写入布尔值 |
| putDouble(configName, key, value) |
写入浮点数 |
读取数据
| 方法 |
说明 |
| getString(configName, key, defaultValue) |
读取字符串 |
| getInt(configName, key, defaultValue) |
读取整数 |
| getLong(configName, key, defaultValue) |
读取长整数 |
| getBoolean(configName, key, defaultValue) |
读取布尔值 |
| getDouble(configName, key, defaultValue) |
读取浮点数 |
其他操作
| 方法 |
说明 |
| remove(configName, key) |
删除键 |
| contains(configName, key) |
判断键是否存在 |
| clear(configName) |
清空配置文件 |
| getConfigMap(configName) |
获取配置文件的所有键值 |
| getConfigPath(configName) |
获取配置文件完整路径 |
回调方法
在脚本中实现以下方法以接收事件。
onMsg - 接收消息
void onMsg(Object msgData)
接收消息时触发,参数为 MsgData 对象。
群变动事件
| 方法 |
说明 |
| joinGroup(JoinData joinData) |
成员入群,参数为 JoinData 对象(字段: troopUin群号, memberUin成员UIN, memberUid原始UID, joinType入群类型131邀请/130主动, desc类型中文描述) |
| quitGroup(QuitData quitData) |
成员退群,参数为 QuitData 对象(字段: troopUin群号, memberUin成员UIN, updateHeadAndName是否触发退场红字提示) |
| shutUpGroup(group, memberUin, time, operatorUin) |
群禁言事件 |
交互事件
| 方法 |
说明 |
| void chatInterface(int chatType, String peerUin, String name) |
进入聊天界面 |
| String getMsg(String text) |
自己发送文本消息时拦截,用于修改发送文本 |
| void onPaiYiPai(String peerUin, String chatType, String operatorUin) |
拍一拍事件 |
| String getSummary(String text) |
自己发送图片消息时拦截,用于修改发送图片的外显 |
生命周期
void unLoadPlugin()
脚本停止/卸载时触发。
菜单功能
脚本菜单 (悬浮窗)
void addItem(String name, String callback)
添加脚本菜单项目。入口在聊天页面(长按右上角三条杠或者右下角加号)
回调定义:
void 回调方法名(int 聊天类型, String PeerUin, String 名称) {
// 处理逻辑
}
消息菜单 (长按消息)
void addMenuItem(String name, String callback, int[] msgTypes)
添加消息菜单项目。最后一个参数为空或不写则默认所有消息。
回调定义:
void 回调方法名(Object msgData) {
// msgData为MsgData对象
}
网络请求
httpGet - GET请求
String httpGet(String url)
String httpGet(String url, int connectTimeout, int readTimeout)
httpPost - POST请求
String httpPost(String url, String body)
String httpPost(String url, String body, String contentType)
downloadFile - 下载文件
boolean downloadFile(String url, String savePath)
反射与Hook
反射方法
| 方法 |
返回值 |
参数 |
说明 |
| callMethod |
Object |
Object obj, String methodName, Object... args |
调用对象方法 |
| callStaticMethod |
Object |
String className, String methodName, Object... args |
调用静态方法 |
| getFieldValue |
Object |
Object obj, String fieldName |
获取字段值 |
| setFieldValue |
void |
Object obj, String fieldName, Object value |
设置字段值 |
| newInstance |
Object |
String className, Object... args |
创建类实例 |
| findClass |
Class |
String className |
查找类 |
| findMethod |
Method |
Object obj, String methodName, int paramCount |
根据参数数量查找方法 |
| findMethod |
Method |
Object obj, String methodName, Class... parameterTypes |
根据参数类型查找方法 |
| findField |
Field |
Object obj, String fieldName |
查找字段 |
Hook方法
| 方法 |
返回值 |
参数 |
说明 |
| hookAfter |
XC_MethodHook.Unhook |
Object member, Object callback |
方法执行后Hook |
| hookBefore |
XC_MethodHook.Unhook |
Object member, Object callback |
方法执行前Hook |
callback为Lambda表达式,参数为XC_MethodHook.MethodHookParam,可访问param.thisObject、param.args、param.getResult()等
UIN/UID转换
| 方法 |
返回值 |
参数 |
说明 |
| getUidFromUin |
String |
String uin |
UIN转UID |
| getUinFromUid |
String |
String uid |
UID转UIN |
| isValidUin |
boolean |
String uin |
验证UIN是否有效 |
| isValidUid |
boolean |
String uid |
验证UID是否有效 |
| isValidQQ |
boolean |
String qq |
验证QQ号是否有效 |
文件操作
| 方法 |
返回值 |
参数 |
说明 |
| deleteFile |
boolean |
String path |
删除文件 |
| existsFile |
boolean |
String path |
检查文件是否存在 |
| mkdirs |
boolean |
String path |
创建目录 |
| getFileName |
String |
String path |
获取文件名 |
| getFileSize |
long |
String path |
获取文件大小(字节) |
| getFileLastModified |
long |
String path |
获取文件最后修改时间 |
| getParentPath |
String |
String path |
获取父目录路径 |
| listFiles |
List<String> |
String dirPath |
列出目录下文件 |
| readFile |
String |
String path |
读取文件内容 |
| writeFile |
void |
String path, String content |
写入文件内容 |
| appendFile |
void |
String path, String content |
追加写入文件 |
编码解码
| 方法 |
返回值 |
参数 |
说明 |
| urlEncode |
String |
String str |
URL编码 |
| urlDecode |
String |
String str |
URL解码 |
| base64Encode |
String |
String str |
Base64编码 |
| base64Decode |
String |
String str |
Base64解码 |
其他方法
日志与提示
| 方法 |
返回值 |
参数 |
说明 |
| log |
void |
String msg |
追加写入日志到脚本目录 |
| log |
void |
String fileName, String msg |
写入指定日志文件 |
| toast |
void |
Object msg |
系统Toast |
| toastLong |
void |
Object msg |
系统长Toast |
| qqToast |
void |
int icon, Object msg |
QQ风格顶部弹窗 (0警告/1错误/2成功) |
动态加载
| 方法 |
返回值 |
参数 |
说明 |
| loadJava |
void |
String path |
加载Java文件 |
| loadJar |
void |
String path |
加载Jar文件 |
| loadDex |
void |
String path |
加载Dex文件 |
| registerActivity |
void |
Class<?> activityClass |
注册Activity |
Activity操作
| 方法 |
返回值 |
参数 |
说明 |
| startQQActivity |
void |
String activityClass |
启动QQ Activity |
| startQQActivity |
void |
String activityClass, Map<String, String> extras |
启动QQ Activity(带参数) |
工具方法
| 方法 |
返回值 |
参数 |
说明 |
| getNowActivity |
Activity |
|
获取当前顶层Activity |
| runOnUiThread |
void |
Runnable runnable |
在主线程执行 |
| runOnBackgroundThread |
void |
Runnable runnable |
在后台线程执行 |
| isMainThread |
boolean |
|
判断是否为主线程 |
| sleep |
void |
long millis |
休眠指定毫秒数 |
| formatTime |
String |
long timestamp |
格式化时间戳(默认格式) |
| formatTime |
String |
long timestamp, String format |
格式化时间戳(自定义格式) |
| getCurrentTimeMillis |
long |
|
获取当前时间戳(毫秒) |
| getCurrentTimeSeconds |
long |
|
获取当前时间戳(秒) |
| getDeviceId |
String |
|
获取设备ID |
| getVersionName |
String |
|
获取模块版本名 |
| getVersionCode |
int |
|
获取模块版本号 |
| sendPacket |
boolean |
String cmd, String jsonStr |
发包: 命令字, Json包体 |
| fetchPacket |
String |
String cmd, String jsonStr |
发包: 命令字, Json包体(可返回数据) |
| sendPacket |
boolean |
String cmd, JSONObject json |
发包: 命令字, JSONObject包体 |
| fetchPacket |
String |
String cmd, JSONObject json |
发包: 命令字, JSONObject包体(可返回数据) |
| readprop |
String |
String file, String name |
读取properties文件中的指定键值 |
自身操作
| 方法 |
返回值 |
参数 |
说明 |
| uploadAvatar |
boolean |
String filePath |
上传头像(支持透明) |
| uploadAvatar |
void |
String filePath, boolean isStatic |
第三方上传头像(支持透明),false为动态头像封面,需要apng格式 |
| uploadCover |
boolean |
String filePath |
上传主页名片图(支持透明) |
| uploadImage |
String |
String imagePath |
上传本地图片到图床,返回图片URL(图片不存在时返回空串) |
| changeMyName |
void |
String nickname |
修改昵称 |
| addFriend |
void |
String uin,String msg,String remark |
添加好友 |
JSON处理
| 方法 |
返回值 |
参数 |
说明 |
| toJson |
String |
Object obj |
对象转JSON字符串 |
| parseJson |
JSONObject |
String jsonStr |
解析JSON对象 |
| parseJsonArray |
JSONArray |
String jsonStr |
解析JSON数组 |
随机数
| 方法 |
返回值 |
参数 |
说明 |
| generateRandomString |
String |
int length |
生成随机字符串 |
| generateRandomInt |
int |
int min, int max |
生成随机整数 |
插件信息
| 方法 |
返回值 |
参数 |
说明 |
| getPluginName |
String |
|
获取插件名称 |
| getPluginId |
String |
|
获取插件ID |
| getPluginPath |
String |
|
获取插件目录路径 |
| isPluginEnabled |
boolean |
|
判断插件是否启用 |
| setPluginEnabled |
void |
boolean enabled |
设置插件启用状态 |
示例脚本
log("脚本开始运行...");
qqToast(2, "Hello World!");
addItem("测试菜单", "onTestClick");
void onTestClick(int chatType, String peerUin, String peerName) {
qqToast(2, "点击了菜单");
sendMsg(peerUin, "你好!", chatType);
}
void onMsg(Object msgData) {
String msg = msgData.msg;
String peerUin = msgData.peerUin;
int type = msgData.type;
log("收到消息: " + msg);
if (msg.contains("ping")) {
sendMsg(peerUin, "pong", type);
}
}
void unLoadPlugin() {
qqToast(0, "脚本停止运行");
log("脚本停止运行");
}