Contribute
Contribute to OShin Development
๐ Hello, Developer! Thank you for your interest in the OShin project.
OShin is a modular enhancement tool based on Xposed. To maintain code cleanliness and maintainability, we have designed a standardized development pattern. This guide will help you get started quickly, from understanding the architecture to submitting your first PR.
๐ ๏ธ Tech Stack Overview
Core Technologies
OShin is built on a modern Android tech stack. You need to understand the following basics:
- ๐ช YukiHookAPI: A modern Xposed API framework based on Kotlin, providing elegant chain calls.
- ๐จ Jetpack Compose: Google's declarative UI toolkit used for building module settings interfaces.
- ๐ DexKit: A high-performance DEX parsing library for runtime static analysis to achieve precise Hooking.
- ๐ Hilt: A standard dependency injection framework for managing dependencies between components.
๐ Project Structure Analysis
Directory Structure Tree
The project follows the "functional modularity" principle. The core code is located in app/src/main/java/com/suqi8/oshin/:
com.suqi8.oshin
โโโ hook/ # โก Core Hook Logic
โ โโโ systemui/ # Classified by target App package name
โ โโโ settings/
โโโ features/ # ๐ฑ UI Definition Directory
โ โโโ systemui/ # Define page structure, switches, sliders, etc.
โโโ ui/ # ๐จ UI Components & Navigation
โ โโโ activity/
โ โ โโโ components/ # Custom Compose components (funSwitch, etc.)
โ โ โโโ feature/ # Concrete implementation of feature pages
โ โโโ main/ # Main interface navigation logic
โโโ models/ # ๐ฆ Data Models๐ How to Contribute Code
Scenario 1: Adding Features to an Existing Page
This is the most common scenario. For example: Adding a "Remove Developer Options Notification" switch to the System UI -> Notification page.
Step 1: Write Hook Logic
Find the corresponding Hooker file hook/systemui/StatusBar/Notification.kt and add logic in onHook():
// Read switch state (key must match UI definition)
if (prefs("systemui\\notification").getBoolean("remove_developer_options_notification", false)) {
loadApp(name = "com.android.systemui") {
// Use DexKit or reflection to find the target method
"com.oplus.systemui.statusbar.controller.SystemPromptController"
.toClass()
.resolve()
.apply {
firstMethod { name = "updateDeveloperMode" }
.hook { replaceUnit { } } // Replace with empty to intercept execution
}
}
}Step 2: Add UI Switch
Open the UI definition file features/systemui/notification.kt and add a new Switch to the items list:
object notification {
val definition = PageDefinition(
category = "systemui\\notification", // Corresponds to prefs read path
items = listOf(
CardDefinition(
items = listOf(
// ... Other switches
Switch(
title = StringResource(R.string.remove_developer_options_notification),
key = "remove_developer_options_notification", // Corresponds to prefs key
defaultValue = false
)
)
)
)
)
}Note
Don't forget to add the corresponding multi-language text in res/values/strings.xml, otherwise the resource ID will be displayed on the interface.
Scenario 2: Creating a Brand New Feature Page
When you need to Hook a new App (e.g., "CoolAPK"), or need an independent settings page.
Click to expand full tutorial
1. Create Directory Structure
- Hook: Create
hook/coolapk/directory, createcoolapk.kt(Entry) andRemoveAds.kt(Feature). - UI: Create
features/coolapk/directory, createcoolapk.kt(UI Definition).
2. Write Core Code
Hooker (RemoveAds.kt):
class RemoveAds : YukiBaseHooker() {
override fun onHook() {
loadApp(name = "com.coolapk.market") {
if (prefs("coolapk").getBoolean("remove_ads", false)) {
// ... Hook Logic ...
}
}
}
}UI Definition (features/coolapk/coolapk.kt):
object coolapk {
val definition = PageDefinition(
category = "coolapk",
appList = listOf("com.coolapk.market"), // Associated App
title = AppName("com.coolapk.market"), // Automatically get App name
items = listOf(
CardDefinition(
items = listOf(
Switch(
title = StringResource(R.string.remove_ads),
key = "remove_ads",
defaultValue = false
)
)
)
)
)
}3. Register New Module
Register Hook Entry (HookEntry.kt):
override fun onHook() {
// ...
loadApp(hooker = coolapk()) // Load new module
}Register UI Page (FeatureRegistry.kt):
object FeatureRegistry {
val screenMap = mapOf(
// ...
"coolapk" to coolapk.definition, // Register new page
)
}๐ก Development Suggestions
Best Practices
- IDE: Recommend using the latest version of Android Studio.
- Debugging: Recommend using a real device or emulator with LSPosed installed for debugging.
- Branch Management: Please create a
feat/xxxbranch based on themainbranch for development, and submit a Pull Request upon completion.
