flutter 插件开发和iOS交互再战江湖

506 阅读4分钟

前言导读

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

效果图

image.png

image.png

具体实现

  • 创建插件工程
flutter create -t plugin --platforms ohos,android,ios <plugin_name>

image.png

image.png

image.png

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

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

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

  • 我们选直接运行下我们的项目 让 Xcode拉一下依赖

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

image.png

手动拉依赖。

进到我们的example 目录下面的ios目录下面 执行pod install

$ cd ios
$ pod instal

使用 xcode 打开 example / ios 目录

image.png

image.png

这个demo我们一共编写了 获取iOS系统版本号和toast的案例

  • 获取iOS系统版本号

  case "getPlatformVersion":
      result("iOS " + UIDevice.current.systemVersion)
        
  • toast

    case  "toast":
        let args = call.arguments as? [String: Any] ?? [:] // 获取参数
        let data = args["param"] as? String ?? "default" // 提取数据
        ToastManager.show(message:data)

这里需要注意我们flutter 端 是通过map传递参数给我们鸿蒙next端的

@override
 toast(String str) async {
  Map<String,dynamic>user={
    'param':str
  };
   await methodChannel.invokeMethod<String>('toast',user);
}
  • 完整插件原生iOS代码

import Flutter
import UIKit

public class DemopluginPlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "demoplugin", binaryMessenger: registrar.messenger())
    let instance = DemopluginPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
  }

  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    switch call.method {
    case "getPlatformVersion":
      result("iOS " + UIDevice.current.systemVersion)
        
    case  "toast":
        let args = call.arguments as? [String: Any] ?? [:] // 获取参数
        let data = args["param"] as? String ?? "default" // 提取数据
        ToastManager.show(message:data)
    default:
      result(FlutterMethodNotImplemented)
    } 
  }
}

  • iOS toast工具类 ToastView
class ToastView: UIView {
    private let label: UILabel = {
        let label = UILabel()
        label.textColor = .white
        label.textAlignment = .center
        label.numberOfLines = 0
        label.font = .systemFont(ofSize: 14)
        return label
    }()
    
    init(message: String) {
        super.init(frame: .zero)
        backgroundColor = UIColor(white: 0, alpha: 0.7)
        layer.cornerRadius = 8
        addSubview(label)
        
        label.text = message
        label.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
            label.topAnchor.constraint(equalTo: topAnchor, constant: 8),
            label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

  • toast 显示工具类 ToastManager
//
//  ToastManager.swift
//  Pods
//
//  Created by xuqing on 2025/7/15.
//
class ToastManager {
    private static var toastWindow: UIWindow?
    
    static func show(message: String, duration: TimeInterval = 2.0) {
        DispatchQueue.main.async {
            let screenSize = UIScreen.main.bounds.size
            let toastView = ToastView(message: message)
            toastView.frame = CGRect(x: 0, y: screenSize.height-100,
                                   width: screenSize.width, height: 60)
            
            toastWindow = UIWindow(frame: UIScreen.main.bounds)
            toastWindow?.windowLevel = .alert + 1
            toastWindow?.backgroundColor = .clear
            toastWindow?.addSubview(toastView)
            toastWindow?.makeKeyAndVisible()
            
            UIView.animate(withDuration: 0.3, delay: duration, options: []) {
                toastView.alpha = 0
            } completion: { _ in
                toastWindow?.isHidden = true
                toastWindow = nil
            }
        }
    }
}


  • flutter端插件代码实现

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

import 'package:plugin_platform_interface/plugin_platform_interface.dart';

import 'demoplugin_method_channel.dart';

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

  static final Object _token = Object();

  static DemopluginPlatform _instance = MethodChannelDemoplugin();

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

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

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

  @override
  toast(String str) async {
    throw UnimplementedError('platformVersion() has not been implemented.');
  }
}
  • 然后再我们的 MethodChannelComeplugin 类里面实现这些方法

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

import 'demoplugin_platform_interface.dart';

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

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



  @override
   toast(String str) async {
    Map<String,dynamic>user={
      'param':str
    };
     await methodChannel.invokeMethod<String>('toast',user);
  }
}
  • 我们通过 MethodChannel 来注册我们的交互的通信的协议demoplugin 这个要跟我的原生端保持一致

  • flutter 端

@visibleForTesting
final methodChannel = const MethodChannel('demoplugin');
  • iOS原生端

  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "demoplugin", binaryMessenger: registrar.messenger())
    let instance = DemopluginPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
  }
  • 然后我们定义 Demoplugin 定义对应的对外方法 给我们的 example 调试工程调用

import 'demoplugin_platform_interface.dart';

class Demoplugin {
  Future<String?> getPlatformVersion() {
    return DemopluginPlatform.instance.getPlatformVersion();
  }


  @override
  toast(String str) async {
    return DemopluginPlatform.instance.toast(str);
  }

}

我们在Demoplugin 里面里面返回我们的 DemopluginPlatform 里面的结果

然后我们在 example里面去调用

  • 获取iOS系统版本号调用
Future<void> initPlatformState() async {
  String platformVersion;
  // Platform messages may fail, so we use a try/catch PlatformException.
  // We also handle the message potentially returning null.
  try {
    platformVersion =
        await _demopluginPlugin.getPlatformVersion() ?? 'Unknown platform version';
  } on PlatformException {
    platformVersion = 'Failed to get platform version.';
  }

  // If the widget was removed from the tree while the asynchronous platform
  // message was in flight, we want to discard the reply rather than calling
  // setState to update our non-existent appearance.
  if (!mounted) return;

  setState(() {
    _platformVersion = platformVersion;
  });
}
  • 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'),
            ElevatedButton(onPressed: ()=>{
              _demopluginPlugin.toast("测试数据")

            }, child: Text("点击toast"))
          ],
        )
      ),
    ),
  );
}

最后总结

到此我们的flutter 插件开发我们就讲完了,那么如何打包插件发布,我们在后面我们补上去,因为篇幅有限我这边就不展开讲,如果同学有兴趣可以自己研究 也可以继续等待老师后续的更新,今天的文章就讲到这里,, 今天的文章就讲到这里有兴趣的 关注我B站教程 谢谢

  • 如果想看Flutter插件开发化android交互在这里

flutter 插件开发化android 交互

  • 如果想看Flutter插件开发化 鸿蒙交互看这里

flutter 鸿蒙化插件开发横空出世