Flutter

[TOC]

0x00 Flutter

flutter是google開發的移動端UI框架,支持android和ios。該框架使用dart語言進行開發,在skia的基礎上開發了一套公共組件達到android與ios共用代碼的目的。

1. Flutter系統架構

flutter_arch.png

2. Platform Channels

flutter使用methodChannel/flutterMethodChannel來訪問系統原生api。


platform_channels.png

0x01 使用Flutter開發應用程序

1. 下載配置Flutter SDK

  • 由于眾所周知的原因,我們首先需要進行如下配置,讓flutter通過國內鏡像下載sdk等依賴。
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
  • 安裝sdk
$ git clone -b beta https://github.com/flutter/flutter.git
$ export PATH=`pwd`/flutter/bin:$PATH
  • 使用flutter doctor檢測本機環境,然后根據提示安裝依賴軟件。
$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[?] Flutter (Channel beta, v0.1.5, on Mac OS X 10.11.6 15G19009, locale zh-Hans)
[?] Android toolchain - develop for Android devices (Android SDK 27.0.3)
[!] iOS toolchain - develop for iOS devices (Xcode 7.2.1)
    ? Flutter requires a minimum Xcode version of 9.0.0.
      Download the latest version or update via the Mac App Store.
    ? ios-deploy not installed. To install:
        brew install ios-deploy
    ? CocoaPods not installed.
        CocoaPods is used to retrieve the iOS platform side's plugin code that responds to your plugin usage on the Dart side.
        Without resolving iOS dependencies with CocoaPods, plugins will not work on iOS.
        For more info, see https://flutter.io/platform-plugins
      To install:
        brew install cocoapods
        pod setup
[?] Android Studio (version 3.0)
[?] Android Studio (version 2.3)
[!] IntelliJ IDEA Community Edition (version 2017.2.6)
    ? Flutter plugin not installed; this adds Flutter specific functionality.
[!] VS Code (version 1.21.0)
[!] Connected devices
    ! No devices available

! Doctor found issues in 4 categories.

2. 使用Android Studio開發Demo

1. 創建應用

create_flutter_app_1.png
create_flutter_app_2.png
create_flutter_app_3.png
create_flutter_app_4.png

2. 項目結構

使用android studio創建出來的項目目錄結構大致如下:

  • ios目錄包含了ios的全部代碼可以直接使用xcode(需要9.0+版本)進行開發。
  • android目錄包含了android的全部代碼,直接使用android studio開發即可。
  • lib目錄中包含了兩端通用的dart代碼,在打包生成應用時,全部的dart代碼會被編譯為本地代碼(如在android端,會被直接編譯為so文件)。
app_struct.png

3. 調試與運行

  • 選擇android/ios設備,然后點擊運行按鈕就可以將應用運行到android/ios設備上。


    app_select_device_and_run.png
  • 點擊調試安妮運行app,就可以調試dart代碼,調試界面與java完全一樣。


    app_debug.png

4. 熱加載

flutter中熱加載的概念和android開發中的Instant run類似,同樣也是點擊??按鈕啟用熱加載功能。但是其擁有以下優點:

  1. 點擊保存按鈕或者保存快捷鍵,也會觸發熱加載功能(??按鈕功能相同)。
  2. 熱加載會保留先前的狀態
  3. 快!快!快! 代碼增量編譯在秒級別,單行代碼改變反應到應用程序UI改變耗時約1.5秒左右。

所以大家就可以像寫web頁面一樣,可以邊寫->邊保存->邊查看效果,開發效率大大加快有沒有,再也不用等等等有沒有。。。

熱加載前 代碼變動 熱加載后
可以看到應用程序的計數器的值是2.
app_hot_reload_before.png
修改字符顯示,添加“吼吼吼吼”到文本中,然后保存觸發熱加載。
app_hot_reload_with_state.png
可以看到文本字符發生改變,但是計數器的值未發生變化,仍然是2.
app_hot_reload_after.png

5. 應用程序結構與兼容性

1. 應用程序結構

  • Debug (slow mode模式)

首先我們打開項目根目錄中的build文件夾,該文件包含了編譯app的全部生成文件,其結構與android應用程序一致(注意:build目錄在android studio中不顯示,可以通過terminal打開或查看)。

apk_location.png

接下來,我們可以通過android studio直接打開該apk,可以發現僅僅只有一個頁面的flutter應用大小已經達到了25MB左右,分析其結構(見下圖),其包含了全部abi類型的so文件,導致apk整體比較大,排除掉x86x86_64平臺的so文件之后,apk整體大小約11MB左右。

apk_struct_with_dart-1.png

  • Release模式

使用release模式時,apk大小約8.1MB,大小比較正常。

apk_struct_mode_release.png

2. 應用程序兼容性

  • andorid最低支持到 api 16;
  • ios最低支持到ios 8.0;

3. 開發Toast模塊

這里我們直接使用android studio進行開發,如果大家需要直接使用flutter進行創建的話,可以直接參考platform-channels進行開發。

1. 使用dart編寫公共的toast模塊

import 'package:flutter/services.dart';

// 下劃線開頭的變量只在當前package中可見。
const _toast = const MethodChannel('com.coofee.flutterdemoapp/sdk/toast');

const int _LENGTH_SHORT = 0;

const int _LENGTH_LONG = 1;

void show(String text, int duration) async {
  try {
    await _toast.invokeMethod("show", {'text': text, 'duration': duration});
  } on Exception catch (e) {
    print(e);
  } on Error catch (e) {
    print(e);
  }
}

void showShort(String text) {
  show(text, _LENGTH_SHORT);
}

void showLong(String text) {
  show(text, _LENGTH_LONG);
}

2. 編寫android端的代碼并注冊

package com.coofee.flutterdemoapp;

import android.os.Bundle;
import android.widget.Toast;

import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class MainActivity extends FlutterActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GeneratedPluginRegistrant.registerWith(this);

        new MethodChannel(getFlutterView(), "com.coofee.flutterdemoapp/sdk/toast")
                .setMethodCallHandler(new MethodChannel.MethodCallHandler() {
                    @Override
                    public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
                        if ("show".equals(methodCall.method)) {
                            String text = methodCall.argument("text");
                            int duration = methodCall.argument("duration");
                            Toast.makeText(MainActivity.this, text, duration).show();
                        }
                    }
                });
    }
}

3. 編寫ios端代碼并注冊

ios端的代碼與android端類似,但是需要使用FlutterMethodChannel進行處理,其他操作與android端一致,打開AppDelegate.m文件,添加如下代碼:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];

  FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;

  FlutterMethodChannel* toastChannel = [FlutterMethodChannel
                                            methodChannelWithName:@"com.coofee.flutterdemoapp/sdk/toast"
                                            binaryMessenger:controller];

  [toastChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
      if ([@"show" isEqualToString:call.method]) {
          // 展示toast;
          NSLog(@"顯示toast....")
      }
  }];

  // Override point for customization after application launch.
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

4. 在flutter中調用toast模塊

import 'sdk/toast.dart';

void _incrementCounter() {
  showShort('你點擊了$_counter次');

  setState(() {
    // This call to setState tells the Flutter framework that something has
    // changed in this State, which causes it to rerun the build method below
    // so that the display can reflect the updated values. If we changed
    // _counter without calling setState(), then the build method would not be
    // called again, and so nothing would appear to happen.
    _counter++;
  });
}

5. 效果

toast_show.png

0x02 使用Dart 2

1. 升級flutter sdk

使用dart 2時,必須保證,Flutter SDK版本必須大于等于以下版本:

  • Beta channel: build 0.1.4 from 2018-02-19, or later
  • Dev channel: build from 2018-02-22, or later
  • Master channel: build from 2018-02-20, or later

在Terminal中執行flutter --version命令,查看flutter的版本:

→ flutter --version
Flutter 0.1.5 ? channel beta ? https://github.com/flutter/flutter.git
Framework ? revision 3ea4d06340 (3 weeks ago) ? 2018-02-22 11:12:39 -0800
Engine ? revision ead227f118
Tools ? Dart 2.0.0-dev.28.0.flutter-0b4f01f759

在Terminal中執行flutter upgrade可以升級flutter。

2. 在android studio中啟用dart 2

在android studio中啟用dart2后,需要重啟android studio使其生效。

dart-2.png

3. dart 1 vs dart 2

從下圖可以看出dart2相對于dart1來說,省略了關鍵字new,使得聲明式布局的可讀性更進一步。

dart1_vs_dart2.png

4. dart2對apk大小的影響

從下圖可以看出來,使用dart2時生成的apk比dart1打5MB左右(slow mode模式)。

apk_dart1_vs_dart2.png

0x03 Flutter's modes

從下圖我們可以看到,flutter mode顯示在在app的右上角。

mode_slow.png

flutter的應用程序有以下4中模式,分別使用不同的命令生成,且不同模式下生成的應用大小不一(如:release模式會去掉x86相關的so文件)

mode 命令
debug flutter run debug模式下的產物,且應用的右上角會顯示slow mode字樣,支持debug。
release flutter run --release UI上面不顯示模式;禁止debug,且刪除了debug相關的信息;關閉全部的斷言檢測,減小包大小,使其達到最佳性能。
profile flutter run --profile 調試性能,不支持模擬器。
test flutter test 和debug模式類似,不支持headless和桌面平臺。

0x04 參考引用

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,258評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,234評論 2 375

推薦閱讀更多精彩內容