Skip to Content
Shadow Nav总览

Shadow Nav

ARM64 Android 上的 GPU 加速控制面板,Shadow paging 生态的前台 App——用 React Native 0.85 + Skia + Reanimated 4,配一套 Kotlin native bridge,通过持久 su 会话做根权限文件 / 模块 / 设备操作。

不是 hack 工具,是控制台:配置内核功能、管文件、管 .ko 模块、配主题。


一句话

给 root 权限 Android 做一个 macOS Finder 质感、GPU 跑满特效、零 shell 的日常控制台。


文档索引

  • 功能分类 — 四张主屏逐一讲:Home / File / Repo / Settings

技术栈

用什么
FrameworkReact Native 0.85 + React 19(New Architecture / Fabric)
UI 组件Tamagui 2.0 rc.38
GPU 渲染@shopify/react-native-skia 2.6.2
动画react-native-reanimated 4.3(worklet / SharedValue / useClock)
手势react-native-gesture-handler 2.31(Pan / Tap / Race / Exclusive / manualActivation)
Native bridgeKotlin(FsModule / DeviceInfoModule / MemModule)
持久化@react-native-async-storage 2.2

没用 ScrollView 做水平滚动(Miller Columns 是自己 Pan + Animated)。没用 RN 布局做动画(全部 position:absolute + 手算坐标 lerp)。所有视觉效果走 Skia Canvas GPU 线程——JS 侧零渲染成本。


架构

┌─ React Native (JS thread) ─────────────────────────────────┐ │ screens/ HomeScreen / FileScreen / RepoScreen / ... │ │ shell/ BottomNav + Content (tab container) │ │ components/ Tamagui-based cards / pills / menus │ │ gpu/ Skia-rendered glow / orbs / hover text │ │ hooks/ useFanGesture (行自 onLongPress 识别) │ └────────────────────────────┬───────────────────────────────┘ ┌──────────┴──────────┐ │ Native Bridge │ │ (Kotlin modules) │ └──────────┬──────────┘ ┌─ 3 个 Kotlin 模块 ───────────────────────────────────────┐ │ FsModule 持久 su 会话池(3 session / 4-thread)│ │ readDir / stat / chmod / chown / ... │ │ DeviceInfoModule SoC / manufacturer / Android 版本快照 │ │ MemModule Java / native / graphics / PSS 监控 │ └──────────────────────────────────────────────────────────┘

所有特权操作都是标准 Linux 系统调用——finit_module / delete_module / openat / fstatat——不打内核补丁。Kernel 侧和 Shadow paging 完全解耦:这个 App 可以在任何 root Android 上跑。


项目布局

shadow_nav/ ├── src/ │ ├── screens/ # 主屏(Home / File / Repo / Settings / Drivers / HWID / PrivIds) │ ├── shell/ # BottomNav + Content tab 容器 │ ├── components/ # Tamagui 卡片 / 药丸 / 菜单 / 汉堡 │ ├── gpu/ # Skia 特效:HoverText / LiquidPill / OrbitGlow / SkiaOrbBackground │ ├── hooks/ # useFanGesture │ ├── native/ # fs.ts / deviceInfo.ts / fileIcons.ts(bridge 包装) │ ├── contexts/ # Theme / Language / ... │ ├── i18n.ts # 中英双语 │ └── theme.ts # HSL 主题 ├── android/ # Kotlin native modules ├── ios/ ├── macos/ └── assets/

屏幕清单(底部 BottomNav 7 个 tab):

中文状态本文档
Home首页01-home
File文件管理02-file
Repo软件仓库03-repo
Settings设置04-settings
Drivers驱动管理🚧 WIP
HWIDHWID 轮换🚧
PrivIds私有 ID🚧

本组文档先覆盖已完成的 4 个主屏。其他屏 stable 之后补。


核心技术要点

1. 持久 su 会话池(FsModule)

Android 上调用 root 最常见的做法是每次 Runtime.exec("su -c ...")——每次都 fork 一个 shell、解析输出、关闭;开销大、状态无共享。

Shadow Nav 的 FsModule3 个常驻 su 会话组成池子:

┌─ JS 请求 readDir("/data") ─┐ │ │ ▼ │ [Bridge] │ │ │ ▼ │ ┌─ 4-thread executor ─────────┴────────────┐ │ session 0: idle │ │ session 1: running chmod /data/xxx ← │ │ session 2: idle │ └──────────────────────────────────────────┘ 写 stdin: "ls /data\n" ← 发给 session 1 读 stdout 直到分隔符:timeout 作 watchdog

关键设计:

  • ThreadLocal SimpleDateFormat:不要每次 new,避免 GC 压力
  • 阻塞 readLine + watchdog:不用 busy-wait loop,节能
  • JS 侧 LRU 缓存 32 个目录:同路径重复访问秒出

非 root 模式直接用 android.system.Os.*(纯 syscall),不过池子。

2. root 模式用 nsenter -t 1 -m -- sh

普通 su 开启的 shell 在 zygote namespace 里,看不到系统全部挂载(某些 /proc 、外部存储挂载点不可见)。

nsenter -t 1 -m -- sh 切换到 PID 1(init)的 mount namespace——一进去就能看到整台机器的完整挂载视图。对文件管理器特别重要。

3. 无内核 patch 的模块装载

finit_module 是 Linux 3.8+ 的标准系统调用,insmod 内部也就是调它。Shadow Nav 直接 NDK 调 syscall:

external fun nativeFinitModule(fd: Int, params: String, flags: Int): Int external fun nativeDeleteModule(name: String, flags: Int): Int

不 spawn 任何 shell——省掉 insmod / rmmod 进程开销,也不泄露命令行到 /proc/$pid/cmdline

4. GPU 特效全程 Skia

所有视觉效果(霓虹光晕、雪花、星空、扫描光圈)都在 Skia Canvas 里走 GPU 线程,JS 线程完全不参与渲染。

关键特效(详见各屏文档):

特效实现
SkiaOrbBackground4 层可开关:径向光晕 blob(blur 预缓存到独立 Canvas)、星空、网格、飘雪;170 粒子 worklet 批成 5 条 SkPath
HoverText文本形状 mask + 轨道径向渐变;Inter-Black + CJK fallback via Skia Paragraph API;三层:半亮底 + 轨道 + 描边
Fan Rings里顺时针 3s + 外逆时针 4s 发光弧;SweepGradient + BlurMask;底圈低 alpha 做”死区” + 线长半径定位
OrbitGlow每张卡片带个相位偏移的轨道光点

5. 坐标系那些事

Hero 标题居中 → 左上角动画:不是用 RN flexbox 变化重排,而是 position:absolute + 手算 lerp (fromX, fromY) → (toX, toY),零布局重算

Drop zone 检测:drag 开始时 measureInWindow 记录矩形,加上容器 offset 偏移补偿absoluteX/Y窗口坐标系,不是父容器的 local 坐标)。这个坑让文件列表拖进 dock 的命中判定差了 64px。

Miller Columns 横向滚动:自己写的 Pan + Animated translateX不用 ScrollView——用了会和列内的纵向 ScrollView 抢手势。

6. 手势决议

Shadow Nav 的交互密度高(同一个 View 要响应 tap / long-press / pan / fan-commit),靠 Race + Exclusive + manualActivation 手动组合:

  • Race:多个手势同时监听,谁先通过 activation criteria 谁赢
  • Exclusive:父子关系手动声明(列滑动赢,行长按让路)
  • manualActivation:长按成功才手动 .activate() pan 手势,避免误触

详细在 File 页有一张图。


构建 & 运行

开发

cd shadow_nav npm install npx pod-install ios # iOS only npm run android # Android npm run ios npm run macos # macOS desktop build

需要 Metro bundler 常驻(默认自动起)。

真机 root 测试

install-debug.sh 脚本会:

  1. 用 adb 推 debug APK
  2. 打开 App
  3. 跳到”设置 → 文件系统 → 执行模式”切到 root
  4. 授予 su 权限(弹窗要求)

已验证设备

  • OnePlus Ace 5 Pro(SM8750,Android 16,KernelSU 1.0.x)

iOS / macOS 是 bonus 目标——部分模块(FsModule root 路径)不适用,会 fallback 到 Os.*


许可证

私有项目,暂未公开。

Last updated on