Flutter

[TOC]

0x00 Flutter

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

1. Flutter系統(tǒng)架構(gòu)

flutter_arch.png

2. Platform Channels

flutter使用methodChannel/flutterMethodChannel來訪問系統(tǒng)原生api。


platform_channels.png

0x01 使用Flutter開發(fā)應(yīng)用程序

1. 下載配置Flutter SDK

  • 由于眾所周知的原因,我們首先需要進(jìn)行如下配置,讓flutter通過國內(nèi)鏡像下載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檢測本機(jī)環(huán)境,然后根據(jù)提示安裝依賴軟件。
$ 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開發(fā)Demo

1. 創(chuàng)建應(yīng)用

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

2. 項(xiàng)目結(jié)構(gòu)

使用android studio創(chuàng)建出來的項(xiàng)目目錄結(jié)構(gòu)大致如下:

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

3. 調(diào)試與運(yùn)行

  • 選擇android/ios設(shè)備,然后點(diǎn)擊運(yùn)行按鈕就可以將應(yīng)用運(yùn)行到android/ios設(shè)備上。


    app_select_device_and_run.png
  • 點(diǎn)擊調(diào)試安妮運(yùn)行app,就可以調(diào)試dart代碼,調(diào)試界面與java完全一樣。


    app_debug.png

4. 熱加載

flutter中熱加載的概念和android開發(fā)中的Instant run類似,同樣也是點(diǎn)擊??按鈕啟用熱加載功能。但是其擁有以下優(yōu)點(diǎn):

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

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

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

5. 應(yīng)用程序結(jié)構(gòu)與兼容性

1. 應(yīng)用程序結(jié)構(gòu)

  • Debug (slow mode模式)

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

apk_location.png

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

apk_struct_with_dart-1.png

  • Release模式

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

apk_struct_mode_release.png

2. 應(yīng)用程序兼容性

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

3. 開發(fā)Toast模塊

這里我們直接使用android studio進(jìn)行開發(fā),如果大家需要直接使用flutter進(jìn)行創(chuàng)建的話,可以直接參考platform-channels進(jìn)行開發(fā)。

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

import 'package:flutter/services.dart';

// 下劃線開頭的變量只在當(dāng)前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進(jìn)行處理,其他操作與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中調(diào)用toast模塊

import 'sdk/toast.dart';

void _incrementCounter() {
  showShort('你點(diǎn)擊了$_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時,必須保證,F(xiàn)lutter 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中執(zhí)行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中執(zhí)行flutter upgrade可以升級flutter。

2. 在android studio中啟用dart 2

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

dart-2.png

3. dart 1 vs dart 2

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

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的應(yīng)用程序有以下4中模式,分別使用不同的命令生成,且不同模式下生成的應(yīng)用大小不一(如:release模式會去掉x86相關(guān)的so文件)

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

0x04 參考引用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容