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

前言

鑑於現階段Flutter技術棧還不是太成熟,在使用Flutter作移動端開發時咱們常常須要藉助Native平臺的力量來補充Flutter在這方面的缺陷,前面兩章咱們經過學習把Flutter項目打包成AAR集成到原平生Flutter與原平生臺交互掌握了Flutter與原平生臺交互的兩種方式,可是有些場景下,咱們但願咱們Flutter跟原生交互的代碼能夠一次開發,多處使用,相似於庫文件同樣,能夠給其餘項目或者其餘開發着使用,這就是咱們本篇文章要介紹的主題Flutter插件開發以及插件如何引用到項目中java

課程目標

  • 學會如何新建Flutter插件,並瞭解插件項目結構
  • 掌握如何把插件引入到現有項目中

1.新建Flutter插件項目

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

1.1新建項目

在這裏插入圖片描述

1.2 選擇Flutter Plugin

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

在這裏插入圖片描述

1.3 插件項目結構

從下面插件工程項目結構圖中咱們能夠看出,Flutter插件項目跟普通的Flutter項目結構上幾乎同樣,可是多出了一個example目錄,讀者打開example目錄後,會發現這個example目錄下面其實就是一個完整的Flutter項目,沒錯這個example就是爲了方便咱們在開發插件方便咱們調試開發的功能是否正常可用,沒問題的話就能夠發佈出去或者給其餘項目正常使用了。 github

在這裏插入圖片描述

插件開發其實用到的知識點就是經過利用咱們上節課中講的Flutter跟原平生臺交互的方式來完成的,讓Flutter藉助Native的功能來完成某種操做,插件化只不過是把調用平臺操做的代碼模塊化,便於後期其餘項目或者別人引入,讓代碼一次開發,多處使用,因爲涉及到的知識點在上一篇文章中咱們都已經講過了,因此這裏就不在細講插件裏的功能代碼實現邏輯了,下面咱們來簡單分析一下此次課程中用到的用Flutter插件工程。app

先看效果圖: async

在這裏插入圖片描述

在上圖的插件工程中咱們實現了,獲取系統版本號跟一個簡單的計算器的功能。下面看一下在插件工程中具體配置。ide

在插件工程的android端的業務實現邏輯:模塊化

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()
        }
    }
}
複製代碼

因爲插件開發完成以後是要在flutter端使用的,換句話說是要給dart文件引用的,因此下面的dart文件中定義的方法聲明纔是咱們開發的插件對調用者提供的方法。以下咱們定義了 getplatformVersion:獲取系統版本號 getResult(int a, int b):計算兩個數的和學習

而兩個方法又經過methodChannel與平臺交互,藉助native端來完成某些具體邏輯,而後把執行完成的結果返回給調用方。插件定義完成而且成功導入到咱們的項目中以後,咱們就能夠在項目中導入相關類以及方法引用,正常去使用咱們本身開發的組件了。ui

插件工程的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;
  }

  /** *計算兩個數的和 */
  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;
  }
}

複製代碼

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

2.插件引入到現有項目中

把咱們開發完成的插件項目導入到現有項目中使用,咱們能夠經過github倉庫引入,或者本地引入,固然也能夠把開發完成的插件工程上傳到flutter的dart packages上而後經過版本號用pubspec.ymal文件引入,上傳dart packages的配置相對麻煩,限於篇幅,這裏我就先只介紹前兩種方式,讀者若是對上傳dart packages感興趣的話能夠私下裏找我交流或者我會在後續的博客單獨整理出一篇博文來具體講解。

2.1 本地引入

在這裏插入圖片描述

如圖,我把插件工程放在項目跟目錄下的plugin文件下,插件項目名咱們本身能夠本身隨便定義,我這裏把它定義成flutter_calc_plugin,那在咱們要引入插件的項目中yaml文件裏咱們經過插件名,加路徑的方式把插件導入以後就能夠正常使用插件裏的功能了。

#本地插件引入
  flutter_calc_plugin:
    path: plugin/flutter_calc_plugin
複製代碼
2.2經過github倉庫地址引入

經過github倉庫地址引入相對簡單一些,就不用把插件拷貝到本地了,只須要在工程的yaml文件中正確配置插件的地址就能夠導入了,兩種方式配置完成以後都別忘了執行flutter packages get讓工程依賴同步一下。

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

複製代碼

這裏順便說一下小細節吧,因爲yaml文件對縮進格式要求特別嚴格,讀者在配置插件引用或者其餘第三方的庫時,必定要注意縮進。

還有就是具體採用上述兩種插件的哪種方式,這個沒有固定的答案徹底看你我的喜愛跟插件的需求吧,舉個例子,若是你的插件開發出來幾乎不須要修改,那筆者建議經過github或者上傳到dart packages的方式引用,這樣不只讓你的工程結構更新清晰並且項目也好管理,可是若是先階段你開發的插件還不太成熟,或者常常須要改動的話,建議使用本地的方式導入,這樣修改後調試代碼也方便,並且也省去了頻繁上傳插件的版本到dart packages或者github上去。

還有一個場景就是,好比使用的插件不是本身開發的,而是從github或者dart packages上找的別人開發好的,但偏偏他開發的插件不能徹底知足你的業務需求,或者你須要在此插件的基礎上從新定製UI或者補充邏輯,那這個時候你也能夠把別人開發好的插件下載到本地,而後經過本地的方式引入到你的項目中再去針對你的業務去修改這個插件,直到修改到你滿意爲止,而後再經過本地方式導入到項目中。

在文章的最後,貼上一下,上述gif圖上示例的具體代碼實現供讀者參考:

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("獲取系統版本"), onPressed: () {
                initPlatformState();
              },
            ),
            Text('當前系統版本 : $_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("結果等於"),
              onPressed: () {
                getAddResult();
              },
            ),
            Text(addResult),
          ],
        )),
      ),
    );
  }
}
複製代碼

最後本章節以及專欄的全部完整代碼以下,讀者若是還不太明白,能夠下載代碼本身跑一篇項目,慢慢的琢磨下具體的實現細節: 專欄代碼倉庫:https://github.com/xiedong11/flutter_app.git

相關文章
相關標籤/搜索