Flutter入門進階之旅(二十)Flutter插件開發(fā)

前言

鑒于現(xiàn)階段Flutter技術(shù)棧還不是太成熟,在使用Flutter做移動端開發(fā)時我們經(jīng)常需要借助Native平臺的力量來補充Flutter在這方面的缺陷,前面兩章我們通過學(xué)習(xí)把Flutter項目打包成AAR集成到原生平Flutter與原生平臺交互掌握了Flutter與原生平臺交互的兩種方式,但是有些場景下,我們希望我們Flutter跟原生交互的代碼可以一次開發(fā),多處使用,類似于庫文件一樣,可以給其他項目或者其他開發(fā)著使用,這就是我們本篇文章要介紹的主題Flutter插件開發(fā)以及插件如何引用到項目中

課程目標(biāo)

  • 學(xué)會如何新建Flutter插件,并了解插件項目結(jié)構(gòu)
  • 掌握如何把插件引入到現(xiàn)有項目中

1.新建Flutter插件項目

新建Flutter插件項目跟新建Flutter項目的步驟一樣,無非是在新建項目的時候選擇的工程類型略有不同。

1.1新建項目
在這里插入圖片描述
1.2 選擇Flutter Plugin

之后跟正常新建Flutter Applicition的操作一樣,正常給項目起名字,選擇工程路徑等一些列的初始化配置一直next到插件項目初始化完畢。之后的操作讀者一看便知,也沒有什么需要特別注意的地方,我就不逐個貼圖了。


在這里插入圖片描述
1.3 插件項目結(jié)構(gòu)

從下面插件工程項目結(jié)構(gòu)圖中我們可以看出,F(xiàn)lutter插件項目跟普通的Flutter項目結(jié)構(gòu)上幾乎一樣,但是多出了一個example目錄,讀者打開example目錄后,會發(fā)現(xiàn)這個example目錄下面其實就是一個完整的Flutter項目,沒錯這個example就是為了方便我們在開發(fā)插件方便我們調(diào)試開發(fā)的功能是否正常可用,沒問題的話就可以發(fā)布出去或者給其他項目正常使用了。


在這里插入圖片描述

插件開發(fā)其實用到的知識點就是通過利用我們上節(jié)課中講的Flutter跟原生平臺交互的方式來完成的,讓Flutter借助Native的功能來完成某種操作,插件化只不過是把調(diào)用平臺操作的代碼模塊化,便于后期其他項目或者別人引入,讓代碼一次開發(fā),多處使用,由于涉及到的知識點在上一篇文章中我們都已經(jīng)講過了,所以這里就不在細講插件里的功能代碼實現(xiàn)邏輯了,下面我們來簡單分析一下這次課程中用到的用Flutter插件工程。

先看效果圖:


在這里插入圖片描述

在上圖的插件工程中我們實現(xiàn)了,獲取系統(tǒng)版本號跟一個簡單的計算器的功能。下面看一下在插件工程中具體配置。

在插件工程的android端的業(yè)務(wù)實現(xiàn)邏輯:


class FlutterCalcPlugin : MethodCallHandler {
    companion object {
        @JvmStatic
        fun registerWith(registrar: Registrar) {
            val channel = MethodChannel(registrar.messenger(), "flutter_calc_plugin")
            channel.setMethodCallHandler(FlutterCalcPlugin())
        }
    }

    override fun onMethodCall(call: MethodCall, result: Result) {
        if (call.method == "getPlatformVersion") {
            result.success("Android ${android.os.Build.VERSION.RELEASE}")
        } else if (call.method == "getResult") {
            var a = call.argument<Int>("a")
            var b = call.argument<Int>("b")
            result.success((a!! + b!!).toString())
        } else {
            result.notImplemented()
        }
    }
}

由于插件開發(fā)完成之后是要在flutter端使用的,換句話說是要給dart文件引用的,所以下面的dart文件中定義的方法聲明才是我們開發(fā)的插件對調(diào)用者提供的方法。如下我們定義了
getplatformVersion:獲取系統(tǒng)版本號
getResult(int a, int b):計算兩個數(shù)的和

而兩個方法又通過methodChannel與平臺交互,借助native端來完成某些具體邏輯,然后把執(zhí)行完成的結(jié)果返回給調(diào)用方。插件定義完成并且成功導(dǎo)入到我們的項目中之后,我們就可以在項目中導(dǎo)入相關(guān)類以及方法引用,正常去使用我們自己開發(fā)的組件了。

插件工程的flutter端代碼:


class FlutterCalcPlugin {
  static const MethodChannel _channel =
      const MethodChannel('flutter_calc_plugin');

  static Future<String> getplatformVersion async {
    final String version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }

  /**
   *計算兩個數(shù)的和
   */
  static Future<String>  getResult(int a, int b) async {
    Map<String, dynamic> map = {"a": a, "b": b};
    String result = await _channel.invokeMethod("getResult", map);
    print(result+"----------aa--");
    return result;
  }
}

這里涉及到跟平臺交互的部分我沒有具體展開講解,因為在上一篇文章中我們已經(jīng)講過相關(guān)的知識點了,如果讀者在這里不太明白平臺交互相關(guān)的邏輯,建議先去讀一下上一篇文章Flutter入門進階之旅(十九)Flutter與原生平臺交互
上述插件完整代碼地址:https://github.com/xiedong11/flutter_calc_plugin.git

2.插件引入到現(xiàn)有項目中

把我們開發(fā)完成的插件項目導(dǎo)入到現(xiàn)有項目中使用,我們可以通過github倉庫引入,或者本地引入,當(dāng)然也可以把開發(fā)完成的插件工程上傳到flutter的dart packages上然后通過版本號用pubspec.ymal文件引入,上傳dart packages的配置相對麻煩,限于篇幅,這里我就先只介紹前兩種方式,讀者如果對上傳dart packages感興趣的話可以私下里找我交流或者我會在后續(xù)的博客單獨整理出一篇博文來具體講解。

2.1 本地引入
在這里插入圖片描述

如圖,我把插件工程放在項目跟目錄下的plugin文件下,插件項目名我們自己可以自己隨便定義,我這里把它定義成flutter_calc_plugin,那在我們要引入插件的項目中yaml文件里我們通過插件名,加路徑的方式把插件導(dǎo)入之后就可以正常使用插件里的功能了。

#本地插件引入
  flutter_calc_plugin:
    path: plugin/flutter_calc_plugin
2.2通過github倉庫地址引入

通過github倉庫地址引入相對簡單一些,就不用把插件拷貝到本地了,只需要在工程的yaml文件中正確配置插件的地址就可以導(dǎo)入了,兩種方式配置完成之后都別忘了執(zhí)行flutter packages get讓工程依賴同步一下。

  #從github上引入插件依賴
  flutter_calc_plugin:
    git:
     url:
      https://github.com/xiedong11/flutter_calc_plugin.git

這里順便說一下小細節(jié)吧,由于yaml文件對縮進格式要求特別嚴格,讀者在配置插件引用或者其他第三方的庫時,一定要注意縮進。

還有就是具體采用上述兩種插件的哪一種方式,這個沒有固定的答案完全看你個人喜好跟插件的需求吧,舉個例子,如果你的插件開發(fā)出來幾乎不需要修改,那筆者建議通過github或者上傳到dart packages的方式引用,這樣不僅讓你的工程結(jié)構(gòu)更新清晰而且項目也好管理,但是如果先階段你開發(fā)的插件還不太成熟,或者經(jīng)常需要改動的話,建議使用本地的方式導(dǎo)入,這樣修改后調(diào)試代碼也方便,而且也省去了頻繁上傳插件的版本到dart packages或者github上去。

還有一個場景就是,比如使用的插件不是自己開發(fā)的,而是從github或者dart packages上找的別人開發(fā)好的,但恰恰他開發(fā)的插件不能完全滿足你的業(yè)務(wù)需求,或者你需要在此插件的基礎(chǔ)上重新定制UI或者補充邏輯,那這個時候你也可以把別人開發(fā)好的插件下載到本地,然后通過本地的方式引入到你的項目中再去針對你的業(yè)務(wù)去修改這個插件,直到修改到你滿意為止,然后再通過本地方式導(dǎo)入到項目中。

在文章的最后,貼上一下,上述gif圖上示例的具體代碼實現(xiàn)供讀者參考:

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

import 'package:flutter/services.dart';
import 'package:flutter_calc_plugin/flutter_calc_plugin.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';
  String addResult = '';
  TextEditingController _addNumber1Controller,_addNumber2Controller;

  @override
  void initState() {
    super.initState();
    _addNumber1Controller = TextEditingController();
    _addNumber2Controller = TextEditingController();
  }

  Future<void> getAddResult() async {
    int addNumber1= int.parse(_addNumber1Controller.value.text);
    int addNumber2=int.parse(_addNumber2Controller.value.text);

    String result = '';
    try {
      result = await FlutterCalcPlugin.getResult(addNumber2, addNumber1);
    } on PlatformException {
      result = '未知錯誤';
    }
    setState(() {
      addResult = result;
    });
  }

  Future<void> initPlatformState() async {
    String platformVersion;

    try {
      platformVersion = await FlutterCalcPlugin.platformVersion;
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('插件示例'),
        ),
        body: Center(
            child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            MaterialButton(
              color: Colors.amber,
              child: Text("獲取系統(tǒng)版本"),
              onPressed: () {
                initPlatformState();
              },
            ),
            Text('當(dāng)前系統(tǒng)版本 : $_platformVersion\n'),
            SizedBox(height: 30),
            Text("加法計算器"),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,

              children: <Widget>[
                SizedBox(
                  width: 80,
                  child: TextField(
                    controller: _addNumber1Controller,
                    keyboardType: TextInputType.number,
                  ),
                ),
                Text("  +  ",style: TextStyle(fontSize: 26),),
                SizedBox(
                  width: 80,
                  child: TextField(
                    controller: _addNumber2Controller,
                    keyboardType: TextInputType.number,
                  ),
                ),
                Text("  = ",style: TextStyle(fontSize: 26),),
              ],
            ),
            SizedBox(height: 30),
            MaterialButton(
              color: Colors.amber,
              child: Text("結(jié)果等于"),
              onPressed: () {
                getAddResult();
              },
            ),
            Text(addResult),
          ],
        )),
      ),
    );
  }
}

最后本章節(jié)以及專欄的所有完整代碼如下,讀者如果還不太明白,可以下載代碼自己跑一篇項目,慢慢的琢磨下具體的實現(xiàn)細節(jié):
專欄代碼倉庫:https://github.com/xiedong11/flutter_app.git

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容