react-native-debug-toolkit 0.3.0 → 0.4.0

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.md CHANGED
@@ -10,6 +10,24 @@ npm install react-native-debug-toolkit
10
10
  yarn add react-native-debug-toolkit
11
11
  ```
12
12
 
13
+ ### iOS Additional Setup
14
+
15
+ This toolkit uses FLEX and DoraemonKit for iOS debugging features. To properly integrate:
16
+
17
+ 1. Make sure CocoaPods is installed in your project
18
+ 2. Add these dependencies to your Podfile:
19
+
20
+ ```ruby
21
+ pod 'FLEX', :configurations => ['Debug']
22
+ pod 'DoraemonKit/Core', :configurations => ['Debug']
23
+ ```
24
+
25
+ 3. Run pod install in your iOS directory:
26
+
27
+ ```bash
28
+ cd ios && pod install
29
+ ```
30
+
13
31
  ## Basic Usage
14
32
 
15
33
  ```javascript
@@ -4,7 +4,6 @@ import com.facebook.react.bridge.ReactApplicationContext;
4
4
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
5
5
  import com.facebook.react.bridge.ReactMethod;
6
6
  import com.facebook.react.bridge.Promise;
7
- import com.facebook.react.bridge.Callback;
8
7
 
9
8
  import java.util.HashMap;
10
9
  import java.util.Map;
@@ -25,36 +24,13 @@ public class BuildTypeModule extends ReactContextBaseJavaModule {
25
24
  @Override
26
25
  public Map<String, Object> getConstants() {
27
26
  final Map<String, Object> constants = new HashMap<>();
28
- constants.put("isDebug", BuildConfig.DEBUG);
27
+ constants.put("buildType", BuildConfig.DEBUG ? "debug" : "release");
29
28
  return constants;
30
29
  }
31
30
 
32
- @ReactMethod
33
- public void isDebugMode(Promise promise) {
34
- try {
35
- promise.resolve(BuildConfig.DEBUG);
36
- } catch (Exception e) {
37
- promise.reject("ERR_UNEXPECTED", e.getMessage(), e);
38
- }
39
- }
40
-
41
- @ReactMethod
42
- public void isReleaseMode(Promise promise) {
43
- try {
44
- promise.resolve(!BuildConfig.DEBUG);
45
- } catch (Exception e) {
46
- promise.reject("ERR_UNEXPECTED", e.getMessage(), e);
47
- }
48
- }
49
-
50
- @ReactMethod(isBlockingSynchronousMethod = true)
51
- public Boolean isDebugModeSync() {
52
- return BuildConfig.DEBUG;
53
- }
54
-
55
31
  @ReactMethod(isBlockingSynchronousMethod = true)
56
- public Boolean isReleaseModeSync() {
57
- return !BuildConfig.DEBUG;
32
+ public String getBuildTypeSync() {
33
+ return BuildConfig.DEBUG ? "debug" : "release";
58
34
  }
59
35
 
60
36
  @ReactMethod
@@ -0,0 +1,65 @@
1
+ package com.reactnative.debuglibs;
2
+
3
+ import android.app.Application;
4
+ import androidx.annotation.NonNull;
5
+
6
+ import com.facebook.react.bridge.ReactApplicationContext;
7
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
8
+ import com.facebook.react.bridge.ReactMethod;
9
+
10
+ import com.didichuxing.doraemonkit.DoKit;
11
+ import com.didichuxing.doraemonkit.kit.AbstractKit;
12
+
13
+ import java.util.ArrayList;
14
+ import java.util.List;
15
+
16
+ public class RNDebugLibsModule extends ReactContextBaseJavaModule {
17
+ private final ReactApplicationContext reactContext;
18
+
19
+ public RNDebugLibsModule(ReactApplicationContext reactContext) {
20
+ super(reactContext);
21
+ this.reactContext = reactContext;
22
+ }
23
+
24
+ @NonNull
25
+ @Override
26
+ public String getName() {
27
+ return "RNDebugLibs";
28
+ }
29
+
30
+ @ReactMethod
31
+ public void showExplorer() {
32
+ // FLEX is iOS only
33
+ }
34
+
35
+ @ReactMethod
36
+ public void hideExplorer() {
37
+ // FLEX is iOS only
38
+ }
39
+
40
+ @ReactMethod
41
+ public void toggleExplorer() {
42
+ // FLEX is iOS only
43
+ }
44
+
45
+ @ReactMethod
46
+ public void installDoraemonKit(String productId) {
47
+ Application app = (Application) reactContext.getApplicationContext();
48
+ List<AbstractKit> kits = new ArrayList<>();
49
+ // Initialize DoKit with custom kits if needed
50
+ DoKit.Builder(app)
51
+ .productId(productId)
52
+ .customKits(kits)
53
+ .build();
54
+ }
55
+
56
+ @ReactMethod
57
+ public void showDoraemonKit() {
58
+ DoKit.showToolPanel();
59
+ }
60
+
61
+ @ReactMethod
62
+ public void hideDoraemonKit() {
63
+ DoKit.hideToolPanel();
64
+ }
65
+ }
@@ -0,0 +1,28 @@
1
+ package com.reactnative.debuglibs;
2
+
3
+ import androidx.annotation.NonNull;
4
+
5
+ import com.facebook.react.ReactPackage;
6
+ import com.facebook.react.bridge.NativeModule;
7
+ import com.facebook.react.bridge.ReactApplicationContext;
8
+ import com.facebook.react.uimanager.ViewManager;
9
+
10
+ import java.util.ArrayList;
11
+ import java.util.Collections;
12
+ import java.util.List;
13
+
14
+ public class RNDebugLibsPackage implements ReactPackage {
15
+ @NonNull
16
+ @Override
17
+ public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
18
+ List<NativeModule> modules = new ArrayList<>();
19
+ modules.add(new RNDebugLibsModule(reactContext));
20
+ return modules;
21
+ }
22
+
23
+ @NonNull
24
+ @Override
25
+ public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
26
+ return Collections.emptyList();
27
+ }
28
+ }
package/index.js CHANGED
@@ -9,6 +9,8 @@ import { createNetworkFeature } from './lib/features/NetworkFeature'
9
9
  import { createPerformanceFeature } from './lib/features/PerformanceFeature'
10
10
  import { createConsoleLogFeature } from './lib/features/ConsoleLogFeature'
11
11
  import { createZustandLogFeature, addZustandLog } from './lib/features/ZustandLogFeature'
12
+ import { createNavigationLogFeature, addNavigationLog } from './lib/features/NavigationLogFeature'
13
+ import { useNavigationLogger } from './lib/hooks/useNavigationLogger'
12
14
 
13
15
  export {
14
16
  DebugToolKit,
@@ -17,7 +19,10 @@ export {
17
19
  createPerformanceFeature,
18
20
  createConsoleLogFeature,
19
21
  createZustandLogFeature,
20
- addZustandLog
22
+ addZustandLog,
23
+ createNavigationLogFeature,
24
+ addNavigationLog,
25
+ useNavigationLogger
21
26
  }
22
27
 
23
28
  export default DebugToolKit
@@ -1,4 +1,9 @@
1
1
  #import <React/RCTBridgeModule.h>
2
2
 
3
+ /**
4
+ * BuildTypeModule
5
+ * Native module that provides information about the current build type (debug or release)
6
+ * Used to conditionally enable debugging tools only in debug builds
7
+ */
3
8
  @interface BuildTypeModule : NSObject <RCTBridgeModule>
4
9
  @end
@@ -12,49 +12,20 @@ RCT_EXPORT_MODULE();
12
12
  - (NSDictionary *)constantsToExport
13
13
  {
14
14
  #ifdef DEBUG
15
- BOOL isDebug = YES;
15
+ NSString *buildType = @"debug";
16
16
  #else
17
- BOOL isDebug = NO;
17
+ NSString *buildType = @"release";
18
18
  #endif
19
19
 
20
- return @{ @"isDebug": @(isDebug) };
20
+ return @{ @"buildType": buildType };
21
21
  }
22
22
 
23
- RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isDebugModeSync)
23
+ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getBuildTypeSync)
24
24
  {
25
25
  #ifdef DEBUG
26
- return @(YES);
26
+ return @"debug";
27
27
  #else
28
- return @(NO);
29
- #endif
30
- }
31
-
32
- RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isReleaseModeSync)
33
- {
34
- #ifdef DEBUG
35
- return @(NO);
36
- #else
37
- return @(YES);
38
- #endif
39
- }
40
-
41
- RCT_EXPORT_METHOD(isDebugMode:(RCTPromiseResolveBlock)resolve
42
- rejecter:(RCTPromiseRejectBlock)reject)
43
- {
44
- #ifdef DEBUG
45
- resolve(@(YES));
46
- #else
47
- resolve(@(NO));
48
- #endif
49
- }
50
-
51
- RCT_EXPORT_METHOD(isReleaseMode:(RCTPromiseResolveBlock)resolve
52
- rejecter:(RCTPromiseRejectBlock)reject)
53
- {
54
- #ifdef DEBUG
55
- resolve(@(NO));
56
- #else
57
- resolve(@(YES));
28
+ return @"release";
58
29
  #endif
59
30
  }
60
31
 
@@ -0,0 +1,10 @@
1
+ #import <React/RCTBridgeModule.h>
2
+
3
+ /**
4
+ * RNDebugLibs
5
+ * Native module that provides access to FLEX and DoraemonKit debugging tools
6
+ * Note: These debugging tools are only available in DEBUG builds
7
+ */
8
+ @interface RNDebugLibs : NSObject <RCTBridgeModule>
9
+
10
+ @end
@@ -0,0 +1,79 @@
1
+ #import "RNDebugLibs.h"
2
+
3
+ #ifdef DEBUG
4
+ #import "FLEXManager.h"
5
+ #import <DoraemonKit/DoraemonManager.h>
6
+ #endif
7
+
8
+ @implementation RNDebugLibs
9
+
10
+ // Export the module
11
+ RCT_EXPORT_MODULE();
12
+
13
+ RCT_EXPORT_METHOD(showExplorer)
14
+ {
15
+ #ifdef DEBUG
16
+ dispatch_async(dispatch_get_main_queue(), ^{
17
+ [[FLEXManager sharedManager] showExplorer];
18
+ });
19
+ #else
20
+ NSLog(@"[RNDebugLibs] showExplorer is only available in DEBUG builds");
21
+ #endif
22
+ }
23
+
24
+ RCT_EXPORT_METHOD(hideExplorer)
25
+ {
26
+ #ifdef DEBUG
27
+ dispatch_async(dispatch_get_main_queue(), ^{
28
+ [[FLEXManager sharedManager] hideExplorer];
29
+ });
30
+ #else
31
+ NSLog(@"[RNDebugLibs] hideExplorer is only available in DEBUG builds");
32
+ #endif
33
+ }
34
+
35
+ RCT_EXPORT_METHOD(toggleExplorer)
36
+ {
37
+ #ifdef DEBUG
38
+ dispatch_async(dispatch_get_main_queue(), ^{
39
+ [[FLEXManager sharedManager] toggleExplorer];
40
+ });
41
+ #else
42
+ NSLog(@"[RNDebugLibs] toggleExplorer is only available in DEBUG builds");
43
+ #endif
44
+ }
45
+
46
+ RCT_EXPORT_METHOD(installDoraemonKit:(NSString *)productId)
47
+ {
48
+ #ifdef DEBUG
49
+ dispatch_async(dispatch_get_main_queue(), ^{
50
+ [[DoraemonManager shareInstance] installWithPid:productId];
51
+ });
52
+ #else
53
+ NSLog(@"[RNDebugLibs] installDoraemonKit is only available in DEBUG builds");
54
+ #endif
55
+ }
56
+
57
+ RCT_EXPORT_METHOD(showDoraemonKit)
58
+ {
59
+ #ifdef DEBUG
60
+ dispatch_async(dispatch_get_main_queue(), ^{
61
+ [[DoraemonManager shareInstance] showDoraemon];
62
+ });
63
+ #else
64
+ NSLog(@"[RNDebugLibs] showDoraemonKit is only available in DEBUG builds");
65
+ #endif
66
+ }
67
+
68
+ RCT_EXPORT_METHOD(hideDoraemonKit)
69
+ {
70
+ #ifdef DEBUG
71
+ dispatch_async(dispatch_get_main_queue(), ^{
72
+ [[DoraemonManager shareInstance] hiddenDoraemon];
73
+ });
74
+ #else
75
+ NSLog(@"[RNDebugLibs] hideDoraemonKit is only available in DEBUG builds");
76
+ #endif
77
+ }
78
+
79
+ @end
@@ -0,0 +1,43 @@
1
+ import { NativeModules, Platform } from 'react-native'
2
+
3
+ const { RNDebugLibs } = NativeModules
4
+
5
+ export default class NativeDebugLibs {
6
+ // FLEX methods (iOS only)
7
+ static showExplorer() {
8
+ if (Platform.OS === 'ios' && RNDebugLibs) {
9
+ RNDebugLibs.showExplorer()
10
+ }
11
+ }
12
+
13
+ static hideExplorer() {
14
+ if (Platform.OS === 'ios' && RNDebugLibs) {
15
+ RNDebugLibs.hideExplorer()
16
+ }
17
+ }
18
+
19
+ static toggleExplorer() {
20
+ if (Platform.OS === 'ios' && RNDebugLibs) {
21
+ RNDebugLibs.toggleExplorer()
22
+ }
23
+ }
24
+
25
+ // DoraemonKit/DoKit methods
26
+ static installDoraemonKit(productId) {
27
+ if (RNDebugLibs) {
28
+ RNDebugLibs.installDoraemonKit(productId)
29
+ }
30
+ }
31
+
32
+ static showDoraemonKit() {
33
+ if (RNDebugLibs) {
34
+ RNDebugLibs.showDoraemonKit()
35
+ }
36
+ }
37
+
38
+ static hideDoraemonKit() {
39
+ if (RNDebugLibs) {
40
+ RNDebugLibs.hideDoraemonKit()
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,47 @@
1
+ const MAX_LOGS = 200; // Max number of navigation logs to store
2
+ const logs = [];
3
+ const originalNavigationMethods = {}; // Store original navigation methods
4
+
5
+ const setup = () => {
6
+ if (!__DEV__) {
7
+ return;
8
+ }
9
+ // Note: Actual navigation interception will be done in the main app code
10
+ // This is just a setup function for compatibility with the feature API
11
+ };
12
+
13
+ // Function to add navigation log
14
+ export const addNavigationLog = (action, from, to, startTime, duration) => {
15
+ // Store log data
16
+ logs.push({
17
+ timestamp: new Date(),
18
+ action: action, // push, pop, replace, etc.
19
+ from: from, // source route info
20
+ to: to, // destination route info
21
+ startTime: startTime,
22
+ duration: duration,
23
+ });
24
+
25
+ // Trim logs if they exceed the maximum limit
26
+ if (logs.length > MAX_LOGS) {
27
+ logs.splice(0, logs.length - MAX_LOGS);
28
+ }
29
+ };
30
+
31
+ const getData = () => {
32
+ return logs;
33
+ };
34
+
35
+ const cleanup = () => {
36
+ logs.length = 0; // Clear array
37
+ };
38
+
39
+ export const createNavigationLogFeature = () => {
40
+ return {
41
+ name: 'navigation',
42
+ label: 'Navigation Logs',
43
+ setup: setup,
44
+ getData: getData,
45
+ cleanup: cleanup,
46
+ };
47
+ };
@@ -0,0 +1,65 @@
1
+ import { Platform } from 'react-native';
2
+ import NativeDebugLibs from '../NativeDebugLibs';
3
+
4
+ // Define available third-party debug libraries
5
+ const availableLibs = [
6
+ {
7
+ id: 'flex',
8
+ name: 'FLEX',
9
+ description: 'In-app debugging and exploration tool for iOS',
10
+ platform: 'ios',
11
+ icon: 'tools',
12
+ actions: [
13
+ { id: 'showExplorer', label: 'Show Explorer', method: NativeDebugLibs.showExplorer },
14
+ { id: 'hideExplorer', label: 'Hide Explorer', method: NativeDebugLibs.hideExplorer },
15
+ ]
16
+ },
17
+ {
18
+ id: 'doraemonkit',
19
+ name: 'DoraemonKit',
20
+ description: 'A full-featured iOS & Android development assistant',
21
+ platform: 'both',
22
+ icon: 'box',
23
+ actions: [
24
+ { id: 'showDoraemonKit', label: 'Show DoraemonKit', method: NativeDebugLibs.showDoraemonKit },
25
+ { id: 'hideDoraemonKit', label: 'Hide DoraemonKit', method: NativeDebugLibs.hideDoraemonKit },
26
+ ]
27
+ }
28
+ ];
29
+
30
+ // Get libraries available for current platform
31
+ const getPlatformLibs = () => {
32
+ const currentPlatform = Platform.OS;
33
+ return availableLibs.filter(lib =>
34
+ lib.platform === 'both' || lib.platform === currentPlatform
35
+ );
36
+ };
37
+
38
+ // Setup function is minimal since we're just presenting UI options
39
+ const setup = () => {
40
+ if (!__DEV__) {
41
+ return;
42
+ }
43
+ // No additional setup needed beyond initialization
44
+ };
45
+
46
+ // Get data - return available libraries for this platform
47
+ const getData = () => {
48
+ return getPlatformLibs();
49
+ };
50
+
51
+ // Cleanup function (if needed)
52
+ const cleanup = () => {
53
+ // Nothing specific to clean up
54
+ };
55
+
56
+ // Export the feature factory function
57
+ export const createThirdPartyLibsFeature = () => {
58
+ return {
59
+ name: 'thirdPartyLibs',
60
+ label: 'Debug Libraries',
61
+ setup,
62
+ getData,
63
+ cleanup
64
+ };
65
+ };
@@ -0,0 +1,92 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { addNavigationLog } from '../features/NavigationLogFeature';
3
+
4
+ /**
5
+ * Custom hook to log React Navigation events for debugging
6
+ *
7
+ * Usage:
8
+ *
9
+ * // In your navigation container
10
+ * import { useNavigationLogger } from 'react-native-debug-toolkit';
11
+ *
12
+ * function App() {
13
+ * const navigationRef = useRef();
14
+ *
15
+ * // Enable navigation logging
16
+ * useNavigationLogger(navigationRef);
17
+ *
18
+ * return (
19
+ * <NavigationContainer ref={navigationRef}>
20
+ * // ... your navigation structure
21
+ * </NavigationContainer>
22
+ * );
23
+ * }
24
+ */
25
+ export function useNavigationLogger(navigationRef) {
26
+ // Track previous state
27
+ const routeRef = useRef(null);
28
+
29
+ useEffect(() => {
30
+ if (!__DEV__ || !navigationRef.current) {
31
+ return;
32
+ }
33
+
34
+ // Create listeners for navigation events
35
+ const unsubscribeReady = navigationRef.current?.addListener('state', (e) => {
36
+ if (!navigationRef.current) return;
37
+
38
+ const state = navigationRef.current.getRootState();
39
+ if (!state) return;
40
+
41
+ const currentRoute = navigationRef.current.getCurrentRoute();
42
+
43
+ if (!currentRoute) return;
44
+
45
+ // First render won't have a previous state
46
+ if (!routeRef.current) {
47
+ routeRef.current = currentRoute;
48
+ return;
49
+ }
50
+
51
+ // Determine the navigation action
52
+ let action = 'navigate';
53
+
54
+ // Check if this was a push (adding to history) or replace
55
+ const routes = state.routes;
56
+ if (routes.length > 0) {
57
+ const prevIndex = routes.findIndex(route => route.key === routeRef.current.key);
58
+ const currentIndex = routes.findIndex(route => route.key === currentRoute.key);
59
+
60
+ if (currentIndex > prevIndex) {
61
+ action = 'push';
62
+ } else if (currentIndex < prevIndex) {
63
+ action = 'pop';
64
+ } else if (currentIndex === prevIndex) {
65
+ action = 'replace';
66
+ }
67
+ }
68
+
69
+ // Log the navigation
70
+ addNavigationLog(
71
+ action,
72
+ {
73
+ name: routeRef.current.name,
74
+ params: routeRef.current.params,
75
+ },
76
+ {
77
+ name: currentRoute.name,
78
+ params: currentRoute.params,
79
+ },
80
+ performance.now(), // Approximate time
81
+ 0 // No duration measurement available for this event type
82
+ );
83
+
84
+ // Update the reference
85
+ routeRef.current = currentRoute;
86
+ });
87
+
88
+ return () => {
89
+ unsubscribeReady && unsubscribeReady();
90
+ };
91
+ }, [navigationRef]);
92
+ }
package/lib/index.js CHANGED
@@ -3,6 +3,9 @@ import { createNetworkFeature } from './features/NetworkFeature'
3
3
  import { createPerformanceFeature} from './features/PerformanceFeature'
4
4
  import { createConsoleLogFeature } from './features/ConsoleLogFeature'
5
5
  import { createZustandLogFeature, zustandLogMiddleware } from './features/ZustandLogFeature'
6
+ import { createNavigationLogFeature, addNavigationLog } from './features/NavigationLogFeature'
7
+ import { createThirdPartyLibsFeature } from './features/ThirdPartyLibsFeature'
8
+ import NativeDebugLibs from './NativeDebugLibs'
6
9
 
7
10
  // Registry mapping feature names (strings) to their creator functions
8
11
  const featureRegistry = {
@@ -10,24 +13,32 @@ const featureRegistry = {
10
13
  console: createConsoleLogFeature,
11
14
  performance: createPerformanceFeature,
12
15
  zustand: createZustandLogFeature,
16
+ navigation: createNavigationLogFeature,
17
+ thirdPartyLibs: createThirdPartyLibsFeature,
13
18
  // Add other built-in features here
14
19
  // 'storage': createStorageFeature,
15
20
  }
16
21
 
17
22
  // List of default features (can use strings now)
18
- const defaultFeatures = ['network', 'console', 'zustand']
23
+ const defaultFeatures = ['network', 'console', 'zustand', 'navigation', 'thirdPartyLibs']
19
24
 
20
25
  /**
21
26
  * Initializes and shows the Debug ToolKit panel with specified features.
22
27
  * Only runs in development mode (__DEV__ === true).
23
28
  * Features can be specified as strings (e.g., 'network') or creator functions.
24
29
  * @param {Array<string|Function>} features - Array of feature names (strings) or creator functions. Defaults to standard features.
30
+ * @param {Object} options - Additional options like doraemonProductId for third-party debug libraries
25
31
  */
26
- export function initializeDebugToolkit(features = defaultFeatures) {
32
+ export function initializeDebugToolkit(features = defaultFeatures, options = {}) {
27
33
 
28
34
  try {
29
35
  const debugToolKit = new DebugToolKit();
30
36
 
37
+ // Initialize third-party debug libraries if configured
38
+ if (options.doraemonProductId) {
39
+ NativeDebugLibs.installDoraemonKit(options.doraemonProductId);
40
+ }
41
+
31
42
  features.forEach(featureIdentifier => {
32
43
  let feature = null;
33
44
  let featureCreator = null;
@@ -81,6 +92,9 @@ export {
81
92
  createPerformanceFeature,
82
93
  createConsoleLogFeature,
83
94
  createZustandLogFeature,
95
+ createNavigationLogFeature,
96
+ createThirdPartyLibsFeature,
97
+ addNavigationLog,
84
98
  zustandLogMiddleware, // Export middleware for use in Zustand stores
85
99
  featureRegistry
86
100
  };
@@ -0,0 +1 @@
1
+