ximsfei/Android-skin-support
Android-skin-support is an easy dynamic skin framework to use for Android, Only one line of code to integrate it. Android 换肤框架, 极低的学习成本, 极好的用户体验. "一行"代码就可以实现换肤, 你值得拥有!!!
Stale — last commit 6y ago
weakest axislast commit was 6y ago; top contributor handles 96% of recent commits…
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
last commit was 6y ago; no CI workflows detected
- ✓3 active contributors
- ✓MIT licensed
- ✓Tests present
Show all 7 evidence items →Show less
- ⚠Stale — last commit 6y ago
- ⚠Small team — 3 contributors active in recent commits
- ⚠Single-maintainer risk — top contributor 96% of recent commits
- ⚠No CI workflows detected
What would change the summary?
- →Use as dependency Mixed → Healthy if: 1 commit in the last 365 days; diversify commit ownership (top <90%)
- →Deploy as-is Mixed → Healthy if: 1 commit in the last 180 days
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/ximsfei/android-skin-support)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/ximsfei/android-skin-support on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: ximsfei/Android-skin-support
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/ximsfei/Android-skin-support shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Stale — last commit 6y ago
- 3 active contributors
- MIT licensed
- Tests present
- ⚠ Stale — last commit 6y ago
- ⚠ Small team — 3 contributors active in recent commits
- ⚠ Single-maintainer risk — top contributor 96% of recent commits
- ⚠ No CI workflows detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live ximsfei/Android-skin-support
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/ximsfei/Android-skin-support.
What it runs against: a local clone of ximsfei/Android-skin-support — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in ximsfei/Android-skin-support | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 2103 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ximsfei/Android-skin-support. If you don't
# have one yet, run these first:
#
# git clone https://github.com/ximsfei/Android-skin-support.git
# cd Android-skin-support
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of ximsfei/Android-skin-support and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ximsfei/Android-skin-support(\\.git)?\\b" \\
&& ok "origin remote is ximsfei/Android-skin-support" \\
|| miss "origin remote is not ximsfei/Android-skin-support (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "android-support/skin-support/src/main/java/skin/support/SkinCompatManager.java" \\
&& ok "android-support/skin-support/src/main/java/skin/support/SkinCompatManager.java" \\
|| miss "missing critical file: android-support/skin-support/src/main/java/skin/support/SkinCompatManager.java"
test -f "android-support/skin-support/src/main/java/skin/support/app/SkinCompatDelegate.java" \\
&& ok "android-support/skin-support/src/main/java/skin/support/app/SkinCompatDelegate.java" \\
|| miss "missing critical file: android-support/skin-support/src/main/java/skin/support/app/SkinCompatDelegate.java"
test -f "android-support/skin-support/src/main/java/skin/support/app/SkinLayoutInflater.java" \\
&& ok "android-support/skin-support/src/main/java/skin/support/app/SkinLayoutInflater.java" \\
|| miss "missing critical file: android-support/skin-support/src/main/java/skin/support/app/SkinLayoutInflater.java"
test -f "android-support/skin-support/src/main/java/skin/support/observe/SkinObservable.java" \\
&& ok "android-support/skin-support/src/main/java/skin/support/observe/SkinObservable.java" \\
|| miss "missing critical file: android-support/skin-support/src/main/java/skin/support/observe/SkinObservable.java"
test -f "android-support/skin-support/src/main/java/skin/support/content/res/SkinCompatResources.java" \\
&& ok "android-support/skin-support/src/main/java/skin/support/content/res/SkinCompatResources.java" \\
|| miss "missing critical file: android-support/skin-support/src/main/java/skin/support/content/res/SkinCompatResources.java"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 2103 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~2073d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/ximsfei/Android-skin-support"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Android-skin-support is a dynamic theming framework that enables runtime skin/theme switching in Android apps with minimal integration overhead. It supports both in-app theme resources and plugin-based skin packages (distributed as APK files), with automatic view inflation hooking and resource substitution—the core claim is 'one line of code' integration via SkinCompatManager.withoutActivity(this).loadSkin(). Modular monorepo under android-support/ with separate Maven-publishable libraries: skin-support (core), skin-support-design (Material Design widgets), skin-support-cardview (CardView v7), skin-support-constraint-layout (ConstraintLayout). Each module contains a Manager class (e.g., SkinCardViewManager) and an Inflater class (e.g., SkinCardViewInflater) that hook into Android's view creation pipeline. Demo apps in demo/ folder.
👥Who it's for
Android developers building consumer apps (social apps, content platforms, utilities) who need to offer users runtime theme switching (dark mode, brand-specific skins, seasonal themes) without app recompilation or complex resource management.
🌱Maturity & risk
Actively maintained as of v4.0.5 with support for both legacy Support Library and modern AndroidX (4.0.0+). The project shows solid architecture with dedicated modules for CardView, ConstraintLayout, and Material Design, but limited public CI/CD configuration visible in repo metadata. Low issue transparency in provided data, but release versioning suggests stable production use.
Single-author maintenance (ximsfei) creates bus-factor risk. Core dependency on reflection-based view inflation interception means breaking changes in Android framework updates could require patching. No visible test suite in file structure is a red flag for refactoring safety. Plugin-loading mechanism (loading APK files at runtime) has inherent security surface if skin packages aren't validated.
Active areas of work
Framework is in maintenance mode rather than active feature development—v4.0.5 represents the latest stable release. The TODO list shows completed items (AndroidX support decoupled, changelog updated) but pending work on native component support, multi-language/font support, and Preference integration. No visible PR queue or recent commits in provided metadata.
🚀Get running
Clone with git clone https://github.com/ximsfei/Android-skin-support.git, then open in Android Studio. Build dependencies defined in Gradle: compileSdkVersion, supportLibraryVersion, and skinAndroidSupportVersion configured in root build.gradle. Run demo apps via demo/skin-app or demo/skin-androidx-app.
Daily commands:
Clone repo → ./gradlew build to compile all modules → open demo/skin-app in Android Studio → deploy to emulator/device. Alternatively, ./gradlew :demo:skin-app:installDebug if Gradle wrapper is present.
🗺️Map of the codebase
android-support/skin-support/src/main/java/skin/support/SkinCompatManager.java— Core singleton manager orchestrating all skin switching logic; every contributor must understand how skins are loaded, cached, and applied globallyandroid-support/skin-support/src/main/java/skin/support/app/SkinCompatDelegate.java— Activity integration hook that intercepts layout inflation and applies skin resources; essential for understanding how views are wrapped with skin supportandroid-support/skin-support/src/main/java/skin/support/app/SkinLayoutInflater.java— Custom LayoutInflater that intercepts view creation to inject skin-compatible variants; critical entry point for all dynamic view themingandroid-support/skin-support/src/main/java/skin/support/observe/SkinObservable.java— Observable pattern implementation for broadcasting skin change events to all registered observers; foundation of real-time skin updatesandroid-support/skin-support/src/main/java/skin/support/content/res/SkinCompatResources.java— Resource resolution layer that switches between default and skin plugin resources at runtime; critical for loading colors, drawables, and layouts from skin packagesandroid-support/skin-support/src/main/java/skin/support/load/SkinAssetsLoader.java— Handles loading skin plugin APKs from assets and SD card; understand this to add new skin distribution mechanismsandroid-support/skin-support/src/main/java/skin/support/content/res/SkinCompatDrawableManager.java— Manages drawable resource caching and state-list creation for skin switching; prevents drawable reload thrashing during theme changes
🛠️How to make changes
Add a new SkinCompat widget for a custom view
- Create a new custom view class extending the target widget and implementing SkinObserver (
android-support/skin-support/src/main/java/skin/support/widget/SkinCompatCardView.java) - Implement onSkinAppeared() to refresh attributes from SkinCompatResources using skin-aware resource names (
android-support/skin-support/src/main/java/skin/support/content/res/SkinCompatResources.java) - Register observer callback in constructor and override onDetachedFromWindow() to unregister (
android-support/skin-support/src/main/java/skin/support/observe/SkinObservable.java) - Create a ViewInflater factory that maps the custom view class name to your SkinCompat variant (
android-support/skin-support-cardview/src/main/java/skin/support/app/SkinCardViewInflater.java) - Create a Manager class registering the inflater with SkinCompatManager.addInflater() (
android-support/skin-support-cardview/src/main/java/skin/support/SkinCardViewManager.java)
Add support for a new Material Design widget
- Create SkinMaterial* wrapper class in skin-support-design module extending the Material widget (
android-support/skin-support-design/src/main/java/skin/support/design/widget/SkinMaterialBottomNavigationView.java) - Implement SkinObserver interface to apply skin colors in onSkinAppeared() callback (
android-support/skin-support-design/src/main/java/skin/support/design/widget/SkinMaterialTabLayout.java) - Add view mapping in SkinMaterialViewInflater to match original class name to SkinMaterial* variant (
android-support/skin-support-design/src/main/java/skin/support/design/app/SkinMaterialViewInflater.java) - Register inflater in SkinMaterialManager.install() method called during SkinCompatManager initialization (
android-support/skin-support-design/src/main/java/skin/support/design/SkinMaterialManager.java)
Create a new skin loading strategy
- Create a new class implementing the SkinLoader interface in skin/support/load/ package (
android-support/skin-support/src/main/java/skin/support/load/SkinAssetsLoader.java) - Implement getSkinResources() to load skin package ResourcesCompat from your source (zip, network, etc.) (
android-support/skin-support/src/main/java/skin/support/load/SkinSDCardLoader.java) - Call SkinCompatManager.getInstance().loadSkin() with your loader instance to activate the skin (
android-support/skin-support/src/main/java/skin/support/SkinCompatManager.java) - Optionally override restoreSkin() if you need custom persistence logic in SkinPreference (
android-support/skin-support/src/main/)
🪤Traps & gotchas
Reflection-heavy implementation means proguard/R8 rules must preserve skin package structures and LayoutInflater hooks—missing rules breaks theming silently. Plugin APKs must have matching resource IDs (res/values/strings.xml, drawables, etc.) or substitution fails without clear errors. AndroidX/Support Library version mismatch between host app and skin plugin causes ClassNotFoundException at runtime. View inflation hooking only works for views inflated via LayoutInflater; programmatically created views (new SkinCompatCardView()) won't auto-theme unless manually registered.
💡Concepts to learn
- LayoutInflater Interception & Decoration — Core mechanism: framework replaces Android's default LayoutInflater factory to inject skin-aware view wrappers without app code changes; understanding Factory pattern and InflateListener is essential to the one-line integration trick
- Resource Substitution via Resource ID Mapping — Instead of replacing APK resources at compile time, skin packages provide parallel resource trees (same IDs, different drawable/color values) that are swapped at runtime via Context.getResources() wrapping
- DexClassLoader for Plugin APK Loading — Skin plugins are distributed as APK files; framework uses DexClassLoader to extract .dex and load resource assets from remote APKs without requiring installation, enabling true plugin architecture
- ObserverPattern / Broadcast for Skin Updates — When user switches skins, framework broadcasts update event to all registered views/activities; each listener refreshes cached resource references—non-intrusive update propagation
- Resource Priority Chain (Dynamic > Strategy > Plugin > Default) — Framework implements a fallback hierarchy: dynamically set colors/drawables override plugin skins, which override sdcard-loaded resources, which override default app resources; understanding this chain prevents surprises when layering skin sources
- Attribute-Based Resource Binding in XML Layouts — Layouts use custom attributes (e.g.,
app:skinAttr='textColor') to declare which resource IDs should be skinned; framework scans these at inflation time and wires up observers
🔗Related repos
Tencent/RapidView— Similar dynamic UI framework but uses custom template rendering instead of inflater hooking; useful comparison for alternative skinning architectureszyyoona7/DynamicSkin— Lighter-weight alternative skin framework for Android focusing on in-app theming; reference for minimal-footprint skinning if this framework feels heavymaterial-components/material-components-android— Official Material Design component library that skin-support-design wraps; needed to understand Material widget APIs being skinnedAndroidX/androidx— Core dependency providing LayoutInflater, Resources, and compatibility widgets that this framework extends and intercepts
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add unit tests for SkinManager core functionality
The repo lacks visible test coverage for core skin-switching logic. The SkinManager and related inflater classes (SkinCardViewInflater, SkinMaterialViewInflater, SkinConstraintViewInflater) handle critical view inflation and skin application but have no corresponding test files. Adding unit tests would ensure the plugin-based skin loading mechanism works correctly across different support library versions.
- [ ] Create android-support/skin-support/src/test/java directory structure
- [ ] Add unit tests for SkinManager.load(), SkinManager.restore(), and resource resolution logic
- [ ] Add tests for SkinCardViewInflater, SkinMaterialViewInflater, and SkinConstraintViewInflater to verify custom view inflation
- [ ] Create mock skin packages to test plugin loading scenarios
- [ ] Ensure tests cover both application-internal and plugin-based skin switching paths
Add comprehensive Javadoc and inline documentation for public APIs
While the README provides high-level usage examples, the actual source code in core files like SkinManager, SkinCardViewManager, SkinMaterialManager lacks detailed Javadoc comments. This makes it harder for contributors to understand the architecture and for API consumers to discover features. The project structure shows multiple manager and inflater classes that need API documentation.
- [ ] Add Javadoc to android-support/skin-support/src/main/java/android/support/v7/app/SkinAppCompatViewInflater.java and core manager classes
- [ ] Document all manager classes (SkinCardViewManager, SkinMaterialManager, SkinConstraintManager) with @param, @return, and usage examples
- [ ] Add inline comments explaining the inflater registration and custom view binding logic
- [ ] Document the lifecycle hooks (e.g., when onSkinApplied callbacks are triggered)
- [ ] Add Javadoc to the public API entry points for plugin loading and dynamic resource setting
Create GitHub Actions CI/CD workflow for automated testing and APK publishing
The repo has no visible CI/CD pipeline configuration. Given the multi-module structure (skin-support, skin-support-cardview, skin-support-design, skin-support-constraint-layout) and the complexity of testing skin switching across different Android support libraries, a GitHub Actions workflow would catch regressions early and automate the publishing_maven.gradle process mentioned in the build config.
- [ ] Create .github/workflows/android-build.yml to compile all modules on push and pull requests
- [ ] Add build matrix testing against multiple Android SDK versions (API 21+) to verify compatibility
- [ ] Configure ProGuard/R8 obfuscation testing using the proguard-rules.pro files in each module
- [ ] Add automated APK signing and Maven Central/JCenter publishing step (integrate with publishing_maven.gradle)
- [ ] Include lint checks to catch deprecated API usage and security issues in custom view inflaters
🌿Good first issues
- Add unit test suite for
SkinCompatResourcesresource priority resolution logic inandroid-support/skin-support/to prevent regressions in loading order (dynamic > strategy > plugin > default). Current structure lacks test coverage visible in repo. - Document the skin plugin APK generation workflow with a step-by-step Gradle recipe in
docs/PluginGeneration.md—README references '打包生成apk' but lacks exact build configuration example for maintainers unfamiliar with plugin packaging. - Implement auto-support for Android native Material 3 (androidx.material3) components by creating
android-support/skin-support-material3/module mirroringskin-support-designstructure; Material 2 is aging and many new projects target Material 3.
⭐Top contributors
Click to expand
Top contributors
- @ximsfei — 96 commits
- @AFeiDaRen — 3 commits
- @wegene_zbt — 1 commits
📝Recent commits
Click to expand
Recent commits
3eaa81f— fix: app_name (ximsfei)4c12db7— feat: SplashActivity background (ximsfei)f3a6c7c— feat: README update (ximsfei)6195659— fix: 解耦androidx (ximsfei)31293d2— feat: main_gradient_bg (ximsfei)152c076— feat: tv_build_time (ximsfei)7b1a887— feat: About Activity (ximsfei)9db76b9— Update README.md (ximsfei)90d0ec7— fix: demo 黑色主题背景色 (ximsfei)b508eba— feat: radio button textColor (ximsfei)
🔒Security observations
The Android-skin-support framework has moderate security posture with several concerns. The most critical issues are the reliance on deprecated Android Support Libraries (no longer receiving security updates) and the dynamic plugin loading mechanism which lacks documented security validation measures. The framework allows loading skin plugins from external storage and ZIP files, which requires robust integrity checking and path validation to prevent malicious plugin injection. Immediate action should be taken to migrate to AndroidX and implement cryptographic verification for dynamically loaded plugins. The codebase appears free of obvious injection vulnerabilities or hardcoded credentials, but security practices around plugin validation and data handling should be strengthened.
- High · Outdated Android Support Library —
android-support/skin-support-cardview/build.gradle. The project uses com.android.support:cardview-v7 dependency which is part of the legacy Android Support Library. Google has deprecated the Support Library in favor of AndroidX (androidx.*). The legacy support library no longer receives security updates and maintenance. Fix: Migrate to AndroidX dependencies. Replace 'com.android.support:cardview-v7' with 'androidx.cardview:cardview' and update all other support library dependencies to their AndroidX equivalents. - Medium · Dynamic Code Loading from External Sources —
android-support/skin-support/src/main/java/skin/support/SkinCompatManager.java and related plugin loading code. The project implements a plugin-based skin loading system that dynamically loads APK files from SDCard and ZIP archives. This presents a potential security risk if the plugin loading mechanism does not properly validate and verify the integrity of loaded plugins before execution. Fix: Implement cryptographic signature verification for all loaded skin plugins. Validate plugin APKs using digital signatures before loading. Implement manifest validation and permission checks. Consider using Android's built-in security mechanisms for plugin verification. - Medium · Missing ProGuard Obfuscation in Debug Builds —
android-support/skin-support-cardview/build.gradle and other module build.gradle files. The build.gradle configuration shows minifyEnabled is set to false for release builds, and there is no explicit configuration for debug builds. This means the code may not be properly obfuscated, exposing internal implementation details and making reverse engineering easier. Fix: Enable minification/obfuscation for release builds by setting minifyEnabled true. Create comprehensive ProGuard rules in proguard-rules.pro to protect sensitive classes and methods while maintaining functionality. - Medium · Overly Permissive File Access —
android-support/skin-support/src/main/java/skin/support (plugin loading mechanism). The skin-support framework loads resources from arbitrary SDCard locations and ZIP files. Without proper path validation, this could lead to directory traversal attacks or loading of unintended resources. Fix: Implement strict path validation to prevent directory traversal. Use canonicalization to resolve paths and verify they are within expected directories. Implement whitelist-based access controls for plugin directories. - Low · No HTTPS Enforcement Documented —
README.md and documentation. The README and documentation do not mention security best practices for downloading skin plugins over the network. If plugins are loaded from remote sources, there is no documented requirement for HTTPS/TLS encryption. Fix: Document and enforce HTTPS-only downloads for remote skin plugins. Implement certificate pinning for critical plugin sources. Provide clear security guidelines for developers integrating this framework. - Low · Missing Sensitive Data Handling Guidelines —
Documentation and SkinCompatManager.java. No documented guidance on secure handling of plugin storage, caching, and memory management for skin resources. Sensitive assets could potentially be exposed in memory or stored insecurely. Fix: Implement secure caching mechanisms with proper encryption. Clear sensitive data from memory after use. Provide developer guidelines for secure plugin storage and resource management.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.