react-native-inapp-inspector 2.4.0 → 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ar.md +163 -0
- package/README.de.md +163 -0
- package/README.es.md +164 -0
- package/README.fr.md +163 -0
- package/README.hi.md +163 -0
- package/README.ja.md +180 -0
- package/README.ko.md +163 -0
- package/README.md +340 -243
- package/README.pt-BR.md +163 -0
- package/README.ru.md +163 -0
- package/README.zh-CN.md +387 -0
- package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +82 -21
- package/assets/banner_dark.svg +186 -0
- package/assets/banner_light.svg +186 -0
- package/assets/icon_circle.svg +148 -0
- package/assets/icon_square.svg +369 -0
- package/assets/inapp_inspector_icon.gif +0 -0
- package/assets/inapp_inspector_icon_original.gif +0 -0
- package/assets/social_preview.png +0 -0
- package/assets/walkthrough.gif +0 -0
- package/dist/commonjs/components/AnimatedBrandOwl.d.ts +7 -0
- package/dist/commonjs/components/AnimatedBrandOwl.js +175 -0
- package/dist/commonjs/components/AppHeaderLogo.d.ts +1 -0
- package/dist/commonjs/components/AppHeaderLogo.js +7 -5
- package/dist/commonjs/components/BrandSquareIcon.d.ts +5 -0
- package/dist/commonjs/components/BrandSquareIcon.js +139 -0
- package/dist/commonjs/components/ConsoleLogCard.d.ts +2 -1
- package/dist/commonjs/components/ConsoleLogCard.js +23 -39
- package/dist/commonjs/components/Inspector/AboutModal.js +44 -54
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +16 -16
- package/dist/commonjs/components/Inspector/ConfirmationModal.d.ts +13 -0
- package/dist/commonjs/components/Inspector/ConfirmationModal.js +32 -0
- package/dist/commonjs/components/Inspector/ConsoleTab.js +15 -15
- package/dist/commonjs/components/Inspector/CrashTab.js +25 -23
- package/dist/commonjs/components/Inspector/DebuggingTab.js +17 -17
- package/dist/commonjs/components/Inspector/FabLauncher.js +22 -30
- package/dist/commonjs/components/Inspector/FeatureUnderDevNotice.js +2 -2
- package/dist/commonjs/components/Inspector/LanguageSelectorModal.d.ts +15 -0
- package/dist/commonjs/components/Inspector/LanguageSelectorModal.js +90 -0
- package/dist/commonjs/components/Inspector/MainScreen.js +46 -33
- package/dist/commonjs/components/Inspector/MediaGalleryTab.js +21 -19
- package/dist/commonjs/components/Inspector/MediaPreviewModal.js +85 -101
- package/dist/commonjs/components/Inspector/NetworkTab.js +50 -50
- package/dist/commonjs/components/Inspector/NpmUpdateToast.js +1 -1
- package/dist/commonjs/components/Inspector/PushCard.d.ts +3 -2
- package/dist/commonjs/components/Inspector/PushCard.js +5 -4
- package/dist/commonjs/components/Inspector/PushDetail.js +32 -23
- package/dist/commonjs/components/Inspector/PushTab.js +13 -13
- package/dist/commonjs/components/Inspector/ReduxDetail.js +32 -32
- package/dist/commonjs/components/Inspector/ReduxTab.js +14 -14
- package/dist/commonjs/components/Inspector/SettingsPanel.js +258 -139
- package/dist/commonjs/components/Inspector/SocketCard.d.ts +5 -0
- package/dist/commonjs/components/Inspector/SocketCard.js +116 -0
- package/dist/commonjs/components/Inspector/SocketDetail.d.ts +4 -0
- package/dist/commonjs/components/Inspector/SocketDetail.js +317 -0
- package/dist/commonjs/components/Inspector/SocketFilterModal.d.ts +13 -0
- package/dist/commonjs/components/Inspector/SocketFilterModal.js +69 -0
- package/dist/commonjs/components/Inspector/SocketTab.d.ts +3 -0
- package/dist/commonjs/components/Inspector/SocketTab.js +112 -0
- package/dist/commonjs/components/Inspector/StorageTab.js +34 -32
- package/dist/commonjs/components/Inspector/SupportModal.d.ts +7 -0
- package/dist/commonjs/components/Inspector/SupportModal.js +125 -0
- package/dist/commonjs/components/Inspector/SupportPage.d.ts +5 -0
- package/dist/commonjs/components/Inspector/SupportPage.js +227 -0
- package/dist/commonjs/components/Inspector/TabBar.js +24 -23
- package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +24 -24
- package/dist/commonjs/components/JsonViewer.js +7 -7
- package/dist/commonjs/components/LogCard.d.ts +3 -2
- package/dist/commonjs/components/LogCard.js +17 -14
- package/dist/commonjs/components/LogSyntaxHighlighter.js +5 -5
- package/dist/commonjs/components/ModuleErrorBoundary.js +2 -2
- package/dist/commonjs/components/NetworkIcons.d.ts +15 -0
- package/dist/commonjs/components/NetworkIcons.js +38 -3
- package/dist/commonjs/components/SegmentedTabs.js +1 -1
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/socketLogger.d.ts +26 -0
- package/dist/commonjs/customHooks/socketLogger.js +2 -0
- package/dist/commonjs/helpers/index.js +3 -3
- package/dist/commonjs/helpers/memoryManager.d.ts +1 -0
- package/dist/commonjs/helpers/memoryManager.js +1 -1
- package/dist/commonjs/helpers/searchQueryParser.d.ts +1 -1
- package/dist/commonjs/helpers/searchQueryParser.js +5 -1
- package/dist/commonjs/helpers/settingsStore.d.ts +1 -0
- package/dist/commonjs/helpers/settingsStore.js +1 -1
- package/dist/commonjs/helpers/shareFormatter.d.ts +3 -1
- package/dist/commonjs/helpers/shareFormatter.js +8 -7
- package/dist/commonjs/i18n/index.d.ts +99 -1
- package/dist/commonjs/i18n/index.js +1 -1
- package/dist/commonjs/i18n/locales/ar.json +1 -1
- package/dist/commonjs/i18n/locales/bn.json +1 -0
- package/dist/commonjs/i18n/locales/de.json +1 -1
- package/dist/commonjs/i18n/locales/en.json +1 -1
- package/dist/commonjs/i18n/locales/es.json +1 -1
- package/dist/commonjs/i18n/locales/fr.json +1 -1
- package/dist/commonjs/i18n/locales/gu.json +1 -0
- package/dist/commonjs/i18n/locales/hi.json +1 -1
- package/dist/commonjs/i18n/locales/id.json +1 -0
- package/dist/commonjs/i18n/locales/it.json +1 -0
- package/dist/commonjs/i18n/locales/ja.json +1 -1
- package/dist/commonjs/i18n/locales/kn.json +1 -0
- package/dist/commonjs/i18n/locales/ko.json +1 -1
- package/dist/commonjs/i18n/locales/ml.json +1 -0
- package/dist/commonjs/i18n/locales/mr.json +1 -0
- package/dist/commonjs/i18n/locales/nl.json +1 -0
- package/dist/commonjs/i18n/locales/pa.json +1 -0
- package/dist/commonjs/i18n/locales/pl.json +1 -0
- package/dist/commonjs/i18n/locales/pt.json +1 -1
- package/dist/commonjs/i18n/locales/ru.json +1 -1
- package/dist/commonjs/i18n/locales/ta.json +1 -0
- package/dist/commonjs/i18n/locales/te.json +1 -0
- package/dist/commonjs/i18n/locales/tr.json +1 -0
- package/dist/commonjs/i18n/locales/vi.json +1 -0
- package/dist/commonjs/i18n/locales/zh.json +1 -1
- package/dist/commonjs/index.d.ts +13 -13
- package/dist/commonjs/index.js +5 -4
- package/dist/commonjs/native/NativeInspector.d.ts +1 -0
- package/dist/commonjs/socket.d.ts +4 -0
- package/dist/commonjs/socket.js +1 -0
- package/dist/commonjs/styles/index.d.ts +23 -0
- package/dist/commonjs/styles/index.js +1 -1
- package/dist/commonjs/types/enums.d.ts +40 -0
- package/dist/commonjs/types/enums.js +1 -1
- package/dist/commonjs/types/interfaces.d.ts +122 -1
- package/dist/esm/components/AnimatedBrandOwl.d.ts +7 -0
- package/dist/esm/components/AnimatedBrandOwl.js +175 -0
- package/dist/esm/components/AppHeaderLogo.d.ts +1 -0
- package/dist/esm/components/AppHeaderLogo.js +7 -5
- package/dist/esm/components/BrandSquareIcon.d.ts +5 -0
- package/dist/esm/components/BrandSquareIcon.js +139 -0
- package/dist/esm/components/ConsoleLogCard.d.ts +2 -1
- package/dist/esm/components/ConsoleLogCard.js +61 -77
- package/dist/esm/components/Inspector/AboutModal.js +85 -95
- package/dist/esm/components/Inspector/AnalyticsTab.js +31 -31
- package/dist/esm/components/Inspector/ConfirmationModal.d.ts +13 -0
- package/dist/esm/components/Inspector/ConfirmationModal.js +32 -0
- package/dist/esm/components/Inspector/ConsoleTab.js +49 -49
- package/dist/esm/components/Inspector/CrashTab.js +40 -38
- package/dist/esm/components/Inspector/DebuggingTab.js +29 -29
- package/dist/esm/components/Inspector/FabLauncher.js +50 -58
- package/dist/esm/components/Inspector/FeatureUnderDevNotice.js +7 -7
- package/dist/esm/components/Inspector/LanguageSelectorModal.d.ts +15 -0
- package/dist/esm/components/Inspector/LanguageSelectorModal.js +90 -0
- package/dist/esm/components/Inspector/MainScreen.js +123 -110
- package/dist/esm/components/Inspector/MediaGalleryTab.js +64 -62
- package/dist/esm/components/Inspector/MediaPreviewModal.js +107 -123
- package/dist/esm/components/Inspector/NetworkTab.js +90 -90
- package/dist/esm/components/Inspector/NpmUpdateToast.js +1 -1
- package/dist/esm/components/Inspector/PushCard.d.ts +3 -2
- package/dist/esm/components/Inspector/PushCard.js +23 -22
- package/dist/esm/components/Inspector/PushDetail.js +34 -25
- package/dist/esm/components/Inspector/PushTab.js +25 -25
- package/dist/esm/components/Inspector/ReduxDetail.js +42 -42
- package/dist/esm/components/Inspector/ReduxTab.js +35 -35
- package/dist/esm/components/Inspector/SettingsPanel.js +495 -376
- package/dist/esm/components/Inspector/SocketCard.d.ts +5 -0
- package/dist/esm/components/Inspector/SocketCard.js +116 -0
- package/dist/esm/components/Inspector/SocketDetail.d.ts +4 -0
- package/dist/esm/components/Inspector/SocketDetail.js +317 -0
- package/dist/esm/components/Inspector/SocketFilterModal.d.ts +13 -0
- package/dist/esm/components/Inspector/SocketFilterModal.js +69 -0
- package/dist/esm/components/Inspector/SocketTab.d.ts +3 -0
- package/dist/esm/components/Inspector/SocketTab.js +112 -0
- package/dist/esm/components/Inspector/StorageTab.js +136 -134
- package/dist/esm/components/Inspector/SupportModal.d.ts +7 -0
- package/dist/esm/components/Inspector/SupportModal.js +125 -0
- package/dist/esm/components/Inspector/SupportPage.d.ts +5 -0
- package/dist/esm/components/Inspector/SupportPage.js +227 -0
- package/dist/esm/components/Inspector/TabBar.js +36 -35
- package/dist/esm/components/Inspector/UpdateAvailableModal.js +22 -22
- package/dist/esm/components/JsonViewer.js +55 -55
- package/dist/esm/components/LogCard.d.ts +3 -2
- package/dist/esm/components/LogCard.js +61 -58
- package/dist/esm/components/LogSyntaxHighlighter.js +5 -5
- package/dist/esm/components/ModuleErrorBoundary.js +23 -23
- package/dist/esm/components/NetworkIcons.d.ts +15 -0
- package/dist/esm/components/NetworkIcons.js +38 -3
- package/dist/esm/components/SegmentedTabs.js +7 -7
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/socketLogger.d.ts +26 -0
- package/dist/esm/customHooks/socketLogger.js +2 -0
- package/dist/esm/helpers/index.js +3 -3
- package/dist/esm/helpers/memoryManager.d.ts +1 -0
- package/dist/esm/helpers/memoryManager.js +1 -1
- package/dist/esm/helpers/searchQueryParser.d.ts +1 -1
- package/dist/esm/helpers/searchQueryParser.js +5 -1
- package/dist/esm/helpers/settingsStore.d.ts +1 -0
- package/dist/esm/helpers/settingsStore.js +1 -1
- package/dist/esm/helpers/shareFormatter.d.ts +3 -1
- package/dist/esm/helpers/shareFormatter.js +8 -7
- package/dist/esm/i18n/index.d.ts +99 -1
- package/dist/esm/i18n/index.js +1 -1
- package/dist/esm/i18n/locales/ar.json +1 -1
- package/dist/esm/i18n/locales/bn.json +1 -0
- package/dist/esm/i18n/locales/de.json +1 -1
- package/dist/esm/i18n/locales/en.json +1 -1
- package/dist/esm/i18n/locales/es.json +1 -1
- package/dist/esm/i18n/locales/fr.json +1 -1
- package/dist/esm/i18n/locales/gu.json +1 -0
- package/dist/esm/i18n/locales/hi.json +1 -1
- package/dist/esm/i18n/locales/id.json +1 -0
- package/dist/esm/i18n/locales/it.json +1 -0
- package/dist/esm/i18n/locales/ja.json +1 -1
- package/dist/esm/i18n/locales/kn.json +1 -0
- package/dist/esm/i18n/locales/ko.json +1 -1
- package/dist/esm/i18n/locales/ml.json +1 -0
- package/dist/esm/i18n/locales/mr.json +1 -0
- package/dist/esm/i18n/locales/nl.json +1 -0
- package/dist/esm/i18n/locales/pa.json +1 -0
- package/dist/esm/i18n/locales/pl.json +1 -0
- package/dist/esm/i18n/locales/pt.json +1 -1
- package/dist/esm/i18n/locales/ru.json +1 -1
- package/dist/esm/i18n/locales/ta.json +1 -0
- package/dist/esm/i18n/locales/te.json +1 -0
- package/dist/esm/i18n/locales/tr.json +1 -0
- package/dist/esm/i18n/locales/vi.json +1 -0
- package/dist/esm/i18n/locales/zh.json +1 -1
- package/dist/esm/index.d.ts +13 -13
- package/dist/esm/index.js +8 -7
- package/dist/esm/native/NativeInspector.d.ts +1 -0
- package/dist/esm/socket.d.ts +4 -0
- package/dist/esm/socket.js +1 -0
- package/dist/esm/styles/index.d.ts +23 -0
- package/dist/esm/styles/index.js +1 -1
- package/dist/esm/types/enums.d.ts +40 -0
- package/dist/esm/types/enums.js +1 -1
- package/dist/esm/types/interfaces.d.ts +122 -1
- package/ios/NetworkInspectorModule.mm +102 -12
- package/package.json +204 -2
- package/src/native/NativeInspector.ts +8 -0
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
# React Native In-App Inspector (应用内全功能调试器)
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<b><a href="./README.md">English</a></b> |
|
|
5
|
+
<b><a href="./README.zh-CN.md">简体中文</a></b> |
|
|
6
|
+
<b><a href="./README.hi.md">हिन्दी</a></b> |
|
|
7
|
+
<b><a href="./README.ja.md">日本語</a></b> |
|
|
8
|
+
<b><a href="./README.es.md">Español</a></b> |
|
|
9
|
+
<b><a href="./README.de.md">Deutsch</a></b> |
|
|
10
|
+
<b><a href="./README.fr.md">Français</a></b> |
|
|
11
|
+
<b><a href="./README.pt-BR.md">Português</a></b> |
|
|
12
|
+
<b><a href="./README.ko.md">한국어</a></b> |
|
|
13
|
+
<b><a href="./README.ru.md">Русский</a></b> |
|
|
14
|
+
<b><a href="./README.ar.md">العربية</a></b>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
<picture>
|
|
19
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/vengatmacuser/react-native-inapp-inspector/main/assets/banner_light.svg">
|
|
20
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/vengatmacuser/react-native-inapp-inspector/main/assets/banner_dark.svg">
|
|
21
|
+
<img alt="React Native In-App Inspector Banner" src="https://raw.githubusercontent.com/vengatmacuser/react-native-inapp-inspector/main/assets/banner_dark.svg" width="100%">
|
|
22
|
+
</picture>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
<p align="center">
|
|
26
|
+
<a href="https://www.npmjs.com/package/react-native-inapp-inspector"><img src="https://img.shields.io/npm/v/react-native-inapp-inspector?color=6366f1&label=npm&logo=npm" alt="npm version" /></a>
|
|
27
|
+
<a href="https://www.npmjs.com/package/react-native-inapp-inspector"><img src="https://img.shields.io/npm/dm/react-native-inapp-inspector?color=3b82f6&label=downloads" alt="npm downloads" /></a>
|
|
28
|
+
<a href="https://github.com/vengatmacuser/react-native-inapp-inspector"><img src="https://img.shields.io/github/stars/vengatmacuser/react-native-inapp-inspector?color=f59e0b&label=stars&logo=github" alt="GitHub stars" /></a>
|
|
29
|
+
<a href="https://github.com/vengatmacuser/react-native-inapp-inspector/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="license" /></a>
|
|
30
|
+
<a href="https://www.npmjs.com/package/react-native-inapp-inspector"><img src="https://img.shields.io/npm/unpacked-size/react-native-inapp-inspector?color=10b981&label=size" alt="unpacked size" /></a>
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
<p align="center">
|
|
34
|
+
<img src="https://img.shields.io/badge/Platform-iOS%20%7C%20Android%20%7C%20Expo-0284c7?logo=apple&logoColor=white" alt="platform" />
|
|
35
|
+
<img src="https://img.shields.io/badge/React%20Native-%E2%89%A50.60-61DAFB?logo=react&logoColor=white" alt="React Native" />
|
|
36
|
+
<img src="https://img.shields.io/badge/Expo-SDK%2048%2B%20%7C%2050%2B%20%7C%2051%2B%20%7C%2052%2B-000020?logo=expo&logoColor=white" alt="Expo" />
|
|
37
|
+
<img src="https://img.shields.io/badge/TypeScript-Strict%20Ready-3178c6?logo=typescript&logoColor=white" alt="TypeScript" />
|
|
38
|
+
<img src="https://img.shields.io/badge/Engine-Hermes%20%7C%20JSC-9333ea" alt="Engine" />
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
<p align="center">
|
|
42
|
+
<img src="https://img.shields.io/badge/WebSockets-ws%20%7C%20wss%20%7C%20Socket.IO-06b6d4?logo=socketdotio&logoColor=white" alt="WebSockets" />
|
|
43
|
+
<img src="https://img.shields.io/badge/Storage-AsyncStorage%20%7C%20MMKV-f59e0b?logo=databricks&logoColor=white" alt="Storage" />
|
|
44
|
+
<img src="https://img.shields.io/badge/Push%20Logger-APNs%20%7C%20FCM-10b981?logo=firebase&logoColor=white" alt="Push" />
|
|
45
|
+
<img src="https://img.shields.io/badge/Localization-25%20Languages-ec4899" alt="Localization" />
|
|
46
|
+
<img src="https://img.shields.io/badge/Screen%20Capture-Video%20%7C%20GIF%20%7C%20Screenshot-8b5cf6" alt="Screen Capture" />
|
|
47
|
+
<a href="https://github.com/vengatmacuser/react-native-inapp-inspector/pulls"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs Welcome" /></a>
|
|
48
|
+
</p>
|
|
49
|
+
|
|
50
|
+
专为 **React Native & Expo** 打造的**零配置、开箱即用的应用内全功能调试器与抓包工具**。无需连接数据线、无需配置 Charles/Proxyman 证书,直接在真机或模拟器上实时监控 HTTP/HTTPS 网络流量、WebSocket 与 Socket.IO 双向数据包、Metro 符号化控制台日志、Redux 状态树差量变动、AsyncStorage 与 MMKV 实时存储、推送通知、原生硬件运行指标,以及真机屏幕录制与截图!
|
|
51
|
+
|
|
52
|
+
> 🚀 **替代 Flipper、Charles、Proxyman 与 Chucker 的现代化轻量级利器** —— 适用于日常开发、自动化测试以及独立打包测试(APK/IPA),完全摆脱电脑数据线和代理端口的束缚。
|
|
53
|
+
|
|
54
|
+
<p align="center">
|
|
55
|
+
<img src="https://raw.githubusercontent.com/vengatmacuser/react-native-inapp-inspector/main/assets/walkthrough.gif" alt="React Native In-App Inspector 演示" width="360" style="border-radius: 20px; box-shadow: 0 12px 36px rgba(0,0,0,0.5);" />
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
<p align="center">
|
|
59
|
+
🎬 <b><a href="https://raw.githubusercontent.com/vengatmacuser/react-native-inapp-inspector/main/docs/video_walkthrough.mp4">查看完整演示视频 (MP4)</a></b> | <b><a href="https://raw.githubusercontent.com/vengatmacuser/react-native-inapp-inspector/main/docs/video_walkthrough.mov">原始 MOV 格式</a></b>
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## ⚡ 核心优势与对比
|
|
65
|
+
|
|
66
|
+
| 功能特性 | **react-native-inapp-inspector** | Flipper | Charles / Proxyman | RN Debugger |
|
|
67
|
+
| :--- | :---: | :---: | :---: | :---: |
|
|
68
|
+
| **真机独立运行(脱离电脑与数据线)** | ✅ | ❌ | ❌ | ❌ |
|
|
69
|
+
| **零渲染性能开销(关闭时 0% 后台 CPU 占用)** | ✅ | ❌ | ❌ | ❌ |
|
|
70
|
+
| **HTTP/HTTPS 网络抓包 (Fetch / Axios / XHR)** | ✅ | ✅ | ✅ | ✅ |
|
|
71
|
+
| **请求耗时瀑布流与 P95 性能指标** | ✅ | ⚠️ | ⚠️ | ❌ |
|
|
72
|
+
| **一键复制 cURL 命令行与 Fetch 代码片段** | ✅ | ⚠️ | ⚠️ | ❌ |
|
|
73
|
+
| **WebSocket & Socket.IO 双向消息帧监听** | ✅ | ❌ | ⚠️ | ⚠️ |
|
|
74
|
+
| **存储查看与实时编辑 (AsyncStorage & MMKV)** | ✅ (在线增删改查) | ⚠️ (仅只读) | ❌ | ⚠️ |
|
|
75
|
+
| **推送通知日志记录 (APNs, FCM, 极光, 个推)** | ✅ | ❌ | ❌ | ❌ |
|
|
76
|
+
| **Console 日志 + Metro 符号化源码定位** | ✅ (精准定位代码行号) | ✅ | ❌ | ✅ |
|
|
77
|
+
| **Redux State 树与 Action 差量对比** | ✅ | ⚠️ | ❌ | ✅ |
|
|
78
|
+
| **崩溃防护与多类型操作面包屑 (Breadcrumbs)** | ✅ | ❌ | ❌ | ❌ |
|
|
79
|
+
| **原生硬件指标 (RAM、堆内存、存储空间、电池、FPS)**| ✅ | ⚠️ | ❌ | ❌ |
|
|
80
|
+
| **真机媒体录屏 (高清截图、MP4 录屏、动态 GIF)** | ✅ | ❌ | ❌ | ❌ |
|
|
81
|
+
| **全球 25 种语言本地化支持(底部抽屉快捷切换)** | ✅ | ❌ (仅英文) | ❌ | ❌ |
|
|
82
|
+
| **Expo (Bare / Managed) & 纯原生 React Native** | ✅ | ⚠️ | ⚠️ | ⚠️ |
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## ✨ 核心功能亮点
|
|
87
|
+
|
|
88
|
+
### 🌐 1. 网络请求抓包与耗时瀑布流 (Network & APIs)
|
|
89
|
+
- **全面拦截**:自动捕获 `fetch`、Axios(包括默认实例与 `axios.create()`)、以及底层 `XMLHttpRequest`。
|
|
90
|
+
- **耗时瀑布流分析**:直观比例条展示 DNS、请求建立、响应下载耗时,智能评级(极速 `<200ms`、普通 `200-800ms`、缓慢 `>800ms`)。
|
|
91
|
+
- **实时统计指标**:顶部常驻展示 **成功率 %**、**平均耗时 (ms)** 以及 **P95 延迟 (ms)**。
|
|
92
|
+
- **载荷解析**:树状高亮 JSON、Raw 原始报文、请求/响应 Headers、Query 参数以及调用来源文件。
|
|
93
|
+
- **一键重放**:支持一键复制为标准 **cURL 命令行** 或 **Fetch 代码片段**,方便在终端或 Postman 中重现。
|
|
94
|
+
|
|
95
|
+
### ⚡ 2. WebSocket & Socket.IO 实时通信监控
|
|
96
|
+
- **全协议覆盖**:支持标准 `ws://`、加密 `wss://` 以及 `Socket.IO v2 / v3 / v4`。
|
|
97
|
+
- **双向帧捕获时间线**:精确标注 ⬆️ 上行发送 与 ⬇️ 下行接收 数据包,附带微秒级时间戳。
|
|
98
|
+
- **多样帧类型识别**:自动解析文本 JSON 载荷、二进制字节长度(ArrayBuffer/Blob)以及 Ping/Pong 心跳包。
|
|
99
|
+
- **握手与连接生命周期**:查看连接状态、握手 Query 参数、传输模式(websocket/polling)、重连事件与断开异常。
|
|
100
|
+
|
|
101
|
+
### 💾 3. 存储实时管理 (AsyncStorage & MMKV)
|
|
102
|
+
- **统一存储引擎**:同时支持 `@react-native-async-storage/async-storage` 与极速键值存储 `react-native-mmkv`。
|
|
103
|
+
- **真机在线 CRUD**:直接在手机屏幕上浏览、检索、修改、新建或删除存储键值对。
|
|
104
|
+
- **智能类型识别**:自动识别并格式化显示 JSON 对象、数组、布尔值、数字与字符串。
|
|
105
|
+
|
|
106
|
+
### 🔔 4. 推送通知拦截器 (Push Notification Logger)
|
|
107
|
+
- **多平台适配**:自动捕获 FCM (`@react-native-firebase/messaging`)、APNs、极光推送、个推、OneSignal 与 Notifee。
|
|
108
|
+
- **应用运行状态跟踪**:精确区分通知是在 **前台 (Foreground)**、**后台 (Background)** 接收,还是通过点击通知从 **完全退出 (Killed)** 状态唤醒启动。
|
|
109
|
+
- **完整 Payload 解析**:查看附加数据参数、跳转 DeepLink、标题、内容正文与通道 ID。
|
|
110
|
+
|
|
111
|
+
### 🪵 5. 控制台日志与 Metro 源码符号化 (Console & Metro Symbolication)
|
|
112
|
+
- **精准源码定位**:拦截 `console.log`、`info`、`warn`、`error`,通过 Metro 符号化实时定位到工程源文件与真实行号(如 `HomeScreen.tsx:42:15`)。
|
|
113
|
+
- **参数单独解构**:每个入参独立卡片展示,支持展开折叠复杂数据结构。
|
|
114
|
+
- **调用栈与 Error 栈分析**:清晰排版 Call Stack 帧卡片(函数名、文件、行列号),捕获 Error 对象内置堆栈。
|
|
115
|
+
- **去重聚合**:自动折叠重复输出并标记频次计数(`×N`),避免日志轰炸。
|
|
116
|
+
|
|
117
|
+
### 🔄 6. Redux 状态与 Action 变动差量 (Redux Inspector)
|
|
118
|
+
- **Redux Toolkit 完美集成**:无缝连接 Redux Store、RTK Query 与 `redux-persist`。
|
|
119
|
+
- **Action 时间线**:按触发顺序排布 Action,记录每次派发耗时与 Payload 载荷。
|
|
120
|
+
- **深度状态 Diff 对比**:清晰标明变动项(**绿色**代表新增,**黄色**代表更新,**红色**代表移除)。
|
|
121
|
+
|
|
122
|
+
### 🛡️ 7. 全局异常捕获与微架构防崩 (Crash Protection)
|
|
123
|
+
- **微 UI 容错隔离**:调试器运行在完全隔离的环境中,即便调试器内部发生意外也绝对不会影响宿主应用。
|
|
124
|
+
- **全局 ErrorBoundary**:优雅捕获未处理的 React 渲染崩溃并提供一键恢复交互。
|
|
125
|
+
- **操作面包屑追溯**:记录崩溃发生前用户的页面跳转、最近网络请求与 Redux Action,助力秒级排查线上 Bug。
|
|
126
|
+
|
|
127
|
+
### 📱 8. 原生硬件、内存与 FPS 监控 (Hardware Telemetry)
|
|
128
|
+
- **低层原生指标**:手机总运行内存、可用空闲内存、原生堆分配、存储剩余空间、电池电量与充电状态、CPU 架构。
|
|
129
|
+
- **实时刷新率监控**:真实测量屏幕渲染 FPS。
|
|
130
|
+
- **内存警告自适应清理**:接收系统低内存广播时自动释放缓存记录,确保宿主应用平稳运行。
|
|
131
|
+
- **摇一摇唤出**:支持摇晃手机物理设备或按下 `Ctrl+Cmd+Z` / `Cmd+M` 切换调试器显隐。
|
|
132
|
+
|
|
133
|
+
### 📸 9. 原生媒体捕获套件 (截图 / 录屏 / GIF)
|
|
134
|
+
- **无状态栏裁剪高清截图**:一键生成当前界面的高保真全屏截图。
|
|
135
|
+
- **手机端屏幕录制**:直接录制操作视频(MP4),支持带麦克风语音讲解。
|
|
136
|
+
- **动态 GIF 生成**:将操作复现步骤录制并导出为轻量动图,方便粘贴到 Issue 或需求评审单中。
|
|
137
|
+
|
|
138
|
+
### 🌍 10. 全球 25 种语言与底部抽屉交互
|
|
139
|
+
- **25 种语言本地化**:简体中文 (`zh`)、繁体中文 (`zh-TW`)、英语、日语、韩语、西班牙语、法语、德语、俄语、印地语等。
|
|
140
|
+
- **现代化底部抽屉**:点击顶部工具栏 `[ 🌐 中文 ▾ ]` 即可滑出抽屉,支持横向国家徽章筛选与模糊搜索,点击即时生效并持久化记忆。
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 🔎 DevTools 高级搜索语法
|
|
145
|
+
|
|
146
|
+
顶部搜索框支持类似 Chrome DevTools 的复合多维过滤:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
# 筛选 POST 请求且状态码为 200
|
|
150
|
+
method:POST status:200
|
|
151
|
+
|
|
152
|
+
# 仅查看 myapp.com 接口,过滤掉埋点与三方请求
|
|
153
|
+
url:api.myapp.com -analytics -facebook
|
|
154
|
+
|
|
155
|
+
# 按 Header 请求头筛选
|
|
156
|
+
header:authorization
|
|
157
|
+
|
|
158
|
+
# 在请求体或响应体 JSON 中搜索关键字段
|
|
159
|
+
body:"orderId"
|
|
160
|
+
|
|
161
|
+
# 按当前所在页面路由名称筛选
|
|
162
|
+
page:CheckoutScreen
|
|
163
|
+
|
|
164
|
+
# 搜索特定 TSX 文件中打印的日志
|
|
165
|
+
file:ProfileView.tsx
|
|
166
|
+
|
|
167
|
+
# 使用负向减号排除干扰项
|
|
168
|
+
-healthcheck -socket.io
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 📦 快速安装
|
|
174
|
+
|
|
175
|
+
### 纯原生 React Native 工程
|
|
176
|
+
```bash
|
|
177
|
+
npm install --save-dev react-native-inapp-inspector react-native-svg
|
|
178
|
+
# 或使用 yarn
|
|
179
|
+
yarn add -D react-native-inapp-inspector react-native-svg
|
|
180
|
+
# 或使用 pnpm
|
|
181
|
+
pnpm add -D react-native-inapp-inspector react-native-svg
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### iOS CocoaPods 安装
|
|
185
|
+
```bash
|
|
186
|
+
cd ios && pod install && cd ..
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Expo 工程
|
|
190
|
+
```bash
|
|
191
|
+
npx expo install react-native-inapp-inspector react-native-svg
|
|
192
|
+
```
|
|
193
|
+
*(完全适配 Expo SDK 48 至 52+ 的 Expo Go 与 Prebuild 原生模式)*
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 🚀 极简集成(1分钟上手)
|
|
198
|
+
|
|
199
|
+
在应用入口根组件(如 `App.tsx` 或 `index.js`)中引入:
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
import React from 'react';
|
|
203
|
+
import { SafeAreaView } from 'react-native';
|
|
204
|
+
import NetworkInspector, {
|
|
205
|
+
setupNetworkLogger,
|
|
206
|
+
setupConsoleLogger,
|
|
207
|
+
setupSocketLogger,
|
|
208
|
+
connectReduxStore,
|
|
209
|
+
connectAsyncStorage,
|
|
210
|
+
} from 'react-native-inapp-inspector';
|
|
211
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
212
|
+
import { store } from './src/store'; // 你的 Redux Store
|
|
213
|
+
|
|
214
|
+
// ⚡ 建议在根组件挂载前初始化,确保初始化阶段的请求与日志也能完整捕获
|
|
215
|
+
setupNetworkLogger();
|
|
216
|
+
setupConsoleLogger();
|
|
217
|
+
setupSocketLogger();
|
|
218
|
+
|
|
219
|
+
if (store) {
|
|
220
|
+
connectReduxStore(store);
|
|
221
|
+
}
|
|
222
|
+
connectAsyncStorage(AsyncStorage);
|
|
223
|
+
|
|
224
|
+
export default function App() {
|
|
225
|
+
return (
|
|
226
|
+
<SafeAreaView style={{ flex: 1 }}>
|
|
227
|
+
{/* 你的业务组件与页面 */}
|
|
228
|
+
<YourAppRoot />
|
|
229
|
+
|
|
230
|
+
{/* 仅在开发环境显示悬浮调试器 */}
|
|
231
|
+
{__DEV__ && (
|
|
232
|
+
<NetworkInspector
|
|
233
|
+
enabled={true}
|
|
234
|
+
environment="DEV"
|
|
235
|
+
/>
|
|
236
|
+
)}
|
|
237
|
+
</SafeAreaView>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 💡 典型场景与进阶用法
|
|
245
|
+
|
|
246
|
+
### 1. 拦截 WebSocket / Socket.IO 通信
|
|
247
|
+
```typescript
|
|
248
|
+
import { setupSocketLogger, recordSocketFrame } from 'react-native-inapp-inspector/socket';
|
|
249
|
+
|
|
250
|
+
// 开启全局 WebSocket 自动拦截
|
|
251
|
+
setupSocketLogger();
|
|
252
|
+
|
|
253
|
+
// 手动录入自定义消息帧:
|
|
254
|
+
recordSocketFrame(connectionId, {
|
|
255
|
+
direction: 'in', // 'in' | 'out'
|
|
256
|
+
type: 'json',
|
|
257
|
+
data: { event: 'PAYMENT_SUCCESS', orderId: '20260912' },
|
|
258
|
+
});
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### 2. 调试 AsyncStorage 与 MMKV 本地存储
|
|
262
|
+
```typescript
|
|
263
|
+
// 连接 AsyncStorage
|
|
264
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
265
|
+
import { connectAsyncStorage } from 'react-native-inapp-inspector/storage';
|
|
266
|
+
|
|
267
|
+
connectAsyncStorage(AsyncStorage);
|
|
268
|
+
|
|
269
|
+
// 连接 MMKV
|
|
270
|
+
import { MMKV } from 'react-native-mmkv';
|
|
271
|
+
import { connectMMKV } from 'react-native-inapp-inspector/storage';
|
|
272
|
+
|
|
273
|
+
export const storage = new MMKV();
|
|
274
|
+
connectMMKV(storage, 'default');
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### 3. 拦截与测试推送通知
|
|
278
|
+
```typescript
|
|
279
|
+
import { autoSetupPushLogger, recordPushNotification } from 'react-native-inapp-inspector/push';
|
|
280
|
+
|
|
281
|
+
// 自动连接支持的推送 SDK
|
|
282
|
+
autoSetupPushLogger();
|
|
283
|
+
|
|
284
|
+
// 手动记录推送通知
|
|
285
|
+
recordPushNotification({
|
|
286
|
+
title: '双十一特惠提醒',
|
|
287
|
+
body: '您关注的商品降价啦,速来抢购!',
|
|
288
|
+
source: 'fcm',
|
|
289
|
+
appState: 'foreground',
|
|
290
|
+
data: { skuId: '10086', deepLink: 'myapp://product/10086' },
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### 4. 屏幕截图与录屏 API
|
|
295
|
+
```typescript
|
|
296
|
+
import { ScreenCapture } from 'react-native-inapp-inspector/capture';
|
|
297
|
+
|
|
298
|
+
// 真机截图
|
|
299
|
+
const screenshot = await ScreenCapture.takeScreenshot({ format: 'png' });
|
|
300
|
+
console.log('截图文件路径:', screenshot.uri);
|
|
301
|
+
|
|
302
|
+
// 开始录制视频
|
|
303
|
+
await ScreenCapture.startRecording({
|
|
304
|
+
audioSource: 'mic', // 'mic' | 'app' | 'none'
|
|
305
|
+
format: 'mp4',
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
// 结束录制
|
|
309
|
+
const video = await ScreenCapture.stopRecording();
|
|
310
|
+
console.log('录屏文件生成:', video.uri, video.duration);
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### 5. 多语言编程控制接口
|
|
314
|
+
```typescript
|
|
315
|
+
import { setLanguage, getLanguage } from 'react-native-inapp-inspector';
|
|
316
|
+
|
|
317
|
+
// 切换为简体中文
|
|
318
|
+
setLanguage('zh');
|
|
319
|
+
|
|
320
|
+
console.log('当前语言:', getLanguage());
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## 📱 模块化轻量导入 (Tree-shaking)
|
|
326
|
+
|
|
327
|
+
若你的应用仅需要部分功能,可按需导入子模块以最小化包体积:
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import { setupNetworkLogger } from 'react-native-inapp-inspector/network';
|
|
331
|
+
import { setupSocketLogger } from 'react-native-inapp-inspector/socket';
|
|
332
|
+
import { connectAsyncStorage, connectMMKV } from 'react-native-inapp-inspector/storage';
|
|
333
|
+
import { autoSetupPushLogger } from 'react-native-inapp-inspector/push';
|
|
334
|
+
import { connectReduxStore, inspectorReduxMiddleware } from 'react-native-inapp-inspector/redux';
|
|
335
|
+
import { setupConsoleLogger } from 'react-native-inapp-inspector/console';
|
|
336
|
+
import { ScreenCapture } from 'react-native-inapp-inspector/capture';
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## 📚 常用 API 清单
|
|
342
|
+
|
|
343
|
+
| API 名称 | 类型 | 功能说明 |
|
|
344
|
+
| :--- | :--- | :--- |
|
|
345
|
+
| `<NetworkInspector />` | 组件 | 应用内悬浮调试球及主交互弹窗。 |
|
|
346
|
+
| `setupNetworkLogger()` | 方法 | 拦截全局 `fetch`、Axios 及 XMLHttpRequest。 |
|
|
347
|
+
| `setupConsoleLogger()` | 方法 | 拦截 `console.log/warn/error` 并通过 Metro 自动解析源码行列号。 |
|
|
348
|
+
| `setupSocketLogger()` | 方法 | 自动拦截 WebSocket 及 Socket.IO 双向消息流。 |
|
|
349
|
+
| `connectReduxStore(store)` | 方法 | 连接 Redux Store,开启 Action 时间线与 State 树差量对比。 |
|
|
350
|
+
| `connectAsyncStorage(storage)` | 方法 | 连接 AsyncStorage 并在 Storage 选项卡中开启实时编辑。 |
|
|
351
|
+
| `connectMMKV(instance, id?)` | 方法 | 连接 MMKV 并在 Storage 选项卡中开启实时编辑。 |
|
|
352
|
+
| `autoSetupPushLogger()` | 方法 | 自动监听并记录接收到的推送通知。 |
|
|
353
|
+
| `ScreenCapture` | 对象 | 提供真机截图、视频录屏及 GIF 导出的完整原生 API。 |
|
|
354
|
+
| `getNativeDeviceMetrics()` | 方法 | 获取手机运行内存、堆分配、磁盘剩余、电池状态等低层指标。 |
|
|
355
|
+
| `setupGlobalCrashHandler()` | 方法 | 捕获全局未处理的 JS 异常并串联前序用户操作面包屑。 |
|
|
356
|
+
| `setLanguage(code)` | 方法 | 动态设置调试器语种(支持全球 25 种主流语言)。 |
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## 🤝 参与贡献
|
|
361
|
+
|
|
362
|
+
欢迎社区贡献!如有 Bug 反馈或新功能想法,欢迎查阅 [CONTRIBUTING.md](CONTRIBUTING.md) 并提交 Issue 或 Pull Request。
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## 💖 支持与赞助
|
|
367
|
+
|
|
368
|
+
`react-native-inapp-inspector` 是由作者在业余时间维护的开源免费项目。如果它为您和团队节省了宝贵的排查时间,欢迎在 GitHub 上点亮一个小星星 ⭐️,或通过 GitHub Sponsors 给予赞助支持!
|
|
369
|
+
|
|
370
|
+
👉 **[在 GitHub Sponsors 上赞助作者 @vengatmacuser](https://github.com/sponsors/vengatmacuser)**
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## 🔍 中文与全球搜索关键词 (Keywords)
|
|
375
|
+
|
|
376
|
+
为了方便中文开发者在百度、Google、GitHub 及 npm 快速检索到本工具,本项目针对常见开发痛点整理了高频搜索词:
|
|
377
|
+
|
|
378
|
+
* **核心痛点检索**:React Native 抓包工具、移动端免电脑抓包、真机抓包、APP 请求监听、网络监控面板、移动端控制台、React Native 调试器、前端移动端 DevTools、接口报错定位。
|
|
379
|
+
* **替代工具检索**:Flipper 替代方案 (Flipper alternative)、Charles 替代、Chucker React Native 版、Proxyman 替代、Whistle 替代、Reactotron 替代。
|
|
380
|
+
* **协议与存储**:WebSocket 实时抓包、Socket.io 帧监听、MMKV 可视化编辑器、AsyncStorage 数据查看、Redux 状态时间旅行、Firebase 埋点事件追踪。
|
|
381
|
+
* **地区生态**:中国大陆 (China)、台湾 (Taiwan)、香港 (Hong Kong)、新加坡 (Singapore) 开发者常用移动端联调利器。
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## 📄 开源协议
|
|
386
|
+
|
|
387
|
+
本项目基于 [MIT License](./LICENSE) 协议开源。
|
|
@@ -14,6 +14,7 @@ import android.os.Build
|
|
|
14
14
|
import android.os.Debug
|
|
15
15
|
import android.os.Environment
|
|
16
16
|
import android.os.Handler
|
|
17
|
+
import android.os.HandlerThread
|
|
17
18
|
import android.os.Looper
|
|
18
19
|
import android.os.StatFs
|
|
19
20
|
import android.util.Base64
|
|
@@ -37,6 +38,7 @@ import java.io.StringWriter
|
|
|
37
38
|
import java.util.Timer
|
|
38
39
|
import java.util.TimerTask
|
|
39
40
|
import java.util.concurrent.Executors
|
|
41
|
+
import java.util.concurrent.atomic.AtomicBoolean
|
|
40
42
|
|
|
41
43
|
|
|
42
44
|
class NetworkInspectorModule(private val reactContext: ReactApplicationContext) :
|
|
@@ -60,6 +62,9 @@ class NetworkInspectorModule(private val reactContext: ReactApplicationContext)
|
|
|
60
62
|
private var recordingTimer: Timer? = null
|
|
61
63
|
private val recordedFrames = mutableListOf<Bitmap>()
|
|
62
64
|
private var recordingFps = 15
|
|
65
|
+
private val isFrameCapturing = AtomicBoolean(false)
|
|
66
|
+
private var captureHandlerThread: HandlerThread? = null
|
|
67
|
+
private var captureBackgroundHandler: Handler? = null
|
|
63
68
|
|
|
64
69
|
private var defaultHandler: Thread.UncaughtExceptionHandler? = null
|
|
65
70
|
private var isProtectionEnabled = false
|
|
@@ -69,6 +74,34 @@ class NetworkInspectorModule(private val reactContext: ReactApplicationContext)
|
|
|
69
74
|
return MODULE_NAME
|
|
70
75
|
}
|
|
71
76
|
|
|
77
|
+
override fun getConstants(): MutableMap<String, Any> {
|
|
78
|
+
val constants = HashMap<String, Any>()
|
|
79
|
+
try {
|
|
80
|
+
val packageManager = reactContext.packageManager
|
|
81
|
+
val packageName = reactContext.packageName
|
|
82
|
+
val packageInfo = packageManager.getPackageInfo(packageName, 0)
|
|
83
|
+
val appInfo = packageManager.getApplicationInfo(packageName, 0)
|
|
84
|
+
val appName = packageManager.getApplicationLabel(appInfo).toString()
|
|
85
|
+
val appVersion = packageInfo.versionName ?: "1.0"
|
|
86
|
+
val appBuild = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
87
|
+
packageInfo.longVersionCode.toString()
|
|
88
|
+
} else {
|
|
89
|
+
@Suppress("DEPRECATION")
|
|
90
|
+
packageInfo.versionCode.toString()
|
|
91
|
+
}
|
|
92
|
+
constants["appName"] = appName
|
|
93
|
+
constants["appVersion"] = appVersion
|
|
94
|
+
constants["appBuild"] = appBuild
|
|
95
|
+
constants["appPackageName"] = packageName
|
|
96
|
+
constants["appBundleId"] = packageName
|
|
97
|
+
} catch (e: Exception) {
|
|
98
|
+
constants["appName"] = "App"
|
|
99
|
+
constants["appVersion"] = "1.0"
|
|
100
|
+
constants["appBuild"] = "1"
|
|
101
|
+
}
|
|
102
|
+
return constants
|
|
103
|
+
}
|
|
104
|
+
|
|
72
105
|
private fun setupNativeCrashProtection() {
|
|
73
106
|
if (isProtectionEnabled) return
|
|
74
107
|
|
|
@@ -715,7 +748,8 @@ class NetworkInspectorModule(private val reactContext: ReactApplicationContext)
|
|
|
715
748
|
return
|
|
716
749
|
}
|
|
717
750
|
|
|
718
|
-
Handler(Looper.getMainLooper())
|
|
751
|
+
val mainHandler = Handler(Looper.getMainLooper())
|
|
752
|
+
mainHandler.post {
|
|
719
753
|
try {
|
|
720
754
|
val decorView = targetWindow.decorView
|
|
721
755
|
val metrics = reactContext.resources.displayMetrics
|
|
@@ -725,22 +759,19 @@ class NetworkInspectorModule(private val reactContext: ReactApplicationContext)
|
|
|
725
759
|
val targetHeight = (origHeight * scale).toInt().coerceAtLeast(1)
|
|
726
760
|
|
|
727
761
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
728
|
-
val
|
|
762
|
+
val destBitmap = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888)
|
|
763
|
+
val copyHandler = captureBackgroundHandler ?: mainHandler
|
|
729
764
|
try {
|
|
730
|
-
PixelCopy.request(targetWindow, null,
|
|
765
|
+
PixelCopy.request(targetWindow, null, destBitmap, { copyResult ->
|
|
731
766
|
if (copyResult == PixelCopy.SUCCESS) {
|
|
732
|
-
|
|
733
|
-
val scaled = Bitmap.createScaledBitmap(rawBitmap, targetWidth, targetHeight, true)
|
|
734
|
-
if (scaled != rawBitmap) rawBitmap.recycle()
|
|
735
|
-
callback(scaled)
|
|
736
|
-
} else {
|
|
737
|
-
callback(rawBitmap)
|
|
738
|
-
}
|
|
767
|
+
callback(destBitmap)
|
|
739
768
|
} else {
|
|
769
|
+
destBitmap.recycle()
|
|
740
770
|
fallbackCanvasCapture(decorView, targetWidth, targetHeight, scale, callback)
|
|
741
771
|
}
|
|
742
|
-
},
|
|
772
|
+
}, copyHandler)
|
|
743
773
|
} catch (e: Exception) {
|
|
774
|
+
destBitmap.recycle()
|
|
744
775
|
fallbackCanvasCapture(decorView, targetWidth, targetHeight, scale, callback)
|
|
745
776
|
}
|
|
746
777
|
} else {
|
|
@@ -864,12 +895,23 @@ class NetworkInspectorModule(private val reactContext: ReactApplicationContext)
|
|
|
864
895
|
recordedFrames.clear()
|
|
865
896
|
}
|
|
866
897
|
|
|
867
|
-
val fps = if (options.hasKey("fps")) options.getInt("fps").coerceIn(5,
|
|
898
|
+
val fps = if (options.hasKey("fps")) options.getInt("fps").coerceIn(5, 60) else 30
|
|
899
|
+
val scale = if (options.hasKey("scale")) options.getDouble("scale").toFloat().coerceIn(0.2f, 1.0f) else 0.5f
|
|
900
|
+
val maxDuration = if (options.hasKey("maxDurationSeconds")) options.getInt("maxDurationSeconds").coerceIn(5, 300) else 120
|
|
868
901
|
recordingFps = fps
|
|
869
|
-
val intervalMs = (1000L / fps).coerceAtLeast(
|
|
902
|
+
val intervalMs = (1000L / fps).coerceAtLeast(16L)
|
|
903
|
+
val maxFrames = (fps * maxDuration).coerceAtMost(3600)
|
|
870
904
|
isRecordingVideo = true
|
|
905
|
+
isFrameCapturing.set(false)
|
|
871
906
|
recordingStartTime = System.currentTimeMillis()
|
|
872
907
|
|
|
908
|
+
if (captureHandlerThread == null) {
|
|
909
|
+
val ht = HandlerThread("InAppInspector-PixelCopy")
|
|
910
|
+
ht.start()
|
|
911
|
+
captureHandlerThread = ht
|
|
912
|
+
captureBackgroundHandler = Handler(ht.looper)
|
|
913
|
+
}
|
|
914
|
+
|
|
873
915
|
recordingTimer = Timer("InAppInspector-Recorder", true).apply {
|
|
874
916
|
scheduleAtFixedRate(object : TimerTask() {
|
|
875
917
|
override fun run() {
|
|
@@ -877,16 +919,34 @@ class NetworkInspectorModule(private val reactContext: ReactApplicationContext)
|
|
|
877
919
|
cancel()
|
|
878
920
|
return
|
|
879
921
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
922
|
+
if (!isFrameCapturing.compareAndSet(false, true)) {
|
|
923
|
+
// Previous frame still copying or processing; drop tick to guarantee smooth scrolling
|
|
924
|
+
return
|
|
925
|
+
}
|
|
926
|
+
// Auto-stop if max duration exceeded
|
|
927
|
+
val elapsed = System.currentTimeMillis() - recordingStartTime
|
|
928
|
+
if (elapsed > maxDuration * 1000L) {
|
|
929
|
+
isFrameCapturing.set(false)
|
|
930
|
+
return
|
|
931
|
+
}
|
|
932
|
+
val curWindow = getActiveWindow()
|
|
933
|
+
if (curWindow == null) {
|
|
934
|
+
isFrameCapturing.set(false)
|
|
935
|
+
return
|
|
936
|
+
}
|
|
937
|
+
captureWindowBitmap(curWindow, scale) { frame ->
|
|
938
|
+
try {
|
|
939
|
+
if (frame != null && isRecordingVideo) {
|
|
940
|
+
synchronized(recordedFrames) {
|
|
941
|
+
if (recordedFrames.size < maxFrames) {
|
|
942
|
+
recordedFrames.add(frame)
|
|
943
|
+
} else {
|
|
944
|
+
frame.recycle()
|
|
945
|
+
}
|
|
888
946
|
}
|
|
889
947
|
}
|
|
948
|
+
} finally {
|
|
949
|
+
isFrameCapturing.set(false)
|
|
890
950
|
}
|
|
891
951
|
}
|
|
892
952
|
}
|
|
@@ -906,6 +966,7 @@ class NetworkInspectorModule(private val reactContext: ReactApplicationContext)
|
|
|
906
966
|
isRecordingVideo = false
|
|
907
967
|
recordingTimer?.cancel()
|
|
908
968
|
recordingTimer = null
|
|
969
|
+
isFrameCapturing.set(false)
|
|
909
970
|
|
|
910
971
|
val durationMs = (System.currentTimeMillis() - recordingStartTime).coerceAtLeast(500L)
|
|
911
972
|
val timestamp = System.currentTimeMillis()
|