https://www.gravatar.com/avatar/7a0c24f697ea1587001c36d00039b60f?s=240&d=mp

flutter插件上传pub.dartlang失败的解决方案

最近开发了一款flutter的插件,想发布到pub.darlang上面去,然后发现命令行各种失败,设置了ss全局|-代|理,命令行export代|理,全都不行,账号验证完毕后,提示上传完成,但是最后一步总是失败。后来无意中发现一次上传过程中出现的地址是flutter-io.cn,我猜测会不会是因为设置了镜像的原因。果断在.zshrc中去掉了镜像地址设置,然后再试,一次成功,完美解决。

# 注释掉这两句
# export PUB_HOSTED_URL=https://pub.flutter-io.cn
# export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn

如果有其他同学遇到类似问题,可以试试去掉镜像再试试。

flutter实用技巧汇总

bottomNavigationBar TabBar Navigator等 使用这些控件时,可能出现跳转后bottomNavigationBar还保留在底部的情况。 截止本文发布为止,目前Flutter开发工具还是有一些莫名其妙的问题的。如果你一直用iOS模拟器调试,发现有些奇葩问题怎么改代码都没效果,不妨切换成android模拟器试试,反之亦然。

获取设备宽高

double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;

标题栏沉浸式

void main() {
  runApp(App());
  if (Platform.isAndroid) {
    SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(statusBarColor: Colors.transparent);
    SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
  }
}

AppBar标题居中和去掉AppBar下侧阴影

Widget _tabbar(BuildContext context) {
    return AppBar(
      ...
      centerTitle: true, // 标题居中
      elevation: 0.0, // 去掉appbar下面的阴影
    );
  }

有状态组件一定要使用createState

class HomeScreen extends StatefulWidget {
  const HomeScreen();

  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateMixin {
  // 使用TickerProvider 记得加 with SingleTickerProviderStateMixin 不然会报错
}

使用ios的动画交互 和 MaterialApp 主题颜色配置不生效的问题 检查是否存在子级MaterialApp。如果有子级MaterialApp请删除,保证全局只有一个MaterialApp,theme就会生效

视频H5 video标签最佳实践

https://cloud.githubusercontent.com/assets/16514704/25273844/2894bc8e-26c0-11e7-87f3-2a051d1e92b9.jpg

随着 4G 的普遍以及 WiFi 的广泛使用,手机上的网速已经足够稳定和高速,以视频为主的 HTML5 也越来越普遍了,相比帧动画,视频的表现更加丰富,这里介绍一些实践经验。

video的属性

<video
  id="video" 
  src="video.mp4" 
  controls = "true"
  poster="images.jpg" /*视频封面*/
  preload="auto" 
  webkit-playsinline="true" /*这个属性是ios 10中设置可以
                     让视频在小窗内播放,也就是不是全屏播放*/  
  playsinline="true"  /*IOS微信浏览器支持小窗内播放*/ 
  x-webkit-airplay="allow" 
  x5-video-player-type="h5"  /*启用H5播放器,wechat安卓版特性*/
  x5-video-player-fullscreen="true" /*全屏设置,
                     设置为 true 是防止横屏*/
  x5-video-orientation="portraint" //播放器支付的方向, landscape横屏portraint竖屏,默认值为竖屏
  style="object-fit:fill">
</video>
  • src: 视频的地址
  • controls: 加上这个属性,Gecko 会提供用户控制,允许用户控制视频的播放,包括音 量,跨帧,暂停/恢复播放。
  • poster: 属性规定视频下载时显示的图像,或者在用户点击播放按钮前显示的图像。如果未设置该属性,则使用视频的第一帧来代替。
  • preload: 属性规定在页面加载后载入视频。
  • webkit-playsinlineplaysinline: 视频播放时局域播放,不脱离文档流 。但是这个属性比较特别, 需要嵌入网页的APP比如WeChat中UIwebview 的allowsInlineMediaPlayback = YES webview.allowsInlineMediaPlayback = YES,才能生效。换句话说,如果APP不设置,你页面中加了这标签也无效,这也就是为什么安卓手机WeChat 播放视频总是全屏,因为APP不支持playsinline,而ISO的WeChat却支持。 这里就要补充下,如果是想做全屏直播或者全屏H5体验的用户,IOS需要设置删除 webkit-playsinline 标签,因为你设置 false 是不支持的 ,安卓则不需要,因为默认全屏。但这时候全屏是有播放控件的,无论你有没有设置control。 做直播的可能用得着播放控件,但是全屏H5是不需要的,那么去除全屏播放时候的控件,需要以下设置:同层播放
  • x-webkit-airplay="allow": 这个属性应该是使此视频支持ios的AirPlay功能。使用AirPlay可以直接从使用iOS的设备上的不同位置播放视频、音乐还有照片文件,也就是说通过AirPlay功能可以实现影音文件的无线播放,当然前提是播放的终端设备也要支持相应的功能
  • x5-video-player-type: 启用同层H5播放器,就是在视频全屏的时候,div可以呈现在视频层上,也是WeChat安卓版特有的属性。同层播放别名也叫做沉浸式播放,播放的时候看似全屏,但是已经除去了control和微信的导航栏,只留下"X"和"<“两键。目前的同层播放器只在Android(包括微信)上生效,暂时不支持iOS。至于为什么同层播放只对安卓开放,是因为安卓不能像ISO一样局域播放,默认的全屏会使得一些界面操作被阻拦,如果是全屏H5还好,但是做直播的话,诸如弹幕那样的功能就无法实现了,所以这时候同层播放的概念就解决了这个问题。不过在测试的过程中发现,不同版本的IOS和安卓效果略有不同
  • x5-video-orientation: 声明播放器支持的方向,可选值landscape 横屏, portraint竖屏。默认值portraint。无论是直播还是全屏H5一般都是竖屏播放,但是这个属性需要x5-video-player-type开启H5模式
  • x5­-video­-player­-fullscreen: 全屏设置。它又两个属性值,ture和false,true支持全屏播放,false不支持全屏播放。其实,IOS 微信浏览器是Chrome的内核,相关的属性都支持,也是为什么X5同层播放不支持的原因。安卓微信浏览器是X5内核,一些属性标签比如playsinline就不支持,所以始终全屏。

全屏处理

  • ios ios加playsinline属性,之前只带webkit前缀的在ios10以后,会吊起系统自带播放器,两个属性都加上基本ios端都可以保证内敛到浏览器webview里面了。如果仍有个别版本的ios会吊起播放器,还可以引用一个库iphone-inline-video(具体用法很简单看它github,这里不介绍了,只需加js一句话,css加点),github地址加上playsinline webkit-playsinline这两个属性和这个库基本可以保证ios端没有问题了(不过亲测,只加这两个属性不引入库好像也是ok的,至今没有在ios端微信没有出现问题,如果你要兼容uc或者qq的浏览器建议带上这个库).
  • android x5-video-player-type="h5"属性,腾讯x5内核系的android微信和手Q内置浏览器用的浏览器webview的内核,使用这个属性在微信中视频会有不同的表现,会呈现全屏状态,貌似播放控件剥去了,至少加了这个属性后视频上层可以有其他dom元素出现了(非腾讯白名单机制的一种处理措施)。
<video id="video" src="xx.mp4" playsinline webkit-playsinline></video>

自动播放

android始终不能自动播放,不多说。值得一提的是经测现在ios10后版本的safari和微信都不让视频自动播放了(顺带音频也不能自动播放了),但微信提供了一个事件WeixinJSBridgeReady,在微信嵌入webview全局的这个事件触发后,视频仍可以自动播放,这个应该是现在在ios端微信的视频自动播放的比较靠谱的方式,其他如手q或者其他浏览器,建议就引导用户出发触屏的行为操作出发比较好。

jenkins+fastlane+ios自动化打包实战

当项目达到一定规模后,为了便于管理,我们都会引入自动化构建。本篇主要是讲述如果通过jenkins和fastlane实现iOS的打包。

关于jenkins的搭建就不多说了,大家可以按照网上的文章去配置,基本都是傻瓜式一键安装。

本文将要解决的问题是如何在jenkins搭建iOS的自动编译job。

构建iOS的包只能在Mac机器上进行,如果Jenkins搭建在Linux或者非Mac机器上,需要在Jenkins中配置slave节点连接到Mac电脑。

1. 准备工作

Q:为何是通过fastlane来构建iOS,而不是通过Jenkins的Xcode插件来构建呢? A:Xcode插件方式不仅配置麻烦,而且配置完成后还需要大量的调试工作才能正确编译。而fastlane只需要配置一次,简单方便。

既然是通过fastlane来构建,那么我们首先得需要配置好fastlane相关的东西。

1.1 安装fastlane

在Mac编译机上需要配置好fastlane

打包iOS我们需要保证xcode命令行已经正确安装

xcode-select --install  //命令行输入,如果未安装会弹出对话框提示安装,否则会提示已经安装

可以通过两种方式来安装fastlane 方式一:

[sudo] gem install fastlane -NV

方式二:

brew cask install fastlane

1.2 项目中配置fastlane

给我们需要自动化编译的iOS工程配置fastlane

假如我们现在有一个BlocklySample的工程,我们需要在项目根目录下执行命令行

fastlane init

会有如下图这样的提示,需要我们选择哪种任务,这里我们可以选2或者3。选择这两个选择后会提示让你输入iOS开发者的账号密码,这样会自动给你生成团队信息、bid和基本编译脚本等等。 http://7xq9ge.com1.z0.glb.clouddn.com/2018-08-15-15343039262110.jpg

执行完成后在项目根目录下会自动新建一个fastlane的目录 http://7xq9ge.com1.z0.glb.clouddn.com/2018-08-15-15343127999279.jpg

修改fastlane目录下的Fastfile文件

# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
#     https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
#     https://docs.fastlane.tools/plugins/available-plugins
#

# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane

default_platform(:ios)

platform :ios do
  desc "Push a new release build to the App Store"
  lane :release_appstore do
    increment_build_number(xcodeproj: "xxx.xcodeproj")
    update_project_provisioning(
        # 之前有sigh下载的描述文件存储路径
        profile:"fastlane/provision/xxx.mobileprovision",
        # 打包配置,Debug,Release
        build_configuration:"Release"
    )
    automatic_code_signing(
        # 工程文件所在路径
        path:"xxx.xcodeproj",
        # 是否使用自动签名,这里如果是打包的话应该一般都为false吧,默认也是false
        use_automatic_signing:false,
        # 这个就不用说了,需要修改的targets
        targets:"xxx",
        # 用哪种方式打包“iPhone Develop”还是“iPhone Distribution”
        code_sign_identity:"iPhone Distribution",
        # 描述文件名称, 也就是使用哪个描述文件打包
        profile_name:"xxx"
    )
    scheme_name = 'xxx'
    configuration = 'AppStore'
    version = get_info_plist_value(path: "./#{scheme_name}/Info.plist", key: "CFBundleShortVersionString")
    build = get_info_plist_value(path: "./#{scheme_name}/Info.plist", key: "CFBundleVersion")
    output_directory = File.expand_path("..", Dir.pwd) + File::Separator + 'build'
    output_name = "#{scheme_name}_#{configuration}_#{version}_#{build}_#{Time.now.strftime('%Y%m%d%H%M%S')}.ipa"
    build_app(workspace: "xxx.xcworkspace", scheme: "xxx", export_method: "app-store", output_directory: output_directory,
      output_name: output_name)
    upload_to_app_store
  end
  desc "Push a new release build to the Testflight"
  lane :release_testflight do
    update_project_provisioning(
        # 之前有sigh下载的描述文件存储路径
        profile:"fastlane/provision/xxx.mobileprovision",
        # 打包配置,Debug,Release
        build_configuration:"Release"
    )
    automatic_code_signing(
        # 工程文件所在路径
        path:"xxx.xcodeproj",
        # 是否使用自动签名,这里如果是打包的话应该一般都为false吧,默认也是false
        use_automatic_signing:false,
        # 这个就不用说了,需要修改的targets
        targets:"xxx",
        # 用哪种方式打包“iPhone Develop”还是“iPhone Distribution”
        code_sign_identity:"iPhone Distribution",
        # 描述文件名称, 也就是使用哪个描述文件打包
        profile_name:"xxx"
    )
    scheme_name = 'xxx'
    configuration = 'AppStore'
    version = get_info_plist_value(path: "./#{scheme_name}/Info.plist", key: "CFBundleShortVersionString")
    build = get_info_plist_value(path: "./#{scheme_name}/Info.plist", key: "CFBundleVersion")
    output_directory = File.expand_path("..", Dir.pwd) + File::Separator + 'build'
    output_name = "#{scheme_name}_#{configuration}_#{version}_#{build}_#{Time.now.strftime('%Y%m%d%H%M%S')}.ipa"
    build_app(workspace: "xxx.xcworkspace", scheme: "xxx", export_method: "app-store", output_directory: output_directory,
      output_name: output_name)
    upload_to_testflight
  end
  desc "Push a new release build to the Ad Hoc"
  lane :release_adhoc do |option|
  	# cocoapods
  	#根据传入参数version设置app的版本号
	# increment_version_number(version_number: option[:version]) 
	#自动增加build号
	#increment_build_number
  	update_project_provisioning(
        # 之前有sigh下载的描述文件存储路径
        profile:"fastlane/provision/xxx.mobileprovision",
        # 打包配置,Debug,Release
        build_configuration:"Release"
    )
  	automatic_code_signing(
        # 工程文件所在路径
        path:"xxx.xcodeproj",
        # 是否使用自动签名,这里如果是打包的话应该一般都为false吧,默认也是false
        use_automatic_signing:false,
        # 打包的team ID, 也就是打包使用的证书中的team ID,这个如果不知道是什么的话可以在xCode中设置好签名用的描述文件后到xcodeproj下的pbxproj文件中搜索“DEVELOPMENT_TEAM”,它的值就是了
        team_id:"RRRRR5555",
        # 这个就不用说了,需要修改的targets
        targets:"xxx",
        # 用哪种方式打包“iPhone Develop”还是“iPhone Distribution”
        code_sign_identity:"iPhone Distribution",
        # 描述文件名称, 也就是使用哪个描述文件打包
        profile_name:"xxx"
    )
    #证书签名
    # sigh
    #编译打包
    scheme_name = 'xxx'
    configuration = 'Release'
    version = get_info_plist_value(path: "./#{scheme_name}/Info.plist", key: "CFBundleShortVersionString")
    build = get_info_plist_value(path: "./#{scheme_name}/Info.plist", key: "CFBundleVersion")
    output_directory = File.expand_path("..", Dir.pwd) + File::Separator + 'build'
    output_name = "#{scheme_name}_#{configuration}_#{version}_#{build}_#{Time.now.strftime('%Y%m%d%H%M%S')}.ipa"
    gym(
    	scheme: scheme_name, 
    	clean: true, 
    	silent:true,
    	export_method:'ad-hoc', 
    	export_options: {
      	  provisioningProfiles: { 
      	  #前面的是bundle id,后面的是对应用到的mobileprovision,只需要名字,不需要后缀
          "me.ithome.xxx" => "xxx"
        }},
        configuration: configuration, 
        output_directory: output_directory, 
        output_name: output_name, 
        # 签名证书的名称,去钥匙串-登录-证书里面复制
        codesigning_identity:'iPhone Distribution: xxx (Rxxx47)',
        export_xcargs: '-allowProvisioningUpdates')
        # 上传到蒲公英,需要安装pgyer插件
        #pgyer(api_key: "aaaa", user_key: "bbbb")
  end
end
  • 上述脚本中有部分xxx之类的东西,需要自行替换成自己项目的。
  • 所有脚本中用到的xxx.mobileprovision都需要双击安装一次,否者会提示找不到。
  • 需要安装好p12证书文件。

修改完成后我们就有了三个命令,用来分别打包上传到appstore、testflight和蒲公英。 fastlane release_appstore fastlane release_testflight fastlane release_adhoc

五年内将取代安卓?来聊聊谷歌新系统Fuchsia

(原标题:Project ‘Fuchsia’: Google Is Quietly Working on a Successor to Android)

http://7xq9ge.com1.z0.glb.clouddn.com/2018-07-20-15320548229338.jpg

网易科技讯 7月20日消息,据国外媒体报道,两年多来,谷歌一个秘而不宣的工程师团队一直致力于Fuchsia项目,他们希望Fuchsia最终将取代占据全球主导地位的移动操作系统Android。随着团队的发展,团队内部围绕Fuchsia的运作方式出现了一些激烈争论,他们将如何应对?

随着更多个人设备和其他小型设备的不断上线,从零起步的Fuchsia项目旨在克服Android的一些局限性,更好地适应设备中的语音交互功能和频繁的安全更新,并实现从笔记本电脑到微型联网传感器等不同设备之间的无缝性。CEO桑达尔·皮查伊(Sundar Pichai)已设定谷歌的发展方向:让人工智能服务瞄准所有消费者。然而,依赖于大量硬件合作伙伴的Android却未能跟上发展的脚步。

2016年,谷歌开始在网上发布Fuchsia系统的代码,并让外部应用序开发者修补了一些开源代码。公司也开始测试该系统的一些应用,如,交互式屏显和YouTube语音命令功能。

据知情人士透露,Fuchsia团队成员已在讨论一项更有野心的计划:打造一个统一的操作系统,既可适用于谷歌的所有内部设备(如Pixel手机和智能音箱),也可用于目前搭载Android或Chrome OS的第三方设备。

据知情人士称,工程师们希望在三年内让Fuchsia应用于音控音箱等智能家居设备,再扩展到笔记本电脑等“较大设备”,并在“未来五年内”取代Android。目前全球逾四分之三的智能手机均搭载Android系统。

但是皮查伊以及Android和Chrome业务主管希罗史·洛克海默尔 (Hiroshi Lockheimer)尚未针对Fuchsia制定产品路线图。由于Android拥有数十个硬件合作伙伴和数千名开发人员,在移动广告上可创收数十亿美元,因此高管们对任何改革Android的计划均保持审慎的态度。Android也是监管审查的对象和一些法律纠纷的起因,这意味着对Android的任何改变都将得到密切关注。近日,欧盟委员会因谷歌使用Android推广服务、损害竞争的做法对其处以50亿美元的反垄断罚款。而在谷歌内部,Fuchsia的设计和部署,特别是隐私功能,已引发一些内部分歧。

谷歌已公开把Fuchsia列为公司鼓励产品创新的典范之一。一名发言人曾在邮件中表示,“谷歌将这些开源实验视为对创新的投资。” 2015年,洛克海默尔在文章中声称,公司未计划让Android取代Chrome操作系统。谷歌发言人表示这一立场今天仍然适用。

知情人士表示,皮查伊已在公司内部表达了对Fuchsia项目的支持。 Fuchsia团队目前拥有100多名成员,其中包括马蒂亚斯·杜阿尔特(Matias Duarte)等资深软件开发者。作为设计主管,杜阿尔特曾在谷歌等公司领导数个开创性项目。不过一位知情人士表示,杜阿尔特只是兼职从事这个项目。

Fuchsia项目的焦点是在与苹果的竞争中,让谷歌拥有更多的优势。虽然在智能手机市场中,Android约85%的市场份额远超过苹果15%的份额,但苹果操作系统在性能、隐私和安全以及跨设备的整合性等方面都占有上风。苹果的另一个关键优势是:大多数iPhone用户在苹果发布新版操作系统时会立刻更新手机,而不到10%的Android用户会这么做。这意味着谷歌的最新系统服务只能覆盖一小部分Android用户。

信息加密应用Confide的联合创始人杰弗里·格罗斯曼(Jeffrey Grossman)表示:“研发Android以外的产品可以让谷歌在他们认为十年前所犯下的任何错误中拥有清零的机会。谷歌或许能够重新获得此前让给设备制造商和电信运营商的一些权力。”

谷歌依靠手机制造商和无线网络运营商向Android设备推送操作系统及其安全更新。在推广最新软件上,这些合作伙伴的积极性远不如谷歌:手机制造商更乐于出售新设备,电信公司还有其他优先事项要考虑。最近谷歌已试图正面解决这个问题。今年5月,谷歌修改了与手机制造商的协议,要求它们每年需数次在设备中更新安全补丁。

有迹象表明Fuchsia正纳入更严格的安全措施。在线发布的软件代码中,工程师将加密的用户密钥整合到系统中,这是一种隐私工具,可确保每次软件更新时信息都能得到保护。团队成员也包括这方面的专业人才。今年1月,Android的首席安全工程师尼克·克拉列维奇(Nick Kralevich)加入了Fuchsia项目。在代码页面中,参与Fuchsia项目的谷歌员工表示,该软件尚未最终确定。

谷歌研发Android时,手机处在采用触摸屏的发展初期。目前,Android无法处理谷歌视为计算未来的语音应用类型。因此,对于正在开发的Fuchsia,其核心是语音交互。它的设计也更灵活,因为它有望适应多种屏幕尺寸,谷歌希望在电视、汽车和冰箱等新产品中推广其软件。

尽管研发团队人才济济,Fuchsia也享有公司的支持,谷歌迄今未公布Fuchsia的实际用途。一些开发者编写过这个操作系统,但还没有人把它设为某款热门商业设备中的应用或服务的基础系统。谷歌开发者网站上发布的最新代码显示,谷歌可能正在开发以Fuchsia为基础的YouTube应用,但谷歌还未公开任何运行该系统的正式服务。

谷歌还需解决一些内部分歧。Fuchsia研发者所追求的一些原则与谷歌的商业模式背道而驰。谷歌的广告业务很大程度依赖着基于位置和活动对用户进行定位的能力。而Fuchsia的隐私功能如果实施,将阻碍这一重要业务的发展。据知情人士透露,针对Fuchsia的安全和隐私功能,广告和工程团队之间至少爆发过一次冲突。而广告团队占了上风。

若考虑弃用Android和Chrome,谷歌可能面临其他风险。大量独立开发者以及三星、华为和LG等设备制造商都依赖着Android操作系统。Chrome也是许多学校和机构的笔记本电脑所采用的重要操作系统。谷歌不能简单地停止支持Android和Chrome操作系统、指望这个庞大的生态系统能够迅速替换成Fuchsia生态。

另一个风险则来自Fuchsia的技术架构。Android和Chrome操作系统都是基于Linux而构建的。“Linux内核”是Google当前这些操作系统的核心,负责处理智能手机和其他设备的硬件和软件之间的指令。 Fuchsia使用了一种名为Zircon的不同内核,它弃用了Linux中的许多旧技术。这可能使一些现有设备不兼容。

不过,弃用Linux也可能有益于谷歌。这就得谈到谷歌和甲骨文之间冗长而又繁杂的诉讼战了:Android的构建使用了甲骨文拥有的Java技术,而甲骨文指控谷歌窃取这些技术用于推动其移动业务。弃用Linux将在这场诉讼中有利于谷歌。

Fuchsia项目带来的另一个有利之处是,为谷歌的资深开源黑客带来技术挑战。谷歌常常安排一些老员工参与这类需耗费大量时间的复杂项目中,以降低他们跳槽的风险。有人这么描述Fuchsia项目,“这个项目旨在留住高级工程师。”

不过据最新消息,谷歌向媒体CNET透露,Fuchsia何时能应用于设备中尚不明确,不存在什么“五年计划”。在一份声明中,谷歌把这个操作系统描述为“谷歌正展开的众多实验性开源项目之一”,目前不存在把它用在未来产品的时间表。(惜辰)

flutter开发系列之二--第一个应用

好了,我们已经配置好环境变量。现在开始我们的第一个Flutter应用。

Flutter项目可以通过命令行创建,也可以用IDE创建。

1. 命令行方式创建Flutter项目

flutter create myapp
cd myapp

也可以指定pkg/bundleid

flutter create --org com.example --template=app myapp
cd myapp

然后,如果当前有模拟器运行,直接flutter run,否者安装下面的命令运行

flutter emulators //列出可用的模拟器
flutter emulators --launch <emulator id> //启动模拟器 emulator id=>apple_ios_simulator

命令行方式就介绍这些了,有兴趣的请自行参考https://flutter.io/developing-packages/

2. Android Studio

好了,重点来了,这也是我所推荐的方式,通过AS来开发一个Flutter应用。

请跟着步骤来吧。

打开AS,启动到导航页,选择Start a new Flutter project http://7xq9ge.com1.z0.glb.clouddn.com/2018-07-24-15324243284543.jpg

第二步,选择Flutter Application,然后Next http://7xq9ge.com1.z0.glb.clouddn.com/2018-07-24-15324244166351.jpg

第三步,填写项目信息,继续Next http://7xq9ge.com1.z0.glb.clouddn.com/2018-07-24-15324246441779.jpg

第四步,填写包名/bundle id,Finish http://7xq9ge.com1.z0.glb.clouddn.com/2018-07-24-15324248890009.jpg