赞
踩
目录:
1. 使用 packages
Flutter 支持使用由其他开发者贡献给 Flutter 和 Dart 生态系统的共享软件包。这使你可以快速构建应用程序,而无需从头开始开发所有应用程序。现有的软件包支持许多使用场景,例如,网络请求 (http),自定义导航/路由处理 (fluro), 集成设备 API (如url_launcher&battery) 以及使用第三方平台 SDK (如 Firebase (需翻墙)))。
如果你正打算开发新的软件包,请参阅开发软件包。如果你希望添加资源、图片或字体,无论是存储在文件还是包中,请参阅资源和图片。
搜索 packages,packages 会被发布到了 Pub 包仓库。Flutter landing 页面显示了与 Flutter 兼容的包 (即声明依赖通常与扑兼容),所有已发布的包都支持搜索。将包依赖项添加到应用程序,要将包 "css_colors" 添加到应用中,请执行以下操作:
如果某个软件包不适用于你的特定需求,则可以开发新的自定义 package (下一章)。
Package versions
所有软件包都有一个版本号,在它们的 pubspec.yaml
文件中指定。Pub 会在其名称旁边显示软件包的当前版本 (例如,请参阅 url_launcher 软件包) 以及所有先前版本的列表。
当 pubspec.yaml
使用速记形式添加包时,plugin1:
这被解释为 plugin1:any
,即可以使用任何版本的包。为了确保某个包在更新后还可以正常使用,我们建议使用以下格式之一指定版本范围:
- dependencies:
- url_launcher: '>=0.1.2 <0.2.0'
- dependencies:
- collection: '^0.1.2'
有关更多详细信息,请参阅 Pub 版本管理指南。
更新依赖包
当你在添加一个包后首次运行 (IntelliJ 中的 "Packages Get") flutter packages get
,Flutter 将找到包的版本保存在pubspec.lock。这确保了如果你或你的团队中的其他开发人员运行 flutter packages get
后回获取相同版本的包。
如果要升级到软件包的新版本,例如使用该软件包中的新功能,请运行 flutter packages upgrade (
在 IntelliJ 中点击Upgrade dependencies)
。 这将根据你在 pubspec.yaml 中指定的版本约束下载所允许的最高可用版本。
依赖未发布的 packages
即使未在 Pub 上发布,软件包也可以使用。对于不用于公开发布的专用插件,或者尚未准备好发布的软件包,可以使用其他依赖项选项:
path:
依赖。路径可以是相对的,也可以是绝对的。例如,要依赖位于应用相邻目录中的插件 "plugin1",请使用以下语法:- dependencies:
- plugin1:
- path: ../plugin1/
- dependencies:
- plugin1:
- git:
- url: git://github.com/flutter/plugin1.git
- dependencies:
- package1:
- git:
- url: git://github.com/flutter/packages.git
- path: packages/package1
最后,你可以使用 ref 参数将依赖关系固定到特定的 git commit,branch 或 tag。有关更多详细信息,请参阅 Pub Dependencies article。
2. 开发 Packages 和插件
使用 package 可以创建可轻松共享的模块化代码。一个最小的 package 包括:
pubspec.yaml
文件:声明了 package 的名称、版本、作者等的元数据文件。lib
文件夹:包括包中公开的 (public) 代码,最少应有一个 <package-name>.dart
文件。
Packages 可以包含多种内容:
fluro
包。battery
插件包。
Step 1: 开发 Dart 包
要创建 Dart 包,请使用 --template=package
来执行 flutter create。
这将在 hello/
文件夹下创建一个具有以下专用内容的 package 工程:
lib/hello.dart
:
test/hello_test.dart
:
Step 2: 实现 package
对于纯 Dart 包,只需在主 lib/<package name>.dart
文件内或 lib
目录中的文件中添加功能 。要测试软件包,请在 test
目录中添加 unit tests。有关如何组织包内容的更多详细信息,请参阅 Dart library package 文档。
如果你想开发一个调用特定平台 API 的包,你需要开发一个插件包,插件包是 Dart 包的专用版本。 插件包包含针对Android (Java 或 Kotlin 代码) 或 iOS (Objective-C 或 Swift 代码) 编写的特定于平台的实现 (可以同时包含 Android 和 Ios 原生的代码)。 API使用 platform channels 连接到特定平台 (Android 或 IOS)。
Step 1: 创建 package
要创建插件包,请使用 --template=plugin
参数执行 flutter create。
使用 --org
选项指定你的组织,并使用反向域名表示法。该值用于生成的 Android 和 iOS 代码中的各种包和包标识符。
flutter create --org com.example --template=plugin hello
这将在 hello/
文件夹下创建一个具有以下专用内容的插件工程:
lib/hello.dart
:
android/src/main/java/com/yourcompany/hello/HelloPlugin.java
:
ios/Classes/HelloPlugin.m
:
example/
:
默认情况下,插件项目针对 iOS 代码使用 Objective-C,Android 代码使用 Java。如果你更喜欢 Swift 或 Kotlin,则可以使用 -i
或 -a
为 iOS 或 Android 指定语言。例如:
flutter create --template=plugin -i swift -a kotlin hello
Step 2: 实现包 package
由于插件包中包含用多种编程语言编写的多个平台的代码,因此需要一些特定的步骤来确保顺畅的体验。
Step 2a: 定义包 API (.dart),插件包的 API 在 Dart 代码中定义。打开主文件夹 hello/,
找到 lib/hello.dart。
Step 2b: 添加 Android 平台代码 (.java / .kt),我们建议你使用 Android Studio 编辑 Android 代码。在 Android Studio 中编辑Android 平台代码之前,首先确保代码至少已经构建过一次 (例如,从 IntelliJ 运行示例应用程序或在终端执行 cd hello/example
; flutter build apk)。
接下来:
hello/example/android/build.gradle
文件。你插件的 Android 平台代码位于 hello/java/com.yourcompany.hello/HelloPlugin。你
可以通过按下 ▶ 按钮从 Android Studio 运行示例应用程序。
Step 2c: 添加 iOS 平台代码 (.h+.m/.swift),我们建议你使用 Xcode 编辑 iOS 代码 。在编辑 Xcode 中的 iOS 平台代码之前,首先确保代码至少已经构建过一次 (例如,从 Xcode 中运行示例应用程序或终端执行 cd hello/example
; flutter build ios --no-codesign)
。
接下来:
hello/example/ios/Runner.xcworkspace
文件。你插件的 iOS 平台代码位于 Pods/DevelopmentPods/hello/Classes/
中。你可以通过按下 ▶ 按钮来运行示例应用程序。
Step 2d: 连接 API 和平台代码,最后,你需要将用 Dart 代码编写的 API 与平台特定的实现连接起来,这是通过 platform channels 完成的。
建议将以下文档添加到所有软件包:
README.md:
介绍包的文件。CHANGELOG.md:
记录每个版本中的更改。LICENSE:
包含软件包许可条款的文件。API documentation
在发布软件包时,API 文档会自动生成并发布到 dartdocs.org,示例请参阅 device_info docs。如果你希望在本地生成 API 文档,请使用以下命令:
cd ~/dev/mypackage。
- export FLUTTER_ROOT=~/dev/flutter (on macOS or Linux)
-
- set FLUTTER_ROOT=~/dev/flutter (on Windows)
dartdoc
工具 (它是 Flutter SDK 的一部分):- $FLUTTER_ROOT/bin/cache/dart-sdk/bin/dartdoc (on macOS or Linux)
-
- %FLUTTER_ROOT%\bin\cache\dart-sdk\bin\dartdoc (on Windows)
有关如何编写 API 文档的提示,请参阅 Effective Dart: Documentation。
一旦你实现了一个包,你可以在 Pub 上发布它 ,这样其他开发人员就可以轻松使用它。在发布之前,检查pubspec.yaml
、README.md
以及CHANGELOG.md
文件,以确保其内容的完整性和正确性。然后,运行 dry-run 命令以查看是否都准备 OK 了:
flutter packages pub publish --dry-run
最后, 运行发布命令:
flutter packages pub publish
有关发布的详细信息,请参阅 Pub publishing docs。
如果您正在开发一个 hello
包,它依赖于另一个包,则需要将该依赖包添加到 pubspec.yaml
文件的 dependencies
部分。 下面的代码使 url_launcher
插件的 Dart API ,这在 hello
包中是可用的:
In hello/pubspec.yaml
:
- dependencies:
- url_launcher: ^0.4.2
现在你可以在 hello
中 import 'package:url_launcher/url_launcher.dart'
然后 launch(someUrl)
了。这与在Flutter 应用程序或任何其他 Dart 项目中引用软件包没有什么不同。但是,如果 hello
碰巧是一个插件包,其平台特定的代码需要访问 url_launcher
公开的特定于平台的 API,那么你还需要为特定于平台的构建文件添加合适的依赖声明,如下所示。
Android
在 hello/android/build.gradle
:
- android {
- // lines skipped
- dependencies {
- provided rootProject.findProject(":url_launcher")
- }
- }
你现在可以在 hello/android/src
源码中 import io.flutter.plugins.urllauncher.UrlLauncherPlugin
访问UrlLauncherPlugin
类。
iOS
在 hello/ios/hello.podspec
:
- Pod::Spec.new do |s|
- # lines skipped
- s.dependency 'url_launcher'
你现在可以在 hello/ios/Classes
源码中 #import "UrlLauncherPlugin.h"
然后访问 UrlLauncherPlugin
类。
解决冲突
假设你想在你的 hello
包中使用 some_package
和 other_package
,并且这两个包都依赖 url_launcher
,但是依赖的是 url_launcher
的不同的版本。那我们就有潜在的冲突,避免这种情况的最好方法是在指定依赖关系时,程序包作者使用版本范围而不是特定版本。
- dependencies:
- url_launcher: ^0.4.2 # Good, any 0.4.x with x >= 2 will do.
- image_picker: '0.1.1' # Not so good, only 0.1.1 will do.
如果 some_package
声明了上面的依赖关系,other_package
声明了 url_launcher
版本像 "0.4.5" 或 "^0.4.0",pub 将能够自动解决问题。 类似的注释适用于插件包对 Gradle 模块和 Cocoa pods 的平台特定的依赖关系。
即使 some_package
和 other_package
声明了不兼容的 url_launcher
版本,它仍然可能会和 url_launcher
以兼容的方式正常工作。 你可以通过向 hello
包的 pubspec.yaml
文件中添加依赖性覆盖声明来处理冲突,从而强制使用特定版本:
强制使用 0.4.3
版本的 url_launcher
,在 hello/pubspec.yaml
中:
- dependencies:
- some_package:
- other_package:
- dependency_overrides:
- url_launcher: '0.4.3'
如果冲突的依赖不是一个包,而是一个特定于 Android 的库,比如 guava
,那么必须将依赖重写声明添加到 Gradle 构建逻辑中。强制使用23.0
版本的 guava
库,在 hello/android/build.gradle
中:
- configurations.all {
- resolutionStrategy {
- force 'com.google.guava:guava:23.0-android'
- }
- }
Cocoapods 目前不提供依赖覆盖功能。
3. 使用平台通道编写平台特定的代码
所谓 "平台特定"或"特定平台",平台指的就是原生 Android 或 IOS,本文主要讲原生和 Flutter 之间如何通信、如何进行功能互调。
本指南介绍如何编写自定义平台特定的代码。一些平台特定的功能可通过现有软件包获得,请参阅使用 packages。
Flutter 使用了一个灵活的系统,允许你调用特定平台的 API,无论在 Android 上的 Java 或 Kotlin 代码中,还是 iOS 上的ObjectiveC 或 Swift 代码中均可用。
Flutter 平台特定的 API 支持不依赖于代码生成,而是依赖于灵活的消息传递的方式:
使用平台通道在客户端 (Flutter UI) 和宿主 (平台) 之间传递消息,如下图所示:
消息和响应是异步传递的,以确保用户界面保持响应 (不会挂起)。
在客户端,MethodChannel
(API) 可以发送与方法调用相对应的消息。 在宿主平台上,MethodChannel
在 Android((API) 和 FlutterMethodChannel iOS (API) 可以接收方法调用并返回结果。这些类允许你用很少的"脚手架"代码开发平台插件。
平台通道数据类型支持和解码器
标准平台通道使用标准消息编解码器,以支持简单的类似 JSON 值的高效二进制序列化,例如 booleans,numbers, Strings, byte buffers, List, Maps (请参阅 StandardMessageCodec
了解详细信息)。 当你发送和接收值时,这些值在消息中的序列化和反序列化会自动进行。
下表显示了如何在宿主上接收 Dart 值,反之亦然:
Dart | Android | iOS |
---|---|---|
null | null | nil (NSNull when nested) |
bool | java.lang.Boolean | NSNumber numberWithBool: |
int | java.lang.Integer | NSNumber numberWithInt: |
int, if 32 bits not enough | java.lang.Long | NSNumber numberWithLong: |
int, if 64 bits not enough | java.math.BigInteger | FlutterStandardBigInteger |
double | java.lang.Double | NSNumber numberWithDouble: |
String | java.lang.String | NSString |
Uint8List | byte[] | FlutterStandardTypedData typedDataWithBytes: |
Int32List | int[] | FlutterStandardTypedData typedDataWithInt32: |
Int64List | long[] | FlutterStandardTypedData typedDataWithInt64: |
Float64List | double[] | FlutterStandardTypedData typedDataWithFloat64: |
List | java.util.ArrayList | NSArray |
Map | java.util.HashMap | NSDictionary |
以下演示如何调用平台特定的 API 来获取和显示当前的电池电量。它通过一个平台消息 getBatteryLevel
调用 Android BatteryManager
API 和 iOS device.batteryLevel
API。
该示例在应用程序内添加了特定于平台的代码。如果你想开发一个通用的平台包,可以在其它应用中也使用的话,你需要开发一个插件,则项目创建步骤稍有不同 (请参阅 开发 packages),但平台通道代码仍以相同方式编写。
注意: 此示例的完整的可运行源代码位于:
/examples/platform_channel/
, 这个示例 Android 是用的 Java, IOS 用的是 Objective-C,IOS Swift 版本请参阅/examples/platform_channel_swift/
Step 1: 创建一个新的应用程序项目
首先创建一个新的应用程序:
flutter create batterylevel。
默认情况下,模板支持使用 Java 编写 Android 代码,或使用 Objective-C 编写 iOS 代码。要使用 Kotlin 或 Swift,请使用 -i 和 /或 -a 标志:
flutter create -i swift -a kotlin batterylevel。
Step 2: 创建 Flutter 平台客户端
该应用的 State
类拥有当前的应用状态,我们需要延长这一点以保持当前的电量。首先,我们构建通道。我们使用 MethodChannel
调用一个方法来返回电池电量。
通道的客户端和宿主通过通道构造函数中传递的通道名称进行连接。单个应用中使用的所有通道名称必须是唯一的; 我们建议在通道名称前加一个唯一的"域名前缀",例如 samples.flutter.io/battery
。
- import 'dart:async';
-
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- ...
- class _MyHomePageState extends State<MyHomePage> {
- static const platform = const MethodChannel('samples.flutter.io/battery');
-
- // Get battery level.
- }
接下来,我们调用通道上的方法,指定通过字符串标识符调用方法 getBatteryLevel
。 该调用可能失败 - 例如,如果平台不支持平台 API (例如在模拟器中运行时),所以我们将 invokeMethod 调用包装在 try-catch 语句中。我们使用返回的结果,在 setState
中来更新用户界面状态 batteryLevel
。
- // Get battery level.
- String _batteryLevel = 'Unknown battery level.';
-
- Future<Null> _getBatteryLevel() async {
- String batteryLevel;
- try {
- final int result = await platform.invokeMethod('getBatteryLevel');
- batteryLevel = 'Battery level at $result % .';
- } on PlatformException catch (e) {
- batteryLevel = "Failed to get battery level: '${e.message}'.";
- }
-
- setState(() {
- _batteryLevel = batteryLevel;
- });
- }
最后,我们在 build 创建包含一个小字体显示电池状态和一个用于刷新值的按钮的用户界面。
- @override
- Widget build(BuildContext context) {
- return new Material(
- child: new Center(
- child: new Column(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- new RaisedButton(
- child: new Text('Get Battery Level'),
- onPressed: _getBatteryLevel,
- ),
- new Text(_batteryLevel),
- ],
- ),
- ),
- );
- }
Step 3a: 使用 Java 添加 Android 平台特定的实现
注意: 以下步骤使用 Java。如果你更喜欢 Kotlin,请跳到步骤 3b。
首先在 Android Studio 中打开你的 Flutter 应用的 Android 部分:
android
文件夹,点击 OK。java
目录下打开 MainActivity.java。
接下来,在 onCreate
里创建 MethodChannel 并设置一个 MethodCallHandler
。确保使用与在 Flutter 客户端使用的通道名称相同。
- import io.flutter.app.FlutterActivity;
- import io.flutter.plugin.common.MethodCall;
- import io.flutter.plugin.common.MethodChannel;
- import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
- import io.flutter.plugin.common.MethodChannel.Result;
-
- public class MainActivity extends FlutterActivity {
- private static final String CHANNEL = "samples.flutter.io/battery";
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
-
- super.onCreate(savedInstanceState);
-
- new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
- new MethodCallHandler() {
- @Override
- public void onMethodCall(MethodCall call, Result result) {
- // TODO
- }
- });
- }
- }
接下来,我们添加 Java 代码,使用 Android 电池 API 来获取电池电量。此代码与你在原生 Android 应用中编写的代码完全相同,首先,添加需要导入的依赖:
- import android.content.ContextWrapper;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.os.BatteryManager;
- import android.os.Build.VERSION;
- import android.os.Build.VERSION_CODES;
- import android.os.Bundle;
然后,将下面的新方法添加到 activity 类中的,位于 onCreate 方法下方:
- private int getBatteryLevel() {
- int batteryLevel = -1;
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
- batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
- } else {
- Intent intent = new ContextWrapper(getApplicationContext()).
- registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
- intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
- }
-
- return batteryLevel;
- }
最后,我们完成之前添加的 onMethodCall
方法。我们需要处理平台方法名为 getBatteryLevel
,所以我们在 call 参数中进行检测是否为 getBatteryLevel
。 这个平台方法的实现只需调用我们在前一步中编写的 Android 代码,并使用 response 参数返回成功和错误情况的响应。如果调用未知的方法,我们也会通知返回:
- @Override
- public void onMethodCall(MethodCall call, Result result) {
- if (call.method.equals("getBatteryLevel")) {
- int batteryLevel = getBatteryLevel();
-
- if (batteryLevel != -1) {
- result.success(batteryLevel);
- } else {
- result.error("UNAVAILABLE", "Battery level not available.", null);
- }
- } else {
- result.notImplemented();
- }
- }
你现就可以在 Android 上运行该应用程序。如果你使用的是 Android 模拟器,则可以通过工具栏中的...
按钮访问 Extended Controls 面板中的电池电量。
如果你希望在多个 Flutter 应用程序中使用特定于平台的代码,将代码分离为位于主应用程序之外的目录中,做一个平台插件会很有用,详情请参阅开发 packages 。
如果你希望与 Flutter 生态系统中的其他开发人员分享你的特定平台的代码,请参阅发[发布 packages](/developing-packages/#publish 以了解详细信息。
除了上面提到的 MethodChannel
,你还可以使用 BasicMessageChannel
,它支持使用自定义消息编解码器进行基本的异步消息传递。 此外,你可以使用专门的 BinaryCodec
,StringCodec
和 JSONMessageCodec
类,或创建自己的编解码器。
4. 读写文件
本指南介绍如何使用 PathProvider
插件和 Dart 的 IO
库在 Flutter 中读写文件 。
PathProvider
插件提供了一种平台透明的方式来访问设备文件系统上的常用位置。该类当前支持访问两个文件系统位置:
NSTemporaryDirectory()
返回的值。在 Android上,这是 getCacheDir()
返回的值。NSDocumentDirectory
。在 Android 上,这是 AppData
目录。一旦你的 Flutter 应用程序有一个文件位置的引用,你可以使用 dart:io API来执行对文件系统的读/写操作。有关使用 Dart 处理文件和目录的更多信息,请参阅此概述和这些示例。
以下示例展示了如何统计应用程序中按钮被点击的次数(关闭重启数据不丢失):
flutter create
或在 IntelliJ 中 File > New Project 创建一个新 Flutter App。pubspec.yaml
文件中声明依赖 PathProvider 插件。lib/main.dart
中的:- import 'dart:io';
- import 'dart:async';
- import 'package:flutter/material.dart';
- import 'package:path_provider/path_provider.dart';
-
- void main() {
- runApp(
- new MaterialApp(
- title: 'Flutter Demo',
- theme: new ThemeData(primarySwatch: Colors.blue),
- home: new FlutterDemo(),
- ),
- );
- }
-
- class FlutterDemo extends StatefulWidget {
- FlutterDemo({Key key}) : super(key: key);
-
- @override
- _FlutterDemoState createState() => new _FlutterDemoState();
- }
-
- class _FlutterDemoState extends State<FlutterDemo> {
- int _counter;
-
- @override
- void initState() {
- super.initState();
- _readCounter().then((int value) {
- setState(() {
- _counter = value;
- });
- });
- }
-
- Future<File> _getLocalFile() async {
- // get the path to the document directory.
- String dir = (await getApplicationDocumentsDirectory()).path;
- return new File('$dir/counter.txt');
- }
-
- Future<int> _readCounter() async {
- try {
- File file = await _getLocalFile();
- // read the variable as a string from the file.
- String contents = await file.readAsString();
- return int.parse(contents);
- } on FileSystemException {
- return 0;
- }
- }
-
- Future<Null> _incrementCounter() async {
- setState(() {
- _counter++;
- });
- // write the variable as a string to the file
- await (await _getLocalFile()).writeAsString('$_counter');
- }
-
- @override
- Widget build(BuildContext context) {
- return new Scaffold(
- appBar: new AppBar(title: new Text('Flutter Demo')),
- body: new Center(
- child: new Text('Button tapped $_counter time${
- _counter == 1 ? '' : 's'
- }.'),
- ),
- floatingActionButton: new FloatingActionButton(
- onPressed: _incrementCounter,
- tooltip: 'Increment',
- child: new Icon(Icons.add),
- ),
- );
- }
- }
5. 在 Flutter 中发起 HTTP 网络请求
本页介绍如何在 Flutter 中创建 HTTP 网络请求。对于 socket,请参阅 dart:io。
注:本篇文档官方使用的是用 dart io 中的
HttpClient
发起的请求,但HttpClient
本身功能较弱,很多常用功能都不支持。我们建议你使用 dio 来发起网络请求,它是一个强大易用的 dart http 请求库,支持 Restful API、FormData、拦截器、请求取消、Cookie 管理、文件上传/下载……详情请查看 github dio。
http 支持位于 dart:io
,所以要创建一个 HTTP client, 我们需要添加一个导入:
- import 'dart:io';
-
- var httpClient = new HttpClient();
该 client 支持常用的 HTTP 操作,such as GET
, POST
, PUT
, DELETE。
注意,HTTP API 在返回值中使用了 Dart Futures。 我们建议使用 async
/await
语法来调用 API。网络调用通常遵循如下步骤:
Several of these steps use Future based APIs. Sample APIs calls for each step above are: 其中的几个步骤使用基于 Future 的API。上面步骤的示例:
- get() async {
- var httpClient = new HttpClient();
- var uri = new Uri.http(
- 'example.com', '/path1/path2', {'param1': '42', 'param2': 'foo'});
- var request = await httpClient.getUrl(uri);
- var response = await request.close();
- var responseBody = await response.transform(UTF8.decoder).join();
- }
使用 dart:convert
库可以简单解码和编码 JSON。 有关其他的 JSON 文档,请参阅 JSON 和序列化。解码简单的 JSON 字符串并将响应解析为 Map:
- Map data = JSON.decode(responseBody);
- // Assume the response body is something like: ['foo', { 'bar': 499 }]
- int barValue = data[1]['bar']; // barValue is set to 499
要对简单的 JSON 进行编码,请将简单值 (字符串,布尔值或数字字面量) 或包含简单值的 Map,list 等传给 encode 方法:
String encodedString = JSON.encode([1, 2, { 'a': null }]);
以下示例显示了如何在 Flutter 应用中对 HTTPS GET 请求返回的 JSON 数据进行解码。
It calls the httpbin.com web service testing API, which then responds with your local IP address. Note that secure networking (HTTPS) is used. 它调用 httpbin.comWeb service 测试 API,请注意,使用安全网络请求 (HTTPS)。
flutter create
,创建一个新的 Flutter 应用。lib/main.dart
替换为一下内容:- import 'dart:convert';
- import 'dart:io';
-
- import 'package:flutter/material.dart';
-
- void main() {
- runApp(new MyApp());
- }
-
- class MyApp extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- return new MaterialApp(
- home: new MyHomePage(),
- );
- }
- }
-
- class MyHomePage extends StatefulWidget {
- MyHomePage({Key key}) : super(key: key);
-
- @override
- _MyHomePageState createState() => new _MyHomePageState();
- }
-
- class _MyHomePageState extends State<MyHomePage> {
- var _ipAddress = 'Unknown';
-
- _getIPAddress() async {
- var url = 'https://httpbin.org/ip';
- var httpClient = new HttpClient();
-
- String result;
- try {
- var request = await httpClient.getUrl(Uri.parse(url));
- var response = await request.close();
- if (response.statusCode == HttpStatus.OK) {
- var json = await response.transform(UTF8.decoder).join();
- var data = JSON.decode(json);
- result = data['origin'];
- } else {
- result =
- 'Error getting IP address:\nHttp status ${response.statusCode}';
- }
- } catch (exception) {
- result = 'Failed getting IP address';
- }
-
- // If the widget was removed from the tree while the message was in flight,
- // we want to discard the reply rather than calling setState to update our
- // non-existent appearance.
- if (!mounted) return;
-
- setState(() {
- _ipAddress = result;
- });
- }
-
- @override
- Widget build(BuildContext context) {
- var spacer = new SizedBox(height: 32.0);
-
- return new Scaffold(
- body: new Center(
- child: new Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: <Widget>[
- new Text('Your current IP address is:'),
- new Text('$_ipAddress.'),
- spacer,
- new RaisedButton(
- onPressed: _getIPAddress,
- child: new Text('Get IP address'),
- ),
- ],
- ),
- ),
- );
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。