@devioarts/capacitor-mdns 0.1.0 → 0.2.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/CHANGELOG.md +110 -0
- package/DevioartsCapacitorMdns.podspec +3 -3
- package/Package.swift +1 -1
- package/README.md +221 -37
- package/android/build.gradle +3 -9
- package/android/src/main/java/com/devioarts/capacitor/mdns/AndroidNsdBackend.kt +145 -0
- package/android/src/main/java/com/devioarts/capacitor/mdns/MdnsOptions.kt +32 -0
- package/android/src/main/java/com/devioarts/capacitor/mdns/MdnsValidation.kt +26 -0
- package/android/src/main/java/com/devioarts/capacitor/mdns/NsdBackend.kt +59 -0
- package/android/src/main/java/com/devioarts/capacitor/mdns/mDNS.kt +467 -243
- package/android/src/main/java/com/devioarts/capacitor/mdns/mDNSPlugin.kt +80 -57
- package/dist/docs.json +250 -14
- package/dist/esm/definitions.d.ts +64 -17
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.js +22 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +6 -1
- package/dist/esm/web.js +23 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +45 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +45 -2
- package/dist/plugin.js.map +1 -1
- package/docs/electron.md +29 -3
- package/docs/platform-setup.md +6 -0
- package/docs/playground.md +33 -2
- package/docs/runtime-behavior.md +68 -2
- package/electron/dist/plugin-settings.js +10 -3
- package/electron/dist/plugin-settings.js.map +1 -1
- package/electron/dist/plugin.cjs.js +519 -89
- package/electron/dist/plugin.cjs.js.map +1 -1
- package/electron/mdns-bridge.cjs +25 -2
- package/electron/mdns.ts +514 -81
- package/electron/rollup.config.mjs +1 -1
- package/electron/src/index.ts +1 -0
- package/electron/src/plugin-settings.ts +10 -3
- package/electron/types-public/index.d.ts +25 -3
- package/ios/Sources/mDNSPlugin/mDNS.swift +407 -117
- package/ios/Sources/mDNSPlugin/mDNSPlugin.swift +77 -24
- package/ios/Tests/mDNSPluginTests/BridgeTests.swift +46 -0
- package/ios/Tests/mDNSPluginTests/MDNSTests.swift +490 -0
- package/package.json +11 -4
- package/ios/Tests/mDNSPluginTests/mDNSPluginTests.swift +0 -9
package/docs/playground.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Playground
|
|
2
2
|
|
|
3
3
|
The `playground` directory is the maintained example app for this package.
|
|
4
|
+
Its application identifier is `com.devioarts.pg.cap` on iOS, Android and Electron.
|
|
4
5
|
|
|
5
6
|
It demonstrates:
|
|
6
7
|
|
|
7
|
-
- starting and stopping an mDNS advertisement;
|
|
8
|
-
- discovering services by type and optional name;
|
|
8
|
+
- starting, updating and stopping an mDNS advertisement with JSON TXT records;
|
|
9
|
+
- discovering services by type and optional name, with visible addresses and TXT;
|
|
10
|
+
- watching several service types, with live service lists, found/lost logs and runtime errors;
|
|
9
11
|
- using the Electron preload bridge;
|
|
10
12
|
- checking `getPluginPlatform()` so you can confirm which runtime implementation handled a call.
|
|
11
13
|
|
|
@@ -17,3 +19,32 @@ npm run dev
|
|
|
17
19
|
```
|
|
18
20
|
|
|
19
21
|
For Electron, use the playground together with `devioarts/capacitor-electron`.
|
|
22
|
+
|
|
23
|
+
If native folders are missing after cloning, create the required platform first with `npx cap add ios`, `npx cap add android`, or `npx cap-electron add` inside `playground`.
|
|
24
|
+
|
|
25
|
+
For native builds, build the plugin first from the repository root (`npm run build`), then:
|
|
26
|
+
|
|
27
|
+
```shell
|
|
28
|
+
cd playground
|
|
29
|
+
npm run build:vite
|
|
30
|
+
npx cap sync
|
|
31
|
+
npm run open-ios # or npm run open-android
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
On macOS, the sync hook adds the Local Network usage description and the default `_http._tcp`, `_airplay._tcp` and `_googlecast._tcp` Bonjour types to the generated iOS project, preserving any existing description and custom types. Add other types to `NSBonjourServices` before testing them on iOS.
|
|
35
|
+
|
|
36
|
+
For Electron use `npm run build` followed by `npm run open-electron` inside `playground`. The build synchronizes the plugin registry before compiling, including all six methods and the three watch events. The default development origin is `http://localhost:5173`.
|
|
37
|
+
A regular browser displays the UI but cannot perform mDNS; unsupported calls show an error.
|
|
38
|
+
|
|
39
|
+
To test continuous discovery:
|
|
40
|
+
|
|
41
|
+
1. Publish `_http._tcp.` with TXT on one device. Keep both devices on the same Wi-Fi network.
|
|
42
|
+
2. On the other device, open Discovery and start watching `_http._tcp., _airplay._tcp., _googlecast._tcp.`.
|
|
43
|
+
3. Check the live name, type, port, IP addresses and TXT. Publish a second type and check both appear.
|
|
44
|
+
4. Stop a publisher and check its lost event and removal. Abrupt disappearance can take until its advertised TTL expires.
|
|
45
|
+
5. Run a one-time search while watching, then stop watching and verify the publisher stays active.
|
|
46
|
+
6. Stop the watch, change the types and start again. Switching tabs keeps both operations active; use their Stop buttons for independent cleanup.
|
|
47
|
+
|
|
48
|
+
Use dots in the advertised name and hyphens in a name filter to verify equivalent matching.
|
|
49
|
+
Run a long search and click Replace search to test replacement; the older request is logged as an error.
|
|
50
|
+
The Logger panel shows full event snapshots, including the last snapshot on loss.
|
package/docs/runtime-behavior.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Runtime behavior
|
|
2
2
|
|
|
3
|
+
## Continuous discovery
|
|
4
|
+
|
|
5
|
+
- `watchServices({ types })` is available on iOS, Android and Electron. A nonempty array of valid
|
|
6
|
+
`_name._tcp.` / `_name._udp.` types is required. Types are trimmed, trailing dots appended and
|
|
7
|
+
duplicates merged. Invalid input leaves the current watch running.
|
|
8
|
+
- One watch group is active. A valid replacement first stops the old group. `watchersStarted`
|
|
9
|
+
counts requested native browsers; asynchronous startup failures arrive through `watchError`.
|
|
10
|
+
- Register `serviceFound`, `serviceLost` and `watchError` listeners before starting. Found/lost
|
|
11
|
+
contain `{ service }` with `name`, full `type`, `domain`, `port`, `hosts` and optional `txt` /
|
|
12
|
+
`hostname`. Found is emitted only after a numeric address resolves. `hosts` is always an array. Lost uses the last resolved snapshot, and is emitted
|
|
13
|
+
only if the service was reported as found. A disappearance during resolve cancels that candidate.
|
|
14
|
+
- Each service emits found once per period of presence. Lost carries the last resolved snapshot;
|
|
15
|
+
this API does not promise continuous updates or separate events for address or TXT changes.
|
|
16
|
+
- A browser / transport failure stops the watch group and emits `{ type, errorMessage,
|
|
17
|
+
watching: false }`. Native resolve errors retry up to three times, then emit the same event with
|
|
18
|
+
`watching: true`; a later discovery can retry that service again.
|
|
19
|
+
- `stopWatching()` returns `{ watching: false, error, errorMessage }`, suppresses old callbacks and
|
|
20
|
+
cancels browsers, pending resolves and retries. Stop failures are reported and cleanup can be
|
|
21
|
+
retried. It does not stop an advertisement or one-shot discovery. Native manager destruction
|
|
22
|
+
also closes the watch group.
|
|
23
|
+
- Android watch groups and one-shot discovery share the pre-API-34 resolver queue and hold separate
|
|
24
|
+
references to the Wi-Fi multicast lock. Resolved NSD TXT attributes are returned as UTF-8 strings.
|
|
25
|
+
- Electron observes Bonjour goodbye packets and PTR TTL expiry. It refreshes browse queries every
|
|
26
|
+
30 seconds and checks expiry every second. Detection after abrupt network loss depends on the
|
|
27
|
+
peer's advertised TTL. Late address packets update the cached snapshot.
|
|
28
|
+
- A regular web browser returns `error: true` for watch startup; stop is an idempotent no-op.
|
|
29
|
+
The manual Electron preload bridge forwards all three event types and supports listener removal.
|
|
30
|
+
|
|
31
|
+
## One-shot discovery and advertising
|
|
32
|
+
|
|
3
33
|
- All methods resolve with the documented result shape. Runtime failures are reported through
|
|
4
34
|
`error` and `errorMessage` instead of rejecting when the platform bridge can recover safely.
|
|
5
35
|
- `getPluginPlatform()` resolves to `ios`, `android`, `electron`, or `web` from the implementation
|
|
@@ -8,7 +38,43 @@
|
|
|
8
38
|
not report publish success or failure, the operation is stopped and returned as an error.
|
|
9
39
|
- Only one advertisement is active at a time. Starting a new advertisement stops the previous one.
|
|
10
40
|
- Discovery is timeboxed and cleans up native listeners, browsers, service-info callbacks, and
|
|
11
|
-
resolvers after completion.
|
|
12
|
-
|
|
41
|
+
resolvers after completion. A valid new discovery replaces the previous request with `error: true` and an empty list on every platform. Invalid requests leave the active search running.
|
|
42
|
+
- Without a name filter, discovery waits for the entire timeout. A matching resolved service with an IP address can finish a filtered search early. A candidate without an address is not returned. Any discovery error discards partial results on every platform.
|
|
13
43
|
- `stopBroadcast()` is idempotent and safe to call repeatedly, including after failed or timed-out
|
|
14
44
|
publish attempts.
|
|
45
|
+
- Android and Electron wait for stop confirmation. A failed or timed-out stop returns `error: true`
|
|
46
|
+
and `publishing: true` because the service may still be active. The registration is retained for
|
|
47
|
+
cleanup, and a replacement advertisement is not started until stopping succeeds.
|
|
48
|
+
- On Android versions before T extension 7, mDNS operations hold a reference-counted Wi-Fi
|
|
49
|
+
multicast lock. Overlapping publishing and discovery keep separate references, so completing
|
|
50
|
+
discovery does not disable multicast for the active advertisement. Failed publish/stop attempts
|
|
51
|
+
release their lock reference while retaining any registration needed for late cleanup.
|
|
52
|
+
- iOS IPv6 addresses with an interface scope retain it as a `%<scope-id>` suffix.
|
|
53
|
+
- All platforms return IPv4 addresses before IPv6, retaining discovery order within each family.
|
|
54
|
+
Electron removes exact duplicate address strings from both discovery and watch snapshots.
|
|
55
|
+
Android retains the scope suffix provided by the OS. Electron's Bonjour library may return
|
|
56
|
+
link-local IPv6 without an interface scope; sorting does not make those addresses usable on an
|
|
57
|
+
IPv6-only network. Try suitable addresses rather than treating `hosts[0]` as a reachability guarantee.
|
|
58
|
+
- On iOS a denied Local Network permission makes `discover()` report an error instead of returning an
|
|
59
|
+
empty list after the timeout.
|
|
60
|
+
- Android resolves discovered services one at a time before API 34 (a platform limit of
|
|
61
|
+
`NsdManager.resolveService`); on API 34+ resolves run concurrently.
|
|
62
|
+
- Service types use `_name._tcp.` or `_name._udp.` (optional trailing dot). The service label has 1–15 ASCII letters/digits/hyphens, includes a letter, starts and ends with a letter or digit, and has no consecutive hyphens. Types are trimmed and lowercased; absent or blank types default to `_http._tcp.` for broadcast/discover. Watch entries must be nonblank.
|
|
63
|
+
- Broadcast names default to `DevIOArtsMDNS` on all platforms, are trimmed, contain no control characters and fit in 63 UTF-8 bytes. Name filters use normalized prefix matching: dots and hyphens compare equally and a final ` (n)` suffix is ignored. Returned names preserve actual advertised spelling. Bonjour on Electron changes dots to hyphens when publishing; native platforms can retain dots.
|
|
64
|
+
- Ports must be integer numbers from 1 to 65535. Timeout defaults to 3000 ms; nonnumeric or non-finite values are errors, fractions are truncated and delays clamped to 0–2147483647 ms.
|
|
65
|
+
- TXT publication works on all three platforms. Values must be strings. Keys must be nonempty printable ASCII without `=`, unique ignoring ASCII case. Each UTF-8 `key=value` entry fits in 255 bytes; the complete TXT record fits in 1300 bytes including the length byte for each entry (the common Android limit). Validation runs before replacing a broadcast.
|
|
66
|
+
- Android cancels an unconfirmed registration immediately through its original listener; it does not wait indefinitely for a publish confirmation. Failed cancellation is retained for a stop retry.
|
|
67
|
+
- Electron reports name conflicts immediately when Bonjour stops its probe; it does not rename the
|
|
68
|
+
service. A service stopped during its probe sends no goodbye records, so a rejected duplicate does
|
|
69
|
+
not evict the original service from other browsers. Once announcement records have been prepared,
|
|
70
|
+
stopping sends goodbye even if the send callback and `up` event have not arrived yet. Stopped
|
|
71
|
+
services ignore late announcement attempts. This behavior is tested with Bonjour 1.4.0;
|
|
72
|
+
the supported dependency range is `~1.4.0`.
|
|
73
|
+
- Electron creates the Bonjour socket only when the first network operation starts. A failed response
|
|
74
|
+
to an incoming query is logged and leaves publication, discovery and watches running. Transport
|
|
75
|
+
`error` events remain fatal: they fail pending operations and stop watches. After a fatal transport
|
|
76
|
+
error, destroy the instance and create a new one.
|
|
77
|
+
- On a fresh iOS installation, the Local Network prompt may outlast a discovery or publish timeout;
|
|
78
|
+
the system may also report denial before the user answers. The plugin does not distinguish a
|
|
79
|
+
pending permission prompt from explicit denial. Explain why access is needed, then allow the user
|
|
80
|
+
to retry the operation after granting it. This first-run sequence still needs physical-device testing.
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Metadata consumed by the capacitor-electron runtime generator (`
|
|
4
|
+
* Metadata consumed by the capacitor-electron runtime generator (`npx cap-electron sync`).
|
|
5
5
|
*
|
|
6
6
|
* Import path for the JS layer: `@devioarts/capacitor-mdns/electron/settings`.
|
|
7
7
|
*/
|
|
8
8
|
const pluginSettings = {
|
|
9
9
|
pluginClass: 'mDNS',
|
|
10
|
-
pluginMethods: [
|
|
11
|
-
|
|
10
|
+
pluginMethods: [
|
|
11
|
+
'getPluginPlatform',
|
|
12
|
+
'startBroadcast',
|
|
13
|
+
'stopBroadcast',
|
|
14
|
+
'discover',
|
|
15
|
+
'watchServices',
|
|
16
|
+
'stopWatching',
|
|
17
|
+
],
|
|
18
|
+
pluginEvents: ['serviceFound', 'serviceLost', 'watchError'],
|
|
12
19
|
};
|
|
13
20
|
|
|
14
21
|
exports.pluginSettings = pluginSettings;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-settings.js","sources":["../build/electron/src/plugin-settings.js"],"sourcesContent":["/**\n * Metadata consumed by the capacitor-electron runtime generator (`
|
|
1
|
+
{"version":3,"file":"plugin-settings.js","sources":["../build/electron/src/plugin-settings.js"],"sourcesContent":["/**\n * Metadata consumed by the capacitor-electron runtime generator (`npx cap-electron sync`).\n *\n * Import path for the JS layer: `@devioarts/capacitor-mdns/electron/settings`.\n */\nexport const pluginSettings = {\n pluginClass: 'mDNS',\n pluginMethods: [\n 'getPluginPlatform',\n 'startBroadcast',\n 'stopBroadcast',\n 'discover',\n 'watchServices',\n 'stopWatching',\n ],\n pluginEvents: ['serviceFound', 'serviceLost', 'watchError'],\n};\n//# sourceMappingURL=plugin-settings.js.map"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACY,MAAC,cAAc,GAAG;AAC9B,IAAI,WAAW,EAAE,MAAM;AACvB,IAAI,aAAa,EAAE;AACnB,QAAQ,mBAAmB;AAC3B,QAAQ,gBAAgB;AACxB,QAAQ,eAAe;AACvB,QAAQ,UAAU;AAClB,QAAQ,eAAe;AACvB,QAAQ,cAAc;AACtB,KAAK;AACL,IAAI,YAAY,EAAE,CAAC,cAAc,EAAE,aAAa,EAAE,YAAY,CAAC;AAC/D;;;;"}
|