Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ dist
pnpm-lock.yaml
extension/ui
docs/privacy-policy.html
examples/nativescript/platforms
examples/nativescript/hooks
examples/nativescript/App_Resources
examples/nativescript/package-lock.json
.all-contributorsrc
37 changes: 21 additions & 16 deletions app/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,6 @@ const VIEW_TABS: Partial<Record<View, Tab[]>> = {
};

const COMING_SOON: Partial<Record<View, ComingSoonInfo>> = {
nativescript: {
id: 'nativescript',
name: 'NativeScript',
badge: 'Coming Soon',
heading: 'NativeScript Support',
summary:
'Inspect NativeScript Angular apps running natively on iOS and Android, with the same tools.',
color: '#3c5afd',
plans: [
'Native overlay that reports the component tree from the device',
'Standalone devtools server your phone or simulator connects to',
'Example NativeScript app to try it end to end',
],
pr: 16,
author: { name: 'Nathan Walker', login: 'NathanWalker' },
},
capacitor: {
id: 'capacitor',
name: 'Capacitor',
Expand All @@ -104,6 +88,26 @@ const COMING_SOON: Partial<Record<View, ComingSoonInfo>> = {
},
};

const NATIVESCRIPT_SETUP: ComingSoonInfo = {
id: 'nativescript',
name: 'NativeScript',
badge: 'Available',
heading: 'Inspect NativeScript apps',
summary:
'A NativeScript Angular app reports from the simulator or device to this server, and its components, signals, injectors and NgRx stores show up in the Angular dock.',
color: '#3c5afd',
plansTitle: 'Set up an app',
plans: [
'Install @santoshyadavdev/ng-devtools and @valor/nativescript-websockets',
'Call initNativeScriptOverlay() in main.ts, before the app bootstraps',
'Run ng-devtools dev --no-auth in the app, then open the Angular dock',
],
link: {
label: 'NativeScript setup guide',
href: 'https://santoshyadavdev.github.io/angular-devtools/guides/nativescript',
},
};

const NOT_ANALOG: ComingSoonInfo = {
id: 'analog',
name: 'Analog',
Expand Down Expand Up @@ -711,6 +715,7 @@ export class App implements OnInit, OnDestroy {
readonly comingSoon = computed(() => {
const view = this.view();
if (view === 'analog') return this.analogKnown() && !this.analog() ? NOT_ANALOG : undefined;
if (view === 'nativescript') return NATIVESCRIPT_SETUP;
if (view === 'angular-native') {
return this.nativeKnown() && !this.nativePageId() ? NO_ANGULAR_NATIVE : undefined;
}
Expand Down
9 changes: 7 additions & 2 deletions app/src/pages/coming-soon.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, input } from '@angular/core';
import { Component, computed, input } from '@angular/core';

export interface ComingSoonInfo {
id: 'nativescript' | 'capacitor' | 'analog' | 'angular-native';
Expand All @@ -8,6 +8,7 @@ export interface ComingSoonInfo {
summary: string;
color: string;
plans: string[];
plansTitle?: string;
pr?: number;
author?: { name: string; login: string };
link?: { label: string; href: string };
Expand Down Expand Up @@ -127,7 +128,7 @@ export interface ComingSoonInfo {
}

<h3 class="plans-title">
{{ info().link ? 'In an ' + info().name + ' app' : 'On the roadmap' }}
{{ plansTitle() }}
</h3>
<ul class="plans">
@for (plan of info().plans; track plan; let i = $index) {
Expand Down Expand Up @@ -486,4 +487,8 @@ export interface ComingSoonInfo {
})
export class ComingSoon {
readonly info = input.required<ComingSoonInfo>();
readonly plansTitle = computed(() => {
const info = this.info();
return info.plansTitle ?? (info.link ? `In an ${info.name} app` : 'On the roadmap');
});
}
2 changes: 1 addition & 1 deletion apps/docs/src/content/getting-started/express.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ A floating button appears on your page. It opens the devtools with one dock entr
| NgRx | Store patterns from source, and live state and actions |
| Analog | File routes, server calls, render modes and lint (a notice in non-Analog apps) |
| Angular Native | Components, signals, injectors and store of a connected [Angular Native](./angular-native.md) app |
| NativeScript | A **Coming Soon** placeholder |
| NativeScript | Setup steps for [NativeScript apps](../guides/nativescript.md) |
| Capacitor | A **Coming Soon** placeholder |

[Popup and hub](./popup-and-hub.md) covers the panel, its dock modes and deep links.
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/src/content/getting-started/popup-and-hub.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ When the page's server mounts the hub (`/__devframes/`), the button opens the wh
| NgRx | The Store tab |
| Analog | The Analog tab, or a notice in apps that do not use Analog |
| Angular Native | Components, Signals, Injectors and Store for a connected [Angular Native](./angular-native.md) app, or a setup notice when none is connected |
| NativeScript | A **Coming Soon** placeholder |
| NativeScript | Setup steps for [NativeScript apps](../guides/nativescript.md) |
| Capacitor | A **Coming Soon** placeholder |

### Full-page viewer
Expand Down
146 changes: 146 additions & 0 deletions apps/docs/src/content/guides/nativescript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
---
title: Set up NativeScript
description: Inspect a NativeScript Angular app from the simulator or a device, step by step.
---

<ngmd-hero title="Set up NativeScript" logo="https://cdn.simpleicons.org/nativescript/3C5AFD" gradient>
A NativeScript overlay walks the native view tree and reports over a WebSocket to a devtools server on your machine.
</ngmd-hero>

# Set up NativeScript

This guide adds the devtools to a NativeScript Angular app. The app has no DOM, so a separate overlay walks the native view tree through *Angular's debug API and reports to the standalone devtools server.

## What you get

<ngmd-card-grid columns="2">
<ngmd-card icon="layers" title="Angular inspectors">
The component tree, the signal graph and the injector tree, including environment injectors and their providers.
</ngmd-card>
<ngmd-card icon="box" title="NgRx stores">
Signal stores and the change log, when your app uses NgRx.
</ngmd-card>
<ngmd-card icon="search" title="Highlight">
The highlight tool outlines a component's view on the simulator or device.
</ngmd-card>
<ngmd-card icon="terminal" title="MCP endpoint">
<code>/__mcp</code> on the devtools server. The source scanners read the app's <code>src/</code>.
</ngmd-card>
</ngmd-card-grid>

## The flow

<ngmd-workflow>
<ngmd-step title="Install the packages">
Add <code>&#64;santoshyadavdev/ng-devtools</code> and <code>&#64;valor/nativescript-websockets</code>.
</ngmd-step>
<ngmd-step title="Add a WebSocket global">
Import <code>&#64;valor/nativescript-websockets</code> first in <code>src/polyfills.ts</code>.
</ngmd-step>
<ngmd-step title="Start the overlay">
Call <code>initNativeScriptOverlay()</code> in <code>src/main.ts</code>, before the app bootstraps.
</ngmd-step>
<ngmd-step title="Run the devtools server">
Start <code>ng-devtools dev</code> in the app's folder and open the UI.
</ngmd-step>
</ngmd-workflow>

## Step 1: Install

```bash group="install" name="npm" image="https://cdn.simpleicons.org/npm/CB3837" active
npm install @santoshyadavdev/ng-devtools @valor/nativescript-websockets
```

```bash group="install" name="pnpm" image="https://cdn.simpleicons.org/pnpm/F69220"
pnpm add @santoshyadavdev/ng-devtools @valor/nativescript-websockets
```

```bash group="install" name="yarn" image="https://cdn.simpleicons.org/yarn/2C8EBB"
yarn add @santoshyadavdev/ng-devtools @valor/nativescript-websockets
```

```bash group="install" name="bun" image="https://bun.sh/logo.svg"
bun add @santoshyadavdev/ng-devtools @valor/nativescript-websockets
```

## Step 2: Add a WebSocket global

The overlay talks to the server over a WebSocket, and the NativeScript runtime has no `WebSocket` global. Import the polyfill first:

```ts
// src/polyfills.ts
import '@valor/nativescript-websockets';
```

## Step 3: Start the overlay

```ts {2,4-6}
// src/main.ts
import {initNativeScriptOverlay} from '@santoshyadavdev/ng-devtools/overlay-nativescript';

if (__DEV__) {
initNativeScriptOverlay();
}
```

Call it before `runNativeScriptAngularApp()`. The injector inspector relies on *Angular's injector profiler, which *Angular only wires while it creates the platform.

### Where the overlay connects

| Target | Default URL |
| ---------------- | ------------------------ |
| iOS simulator | `http://localhost:9999/` |
| Android emulator | `http://10.0.2.2:9999/` |
| Physical device | Pass `{ baseURL }` |

For a physical device, pass the address of your machine as `baseURL`, and allow plain HTTP to that address in `Info.plist` and `AndroidManifest.xml`.

## Step 4: Run the devtools server

Run the server in the app's folder, so the source scanners read its `src/`:

```bash
cd my-nativescript-app
npx @santoshyadavdev/ng-devtools dev --no-auth
```

The server listens on `localhost` only, which the iOS simulator and the Android emulator reach. `--no-auth` is needed because the app cannot enter the one-time code the panel asks for.

| What | Where |
| ------------ | ----------------------------- |
| Devtools UI | `http://localhost:9999/` |
| MCP endpoint | `http://localhost:9999/__mcp` |

A physical device reaches your machine over the network, so the server has to listen on an interface the device can reach:

```bash
npx @santoshyadavdev/ng-devtools dev --host 192.168.1.20 --no-auth
```

<ngmd-alert severity="warning" label="Trusted networks only">
With <code>--host</code> and <code>--no-auth</code>, every host that can reach that address can call the devtools RPC and MCP endpoints without a code. Use it on a trusted network only, and bind to the one interface the device uses rather than <code>0.0.0.0</code>.
</ngmd-alert>

See [Standalone CLI](../getting-started/cli.md) for the other server options and [Security](../security.md) for what `--no-auth` turns off.

## Try the demo

`examples/nativescript` is a `ns create --ng` project wired up this way, with a small showcase component (signals, a computed, an effect and a component-level provider). It is tested on the iOS simulator. Android is untested.

The demo maps `@santoshyadavdev/ng-devtools/*` to the package's build output in `packages/ng-devtools/dist`, so build the package first:

```bash
pnpm devtools:build-pkg
pnpm devtools:nativescript
cd examples/nativescript && npm install && ns debug ios --no-hmr
```

`pnpm devtools:nativescript` starts the devtools server on `localhost`, scanning `examples/nativescript/src`. For a physical device, `pnpm devtools:nativescript:device` listens on every interface instead, with the same warning as above.

## Where to next

<ngmd-pill-row>
<ngmd-pill href="/getting-started/cli" title="Standalone CLI"></ngmd-pill>
<ngmd-pill href="/inspectors/components" title="Components inspector"></ngmd-pill>
<ngmd-pill href="/agents/mcp-server" title="MCP server"></ngmd-pill>
</ngmd-pill-row>
1 change: 1 addition & 0 deletions apps/docs/src/ngmd.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ const config: NgmdConfig = {
{label: 'Restore NgRx signal state', href: '/guides/ngrx-signals-restore'},
{label: 'Set up SSR & HTTP', href: '/guides/ssr-http'},
{label: 'Set up Analog', href: '/guides/analog'},
{label: 'Set up NativeScript', href: '/guides/nativescript'},
],
},
{
Expand Down
19 changes: 19 additions & 0 deletions examples/nativescript/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8

[*.json]
indent_style = space
indent_size = 2

[*.js]
indent_style = space
indent_size = 2

[*.ts]
indent_style = space
indent_size = 2
28 changes: 28 additions & 0 deletions examples/nativescript/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# NativeScript
hooks/
node_modules/
platforms/

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# General
.DS_Store
.AppleDouble
.LSOverride
.idea
.cloud
.project
tmp/
typings/

# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
3 changes: 3 additions & 0 deletions examples/nativescript/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["nativescript.nativescript"]
}
25 changes: 25 additions & 0 deletions examples/nativescript/App_Resources/Android/app.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// You can add your native dependencies here
dependencies {
// implementation 'androidx.multidex:multidex:2.0.1'
}

android {
compileSdkVersion 36
buildToolsVersion "36"
// ndkVersion ""

defaultConfig {
minSdkVersion 24
targetSdkVersion 36

// Version Information
versionCode 1
versionName "1.0.0"

generatedDensities = []
}

aaptOptions {
additionalParameters "--no-version-vectors"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// this configurations is loaded before building plugins, as well as before building
// the app - this is where you can apply global settings and overrides

project.ext {
// androidXAppCompat = "1.4.1"
// androidXExifInterface = "1.3.3"
// androidXFragment = "1.4.1"
// androidXMaterial = "1.5.0"
// androidXMultidex = "2.0.1"
// androidXTransition = "1.4.1"
// androidXViewPager = "1.0.0"

// useKotlin = true
// kotlinVersion = "1.6.0"
}
Loading
Loading