参与开发
2025/11/21...大约 3 分钟指南开发贡献
参与 OShin 项目开发
👋 你好,开发者! 感谢你对 OShin 项目的关注。
OShin 是一个基于 Xposed 的模块化增强工具。为了保持代码的整洁与可维护性,我们设计了一套标准化的开发模式。本指南将带你快速上手,从了解架构到提交你的第一个 PR。
🛠️ 技术栈概览
核心技术构成
OShin 构建在现代化的 Android 技术栈之上,你需要了解以下基础:
- 🪝 YukiHookAPI: 基于 Kotlin 的现代化 Xposed API 框架,提供简洁优雅的链式调用。
- 🎨 Jetpack Compose: Google 推出的声明式 UI 工具包,用于构建模块设置界面。
- 🔍 DexKit: 高性能 DEX 解析库,用于运行时静态分析,实现精准 Hook。
- 💉 Hilt: 标准的依赖注入框架,管理组件间的依赖关系。
📂 项目结构解析
目录结构树
项目遵循“功能模块化”原则,核心代码位于 app/src/main/java/com/suqi8/oshin/:
com.suqi8.oshin
├── hook/ # ⚡ 核心 Hook 逻辑
│ ├── systemui/ # 按目标 App 包名分类
│ └── settings/
├── features/ # 📱 UI 定义目录
│ └── systemui/ # 定义页面结构、开关、滑块等
├── ui/ # 🎨 UI 组件与导航
│ ├── activity/
│ │ ├── components/ # 自定义 Compose 组件 (funSwitch 等)
│ │ └── feature/ # 功能页面具体实现
│ └── main/ # 主界面导航逻辑
└── models/ # 📦 数据模型🚀 如何贡献代码
场景一:向现有页面添加功能
这是最常见的场景。例如:在 系统界面 -> 通知 页面添加一个 “移除开发者选项通知” 的开关。
步骤 1:编写 Hook 逻辑
找到对应的 Hooker 文件 hook/systemui/StatusBar/Notification.kt,在 onHook() 中添加逻辑:
// 读取开关状态 (key 必须与 UI 定义一致)
if (prefs("systemui\\notification").getBoolean("remove_developer_options_notification", false)) {
loadApp(name = "com.android.systemui") {
// 使用 DexKit 或反射找到目标方法
"com.oplus.systemui.statusbar.controller.SystemPromptController"
.toClass()
.resolve()
.apply {
firstMethod { name = "updateDeveloperMode" }
.hook { replaceUnit { } } // 替换为空,拦截执行
}
}
}步骤 2:添加 UI 开关
打开 UI 定义文件 features/systemui/notification.kt,在 items 列表中加入新的 Switch:
object notification {
val definition = PageDefinition(
category = "systemui\\notification", // 对应 prefs 读取路径
items = listOf(
CardDefinition(
items = listOf(
// ... 其他开关
Switch(
title = StringResource(R.string.remove_developer_options_notification),
key = "remove_developer_options_notification", // 对应 prefs key
defaultValue = false
)
)
)
)
)
}注意事项
别忘了在 res/values/strings.xml 中添加对应的多语言文案,否则界面会显示资源 ID。
场景二:创建全新的功能页面
当你需要 Hook 一个新的 App(例如“酷安”),或者需要一个独立的设置页时。
点击展开完整教程
1. 创建目录结构
- Hook: 创建
hook/coolapk/目录,新建coolapk.kt(入口) 和RemoveAds.kt(功能)。 - UI: 创建
features/coolapk/目录,新建coolapk.kt(UI定义)。
2. 编写核心代码
Hooker (RemoveAds.kt):
class RemoveAds : YukiBaseHooker() {
override fun onHook() {
loadApp(name = "com.coolapk.market") {
if (prefs("coolapk").getBoolean("remove_ads", false)) {
// ... Hook 逻辑 ...
}
}
}
}UI 定义 (features/coolapk/coolapk.kt):
object coolapk {
val definition = PageDefinition(
category = "coolapk",
appList = listOf("com.coolapk.market"), // 关联 App
title = AppName("com.coolapk.market"), // 自动获取 App 名称
items = listOf(
CardDefinition(
items = listOf(
Switch(
title = StringResource(R.string.remove_ads),
key = "remove_ads",
defaultValue = false
)
)
)
)
)
}3. 注册新模块
注册 Hook 入口 (HookEntry.kt):
override fun onHook() {
// ...
loadApp(hooker = coolapk()) // 加载新模块
}注册 UI 页面 (FeatureRegistry.kt):
object FeatureRegistry {
val screenMap = mapOf(
// ...
"coolapk" to coolapk.definition, // 注册新页面
)
}💡 开发建议
最佳实践
- IDE: 推荐使用最新版 Android Studio。
- 调试: 建议使用安装了 LSPosed 的真机或模拟器进行调试。
- 分支管理: 请基于
main分支创建feat/xxx分支进行开发,完成后提交 Pull Request。
