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
13 changes: 12 additions & 1 deletion .github/workflows/dart-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ jobs:
- name: Analyze code
run: dart pub global run melos run analyze

- name: Check public Dart entrypoints on stable
run: python3 bindings/dart/nativeapi/tool/check_entrypoints.py --web --standalone

- name: Set up Dart beta
uses: dart-lang/setup-dart@65eb853c7ba17dde3be364c3d2858773e7144260
with:
sdk: 3.14.0-315.3.beta

- name: Check ordinary Dart and web entrypoints on beta
run: python3 bindings/dart/nativeapi/tool/check_entrypoints.py --web

test:
name: Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -309,4 +320,4 @@ jobs:
- name: Build nativeapi example Windows
run: |
cd bindings/dart/nativeapi_flutter/example
flutter build windows --release
flutter build windows --release
4 changes: 3 additions & 1 deletion bindings/dart/README-ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ window?.isAlwaysOnTop = true;

不依赖 Flutter 的 Dart 程序也能开窗口。把应用交给 `runNativeApp()`:它让应用跑在平台的 UI 线程上,并在 Dart 的定时器和 future 之间持续驱动平台事件循环:

这个实验性运行器有独立入口 `package:nativeapi/standalone.dart`,同时导出普通 nativeapi API。它目前依赖 Dart 3.13 的实验性 VM API,不支持 Dart 3.14。Flutter 应用及仅导入 `package:nativeapi/nativeapi.dart` 的程序不依赖这个运行器。

```dart
import 'package:nativeapi/nativeapi.dart';
import 'package:nativeapi/standalone.dart';

void app() {
final window = Window.create()!..title = 'Hello';
Expand Down
4 changes: 3 additions & 1 deletion bindings/dart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ All windows share one engine and one isolate, so they talk to each other through

A Dart program without Flutter can open windows too. Hand the app to `runNativeApp()`, which runs it on the platform's UI thread and keeps the platform loop turning between Dart's timers and futures:

The experimental runner has its own entrypoint, `package:nativeapi/standalone.dart`, which also exports the ordinary nativeapi API. It currently requires Dart 3.13's experimental VM APIs and is not supported on Dart 3.14. Flutter apps and programs importing only `package:nativeapi/nativeapi.dart` do not depend on this runner.

```dart
import 'package:nativeapi/nativeapi.dart';
import 'package:nativeapi/standalone.dart';

void app() {
final window = Window.create()!..title = 'Hello';
Expand Down
5 changes: 5 additions & 0 deletions bindings/dart/nativeapi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## Unreleased

- **Breaking (Dart):** move the experimental `runNativeApp()` helper to `package:nativeapi/standalone.dart`. Plain Dart apps using the helper must change their import; the standalone entrypoint also exports the ordinary nativeapi API. The helper still requires Dart 3.13's experimental VM APIs and is not supported on Dart 3.14.
- Keep the ordinary `nativeapi.dart` import independent of the experimental runner, fixing compilation on Dart 3.14 when the helper is unused ([#22](https://github.com/libnativeapi/nativeapi/issues/22)).

## 0.5.10

- Linux: fix mouse input remaining limited to the old shadow rectangle after restoring the title bar and enlarging a window ([nativeapi-core#90](https://github.com/libnativeapi/nativeapi-core/pull/90)).
Expand Down
9 changes: 5 additions & 4 deletions bindings/dart/nativeapi/lib/nativeapi.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/// Cross-platform native system APIs for Dart and Flutter.
///
/// The experimental plain-Dart event loop is available separately through
/// `package:nativeapi/standalone.dart`, so ordinary imports do not depend on
/// its SDK-specific VM APIs.
library;

// Every generated module. The list itself is generated too, so adding a header
Expand All @@ -9,7 +14,3 @@ library;
// still depend on nativeapi and guard its calls with `kIsWeb`.
export 'src/generated.dart'
if (dart.library.js_interop) 'src/web/generated.dart';

// Hand-written.
export 'src/run_native_app.dart'
if (dart.library.js_interop) 'src/run_native_app_web.dart';
4 changes: 4 additions & 0 deletions bindings/dart/nativeapi/lib/src/run_native_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ const _idleWaitMs = 8;

/// Runs a desktop app from a plain Dart program (`dart run`), without Flutter.
///
/// Import this helper through `package:nativeapi/standalone.dart`. It requires
/// experimental VM APIs available in Dart 3.13 and is not supported on Dart
/// 3.14. The ordinary nativeapi and Flutter entrypoints do not import it.
///
/// [main] builds the app: it creates windows and views and registers
/// listeners. It runs in a new isolate that lives on the platform's UI thread,
/// where every call into nativeapi and every event callback then happens,
Expand Down
14 changes: 14 additions & 0 deletions bindings/dart/nativeapi/lib/standalone.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/// Native system APIs and the experimental event loop for plain Dart apps.
///
/// Re-exports `package:nativeapi/nativeapi.dart` and adds `runNativeApp`.
/// The runner requires experimental VM APIs available in Dart 3.13 and is not
/// supported on Dart 3.14, where those APIs were removed.
///
/// Use `package:nativeapi/nativeapi.dart` for the ordinary API, or
/// `package:nativeapi_flutter/nativeapi_flutter.dart` in Flutter apps. Those
/// entrypoints do not import the experimental runner.
library;

export 'nativeapi.dart';
export 'src/run_native_app.dart'
if (dart.library.js_interop) 'src/run_native_app_web.dart';
46 changes: 46 additions & 0 deletions bindings/dart/nativeapi/tool/check_entrypoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env python3
"""Compile public entrypoints independently from the opt-in standalone runner.

Run after `flutter pub get` at the workspace root. Pass --standalone only on
Dart 3.13, whose experimental VM APIs the native standalone runner currently uses.
"""
import argparse
from pathlib import Path
import shutil
import subprocess
import tempfile


def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--dart', default=shutil.which('dart'))
parser.add_argument('--packages', type=Path)
parser.add_argument('--web', action='store_true')
parser.add_argument('--standalone', action='store_true')
args = parser.parse_args()
if not args.dart:
parser.error('Provide --dart or put the Dart SDK on PATH')
package = Path(__file__).resolve().parents[1]
workspace = package.parents[2]
config = (args.packages or workspace / '.dart_tool/package_config.json').resolve()
if not config.is_file():
parser.error('Run flutter pub get at the workspace root first')
fixtures = package / 'tool/entrypoints'
cases = [('kernel', 'nativeapi_import.dart')]
if args.standalone:
cases.append(('kernel', 'standalone_import.dart'))
if args.web:
cases += [('js', 'nativeapi_import.dart'), ('js', 'standalone_import.dart')]
subprocess.run([args.dart, '--version'], check=True)
with tempfile.TemporaryDirectory(prefix='nativeapi-entrypoints-') as temporary:
for kind, source in cases:
target = Path(temporary) / (Path(source).stem + ('.js' if kind == 'js' else '.dill'))
subprocess.run([
args.dart, 'compile', kind, '--packages=' + str(config),
'-o', str(target), str(fixtures / source),
], check=True)
print('PASS', kind, source, flush=True)


if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion bindings/dart/nativeapi/tool/clipboard_smoke.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Runs on the UI isolate. Wrap with core/build/tests/clipboard_macos_test on macOS.
import 'dart:async';

import 'package:nativeapi/nativeapi.dart';
import 'package:nativeapi/standalone.dart';

void check(bool value) {
if (!value) throw StateError('clipboard assertion failed');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Compile this entrypoint on supported SDKs without opting into VM experiments.
import 'package:nativeapi/nativeapi.dart';

void main() {
const size = Size(width: 800, height: 600);
print('${WindowManager.instance}: ${size.width}x${size.height}');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// The native runner is opt-in; its web entrypoint retains the unsupported stub.
import 'package:nativeapi/standalone.dart';

void main() => print(runNativeApp);
19 changes: 19 additions & 0 deletions bindings/dart/nativeapi/tool/entrypoints/standalone_runtime.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// No input or visible window: verify UI-thread creation, a Dart timer and quit.
import 'dart:async';

import 'package:nativeapi/standalone.dart';

void appMain() {
final window = Window.create();
if (window == null) throw StateError('Could not create a native window');
window.title = 'Standalone entrypoint smoke';
Timer(const Duration(milliseconds: 100), () {
if (window.title != 'Standalone entrypoint smoke') {
throw StateError('Native window did not retain its title');
}
print('PASS standalone callback, native window, Dart timer and quit');
Application.instance.quit(0);
});
}

void main() => runNativeApp(appMain);
4 changes: 4 additions & 0 deletions bindings/dart/nativeapi_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Unreleased

- Stop importing the experimental plain-Dart event-loop helper so Flutter apps compile on Dart 3.14 without the removed isolate APIs or experimental flags ([#22](https://github.com/libnativeapi/nativeapi/issues/22)).

## 0.5.10

- Linux: fix mouse input remaining limited to the old shadow rectangle after restoring the title bar and enlarging a window ([nativeapi-core#90](https://github.com/libnativeapi/nativeapi-core/pull/90)).
Expand Down
6 changes: 3 additions & 3 deletions bindings/dart/nativeapi_flutter/lib/nativeapi_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
/// window.contentView?.addSubview(field);
/// ```
///
/// `runNativeApp` is left out too: it is for plain Dart programs, and a
/// Flutter app's engine already runs the event loop.
/// Flutter's engine already runs its event loop. The experimental plain-Dart
/// `runNativeApp` helper belongs to `package:nativeapi/standalone.dart` and is
/// not imported by this library.
library;

export 'package:nativeapi/nativeapi.dart'
Expand All @@ -34,7 +35,6 @@ export 'package:nativeapi/nativeapi.dart'
EdgeInsets,
Image,
ModifierKey,
runNativeApp,
ShortcutManager,
Size,
TextField,
Expand Down
11 changes: 9 additions & 2 deletions examples/dart_view_example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ A workbench of native views driven from a plain Dart program: no Flutter, just
`dart run`. Everything on screen is a platform control (AppKit on macOS, Win32
on Windows, GTK 3 on Linux) created through `package:nativeapi`.

The standalone runner currently requires Dart 3.13's experimental VM APIs and
is not supported on Dart 3.14. This restriction applies to
`package:nativeapi/standalone.dart`; ordinary nativeapi and Flutter imports
do not depend on the runner.

```bash
dart run bin/main.dart
```
Expand Down Expand Up @@ -39,9 +44,11 @@ Enter to flash that view.

## How it runs without Flutter

`main()` hands the app to `runNativeApp()`:
`main()` imports the standalone entrypoint and hands the app to `runNativeApp()`:

```dart
import 'package:nativeapi/standalone.dart';

void main() => runNativeApp(app);
```

Expand All @@ -51,7 +58,7 @@ keep working while the platform loop is pumped between them. On macOS that
thread is the process's first thread, which AppKit insists on. The standalone
Dart VM keeps it parked while `main()` runs elsewhere, so `runNativeApp()`
takes it over. On Windows and Linux the app gets a thread of its own. See
`runNativeApp()` in `package:nativeapi` for the details.
`runNativeApp()` in `package:nativeapi/standalone.dart` for the details.

## Code

Expand Down
2 changes: 1 addition & 1 deletion examples/dart_view_example/bin/main.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// A workbench of native views — labels, buttons, text fields and an image view
// in rows and columns — from a plain Dart program: `dart run`, no Flutter.

import 'package:nativeapi/nativeapi.dart';
import 'package:nativeapi/standalone.dart';
import 'package:view_example/view_example.dart';

void main() => runNativeApp(app);
Loading