Skip to content
Open
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
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,10 @@ companion app — one `main.dart`, running on both devices.
## List of plugins

Every plugin below has a watchOS implementation, and each package's example
builds and starts on the watchOS 27.0 Simulator. Three of those examples
builds and starts on the watchOS 27.0 Simulator. Two of those examples
start with an error: `sensors_plus_watchos` (the barometer is not
implemented), `in_app_purchase_watchos` (the StoreKit platform addition it
asks for fails) and `network_info_plus_watchos` (the example's
`permission_handler` has no watchOS implementation). What each package
implemented) and `in_app_purchase_watchos` (the StoreKit platform addition
it asks for fails). What each package
covers and what it leaves out are in its `README.md`. Its
`PORTING_REPORT.md` records how the package was ported and what was checked
at the time; the last full run on the Simulator is under
Expand Down
14 changes: 14 additions & 0 deletions packages/network_info_plus_watchos/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
## 0.1.1

* Example: `lib/main.dart` is network_info_plus 8.2.2's own again. Its
location request at start, behind `Platform.isIOS`, which is true on the
watch, is now answered by `permission_handler_watchos`, which the
example's pubspec adds in place of `flutter_watchos` and the
`FlutterWatchosPlatform.isIos` guard. The pubspec names
`permission_handler: ^13.0.2`, as upstream's, and the Info.plist has
upstream's `NSLocationWhenInUseUsageDescription`.
* Example: the start test checks a start without an error, and then the
network info, which waits for the location prompt: it is skipped on a
fresh install with no one to answer the prompt, unless the run passes
`--dart-define=NIP_PROMPT=true`.

## 0.1.0

* The version moves from 0.0.1 to 0.1.0, so that a `^0.1.0` constraint
Expand Down
2 changes: 1 addition & 1 deletion packages/network_info_plus_watchos/PORTING_REPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
| watchOS capability | Partial — Wi-Fi IP only; SSID/BSSID unsupported on watchOS |
| Host unit tests (`flutter-watchos test`) | ✅ pass |
| Upstream integration test | ✅ passes verbatim |
| Example deviations | `example/lib/main.dart`: both permission requests use `FlutterWatchosPlatform.isIos` instead of `Platform.isIOS` (true on the watch), because `permission_handler` has no watchOS implementation and the upstream example started with a `MissingPluginException`; `example/pubspec.yaml` adds `flutter_watchos: ^0.1.0` for it. `example/watchos/Runner/Info.plist` sets `FlutterWatchOSContentScale` to 0.4, because the phone app overflowed the watch screen; `example/test/watchos_content_scale_test.dart` lays it out at that scale on every watch screen size. `example/integration_test/watchos_example_start_test.dart` checks that the example starts cleanly; it passes on the watchOS 27.0 Simulator (Apple Watch Series 12, 46 mm, 2026-10-04) |
| Example deviations | `example/lib/main.dart` is upstream's, unchanged: its location request at start, behind `Platform.isIOS` (true on the watch), is answered by `permission_handler_watchos`, which `example/pubspec.yaml` adds; the Info.plist has upstream's `NSLocationWhenInUseUsageDescription`. Until 0.1.1 the request was guarded with `FlutterWatchosPlatform.isIos`, because `permission_handler` had no watchOS implementation. `example/watchos/Runner/Info.plist` sets `FlutterWatchOSContentScale` to 0.4, because the phone app overflowed the watch screen; `example/test/watchos_content_scale_test.dart` lays it out at that scale on every watch screen size. `example/integration_test/watchos_example_start_test.dart` checks that the example starts cleanly, then that it shows its network info once the location prompt is answered; with no one to answer it, that part is skipped. On the watchOS 27.0 Simulator (Apple Watch Series 12, 46 mm, 2026-11-02) the example showed no exception and no overflow in its first 15 seconds, asked for location with upstream's text, and showed its network info once allowed; the start test passed with location answered before and with the prompt answered during the run (`--dart-define=NIP_PROMPT=true`), and skipped its second part on a fresh install; upstream's `network_info_plus_test.dart` passed |
| Internal unified demo | ✅ included |

Marking: ✅ full / passes · ◐ partial — reason given · ○ not applicable (no upstream test) · ✗ unsupported on watchOS.
Expand Down
20 changes: 13 additions & 7 deletions packages/network_info_plus_watchos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,22 @@ both unchanged except for these watchOS deviations:

| Where | Change | Why |
|---|---|---|
| `example/lib/main.dart`, both permission requests | `Platform.isIOS` becomes `FlutterWatchosPlatform.isIos` | `Platform.isIOS` is true on the watch, and `permission_handler` has no watchOS implementation, so the request failed with `MissingPluginException` at start |
| `example/pubspec.yaml` | adds `flutter_watchos: ^0.1.0` | for `FlutterWatchosPlatform` |
| `example/pubspec.yaml` | adds `permission_handler_watchos` | the example asks `permission_handler` for location at start, behind `Platform.isIOS`, which is true on the watch; this package answers it there |
| `example/watchos/Runner/Info.plist` | sets `FlutterWatchOSContentScale` to `0.4` | the app is designed for a phone and overflowed the watch screen (by 107 pixels on a 46 mm Simulator); the scale makes it lay out in a logical space 2.5 times the screen's size and draws it smaller, without touching the Dart code |

`example/watchos/Runner/Info.plist` has upstream's
`NSLocationWhenInUseUsageDescription`, which the location prompt shows.

`example/integration_test/watchos_example_start_test.dart` is a watchOS test
beside the upstream one: it starts the example and checks that it shows its
network info without an error. The watchOS widget test
`example/test/watchos_content_scale_test.dart` lays the app out at its content
scale on every watch screen size, with a global IPv6 address on screen, and
fails on any overflow.
beside the upstream one: it starts the example and checks that it starts
without an error and then shows its network info. The network info waits for
the answer to the location prompt, so on a fresh install with no one to
answer it that check is skipped; run with `--dart-define=NIP_PROMPT=true` and
answer the prompt, or grant location first with `xcrun simctl privacy`.

The watchOS widget test `example/test/watchos_content_scale_test.dart` lays
the app out at its content scale on every watch screen size, with a global
IPv6 address on screen, and fails on any overflow.

## Not supported on watchOS

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,19 @@
//
// A watchOS supplement to the upstream network_info_plus_test.dart, which
// stays verbatim. The upstream example asks permission_handler for location
// access behind Platform.isIOS, which is true on the watch, and
// permission_handler has no watchOS implementation: the example started with
// a MissingPluginException. The example now guards that call with
// FlutterWatchosPlatform.isIos. This starts the example and checks that it
// reaches its network info without an error.
// access at start, behind Platform.isIOS, which is true on the watch;
// permission_handler_watchos answers it there. This starts the example,
// checks that it starts without an error, and then that it reaches its
// network info.
//
// The network info waits for the answer to the location prompt. A run where
// location was answered before (the Simulator keeps the answer across
// installs) checks it at once. On a fresh install the prompt stays up with
// no one to answer it, so that check is skipped unless the run passes
// --dart-define=NIP_PROMPT=true, where someone answers the prompt within a
// minute. Answering it in advance also works:
// xcrun simctl privacy <watch-sim> grant location \
// com.example.networkInfoPlusExample.watchkitapp
//
// Run on the watch Simulator:
// flutter-watchos drive --driver=test_driver/integration_test.dart \
Expand All @@ -17,19 +25,41 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:network_info_plus_example/main.dart' as app;
import 'package:permission_handler/permission_handler.dart';

/// Whether someone answers the location prompt on this run
/// (`--dart-define=NIP_PROMPT=true`).
const bool _prompt = bool.fromEnvironment('NIP_PROMPT');

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

testWidgets('the example starts and shows its network info',
(WidgetTester tester) async {
// "denied" is a location prompt not answered yet: the example's request
// at start shows it, and the network info waits for it.
final bool answered =
await Permission.locationWhenInUse.status != PermissionStatus.denied;

app.main();
final Stopwatch elapsed = Stopwatch()..start();
while (elapsed.elapsed < const Duration(seconds: 3)) {
await tester.pump(const Duration(milliseconds: 100));
}
expect(tester.takeException(), isNull);

// The info arrives after seven native reads; give it up to 10 s.
if (!answered && !_prompt) {
markTestSkipped('the location prompt is up with no one to answer it: '
'run with --dart-define=NIP_PROMPT=true and answer it, or grant '
'location first');
return;
}

// The info arrives after the answer and seven native reads.
final Duration limit =
answered ? const Duration(seconds: 10) : const Duration(seconds: 60);
final Finder info = find.textContaining('Wifi IPv4:');
final Stopwatch elapsed = Stopwatch()..start();
while (info.evaluate().isEmpty &&
elapsed.elapsed < const Duration(seconds: 10)) {
while (info.evaluate().isEmpty && elapsed.elapsed < limit) {
await tester.pump(const Duration(milliseconds: 100));
}

Expand Down
9 changes: 2 additions & 7 deletions packages/network_info_plus_watchos/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_watchos/flutter_watchos.dart';
import 'package:network_info_plus/network_info_plus.dart';
import 'package:permission_handler/permission_handler.dart';

Expand Down Expand Up @@ -99,9 +98,7 @@ class _MyHomePageState extends State<MyHomePage> {
wifiSubmask;

try {
// watchOS deviation: Platform.isIOS is true on the watch, where
// permission_handler has no implementation, so this asks on iPhone only.
if (!kIsWeb && (Platform.isAndroid || FlutterWatchosPlatform.isIos)) {
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
// Request permissions as recommended by the plugin documentation:
// https://github.com/fluttercommunity/plus_plugins/tree/main/packages/network_info_plus/network_info_plus
if (await Permission.locationWhenInUse.request().isGranted) {
Expand All @@ -118,9 +115,7 @@ class _MyHomePageState extends State<MyHomePage> {
}

try {
// watchOS deviation: Platform.isIOS is true on the watch, where
// permission_handler has no implementation, so this asks on iPhone only.
if (!kIsWeb && (Platform.isAndroid || FlutterWatchosPlatform.isIos)) {
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
// Request permissions as recommended by the plugin documentation:
// https://github.com/fluttercommunity/plus_plugins/tree/main/packages/network_info_plus/network_info_plus
if (await Permission.locationWhenInUse.request().isGranted) {
Expand Down
9 changes: 5 additions & 4 deletions packages/network_info_plus_watchos/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ environment:
dependencies:
flutter:
sdk: flutter
# For FlutterWatchosPlatform.isIos, which the watchOS guard in lib/main.dart
# uses.
flutter_watchos: ^0.1.0
network_info_plus: ^8.2.1
network_info_plus_watchos:
path: ../
permission_handler: ^12.0.0+1
# Upstream's example asks permission_handler for location; this answers it
# on the watch.
permission_handler: ^13.0.2
permission_handler_watchos:
path: ../../permission_handler_watchos

dev_dependencies:
network_info_plus_platform_interface: ^3.1.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// found in the LICENSE file.
//
// A watchOS supplement, not an upstream test. The example is network_info_plus's
// own phone app, kept verbatim but for the watchOS guard on its permission
// request; it fits a watch only through the FlutterWatchOSContentScale in
// own phone app, kept verbatim; it fits a watch only through the
// FlutterWatchOSContentScale in
// watchos/Runner/Info.plist. This lays the app out in the logical space that
// scale gives each watch screen, with room for the system insets, and fails on
// any overflow.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import FlutterWatchOS
@main
struct NetworkInfoPlusExampleApp: App {
#if !arch(arm64_32)
// Remote-notification plumbing (APNs device token, notification payloads)
// for plugins that need it, e.g. firebase_messaging. Safe to keep even if
// no plugin uses notifications.
@WKApplicationDelegateAdaptor(FlutterWatchOSAppDelegate.self)
private var flutterAppDelegate

init() {
// Native platform views: register a SwiftUI factory for every
// `viewType` your Dart code embeds with WatchPlatformView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>FlutterWatchOSContentScale</key>
<real>0.4</real>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Obtain WIFI Name</string>
<key>WKApplication</key>
<true/>
<key>WKWatchOnly</key>
Expand Down
2 changes: 1 addition & 1 deletion packages/network_info_plus_watchos/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: network_info_plus_watchos
description: "watchOS implementation of the network_info_plus plugin, exposing Wi-Fi IPv4 and IPv6 addresses via getifaddrs and dart:ffi (SSID is unavailable on watchOS)."
version: 0.1.0
version: 0.1.1
homepage: https://flutterwatch.dev
repository: https://github.com/flutterwatch/plugins/tree/main/packages/network_info_plus_watchos
issue_tracker: https://github.com/flutterwatch/plugins/issues
Expand Down
Loading