Flutter - 插件(iOS)

625 阅读3分钟

插件是Flutter开发中不可获取的一部分,它能为Flutter提供一些原生平台的功能,比如最常用的shared_preferences,废话不多说直接开始看一下怎么封装自己所需要的插件功能。

Demo在这里

本地插件

直接在项目中使用的简单插件

iOS部分

Flutter项目创建后,ios项目中会有一个GeneratedPluginRegistrant类,你所导入的pub库中的插件都会在此注册,因为是我们自己项目中单独的Plugin,可以考虑照葫芦画瓢,创建一个CustomPluginRegistrant的类,用于注册自己封装的插件。

AppDelegate

override func application(

        _ application: UIApplication,

        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?

    ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)

        CustomPluginRegistrant.register(with: self)

        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

CustomPluginRegistrant

class CustomPluginRegistrant {
    static func register(with registry: FlutterPluginRegistry) {
        SimplePlugin.register(with: registry.registrar(forPlugin: "SimplePlugin")!)
    }
}

SimplePlugin

open class SimplePlugin: NSObject, FlutterPlugin {
    public static let shared = SimplePlugin()

    private var channel: FlutterMethodChannel?

    private override init() {}

    public static func register(with registrar: FlutterPluginRegistrar) {

        let channel = FlutterMethodChannel(name: "flutter_simple_channel", binaryMessenger: registrar.messenger())

        shared.channel = channel

        registrar.addMethodCallDelegate(shared, channel: channel)

    }

    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        switch call.method {
        case "method":
            result(method())
        case "methodWithAruguments":
            result(method(with: call.arguments))
        case "closureMethod":
            closureMethod { result($0) }
        default:
            print("other")
        }
    }

    /// method
    private func method() -> String {
        return "method result"
    }
    
    /// methodWithAruguments
    private func method(with arguments: Any) -> String {
        /// 原生调用flutter
        channel?.invokeMethod("print", arguments: arguments, result: { result **in**
            print(result)
        })
        return "method with arguments result"
    }

    /// closureMethod
    private func closureMethod(_ callback: @escaping (String) -> Void) {
        return callback("closure method result")
    }
}

Flutter部分


class SimplePlugin {
  late MethodChannel _channel = MethodChannel('flutter_simple_channel');

  static SimplePlugin instance = SimplePlugin._();

  SimplePlugin._() {
    _channel.setMethodCallHandler((call) async {
      print(call.method);
      print(call.arguments);
    });
  }

  Future<String> method() async {
    return _channel.invokeMethod('method').then((value) => value);
  }

  Future<String> methodWithAruguments(String arg) {
    return _channel
        .invokeMethod('methodWithAruguments', arg)
        .then((value) => value);
  }

  Future<String> closureMethod() {
    return _channel.invokeMethod('closureMethod').then((value) => value);
  }
}

调用

    SimplePlugin.instance.method().then((value) {
      print(value);
    });
    SimplePlugin.instance.methodWithAruguments('flutter arg').then((value) {
      print(value);
    });
    SimplePlugin.instance.closureMethod().then((value) {
      print(value);
    });

pub 插件

团队需要封装公用组件,或者你想开源封装的组件的时候可以参考, 方便起见直接在上方Demo中创建plugin。可以查看创建后的项目,已经为我们提供了相应的模板,可以查看一下 基本和上方代码差不多。

/// 创建plugin的命令 这里只是创建了ios
flutter create --org com.example --template=plugin --platforms=ios -i swift easy_permission

/// 开始之前我们现在demo的pubspec.yaml中添加 
easy_permission:
  path: ../easy_permission

执行pub get后其实你已经可以在flutter端调用模板中的方法了。

    EasyPermission().getPlatformVersion().then((value) => print(value));

iOS部分

如果你熟悉ios开发,easy_promission/ios 其实就是一个单独的cocoapods库,和我们之前开发三方库的逻辑是一样的,你也可以在其中引入其他的ios三方库, 这里我直接使用我自己的开源库来演示了。

/// 在easy_permission.podspec中修改
...
  s.dependency 'Flutter'
  s.dependency 'EasyKits/EasyPermission/EasyCamera'
  s.platform = :ios, '10.0'
...

/// 在引入的工程中,此处是plugin_demo的ios的Info.plist中添加相机权限
<key> NSCameraUsageDescription </key>
<string> 我想用用相机 </string>

修改SwiftEasyPermissionPlugin中的代码 建议这里最好都先实现了ios库,之后再引入,当然如果你的库功能很简单,就直接在此处实现即可。

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

  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
      switch call.method {
      case "cameraStatus":
          Permission.camera.status { status in
              result(status.value)
          }
      case "requestCamera":
          Permission.camera.request { status in
              result(status.value)
          }
      case "accessCamera":
          Permission.camera.access { status in
              result(status.value)
          }
      default:
          result(PermissionStatus.notSupported.value)
      }
  }
}

extension PermissionStatus {
    var value: String {
        return "\(self)"
    }
}

Flutter部分

只粘贴部分代码

class MethodChannelEasyPermission extends EasyPermissionPlatform {
  /// The method channel used to interact with the native platform.
  @visibleForTesting
  final methodChannel = const MethodChannel('easy_permission');

  /// 只是查看权限
  @override
  Future<EasyPermissionStatus> cameraStatus() async {
    final status = await methodChannel.invokeMethod<String>('cameraStatus');
    return permisionStatusMap[status] ?? EasyPermissionStatus.notSupported;
  }

  /// 直接申请权限
  @override
  Future<EasyPermissionStatus> requestCamera() async {
    final status = await methodChannel.invokeMethod<String>('requestCamera');
    return permisionStatusMap[status] ?? EasyPermissionStatus.notSupported;
  }

  /// 访问相机权限,没有权限会申请权限
  @override
  Future<EasyPermissionStatus> accessCamera() async {
    final status = await methodChannel.invokeMethod<String>('accessCamera');
    return permisionStatusMap[status] ?? EasyPermissionStatus.notSupported;
  }
}

使用部分

    EasyPermission().cameraStatus().then((value) => print(value));
    EasyPermission().requestCamera().then((value) => print(value));
    EasyPermission().accessCamera().then((value) => print(value));```

最后就是插件的发布,可以自行搜索。