Interoperability enhancements, platform-specific networking components, optimized type inference, and recent updates to the null-safe language milestone
Posted by Michael Thomsen, Product Manager, Flutter & Dart, Google
The Dart 2.18 stable release was also released alongside the Flutter 3.3 stable release. This update brings a preview of Dart's Objective-C \& Swift interoperability feature, as well as a package of iOS/macOS web components built on this feature. The new Dart also includes type inference optimizations for generic methods, performance improvements for asynchronous code, new functionality in pub.dev, and some tweaks to our tools and core libraries.
At the end of the article, we also give the latest data on the state of the null-safe migration, and an important update on the roadmap for the eventual full implementation of Dart's null-safe features. Be sure to read to the end.
Dart intermodulates with Objective-C and Swift
Back in 2020, we released a preview of the Foreign Functional Interface (FFI) for calling native C language interfaces, and we will release it in Dart 2.12 in 2021. Since then, a large number of packages have integrated with the existing native C language interface API by taking advantage of FFI, such as file_picker
, printing
, win32
、 objectbox
、 realm
、 isar
、 tflite_flutter
dbus
package。
The Dart team hopes that interoperability between mainstream programming languages can be supported on all platforms that Dart can run on. The official version 2.18 has reached the next milestone of this goal. Now, Dart code can directly call Objective-C and Swift code, Mainly used to call APIs on macOS and iOS platforms. Dart supports "full call" - from the command line code on the backend to the Flutter interface on the frontend, you can use this interoperability mechanism in any application.
This new mechanism stems from the fact that Objective-C and Swift code can be called from C code through the API binding mechanism. Dart's ffigen tool can create these bindings through API header files. Let's look at an example.
Example of Manipulating Time Zones in Objective-C
There is an API for querying time zone information on macOS, which can be called through the NSTimeZone class. Developers can use this API to query the time zone and UTC time zone offset set by the user for the device.
The following sample Objective-C application calls this time zone API to get the system time zone setting and GMT offset.
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSTimeZone *timezone = [NSTimeZone systemTimeZone]; // Get current time zone.
NSLog(@"Timezone name: %@", timezone.name);
NSLog(@"Timezone offset GMT: %ld hours", timezone.secondsFromGMT/60/60);
}
return 0;
}
The sample application first imports the Foundation.h
header file, which contains the API headers for Apple's base library. In the following method body, it calls the systemTimeZone
method of NSTimeZone, which returns an instantiated NSTimeZone
and contains the time zone information set by the device.
Finally, the application prints two lines to the console, containing the timezone name and the hourly offset from UTC:
Timezone name: Europe/Copenhagen
Timezone offset GMT: 2 hours
Example of manipulating timezones in Dart
Let's repeat the implementation just now with Dart and Objective-C interop.
First create an application via the Dart command line:
$ dart create timezones
Next, add the configuration parameters of ffigen
4998472e1677b0d9514aea95e4de7836--- to your pubspec
file. These configurations will set the header file path in the headers and list the wrapper classes to be generated. Objective-C interface:
ffigen:
name: TimeZoneLibrary
language: objc
output: "foundation_bindings.dart"
exclude-all-by-default: true
objc-interfaces:
include:
- "NSTimeZone"
headers:
entry-points:
- "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/
Headers/NSTimeZone.h"
This configures Objective-C bindings for the NSTimeZone.h
header file, and only includes the APIs in the NSTimeZone
interface, then runs the following code to generate the wrapper class:
$ dart run ffigen
This command will create a new dart file containing various API bindings foundation_bindings.dart
, after calling this file, we can write the main Dart method ( main
), this method "Mirror" the Objective-C code, as follows:
void main(List<String> args) async {
const dylibPath =
'/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation';
final lib = TimeZoneLibrary(DynamicLibrary.open(dylibPath));
final timeZone = NSTimeZone.getLocalTimeZone(lib);
if (timeZone != null) {
print('Timezone name: ${timeZone.name}');
print('Offset from GMT: ${timeZone.secondsFromGMT / 60 / 60} hours');
}
}
That's it, this new feature is available as experimental support since Dart 2.18. It enhances Dart's basic interoperability features and can call macOS and iOS APIs directly in Dart code or through Flutter plugins.
We very much welcome feedback from developers, and you can give us feedback via our GitHub Issue, let us know what is working well, what needs to be improved, and any issues you encounter. For more information on interoperability, see the Dart documentation: Interoperating with Objective-C and Swift using package:ffigen .
Platform specific http library
Dart comes with a common library http
which can be applied to multiple platforms. Using this library for network requests can avoid considering the different situations of each platform. But sometimes, developers may want to build on a platform using the platform's network request API.
For example, Apple's network request library NSURLSession can restrict access to Wi-Fi only or require a VPN to connect. To support these use cases, we created a new network request package: cupertino_http
, which is based on the new Objective-C interop mentioned in the previous section, and from the network request library in the Apple Foundation library "Extract" a large number of APIs.
cupertino_http
Example
In this example, the HTTP client for the Flutter app uses the cupertino_http
on macOS and iOS, and the normal dart:io
library on other platforms:
late Client client;
if (Platform.isIOS || Platform.isMacOS) {
final config = URLSessionConfiguration.ephemeralSessionConfiguration()
..allowsCellularAccess = false
..allowsExpensiveNetworkAccess = false;
client = CupertinoClient.fromSessionConfiguration(config);
} else {
client = Client(); // 使用基于 dart:io 的 HTTP 客户端
}
After initial configuration like this, the application will perform specific network requests on different platforms, such as the current get()
request similar to the following:
final response = await get(
Uri.https(
'www.googleapis.com',
'/books/v1/volumes',
{'q': 'HTTP', 'maxResults': '40', 'printType': 'books'},
),
);
When the common interface cannot be used, you can call Apple's network request API through cupertino_http
:
final session = URLSession.sessionWithConfiguration(
URLSessionConfiguration.backgroundSession('com.example.bgdownload'),
onFinishedDownloading: (s, t, fileUri) {
actualContent = File.fromUri(fileUri).readAsStringSync();
});
final task = session.downloadTaskWithRequest(
URLRequest.fromUrl(Uri.https(...))
..resume();
Use platform-specific networking in multi-platform applications
Our design goal is still to maintain the multi-platform versatility of the application as much as possible, so we reserve the basic network requests and other operations common to multiple platforms for the http
API, and can configure the network on different platforms through configuration files. request library. Developers can use the package:http
Client API to reduce writing platform-specific code, which can be configured per platform and used in a platform-independent manner.
Dart 2.18 provides experimental support for the platform-specific http library for the package:http
Client API :
- Using NSURLSession based on macOS/iOS
- Using Cronet on Android is based on Cronet , a very popular network request library on Android
Combining a common Client API with several different network request implementations gives you the benefit of both using platform-specific behavior while still maintaining the same set of shared network request resources. We'd love to hear your feedback on GitHub .
Enhanced type inference
Dart uses many common methods, consider this fold method that converts a collection element to a single value. Here is an example of summing the numbers in a collection:
List<int> numbers = [1, 2, 3];
final sum = numbers.fold(0, (x, y) => x + y);
print(‘The sum of $numbers is $sum’);
Before Dart 2.17 this method would return a type error:
line 2 • The operator ‘+’ can’t be unconditionally invoked because the receiver can be ‘null’.
Dart cannot combine information between multiple parameters for type inference. This resulted in x
type being indeterminate. To correct this potential error, you need to specify the type:
final sum = numbers.fold(0, (int x, int y) => x + y)
Dart 2.18 enhances type inference. In the previous example, Dart would perform static analysis and deduce that both x and y are non-null integers. This change allows you to write more concise Dart code while retaining the robustness of strong type inference.
Asynchronous function performance enhancement
This version of Dart optimizes the way the Dart VM executes async
and async*
/ sync*
. This reduces code size: on two of Google's large applications, we saw about a 10% reduction in AOT snapshot product size. The performance improvement is also reflected in our microbenchmarks.
There are some additional minor behavioral changes included with the VM, see the release notes for more.
Improvements to the Pub.dev website
Combined with the changes released in version 2.18, we have also brought two new changes to the package ecological website pub.dev
.
Typically, individual package developers maintain and release new packages in their spare time, which can consume a lot of their time and resources. In order to facilitate other users to sponsor, we support a brand new funding
tag in pubspec
9732681576d92d60f90bae44076e42c2---, which package developers can use to list one or more links to sponsor their continuous development, These links will appear in the pub.dev
sidebar of the website.
To learn more visit the pubspec documentation .
In addition, we also want to promote a rich ecosystem of open source packages, and to highlight this, the automatic scoring system at pub.dev
will award an additional 10 points for packages using an OSI-approved license .
some breaking changes
Dart has a strong focus on simplicity and learnability, so we've been careful when adding new features. One way to keep it simple is to remove old features and APIs that are rarely used or have better replacements. Dart 2.18 cleans up this type of entry and includes a few breaking changes:
- We added unified
dart
CLI developer tools in October 2020. In 2.18, we completed this transition. This release removes the last two deprecated command line tools:dart2js
(replaced to usedart compile js
) anddartanalyzer
(replaced to usedart analyze
). - With the introduction of language versioning, the
pub
command will generate a new parsing file:.dart_tool/package_config.json
(previously used.packages
format files cannot contain versions), Now that we have stopped using the.packages
files, if you have any.packages
files, you can delete them. - Classes that do not inherit from
Object
can no longer be used as mixins (breaking change #48167 ), this behavior was never intentionally encouraged. -
dart:io
inRedirectException
uri
property changed to nullable (breaking change #49045 ). -
dart:io
Constant following theSCREAMING_SNAKE
convention in the web request API has been removed (breaking change #34218 ), use the corresponding lowerCamelCase constant instead. - Dart VM no longer restores initial terminal settings on exit, programs that change standard input settings
lineMode
andechoMode
are now responsible for restoring settings when the program exits (breaking change #45630 ).
empty security update
Since airsafe was released in beta in November 2020 and officially launched with Dart 2.12 in March 2021, we're happy to see airsafe widely used.
First, developers of most of the popular packages on pub.dev
have migrated to null-safe. Our analysis shows that the top 250 most used packages already support null safety, and 98% of the top 1,000 packages already support null safety.
Second, most developers are already developing in a codebase with complete null safety. This is critical because Dart's sane null-safety doesn't come into play until all code and all dependencies (including transitive) are migrated, which we're tracking via telemetry from the flutter run
command at this point.
The figure below shows a comparison of flutter run
command execution in Unsound and Sound null safety. Both were zero before null safety was introduced. Then the non-sound null security grew rapidly. At this time, the application began to gradually migrate to null security. The developers first migrated some parts, but some parts still need to be migrated. Over time, we can see a steady increase in the sound air safety curve, and by the end of last month, sound air safety had four times more executions compared to non-sound air safety. We hope that over the next few quarters we will see sound air safety reach 100%!
Important Air Safety Roadmap Update
Supporting both non-sane and sane null safety inevitably adds overhead and complexity.
First, Dart developers need to learn and understand both patterns. Whenever you read a piece of Dart code, you need to check the language version .
Second, supporting both modes at the compiler and runtime also slows down the development of the Dart SDK to support new features.
Based on the overhead of non-sound null-safety and the very impressive stats mentioned in the previous section, our goal is to transition to supporting only sane null-safe and stop supporting both non-null-safe and non-sane null-safe modes, we temporarily It is scheduled for release in mid-2023.
This will mean the end of support for Dart 2.11 and earlier. pubspec
with SDK constraints and lower bound less than 2.12 will no longer be resolved in Dart 3 and later. In source code containing language tags, it will fail if set to less than 2.12 (eg //@dart=2.9
).
If you've migrated to sane null-safety, your code will work with full null-safety in Dart 3. If you haven't already, our advice is to start migrating now. Learn more about these changes in this issue .
Summarize
Interop with the likes of Objective-C and Swift, the network request library, type inference for the Dart programming language, and updates to pub.dev are officially available. To start the experience, please download the latest Dart 2.18 official version, or experience it directly in Flutter 3.3, or directly experience the Dart programming language in DartPad.
Finally, the migration of null safety, please start the migration now, and work with us to build and experience the Dart programming language with sound null safety features!
Original link :
https://medium.com/dartlang/dart-2-18-f4b3101f146c
Localization : CFUG Team: \@chenglu, \@Vadaski, \@MeandNi, \@Realank
Chinese link :
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。