@truewatchtech/mobile-react-native-navigation 0.0.0-stage → 0.4.3-alpha.1
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 +76 -2
- package/lib/commonjs/FTRumReactNativeNavigationTracking.js +85 -0
- package/lib/commonjs/FTRumReactNativeNavigationTracking.js.map +1 -0
- package/lib/commonjs/index.js +13 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/module/FTRumReactNativeNavigationTracking.js +78 -0
- package/lib/module/FTRumReactNativeNavigationTracking.js.map +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -0
- package/lib/typescript/FTRumReactNativeNavigationTracking.d.ts +11 -0
- package/lib/typescript/index.d.ts +1 -0
- package/package.json +62 -4
- package/src/FTRumReactNativeNavigationTracking.ts +79 -0
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -1,3 +1,77 @@
|
|
|
1
|
-
#
|
|
1
|
+
# TrueWatch React Native Navigation plugin
|
|
2
2
|
|
|
3
|
-
This
|
|
3
|
+
This plugin tracks Wix `react-native-navigation` screen appearances as TrueWatch
|
|
4
|
+
RUM Views and measures appearance loading.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
yarn add @truewatchtech/react-native-mobile @truewatchtech/mobile-react-native-navigation
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Keep your existing `react-native-navigation` dependency and its native setup.
|
|
13
|
+
This plugin contains only JavaScript and types; it adds no native linking or
|
|
14
|
+
build configuration.
|
|
15
|
+
|
|
16
|
+
## View tracking
|
|
17
|
+
|
|
18
|
+
Initialize the mobile SDK and RUM, then start tracking before displaying the
|
|
19
|
+
navigation root:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { Navigation } from 'react-native-navigation';
|
|
23
|
+
import { FTRumReactNativeNavigationTracking } from '@truewatchtech/mobile-react-native-navigation';
|
|
24
|
+
|
|
25
|
+
FTRumReactNativeNavigationTracking.startTracking();
|
|
26
|
+
|
|
27
|
+
Navigation.events().registerAppLaunchedListener(() => {
|
|
28
|
+
// Register your screens, then display the root as usual.
|
|
29
|
+
void Navigation.setRoot({
|
|
30
|
+
root: { stack: { children: [{ component: { name: 'Home' } }] } },
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Before shutting down the SDK or disposing the navigation integration:
|
|
35
|
+
FTRumReactNativeNavigationTracking.stopTracking();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`startTracking()` is idempotent. `stopTracking()` removes all registered global screen
|
|
39
|
+
listeners and the AppState subscription. You can start tracking again; callbacks
|
|
40
|
+
queued by an old registration cannot restart or stop the new registration's View.
|
|
41
|
+
Starting after a screen is already visible only tracks subsequent appearance
|
|
42
|
+
events, so start before `setRoot`.
|
|
43
|
+
|
|
44
|
+
The plugin listens directly to `componentDidAppear` and `componentDidDisappear`,
|
|
45
|
+
and to `componentWillAppear` when the navigation library exposes it. It works
|
|
46
|
+
without patching `React.createElement` and also
|
|
47
|
+
covers screens using the automatic JSX runtime. Only events with
|
|
48
|
+
`componentType: 'Component'` are treated as screens. Top bar titles, backgrounds,
|
|
49
|
+
and buttons are excluded. `componentName` becomes the View name and `componentId`
|
|
50
|
+
identifies the screen instance.
|
|
51
|
+
|
|
52
|
+
## Loading and lifecycle
|
|
53
|
+
|
|
54
|
+
Loading is the monotonic elapsed time from `componentWillAppear` to
|
|
55
|
+
`componentDidAppear`, reported in nanoseconds: 25.5 ms is 25,500,000 ns. This is the
|
|
56
|
+
observed appearance interval, not the completion of asynchronous content loading.
|
|
57
|
+
If the navigation library has no will-appear API, Views are collected without
|
|
58
|
+
loading data. Missing starts and non-positive durations also omit loading data.
|
|
59
|
+
Duplicate callbacks do not submit loading twice. Native closes automatic Views in
|
|
60
|
+
the background; foreground recovery starts the current screen without replaying
|
|
61
|
+
old loading data. A late disappearance from the previous screen cannot close a
|
|
62
|
+
different active screen.
|
|
63
|
+
|
|
64
|
+
Use one automatic navigation integration at a time. The SDK has one active View;
|
|
65
|
+
when multiple screens are simultaneously visible, the latest accepted appearance
|
|
66
|
+
owns it. This package does not need React Navigation or
|
|
67
|
+
`@truewatchtech/mobile-react-navigation`.
|
|
68
|
+
|
|
69
|
+
## Migration
|
|
70
|
+
|
|
71
|
+
Replace the copied `example/src/FTRumReactNativeNavigationTracking.tsx` import
|
|
72
|
+
with `@truewatchtech/mobile-react-native-navigation`, retaining the class name and
|
|
73
|
+
methods. Remove the copied implementation so it cannot collect Views twice.
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
Apache 2.0
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.FTRumReactNativeNavigationTracking = void 0;
|
|
7
|
+
var _reactNativeNavigation = require("react-native-navigation");
|
|
8
|
+
var _reactNativeMobile = require("@truewatchtech/react-native-mobile");
|
|
9
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
10
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
11
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
12
|
+
/** Tracks screen events directly, including screens rendered with the JSX runtime. */
|
|
13
|
+
class FTRumReactNativeNavigationTracking {
|
|
14
|
+
/** Call after RUM initialization and before displaying the navigation root. */
|
|
15
|
+
static startTracking() {
|
|
16
|
+
if (this.subscriptions.length) return;
|
|
17
|
+
const lifecycle = ++this.lifecycle;
|
|
18
|
+
const current = () => lifecycle === this.lifecycle;
|
|
19
|
+
this.tracker.start();
|
|
20
|
+
const events = _reactNativeNavigation.Navigation.events();
|
|
21
|
+
try {
|
|
22
|
+
// Older releases expose only did-appear/disappear. Without a start
|
|
23
|
+
// boundary, collect Views without reporting an appearance duration.
|
|
24
|
+
if (typeof events.registerComponentWillAppearListener === 'function') {
|
|
25
|
+
this.subscriptions.push(events.registerComponentWillAppearListener(event => {
|
|
26
|
+
if (!current() || event.componentType !== 'Component') return;
|
|
27
|
+
const key = event.componentId;
|
|
28
|
+
const existing = this.appearances.get(key);
|
|
29
|
+
// A duplicate will-appear must not replace the original loading start.
|
|
30
|
+
if (!existing || existing.order !== this.appearance) {
|
|
31
|
+
this.appearances.set(key, {
|
|
32
|
+
order: ++this.appearance
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
this.tracker.setCurrent({
|
|
36
|
+
key,
|
|
37
|
+
name: event.componentName
|
|
38
|
+
});
|
|
39
|
+
this.tracker.beginLoad(key);
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
this.subscriptions.push(events.registerComponentDidAppearListener(event => {
|
|
43
|
+
var _appearance$order;
|
|
44
|
+
if (!current() || event.componentType !== 'Component') return;
|
|
45
|
+
const key = event.componentId;
|
|
46
|
+
const appearance = this.appearances.get(key);
|
|
47
|
+
if (appearance && appearance.order !== this.appearance) return;
|
|
48
|
+
const generation = this.tracker.show({
|
|
49
|
+
key,
|
|
50
|
+
name: event.componentName
|
|
51
|
+
});
|
|
52
|
+
this.appearances.set(key, {
|
|
53
|
+
order: (_appearance$order = appearance === null || appearance === void 0 ? void 0 : appearance.order) !== null && _appearance$order !== void 0 ? _appearance$order : ++this.appearance,
|
|
54
|
+
generation
|
|
55
|
+
});
|
|
56
|
+
}));
|
|
57
|
+
this.subscriptions.push(events.registerComponentDidDisappearListener(event => {
|
|
58
|
+
if (!current() || event.componentType !== 'Component') return;
|
|
59
|
+
const key = event.componentId;
|
|
60
|
+
const appearance = this.appearances.get(key);
|
|
61
|
+
if (!appearance) return;
|
|
62
|
+
// Retain the appearance's generation: foreground recovery owns a new one.
|
|
63
|
+
this.tracker.hide(key, appearance.generation);
|
|
64
|
+
this.appearances.delete(key);
|
|
65
|
+
}));
|
|
66
|
+
} catch (error) {
|
|
67
|
+
this.stopTracking();
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
static stopTracking() {
|
|
72
|
+
++this.lifecycle;
|
|
73
|
+
this.subscriptions.forEach(subscription => subscription.remove());
|
|
74
|
+
this.subscriptions = [];
|
|
75
|
+
this.appearances.clear();
|
|
76
|
+
this.tracker.stop();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.FTRumReactNativeNavigationTracking = FTRumReactNativeNavigationTracking;
|
|
80
|
+
_defineProperty(FTRumReactNativeNavigationTracking, "tracker", new _reactNativeMobile.FTRumViewTracking());
|
|
81
|
+
_defineProperty(FTRumReactNativeNavigationTracking, "subscriptions", []);
|
|
82
|
+
_defineProperty(FTRumReactNativeNavigationTracking, "appearances", new Map());
|
|
83
|
+
_defineProperty(FTRumReactNativeNavigationTracking, "appearance", 0);
|
|
84
|
+
_defineProperty(FTRumReactNativeNavigationTracking, "lifecycle", 0);
|
|
85
|
+
//# sourceMappingURL=FTRumReactNativeNavigationTracking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNativeNavigation","require","_reactNativeMobile","_defineProperty","e","r","t","_toPropertyKey","Object","defineProperty","value","enumerable","configurable","writable","i","_toPrimitive","Symbol","toPrimitive","call","TypeError","String","Number","FTRumReactNativeNavigationTracking","startTracking","subscriptions","length","lifecycle","current","tracker","start","events","Navigation","registerComponentWillAppearListener","push","event","componentType","key","componentId","existing","appearances","get","order","appearance","set","setCurrent","name","componentName","beginLoad","registerComponentDidAppearListener","_appearance$order","generation","show","registerComponentDidDisappearListener","hide","delete","error","stopTracking","forEach","subscription","remove","clear","stop","exports","FTRumViewTracking","Map"],"sources":["FTRumReactNativeNavigationTracking.ts"],"sourcesContent":["import { Navigation } from 'react-native-navigation';\nimport { FTRumViewTracking } from '@truewatchtech/react-native-mobile';\n\ntype Appearance = { order: number; generation?: number };\n\n/** Tracks screen events directly, including screens rendered with the JSX runtime. */\nexport class FTRumReactNativeNavigationTracking {\n private static tracker = new FTRumViewTracking();\n private static subscriptions: { remove(): void }[] = [];\n private static appearances = new Map<string, Appearance>();\n private static appearance = 0;\n private static lifecycle = 0;\n\n /** Call after RUM initialization and before displaying the navigation root. */\n static startTracking(): void {\n if (this.subscriptions.length) return;\n const lifecycle = ++this.lifecycle;\n const current = (): boolean => lifecycle === this.lifecycle;\n this.tracker.start();\n const events = Navigation.events();\n try {\n // Older releases expose only did-appear/disappear. Without a start\n // boundary, collect Views without reporting an appearance duration.\n if (typeof events.registerComponentWillAppearListener === 'function') {\n this.subscriptions.push(\n events.registerComponentWillAppearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const existing = this.appearances.get(key);\n // A duplicate will-appear must not replace the original loading start.\n if (!existing || existing.order !== this.appearance) {\n this.appearances.set(key, { order: ++this.appearance });\n }\n this.tracker.setCurrent({ key, name: event.componentName });\n this.tracker.beginLoad(key);\n })\n );\n }\n this.subscriptions.push(\n events.registerComponentDidAppearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const appearance = this.appearances.get(key);\n if (appearance && appearance.order !== this.appearance) return;\n const generation = this.tracker.show({\n key,\n name: event.componentName,\n });\n this.appearances.set(key, {\n order: appearance?.order ?? ++this.appearance,\n generation,\n });\n })\n );\n this.subscriptions.push(\n events.registerComponentDidDisappearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const appearance = this.appearances.get(key);\n if (!appearance) return;\n // Retain the appearance's generation: foreground recovery owns a new one.\n this.tracker.hide(key, appearance.generation);\n this.appearances.delete(key);\n })\n );\n } catch (error) {\n this.stopTracking();\n throw error;\n }\n }\n\n static stopTracking(): void {\n ++this.lifecycle;\n this.subscriptions.forEach((subscription) => subscription.remove());\n this.subscriptions = [];\n this.appearances.clear();\n this.tracker.stop();\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "FTRumReactNativeNavigationTracking", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _FTRumReactNativeNavigationTracking.FTRumReactNativeNavigationTracking;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
var _FTRumReactNativeNavigationTracking = require("./FTRumReactNativeNavigationTracking");
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_FTRumReactNativeNavigationTracking","require"],"sources":["index.ts"],"sourcesContent":["export { FTRumReactNativeNavigationTracking } from './FTRumReactNativeNavigationTracking';\n"],"mappings":";;;;;;;;;;;AAAA,IAAAA,mCAAA,GAAAC,OAAA","ignoreList":[]}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
2
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
3
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
4
|
+
import { Navigation } from 'react-native-navigation';
|
|
5
|
+
import { FTRumViewTracking } from '@truewatchtech/react-native-mobile';
|
|
6
|
+
/** Tracks screen events directly, including screens rendered with the JSX runtime. */
|
|
7
|
+
export class FTRumReactNativeNavigationTracking {
|
|
8
|
+
/** Call after RUM initialization and before displaying the navigation root. */
|
|
9
|
+
static startTracking() {
|
|
10
|
+
if (this.subscriptions.length) return;
|
|
11
|
+
const lifecycle = ++this.lifecycle;
|
|
12
|
+
const current = () => lifecycle === this.lifecycle;
|
|
13
|
+
this.tracker.start();
|
|
14
|
+
const events = Navigation.events();
|
|
15
|
+
try {
|
|
16
|
+
// Older releases expose only did-appear/disappear. Without a start
|
|
17
|
+
// boundary, collect Views without reporting an appearance duration.
|
|
18
|
+
if (typeof events.registerComponentWillAppearListener === 'function') {
|
|
19
|
+
this.subscriptions.push(events.registerComponentWillAppearListener(event => {
|
|
20
|
+
if (!current() || event.componentType !== 'Component') return;
|
|
21
|
+
const key = event.componentId;
|
|
22
|
+
const existing = this.appearances.get(key);
|
|
23
|
+
// A duplicate will-appear must not replace the original loading start.
|
|
24
|
+
if (!existing || existing.order !== this.appearance) {
|
|
25
|
+
this.appearances.set(key, {
|
|
26
|
+
order: ++this.appearance
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
this.tracker.setCurrent({
|
|
30
|
+
key,
|
|
31
|
+
name: event.componentName
|
|
32
|
+
});
|
|
33
|
+
this.tracker.beginLoad(key);
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
this.subscriptions.push(events.registerComponentDidAppearListener(event => {
|
|
37
|
+
var _appearance$order;
|
|
38
|
+
if (!current() || event.componentType !== 'Component') return;
|
|
39
|
+
const key = event.componentId;
|
|
40
|
+
const appearance = this.appearances.get(key);
|
|
41
|
+
if (appearance && appearance.order !== this.appearance) return;
|
|
42
|
+
const generation = this.tracker.show({
|
|
43
|
+
key,
|
|
44
|
+
name: event.componentName
|
|
45
|
+
});
|
|
46
|
+
this.appearances.set(key, {
|
|
47
|
+
order: (_appearance$order = appearance === null || appearance === void 0 ? void 0 : appearance.order) !== null && _appearance$order !== void 0 ? _appearance$order : ++this.appearance,
|
|
48
|
+
generation
|
|
49
|
+
});
|
|
50
|
+
}));
|
|
51
|
+
this.subscriptions.push(events.registerComponentDidDisappearListener(event => {
|
|
52
|
+
if (!current() || event.componentType !== 'Component') return;
|
|
53
|
+
const key = event.componentId;
|
|
54
|
+
const appearance = this.appearances.get(key);
|
|
55
|
+
if (!appearance) return;
|
|
56
|
+
// Retain the appearance's generation: foreground recovery owns a new one.
|
|
57
|
+
this.tracker.hide(key, appearance.generation);
|
|
58
|
+
this.appearances.delete(key);
|
|
59
|
+
}));
|
|
60
|
+
} catch (error) {
|
|
61
|
+
this.stopTracking();
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
static stopTracking() {
|
|
66
|
+
++this.lifecycle;
|
|
67
|
+
this.subscriptions.forEach(subscription => subscription.remove());
|
|
68
|
+
this.subscriptions = [];
|
|
69
|
+
this.appearances.clear();
|
|
70
|
+
this.tracker.stop();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
_defineProperty(FTRumReactNativeNavigationTracking, "tracker", new FTRumViewTracking());
|
|
74
|
+
_defineProperty(FTRumReactNativeNavigationTracking, "subscriptions", []);
|
|
75
|
+
_defineProperty(FTRumReactNativeNavigationTracking, "appearances", new Map());
|
|
76
|
+
_defineProperty(FTRumReactNativeNavigationTracking, "appearance", 0);
|
|
77
|
+
_defineProperty(FTRumReactNativeNavigationTracking, "lifecycle", 0);
|
|
78
|
+
//# sourceMappingURL=FTRumReactNativeNavigationTracking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Navigation","FTRumViewTracking","FTRumReactNativeNavigationTracking","startTracking","subscriptions","length","lifecycle","current","tracker","start","events","registerComponentWillAppearListener","push","event","componentType","key","componentId","existing","appearances","get","order","appearance","set","setCurrent","name","componentName","beginLoad","registerComponentDidAppearListener","_appearance$order","generation","show","registerComponentDidDisappearListener","hide","delete","error","stopTracking","forEach","subscription","remove","clear","stop","_defineProperty","Map"],"sources":["FTRumReactNativeNavigationTracking.ts"],"sourcesContent":["import { Navigation } from 'react-native-navigation';\nimport { FTRumViewTracking } from '@truewatchtech/react-native-mobile';\n\ntype Appearance = { order: number; generation?: number };\n\n/** Tracks screen events directly, including screens rendered with the JSX runtime. */\nexport class FTRumReactNativeNavigationTracking {\n private static tracker = new FTRumViewTracking();\n private static subscriptions: { remove(): void }[] = [];\n private static appearances = new Map<string, Appearance>();\n private static appearance = 0;\n private static lifecycle = 0;\n\n /** Call after RUM initialization and before displaying the navigation root. */\n static startTracking(): void {\n if (this.subscriptions.length) return;\n const lifecycle = ++this.lifecycle;\n const current = (): boolean => lifecycle === this.lifecycle;\n this.tracker.start();\n const events = Navigation.events();\n try {\n // Older releases expose only did-appear/disappear. Without a start\n // boundary, collect Views without reporting an appearance duration.\n if (typeof events.registerComponentWillAppearListener === 'function') {\n this.subscriptions.push(\n events.registerComponentWillAppearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const existing = this.appearances.get(key);\n // A duplicate will-appear must not replace the original loading start.\n if (!existing || existing.order !== this.appearance) {\n this.appearances.set(key, { order: ++this.appearance });\n }\n this.tracker.setCurrent({ key, name: event.componentName });\n this.tracker.beginLoad(key);\n })\n );\n }\n this.subscriptions.push(\n events.registerComponentDidAppearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const appearance = this.appearances.get(key);\n if (appearance && appearance.order !== this.appearance) return;\n const generation = this.tracker.show({\n key,\n name: event.componentName,\n });\n this.appearances.set(key, {\n order: appearance?.order ?? ++this.appearance,\n generation,\n });\n })\n );\n this.subscriptions.push(\n events.registerComponentDidDisappearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const appearance = this.appearances.get(key);\n if (!appearance) return;\n // Retain the appearance's generation: foreground recovery owns a new one.\n this.tracker.hide(key, appearance.generation);\n this.appearances.delete(key);\n })\n );\n } catch (error) {\n this.stopTracking();\n throw error;\n }\n }\n\n static stopTracking(): void {\n ++this.lifecycle;\n this.subscriptions.forEach((subscription) => subscription.remove());\n this.subscriptions = [];\n this.appearances.clear();\n this.tracker.stop();\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["FTRumReactNativeNavigationTracking"],"sources":["index.ts"],"sourcesContent":["export { FTRumReactNativeNavigationTracking } from './FTRumReactNativeNavigationTracking';\n"],"mappings":"AAAA,SAASA,kCAAkC,QAAQ,sCAAsC","ignoreList":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Tracks screen events directly, including screens rendered with the JSX runtime. */
|
|
2
|
+
export declare class FTRumReactNativeNavigationTracking {
|
|
3
|
+
private static tracker;
|
|
4
|
+
private static subscriptions;
|
|
5
|
+
private static appearances;
|
|
6
|
+
private static appearance;
|
|
7
|
+
private static lifecycle;
|
|
8
|
+
/** Call after RUM initialization and before displaying the navigation root. */
|
|
9
|
+
static startTracking(): void;
|
|
10
|
+
static stopTracking(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { FTRumReactNativeNavigationTracking } from './FTRumReactNativeNavigationTracking';
|
package/package.json
CHANGED
|
@@ -1,6 +1,64 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truewatchtech/mobile-react-native-navigation",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.4.3-alpha.1",
|
|
4
|
+
"description": "Automatic TrueWatch RUM View tracking for react-native-navigation.",
|
|
5
|
+
"main": "lib/commonjs/index",
|
|
6
|
+
"module": "lib/module/index",
|
|
7
|
+
"types": "lib/typescript/index.d.ts",
|
|
8
|
+
"react-native": "src/index",
|
|
9
|
+
"source": "src/index",
|
|
10
|
+
"files": [
|
|
11
|
+
"src",
|
|
12
|
+
"lib",
|
|
13
|
+
"README.md",
|
|
14
|
+
"!**/__tests__",
|
|
15
|
+
"!**/__mocks__"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"lint": "yarn run -T eslint \"src/**/*.{ts,tsx}\" \"tests/**/*.ts\"",
|
|
19
|
+
"prepare": "yarn run -T bob build",
|
|
20
|
+
"prepack": "yarn run -T check-version && yarn prepare",
|
|
21
|
+
"test": "yarn run -T jest",
|
|
22
|
+
"typescript": "yarn run -T tsc --noEmit"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/TrueWatchTech/datakit-react-native.git"
|
|
27
|
+
},
|
|
28
|
+
"license": "Apache-2.0",
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public",
|
|
31
|
+
"registry": "https://registry.npmjs.org/"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@truewatchtech/react-native-mobile": "^0.4.3",
|
|
35
|
+
"react": ">=16.13.1",
|
|
36
|
+
"react-native": ">=0.63.4 <1.0",
|
|
37
|
+
"react-native-navigation": "^7.5.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"react-native-navigation": "7.40.1"
|
|
41
|
+
},
|
|
42
|
+
"react-native-builder-bob": {
|
|
43
|
+
"source": "src",
|
|
44
|
+
"output": "lib",
|
|
45
|
+
"targets": [
|
|
46
|
+
"commonjs",
|
|
47
|
+
"module",
|
|
48
|
+
[
|
|
49
|
+
"typescript",
|
|
50
|
+
{
|
|
51
|
+
"tsc": "../../node_modules/.bin/tsc",
|
|
52
|
+
"project": "tsconfig.build.json"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"jest": {
|
|
58
|
+
"preset": "react-native",
|
|
59
|
+
"modulePathIgnorePatterns": [
|
|
60
|
+
"<rootDir>/lib/"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"gitHead": "7c1fd9454260071fc48c74b8e5bdb9669eee0b7f"
|
|
64
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Navigation } from 'react-native-navigation';
|
|
2
|
+
import { FTRumViewTracking } from '@truewatchtech/react-native-mobile';
|
|
3
|
+
|
|
4
|
+
type Appearance = { order: number; generation?: number };
|
|
5
|
+
|
|
6
|
+
/** Tracks screen events directly, including screens rendered with the JSX runtime. */
|
|
7
|
+
export class FTRumReactNativeNavigationTracking {
|
|
8
|
+
private static tracker = new FTRumViewTracking();
|
|
9
|
+
private static subscriptions: { remove(): void }[] = [];
|
|
10
|
+
private static appearances = new Map<string, Appearance>();
|
|
11
|
+
private static appearance = 0;
|
|
12
|
+
private static lifecycle = 0;
|
|
13
|
+
|
|
14
|
+
/** Call after RUM initialization and before displaying the navigation root. */
|
|
15
|
+
static startTracking(): void {
|
|
16
|
+
if (this.subscriptions.length) return;
|
|
17
|
+
const lifecycle = ++this.lifecycle;
|
|
18
|
+
const current = (): boolean => lifecycle === this.lifecycle;
|
|
19
|
+
this.tracker.start();
|
|
20
|
+
const events = Navigation.events();
|
|
21
|
+
try {
|
|
22
|
+
// Older releases expose only did-appear/disappear. Without a start
|
|
23
|
+
// boundary, collect Views without reporting an appearance duration.
|
|
24
|
+
if (typeof events.registerComponentWillAppearListener === 'function') {
|
|
25
|
+
this.subscriptions.push(
|
|
26
|
+
events.registerComponentWillAppearListener((event) => {
|
|
27
|
+
if (!current() || event.componentType !== 'Component') return;
|
|
28
|
+
const key = event.componentId;
|
|
29
|
+
const existing = this.appearances.get(key);
|
|
30
|
+
// A duplicate will-appear must not replace the original loading start.
|
|
31
|
+
if (!existing || existing.order !== this.appearance) {
|
|
32
|
+
this.appearances.set(key, { order: ++this.appearance });
|
|
33
|
+
}
|
|
34
|
+
this.tracker.setCurrent({ key, name: event.componentName });
|
|
35
|
+
this.tracker.beginLoad(key);
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
this.subscriptions.push(
|
|
40
|
+
events.registerComponentDidAppearListener((event) => {
|
|
41
|
+
if (!current() || event.componentType !== 'Component') return;
|
|
42
|
+
const key = event.componentId;
|
|
43
|
+
const appearance = this.appearances.get(key);
|
|
44
|
+
if (appearance && appearance.order !== this.appearance) return;
|
|
45
|
+
const generation = this.tracker.show({
|
|
46
|
+
key,
|
|
47
|
+
name: event.componentName,
|
|
48
|
+
});
|
|
49
|
+
this.appearances.set(key, {
|
|
50
|
+
order: appearance?.order ?? ++this.appearance,
|
|
51
|
+
generation,
|
|
52
|
+
});
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
this.subscriptions.push(
|
|
56
|
+
events.registerComponentDidDisappearListener((event) => {
|
|
57
|
+
if (!current() || event.componentType !== 'Component') return;
|
|
58
|
+
const key = event.componentId;
|
|
59
|
+
const appearance = this.appearances.get(key);
|
|
60
|
+
if (!appearance) return;
|
|
61
|
+
// Retain the appearance's generation: foreground recovery owns a new one.
|
|
62
|
+
this.tracker.hide(key, appearance.generation);
|
|
63
|
+
this.appearances.delete(key);
|
|
64
|
+
})
|
|
65
|
+
);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
this.stopTracking();
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static stopTracking(): void {
|
|
73
|
+
++this.lifecycle;
|
|
74
|
+
this.subscriptions.forEach((subscription) => subscription.remove());
|
|
75
|
+
this.subscriptions = [];
|
|
76
|
+
this.appearances.clear();
|
|
77
|
+
this.tracker.stop();
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { FTRumReactNativeNavigationTracking } from './FTRumReactNativeNavigationTracking';
|