Flutter混合開發(一):Android專案整合Flutter模組詳細指南

李四爺發表於2019-11-07

本文首發於微信公眾號「Android開發之旅」,歡迎關注 ,獲取更多技術乾貨

混合開發應用場景

目前在國內開發純Flutter的應用還是比較少的,絕大部分使用Flutter來開發的公司也都是使用混合開發。那麼混合開發的主要使用場景有哪些呢?

  • 作為獨立的頁面進行加入,可以從原生頁面跳轉到Flutter頁面,也可以從Flutter頁面跳轉到原生頁面。

Flutter混合開發(一):Android專案整合Flutter模組詳細指南

  • 作為頁面的一部分嵌入。

Flutter混合開發(一):Android專案整合Flutter模組詳細指南

建立Flutter module

既然是做混合開發,那麼我們肯定是由Android原生專案的。假如native專案的路徑是這樣的:flutter/flutter_hybrid/native,那麼我們需要在native上一層目錄flutter_hybrid中建立Flutter module。

cd flutter/flutter_hybrid/
//建立支援AndroidX的flutter_module
flutter create --androidx -t module flutter_module 
//建立不支援AndroidX的flutter_module
flutter create -t module flutter_module
複製程式碼

所以我們在建立模組的時候首先要確定native專案是不是已經支援AndroidX,如果支援就需要加上 --androidx 引數。

輸入後控制檯列印如下:

$ flutter create -t module flutter_module
Creating project flutter_module...
  flutter_module/test/widget_test.dart (created)
  flutter_module/flutter_module.iml (created)
  flutter_module/.gitignore (created)
  flutter_module/.metadata (created)
  flutter_module/pubspec.yaml (created)
  flutter_module/README.md (created)
  flutter_module/lib/main.dart (created)
  flutter_module/flutter_module_android.iml (created)
  flutter_module/.idea/libraries/Flutter_for_Android.xml (created)
  flutter_module/.idea/libraries/Dart_SDK.xml (created)
  flutter_module/.idea/modules.xml (created)
  flutter_module/.idea/workspace.xml (created)
Running "flutter pub get" in flutter_module...                      1.2s
Wrote 12 files.

All done!
Your module code is in flutter_module/lib/main.dart.
複製程式碼

看到All done就表示我們專案建立好了。整個module目錄和原生Flutter基本一樣,主要就是Android、iOS的宿主工程和lib目錄以及pubspec.yaml檔案。

新增Flutter module依賴

module專案建立好後就需要新增到Android專案中了。我們開啟Android專案的setting.gradle檔案,新增如下程式碼:

setBinding(new Binding([gradle: this]))
evaluate(new File(
        settingsDir.parentFile,
        //flutter_module即為建立的模組名稱
        'flutter_module/.android/include_flutter.groovy'
))
複製程式碼

setBinding與evaluate允許Flutter模組包括它自己在內的任何Flutter外掛,在settings.gradle中以類似 :flutter、package_info、:video_player的方式存在。

然後開啟app/build.gradle在dependencies標籤中新增依賴:

implementation project(':flutter')
複製程式碼

這樣兩步就完成了依賴的新增,這裡為什麼新增的叫“flutter” 而不是 “flutter_module”呢?因為專案編譯完成後會在Android專案的目錄下生成叫Flutter的目錄,這就是需要我們依賴的。還有個需要注意是gradle中的minSdkVersion必須要大於等於16,因為這個flutter支援的最低版本。同時新增使用java8來編譯。在app/build.gradle中的android標籤中新增:

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
複製程式碼

呼叫Flutter module

依賴完成後我們就可以呼叫flutter模組來建立UI了。Flutter為我們提供了兩種方式呼叫,一種是createView,以view的形式載入。另一種是createFragment,以Android中的fragment的形式載入。

createView方式:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);

        FlutterView flutterView = Flutter.createView(this, getLifecycle(), "initialRoute");
        setContentView(flutterView);

    }
}
複製程式碼

createFragment方式:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        //container為activity_main佈局中的佔位符FrameLayout
        transaction.replace(R.id.container, Flutter.createFragment("initialRoute"));
        transaction.commit();

    }
}
複製程式碼

這樣就將Flutter預設的首頁載入到應用上了。

Flutter混合開發(一):Android專案整合Flutter模組詳細指南

從上面兩部分程式碼中我們可以看到都有一個 “initialRoute” 引數,這個引數是用來告訴Dart程式碼在Flutter檢視中顯示哪個小部件。下面我們就來修改module中的main.dart程式碼來載入我們自己的頁面。

我們設定兩個route,分別展示route1Widget,和route2Widget,當沒有匹配的時候展示提醒文字。

import 'package:flutter/material.dart';
import 'dart:ui';

void main() => runApp(MyApp(
      //通過window.defaultRouteName獲取從native傳遞過來的引數,需要匯入dart:ui包
      initParams: window.defaultRouteName,
    ));

class MyApp extends StatelessWidget {
  final String initParams;

  MyApp({Key key, this.initParams}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter_Android混合開發',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(initParams: initParams),
    );
  }
}

class HomePage extends StatefulWidget {
  final String initParams;

  const HomePage({Key key, this.initParams}) : super(key: key);

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

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: _widgetRoute(widget.initParams),
      ),
    );
  }
}

///路由轉發
Widget _widgetRoute(String route) {
  switch (route) {
    case "route1":
      return route1Widget();
    case "route2":
      return route2Widget();
    default:
      return notFoundWidget();
  }
}

Widget route1Widget() {
  return Center(
    child: Text(
      "this is route1Widget",
      style: TextStyle(color: Colors.red, fontSize: 20),
    ),
  );
}

Widget route2Widget() {
  return Center(
    child: Text(
      "this is route2Widget",
      style: TextStyle(color: Colors.blue, fontSize: 20),
    ),
  );
}

Widget notFoundWidget() {
  return Center(
    child: Text(
      "未匹配到路由111",
      style: TextStyle(fontSize: 40),
    ),
  );
}

複製程式碼

我們現在將載入Flutter時的initialRoute引數替換為 “route1”,那頁面將載入route1Widget,替換為 “route2”,將載入route2Widget。否則將展示notFoundWidget。當然我們可以直接傳路由引數,但是因為這個引數本身是一個字串,所以我們可以來搞事情。比如傳遞一個json串,那麼是不是可以做很多事呢?這裡我就不貼demo了,因為和上面的邏輯基本一樣,大家可以去試試看。

熱重啟/重新載入

大家在寫純Flutter應用的時候,知道是有熱重啟/重新載入功能的,但是在做混合開發的過程中,你會發現熱重啟/重新載入功能失效了。那麼如何在混合開發中開啟熱重啟/重新載入功能呢?

  • 首先接入我們的裝置或者模擬器
  • 將我們的App關閉,退出後臺,在terminal中執行 flutter attach命令
$ flutter attach
Waiting for a connection from Flutter on Android SDK built for x86...

複製程式碼

此時就在等待裝置的連線。這裡要注意的是,如果電腦連線了多臺裝置需要使用 -d 命令來指定一臺裝置,引數為裝置的id。

 flutter attach -d '你的裝置id'
複製程式碼
  • 然後啟動我們的應用會看到控制檯輸出:
Done.
Syncing files to device Android SDK built for x86...             1,393ms

?  To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler on Android SDK built for x86 is available at: http://127.0.0.1:59354/zRsDBfpesrk=/
For a more detailed help message, press "h". To detach, press "d"; to quit, press "q".
複製程式碼

這樣就表示我們連線成功了。在輸出的日誌中也告訴了我們如何使用熱重啟/重新載入功能。

在Terminal中輸入以下命令​:​

r : 熱載入;
R : 熱重啟;
h : 獲取幫助;
d : 斷開連線;
q : 退出;
複製程式碼

這裡的的 d 和 q 的命令都有退出除錯,區別在於 d 命令只是單純的斷開而 q 命令會將應用退到後臺。

除錯Dart程式碼

同樣在混合開發過程中我們如何除錯dart程式碼呢?

  • 關閉我們的應用
  • 點選Android Studio工具欄上的Flutter Attach按鈕(需要安裝Flutter與Dart外掛)

Flutter混合開發(一):Android專案整合Flutter模組詳細指南

  • 啟動我們的應用

接下來就可以像除錯普通Flutter專案一樣來除錯混合開發模式下的Dart程式碼了。

總結

以上就是如何在Android原生專案中接入Flutter模組的基礎講解,主要就是模組的建立、依賴、呼叫以及除錯等等。其它的像iOS接入Flutter模組,Android專案和Flutter專案之間的通訊以及iOS專案和Flutter之間的通訊都將在之後的文章中進行講解。因為寫在一篇中篇幅太長,朋友們讀起來也累。所以後續還會有至少三篇相關的文章和大家見面。動動手關注公眾號,即時獲取相關文章的推送。

全部Demo原始碼已經上傳到後臺,關注公眾號回覆「Android混合開發」即可獲得下載連結。

如果你覺得文章還不錯,請大家點贊分享下,你的肯定是對我最大的鼓勵和支援。

很多朋友私信我說想加我個人微信,坑位有限,限時入坑。

Flutter混合開發(一):Android專案整合Flutter模組詳細指南

推薦閱讀

Flutter開發必備Dart基礎:Dart快速入門

掃描下方二維碼關注公眾號,獲取更多技術乾貨。

Flutter混合開發(一):Android專案整合Flutter模組詳細指南

相關文章