前言

近来大前端时代成为了一个很火热的词,各种跨平台的前端框架也不断涌现。不过我个人其实并不太看好这种框架,个人感觉一套代码全平台通用的想法是很好,但是平台是存在差异性的,特别是每个平台还有很多特有的属性,所以要做好终归只能原生。不过作为程序员,学习和了解新技术总没什么错,特别是要清楚本质,所以这里记录下自己学习flutter的过程。

Flutter是啥

flutter是Google开发,用于跨平台开发(目前支持Android和iOS)的一个框架。相比于H5+原生混合开发、React Native或Weex,flutter诞生的比较晚,从第一个beta版本到现在也不过一年。但是可以看到在Google强大的号召力下,开源社区非常火热。flutter和React Native、Weex这些框架最大的区别,应该在于flutter采用自绘引擎,既不使用原生控件,也不使用webView。这样的好处是能做到多端UI表现的一致,也就是真正意义的跨平台了。不过UI其实只是一部分,将来希望能做到更多API的统一。

安装

万丈高楼平地起,这一章主要说安装。

flutter的社区很火热,在国内有专门的中文网,仔细阅读就能解决国内开发基本都会碰到的问题。所以上面写了的我就简单略过,只讲自己碰到的坑。

因为安卓是亲儿子,flutter对于Android的支持完善的多,而苦逼的iOS搭建完整的开发环境还是相对麻烦。本人使用VSCode+插件的方式开发,前面的配置环境变量,安装插件什么的一切顺利,主要问题出现在了安装iOS设备工具这里。

本人使用的是稳定版本,目前是v1.2.1
官方的说明很简单,通过Homebrew一键安装:

1
2
3
4
brew update
brew install --HEAD libimobiledevice
brew install ideviceinstaller ios-deploy cocoapods
pod setup

问题出在了brew install --HEAD libimobiledevice这个东西上。
因为Homebrew会自动检测包依赖,然后他帮我装了python,这就是噩梦的开始。

默认Homebrew安装的是python3,而Mac OS自带的是python2。所以就会出现两个版本。不过不用担心Homebrew会帮你处理好。由于本人python只是略懂皮毛,所以以下的处理方式可能在专业人士看来比较不妥,有更好的方式欢迎给我提issue。

安装出现了这个错误:

1
2
3
4
5
6
7
8
9
10
11
checking consistency of all components of python development environment... no
configure: error:
Could not link test program to Python. Maybe the main Python library has been
installed in some non-standard library path. If so, pass it to configure,
via the LDFLAGS environment variable.
Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib"
============================================================================
ERROR!
You probably have to install the development version of the Python package
for your distribution. The exact name of this package varies among them.
============================================================================

emmm …… 我当时就是这个表情img

查了下发现libimobiledevice这是一个用来和iPhone通信的库,如果不管其实也可以,但是就没法体验flutter的热重载了。所以我们还是得上。错误大致上是说不能链接到python。于是看了看flutter在github上的issue,发现还真有人碰到。大致说这是Homebrew的问题,但是解决方法没说明白。再google,有一些和flutter无关的搜索结果,给出的解决方案大多是安装python-dev,这玩意是Linux上的,mac没有,那就只能自己琢磨了。

一开始猜测可能是多版本python的问题,导致脚本找不到python真正的目录,google之后发现可以通过配置$PATH的方式将python路径加入到环境变量中。命令如下:

1
export PATH=${PATH}:/Library/Frameworks/Python.framework/Versions/3.6/bin

满怀希望的再装一次,发现还是报这个错。于是看看他的log,有这么一段话:

1
2
via the LDFLAGS environment variable.
Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib"

大概是让我执行./configure这个文件的时候指定LDFLAGS这个环境变量为外部的python路径。log里有报错的脚本路径,我的在这里:

1
~/Library/Caches/Homebrew/libimobiledevice:

cd到这个目录,发现是Homebrew缓存libimobiledevice安装脚本的目录。里面有Log提到的configure文件。熟悉Linux的同学应该知道这玩意,这个是手动编译一些库的时候常见的配置脚本。其实这里就是要我们自己手动安装了。好,那我们自己手动加上Python的外部路径,Homebrew的python安装在这里:

1
/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib

在当前目录执行

1
./configure LDFLAGS="-L/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib"

满心欢喜,发现并没有什么卵用。以为是书写方式或者路径不对,做了很多尝试,依然无果。img1 只能看看脚本写的是啥了。

编辑器打开./configure,发现是个shell脚本。搜了下报错信息,发现了这么些代码:

1
2
3
4
5
6
7
8
9
10
if ac_fn_c_try_link "$LINENO"; then :
pythonexists=yes
else
pythonexists=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext

{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pythonexists" >&5
$as_echo "$pythonexists" >&6; }

以我半桶水的shell基础大致就是尝试链接python,底下的代码会通过pythonexists这个标识判断是否链接成功。我们的python其实是能找到的,但是上面的代码不知道为啥报错了,于是我试着在rm -f core conftest.err conftest.$ac_objext的上一行直接粗暴的把pythonexists改为yes。像这样:

1
2
3
4
5
6
7
if ac_fn_c_try_link "$LINENO"; then :
pythonexists=yes
else
pythonexists=no
fi
pythonexists=yes # 加入这行
rm -f core conftest.err conftest.$ac_objext \

保存运行,发现真的没报这个错了。但是又迎来了另一个错误:

1
2
checking for openssl >= 0.9.8... no
configure: error: OpenSSL support explicitly requested but OpenSSL could not be found

WTF?OpenSSL我明明装了,这又搞毛线。google一下发现是mac自带的版本比较旧,最简单的方法是这样:

1
./autogen.sh --disable-openssl

然后居然没报错,Every Thing is OK. 接下来 make install就好了。

然后没有两秒又报错了???img2

好吧,看看报错。

1
2
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/inttypes.h:250:8: error:
unknown type name 'intmax_t'

说的是系统的SDK里没有定义intmax_t这东西,猜测是编译版本的问题。goolge发现人家直接简单粗暴给你加上定义。我们打开Xcode看下intmax_t的定义。

长这样的

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef _INTMAX_T
#define _INTMAX_T
#ifdef __INTMAX_TYPE__
typedef __INTMAX_TYPE__ intmax_t;
#else
#ifdef __LP64__
typedef long int intmax_t;
#else
typedef long long int intmax_t;
#endif /* __LP64__ */
#endif /* __INTMAX_TYPE__ */
#endif /* _INTMAX_T */

其实就是个INTMAX的别名。然后我们把他粘贴到上面报错的头文件中。(uintmax_t也是一样)

之后出现的错误都类似处理,补全定义。

然后,编译通过了~ img3

当然,随便改系统定义的头文件不知道会有什么后果,所以在安装完成之后我就把他复原了。接下来试试flutter的热重载,正常,安装到此结束。

后记

其实还尝试过Android Studio,结果新建flutter工程直接卡死,心累不想找解决方案了,以后flutter能省点心就好了。