去年参加 Google Developer Days 的时候就被好好安利了一波,这一周好好研究了以下,成功实现了从 dart 零基础到写出跨 iOS 和 Android 的应用。为了编译成 iOS App,我还不得不花了点时间在 g470 上安装了黑苹果,效果居然还不错。
安装配置 Flutter SDK
windows
首先从 flutter 官网上下载 flutter sdk, 无法访问的可以尝试 国内镜像, 下载下来是一个压缩包,解压到目录下
点击 flutter_console ,看到这样的界面就已经可以使用了。
为了在 cmd 中能够全局使用,我们可以把 flutter sdk 加入系统环境变量。打开 控制面板\系统和安全\系统 ,点击 高级系统设置–> 环境变量 :
点击 Path ,选择 编辑
在弹出的界面里面选择 新建 ,复制粘贴解压的 flutter\bin
目录到文本框内就可以了:
再试着打开 cmd , 输入 flutter doctor
, 就能看到相应的输出。
Mac os
Mac os 上面的配置过程类似,下载好 SDK 后,将 flutter sdk 加入 path 变量即可。以 zsh shell 为例,编辑 ~/.zshrc,将 /flutter/bin 目录加到PATH 这一行就可以
1 | export PATH=[PATH_TO_FLUTTER_GIT_DIRECTORY]/flutter/bin:$PATH |
配置Xcode 实机调试
flutter 框架写出来的程序可以编译在 android 和 iOS 两大平台上运行。编译成 apk 的方法在 官网 上有详细的教程,这里记录一下在 Mac os 上利用 xcode 编译遇到的问题。
- flutter 配置部署需要依赖安装 cocoapods:
1
2
3
4brew update
brew install --HEAD libimobiledevice
brew install ideviceinstaller ios-deploy cocoapods
pod setup - 由于我的系统还停留在 10.12.6,因此应用商店上下载的 xcode 并不是最新版本,而在使用 11.3 系统的 iphone 真机调试的时候会报出警告
Could not locate device support files
解决办法也很简单,参考了这篇 博客 。不需要升级系统或者下载更新 xcode ,只需要拷贝一个文件即可: 从 github 上下载支持文件,然后将其拖放到Contents-->Developer-->Platforms-->iPhoneOS.platform-->DeviceSupport/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
相应的系统目录下就可以。 - 应用签名的问题。现在的 xcode 不需要开发者账户也能在实体设备上安装调试应用(但是发布到应用商店是必须要的),参看 这篇博客教程 ,添加个人 appStore 账户作为个人开发者也可以调试运行
Json 文件本地存储与读取
这个问题花了我一点时间,总体的结局思路是 dart object 和 json object之间的互转,再将本地 json 作为 String 写入文本文档。
文件 IO
dart 提供了内置的 io 库,flutter 上面也有 path_provider 插件。
- 安装 path_provider插件
编辑 pubspec.yml 文件,加入依赖:点击 Android Studio 里面的 Packages get 之后,就会自动下载安装依赖。1
2
3
4
5
6
7
8dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.0
path_provider: ^0.4.0 - 获取应用程序目录和缓存目录,参考 官方示例
1
2
3
4
5
6
7import 'dart:io';
import 'package:path_provider/path_provider.dart';
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;读取 Json
查看 dart 官方库里面的 json.dart 源代码,有如下的代码注释:可见 json.decode 是将符合 json 标准 的字符串转变为 object ,可以是 List, Map.1
2
3
4
5
6
7
8
9
10
11
12
13
14* Parses the string and returns the resulting Json object.
*
* The optional [reviver] function is called once for each object or list
* property that has been parsed during decoding. The `key` argument is either
* the integer list index for a list property, the string map key for object
* properties, or `null` for the final result. Like this:
*
* The default [reviver] (when not provided) is the identity function.
*/
dynamic decode(String source, {reviver(Object key, Object value)}) {
if (reviver == null) reviver = _reviver;
if (reviver == null) return decoder.convert(source);
return new JsonDecoder(reviver).convert(source);
}
object 与 json
官方文档里面是这样描述的:
Decoding and encoding JSON
Decode a JSON-encoded string into a Dart object with jsonDecode():
1 | // NOTE: Be sure to use double quotes ("), |
Encode a supported Dart object into a JSON-formatted string with jsonEncode():
1 | var scores = [ |
Only objects of type int, double, String, bool, null, List, or Map (with string keys) are directly encodable into JSON. List and Map objects are encoded recursively.
实现思路
- 在 NotePage 中使用 RadioListTile widget,利用用户的选择值和时间构造 json 数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17List<Widget> makeRadioList() {
List<Widget> list = new List<Widget>();
for (int i = -2; i < 3; i++) {
list.add(new RadioListTile(
value: i,
title: new Text('心情 $i'),
activeColor: Colors.deepOrange,
groupValue: _selected,
onChanged: (int value) {
onChanged(value);
},
subtitle: new Text('心情值'),
secondary: new Icon(Icons.favorite),
));
}
return list;
} - 将每次获取到的 json 数据添加到一个 List 之中。采用字符串手动拼接构建 List:
1
2
3
4
5
6
7
8
9var moodObject =
{
'Time': key,
'Value': value,
};
print("mood object is: " + moodObject.toString());
var jsonText = json.encode(moodObject);
// manually construct a List
jsonText = '[' + jsonText + ']';后续TODO
模块化和页面跳转
界面优化
接入野狗 SDK