跳到主要内容
版本:dev

Web Platform Support

Fory Dart supports Dart VM/AOT, Flutter, browser, and Flutter web builds through generated serializers and platform-specific implementations. The public API and registration flow are the same across these platforms, but web builds have stricter integer precision rules because Dart int is represented by JavaScript numbers.

Supported Targets

Fory Dart supports:

  • Dart VM/JIT applications.
  • Dart AOT/native applications.
  • Flutter mobile and desktop applications.
  • Dart applications compiled to JavaScript for browsers.
  • Flutter web applications.
  • Generated @ForyStruct serializers and manually registered serializers on all supported targets.
  • Ordinary generated inheritance, including typed cross-library private-field companions.
  • External structural serializers generated with @ForyStruct(target: ...).

Code Generation Is Required

Fory Dart uses explicit registration instead of runtime reflection. For annotated structs, run code generation and register the generated serializer before serializing or deserializing values:

import 'package:fory/fory.dart';

part 'account.fory.dart';

()
class Account {
Account();

String name = '';
Int64 sequence = Int64(0);
}

void main() {
final fory = Fory();
AccountForyModule.register(
fory,
Account,
name: 'example.Account',
);

final bytes = fory.serialize(Account()..name = 'web');
final account = fory.deserialize<Account>(bytes);
print(account.name);
}

Generate the companion file before building or testing:

cd dart/packages/fory
dart run build_runner build

The registration call is the same on VM/AOT, Flutter, and web. Custom serializers use registerSerializer(...); generated structs use the generated register wrapper.

Included inherited fields use the same statically generated code on every platform. ignoreInheritedPrivateFields is applied during generation and adds no runtime branch. See Struct Inheritance for cross-library provider setup.

64-Bit Integer Rules

Dart VM int values are signed 64-bit values. Dart web int values are backed by JavaScript numbers and are precise only in the JS-safe integer range:

-9007199254740991 <= value <= 9007199254740991

Use this rule when choosing field types:

Logical valueRecommended Dart field type on webNotes
Signed 64-bit value within JS-safe rangeintWorks with default int64 mapping and @ForyField(type: Int64Type(...)) encodings.
Full signed 64-bit rangeInt64Preserves values outside the JS-safe range.
Unsigned 64-bit valueUint64Required for values that do not fit in signed or JS-safe Dart int.
8/16/32-bit integerint + @ForyField(type: ...)Use explicit field metadata to match peer languages exactly.

@ForyField(type: Int64Type(...)) controls the wire encoding of a Dart int field:

()
class SafeCounter {
SafeCounter();

(type: Int64Type(encoding: Encoding.tagged))
int count = 0; // keep web values inside the JS-safe range
}

It does not make Dart int capable of storing every 64-bit value on web. For full-range signed values, use Int64:

()
class FullRangeCounter {
FullRangeCounter();

Int64 count = Int64(0);
}

For unsigned values, use Uint64:

()
class StorageExtent {
StorageExtent();

Uint64 byteOffset = Uint64(0);
}

Custom Serializers

Custom serializers can use the same Buffer, WriteContext, and ReadContext APIs on VM/AOT, Flutter, and web. For 64-bit values:

  • Use buffer.writeInt64(Int64(...)) and buffer.readInt64() for full-range signed 64-bit values.
  • Use buffer.writeUint64(Uint64(...)) and buffer.readUint64() for full-range unsigned 64-bit values.
  • Use writeInt64FromInt, writeVarInt64FromInt, and matching AsInt reads only when the value is intended to be a Dart int and therefore must stay JS-safe on web.

Example:

final class OffsetSerializer extends Serializer<StorageExtent> {
const OffsetSerializer();


void write(WriteContext context, StorageExtent value) {
context.buffer.writeUint64(value.byteOffset);
}


StorageExtent read(ReadContext context) {
return StorageExtent()..byteOffset = context.buffer.readUint64();
}
}

Collections And Typed Arrays

List, Set, Map, Uint8List, numeric typed arrays, Int64List, and Uint64List are supported on web. The Int64List and Uint64List implementations preserve 64-bit values without depending on JavaScript integer precision. Use the Fory wrapper list types when the schema is array<int64> or array<uint64>.

Testing Browser Builds

Run the package tests in both VM and Chrome when changing code that must work on web:

cd dart/packages/fory
dart run build_runner build
dart test
dart test -p chrome

For an application smoke test, also compile and execute the actual generated entry point:

dart compile js --fatal-warnings bin/app.dart -o build/app.js
node build/app.js

Use a model with the same hierarchy and imports as the production application when validating cross-library private fields. Compilation alone does not prove that registration and round-trip execution work.

If Chrome tests fail with a stale generated file or missing part file, rerun build_runner and then retry the test command from dart/packages/fory.

Common Web Failures

Dart int value ... is outside the JS-safe signed int64 range

The serializer is trying to write a Dart int as a signed 64-bit value on web, but the value is outside the range that JavaScript numbers can represent exactly. Change the field type to Int64, or keep the value inside the JS-safe range.

Int64 value ... is not a JS-safe int

The deserializer read a full-range Int64, but the target field or custom serializer asked for a Dart int. Change the field type to Int64, or decode with readInt64() instead of an AsInt helper.

Uint64 value ... is not a JS-safe int

The code is converting a Uint64 to Dart int on web. Keep the value as Uint64 unless the application has already validated that it is in the JS-safe non-negative range.