flutter插件开发 再战江湖

930 阅读4分钟

前言导读

之前有同学问我flutter插件如何开发, 今天就分享一起flutter插件的开发。带着大家从零开始开发属于自己的插件

效果图

Screenshot_2025-07-01-20-17-19-164_com.example.co.jpg

具体实现

  • 1 创建插件工程

image.png

选择flutter工程然后选定自己的sdk

image.png

我们这个project type 选择plugin

image.png

插件工程

image.png

  • 1 我们的lib目录下面编写我们的插件和原生交互的dart代码

  • 2 example 下面是我们调试插件的代码

  • 3 android 是我们的插件原生部分代码

  • 我们选直接运行下我们的项目 让android studio 拉一下我们的gradle

  • 我们打开example 项目下面的Android工程 (谨记不是根目录下面的Android工程)

image.png

  • 然后让android studio 构建

image.png

ComepluginPlugin 就是我们插件原生代码 在这里编写和我们的flutter交互的代码

image.png

我们一共编写获取Android版本号 获取versionname 获取versioncode toast 弹出等等

  • 获取Android版本号

if (call.method.equals("getPlatformVersion")) {
  result.success("Android " + android.os.Build.VERSION.RELEASE);
} 
  • 获取versionname

 if (call.method.equals("getVersionName")) {
  result.success(versionName(this.flutterPluginBinding.getApplicationContext()));
}
  • 获取versioncode

if(call.method.equals("getVersionCode")) {
  result.success((versionCode(this.flutterPluginBinding.getApplicationContext())));
  • toast

这里需要注意我们flutter 端 是通过json传递参数给我们Android端的

 if(call.method.equals("toast")) {
  String param = call.argument("param"); // 获取参数
 Toast.makeText(this.flutterPluginBinding.getApplicationContext(),param,Toast.LENGTH_LONG).show();

完整插件原生Android代码

package com.example.comeplugin;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.widget.Toast;

import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;

/** ComepluginPlugin */
public class ComepluginPlugin implements FlutterPlugin, MethodCallHandler {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel channel;


  FlutterPluginBinding flutterPluginBinding;


  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "comeplugin");
    channel.setMethodCallHandler(this);
    this.flutterPluginBinding=flutterPluginBinding;
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else if (call.method.equals("getVersionName")) {
      result.success(versionName(this.flutterPluginBinding.getApplicationContext()));
    } else if(call.method.equals("getVersionCode")) {
      result.success((versionCode(this.flutterPluginBinding.getApplicationContext())));
    }else if(call.method.equals("toast")) {
      String param = call.argument("param"); // 获取参数
     Toast.makeText(this.flutterPluginBinding.getApplicationContext(),param,Toast.LENGTH_LONG).show();
    }else {
      result.notImplemented();
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }


  /***
   *
   * 获取versioncode
   * @param context
   * @return
   */
  public  String versionCode(Context context) {
    PackageManager manager = context.getPackageManager();
    int code = 0;
    try {
      PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
      code = info.versionCode;
    } catch (PackageManager.NameNotFoundException e) {
      e.printStackTrace();
    }

    return String.valueOf(code);
  }

  /***
   *
   *
   * versioncode
   * @param context
   * @return
   */

  public String versionName(Context context) {
    PackageManager manager = context.getPackageManager();
    String name = null;
    try {
      PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
      name = info.versionName;
    } catch (PackageManager.NameNotFoundException e) {
      e.printStackTrace();
    }
    return name;
  }

}
  • flutter端插件代码实现

我们先再插件父类抽象类里面 定义我们跟原生端交互的方法

import 'package:plugin_platform_interface/plugin_platform_interface.dart';

import 'comeplugin_method_channel.dart';

abstract class ComepluginPlatform extends PlatformInterface {
  /// Constructs a ComepluginPlatform.
  ComepluginPlatform() : super(token: _token);

  static final Object _token = Object();

  static ComepluginPlatform _instance = MethodChannelComeplugin();

  /// The default instance of [ComepluginPlatform] to use.
  ///
  /// Defaults to [MethodChannelComeplugin].
  static ComepluginPlatform get instance => _instance;

  /// Platform-specific implementations should set this with their own
  /// platform-specific class that extends [ComepluginPlatform] when
  /// they register themselves.
  static set instance(ComepluginPlatform instance) {
    PlatformInterface.verifyToken(instance, _token);
    _instance = instance;
  }

  Future<String?> getPlatformVersion() {
    throw UnimplementedError('platformVersion() has not been implemented.');
  }

  Future<String?> getVersionName() {
    throw UnimplementedError('platformVersion() has not been implemented.');
  }


  Future<String?> getVersionCode() {
    throw UnimplementedError('platformVersion() has not been implemented.');
  }

  toast(String  str){
    throw UnimplementedError('platformVersion() has not been implemented.');
  }


}
  • 然后再我们的 MethodChannelComeplugin 类里面实现这些方法

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'comeplugin_platform_interface.dart';

/// An implementation of [ComepluginPlatform] that uses method channels.
class MethodChannelComeplugin extends ComepluginPlatform {
 /// The method channel used to interact with the native platform.
 @visibleForTesting
 final methodChannel = const MethodChannel('comeplugin');

 @override
 Future<String?> getPlatformVersion() async {
   final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
   return version;
 }

 @override
 Future<String?> getVersionName() async {
   final versionname = await methodChannel.invokeMethod<String>('getVersionName');
   return versionname;
 }

 @override
 Future<String?> getVersionCode() async {
   final versioncode = await methodChannel.invokeMethod<String>('getVersionCode');
   return versioncode;
 }

 @override
   toast(String str) async {
   await methodChannel.invokeMethod('toast', {'param': str});
 }


}
  • 我们通过 MethodChannel 来注册我们的交互的通信的协议 comeplugin 这个要跟我的原生端保持一致

flutter 端
final methodChannel = const MethodChannel('comeplugin');
原生端
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
  channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "comeplugin");
  channel.setMethodCallHandler(this);
  this.flutterPluginBinding=flutterPluginBinding;
}
  • 然后我们定义 Comeplugin 定义对应的对外方法 给我们的 example 调试工程调用


import 'comeplugin_platform_interface.dart';

class Comeplugin {
  Future<String?> getPlatformVersion() {
    return ComepluginPlatform.instance.getPlatformVersion();
  }


  Future<String?> getVersionName() {
    return ComepluginPlatform.instance.getVersionName();
  }


  Future<String?> getVersionCode() {
    return ComepluginPlatform.instance.getVersionCode();
  }

  toast(String  str) async {
    return ComepluginPlatform.instance.toast(str);
  }

}

我们在Comeplugin 里面里面返回我们的 ComepluginPlatform 里面的结果

然后我们在 example里面去调用

  • 获取Android版本号 获取versionname 获取versioncode 调用

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

  try {
    platformVersion =
        await _comepluginPlugin.getPlatformVersion() ?? 'Unknown platform version';
    print("platformVersion -- >"+platformVersion);


    versionname =
        await _comepluginPlugin.getVersionName() ?? 'Unknown versionname';
    print("versionname -- >"+versionname);
    versioncode =
        await _comepluginPlugin.getVersionCode() ?? 'Unknown versioncode version';

    print("versioncode -- >"+versioncode);

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

  if (!mounted) return;

  setState(() {
    _platformVersion = platformVersion;
     _veriosnName= versionname.toString();
     _versionCode= versioncode.toString();
  });
}
  • toast调用

@override
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: const Text('Plugin example app'),
      ),
      body: Center(
        child:Column(
          children: [
           Text('Running on: $_platformVersion\n'),
            Text('Versionname: $_veriosnName\n'),
            Text('VersionCode: $_versionCode\n'),
        ElevatedButton(
          onPressed: () =>{
           _comepluginPlugin.toast("测试哈哈哈")
          },
          child: const Text("点击toast"),
        ),
          ],
        )

      ),
    ),
  );
}

最后总结

到此我们的flutter插件开发我们就讲完了,那么如何打包插件发布还有和其他端交互例如 ios还有鸿蒙,我们在后面我们补上去,因为篇幅有限我这边就不展开讲,原理都差不多 也是使用Methodchannel 交互的,如果同学有兴趣可以自己研究 也可以继续等待老师后续的更新,今天的文章就讲到这里,, 今天的文章就讲到这里有兴趣的 关注我B站教程 了解更多鸿蒙开发的知识 可以关注坚果派公众号 。 谢谢

课程地址

flutter开发鸿蒙next零基础到精通教程

项目内容:

  • 1 Flutter 鸿蒙化开发环境搭建和项目运行介绍和实战使用
  • 2 Flutter 鸿蒙化flutter页面添加到现有的鸿蒙项目中
  • 3 Flutter鸿蒙化之flutter代码和鸿蒙next原生代码通信 MethodChannel 方式通信
  • 4 Flutter鸿蒙化之flutter代码和鸿蒙next原生代码通信 EventChannel 方式通信
  • 5 Flutter鸿蒙化之flutter代码和鸿蒙next原生代码通信 BasicMessageChannel 方式通信 实现透传
  • 6 Flutter 鸿蒙化PlatformView实现混合渲染