Flutter 插件开发实践(一)

作者: 向日花开 | 来源:发表于2019-12-27 14:10 被阅读0次

    Flutter 插件开发记录

    工具

    • Flutter 1.9.1

    • AndroidStudio 3.5.3

    • XCode 11.2.1

    新建一个 名为 flutter_plugin_demo 的 Flutter 工程,以下称为主工程。

    Android 部分插件开发

    右键工程名,新建一个名为 flutter_plugin 的 Moudle ,所选模块为 Flutter Plugin,其间你可以根据选择依赖插件所支持的 Kotlin 或者是 Swift 语言。

    创建完 Plugin 之后,flutter_plugin 会自动创建一个 example 的 Flutter 项目,因为 example 下面 test 包下面的 MyApp 类名会和主工程的类名冲突,所以替换以下即可。

    运行 example 工程

    右键 example/lib/main.dart,Run main.dart。如果在 IOS 模拟器中 build 成功但是包如下错误:

    The application's Info.plist does not contain CFBundleVersion.
    

    则在 example/pubspec.yaml 中添加

    version: 1.0.0+1
    

    再次运行即可。

    这说明其实插件本身已经帮我们实现了获取运行平台的功能,下面以简单的实现 toast 功能。

    用 AndroidStudio File/Open, 打开 flutter_plugin 工程:

    除此之外,还可以选中 android 文件夹,右键点击,找到 Flutter,Open Android module in Android Studio,如下图,因为有时候我用这种方式打开之后编写代码没有 API 提示,就各种尝试,看个人了,迷之正确。

    编辑 FlutterPlugin.java

    package com.hcl.flutter_plugin;
    
    import android.util.Log;
    import android.widget.Toast;
    
    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;
    import io.flutter.plugin.common.PluginRegistry.Registrar;
    
    /** FlutterPlugin */
    public class FlutterPlugin implements MethodCallHandler {
    
      private static final String TAG = FlutterPlugin.class.getSimpleName();
    
    
      private final Registrar registrar;
    
      //构造
      private FlutterPlugin(Registrar registrar) {
        this.registrar = registrar;
      }
    
    
      /**
       * Plugin registration.
       */
      public static void registerWith(Registrar registrar) {
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_plugin");
        channel.setMethodCallHandler(new FlutterPlugin(registrar));
      }
    
    
      //来自Flutter的方法调用
      @Override
      public void onMethodCall(MethodCall call, Result result) {
    
        String target = call.method;
        switch (target) {
          case "getPlatformVersion":
            result.success("Android " + android.os.Build.VERSION.RELEASE);
            break;
          case "toast":
            String content = (String) call.arguments;
            Log.d(TAG, "toast: " + content);
            showToast(content);
            break;
          default:
            result.notImplemented();
            break;
        }
    
      }
    
    
      /**
       * 显示Toast
       *
       * @param content
       */
      private void showToast(String content) {
        Toast.makeText(registrar.context(), content, Toast.LENGTH_SHORT).show();
      }
    
    
    }
    
    

    编辑 flutter_plugin.dart

    • flutter_plugin/lib
    import 'dart:async';
    
    import 'package:flutter/services.dart';
    
    class FlutterPlugin {
    
      //除了 MethodChannel 还有其他交互方式
      static const MethodChannel _channel =
          const MethodChannel('flutter_plugin');
    
      static Future<String> get platformVersion async {
        final String version = await _channel.invokeMethod('getPlatformVersion');
        return version;
      }
    
      /**
       * 显示Toast
       */
      static Future<void> showToast(String content)async {
        await _channel.invokeMethod("toast",content);
      }
    }
    
    

    调用运行

     FlutterAndroidPlugin.showToast("Hello World");
    

    这里只实现了 Android 部分的代码,所以只能运行到 Android 模拟器。

    IOS 端的实现

    用 XCode 打开 Xcode 打开 example 工程中 iOS 项目,找到 ios 目录下的 Runner.xcworkspace。找到 FlutterPlugin.m 文件,目录结构如下:

    修改 handleMethodCall 方法

    - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
        NSString* methodName=call.method;
        NSString * params = call.arguments;
      if ([@"getPlatformVersion" isEqualToString:methodName]) {
        result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
      } else if([@"toast" isEqualToString:methodName ]){
    
          [self showMessage:params duration:2];
    
      }else{
    
          result(FlutterMethodNotImplemented);
      }
    }
    
    

    再添加方法:

    //Toast
    -(void)showMessage:(NSString *)message duration:(NSTimeInterval)time
    {
        CGSize screenSize = [[UIScreen mainScreen] bounds].size;
    
        UIWindow * window = [UIApplication sharedApplication].keyWindow;
        UIView *showview =  [[UIView alloc]init];
        showview.backgroundColor = [UIColor grayColor];
        showview.frame = CGRectMake(1, 1, 1, 1);
        showview.alpha = 1.0f;
        showview.layer.cornerRadius = 5.0f;
        showview.layer.masksToBounds = YES;
        [window addSubview:showview];
    
        UILabel *label = [[UILabel alloc]init];
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init];
        paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
    
        NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:15.f],
                                     NSParagraphStyleAttributeName:paragraphStyle.copy};
    
        CGSize labelSize = [message boundingRectWithSize:CGSizeMake(207, 999)
                                                 options:NSStringDrawingUsesLineFragmentOrigin
                                              attributes:attributes context:nil].size;
        label.frame = CGRectMake(10, 5, labelSize.width +20, labelSize.height);
        label.text = message;
        label.textColor = [UIColor whiteColor];
        label.textAlignment = 1;
        label.backgroundColor = [UIColor clearColor];
        label.font = [UIFont boldSystemFontOfSize:15];
        [showview addSubview:label];
    
        showview.frame = CGRectMake((screenSize.width - labelSize.width - 20)/2,
                                    screenSize.height - 100,
                                    labelSize.width+40,
                                    labelSize.height+10);
        [UIView animateWithDuration:time animations:^{
            showview.alpha = 0;
        } completion:^(BOOL finished) {
            [showview removeFromSuperview];
        }];
    }
    

    即可。运行测试:

    Flutter Plugin 的引用

    这里只说本地引用,之前测试的都是在插件的 example/main.dart 中进行的,现在如果要让要主工程也引用该插件,则只需在主工程的 pubspec.yaml 中添加依赖:

    dev_dependencies:
      flutter_test:
        sdk: flutter
      flutter_plugin:
        path: flutter_plugin  #这个路径根据你插件的路径填写
    
    import 'package:flutter/material.dart';
    import 'package:flutter_plugin/flutter_plugin.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Main"),
          ),
          body: Center(
            child: RaisedButton(
              onPressed: () {
                FlutterPlugin.showToast("Say Hello");
              },
              child: Text("Say Hello"),
            ),
          ),
        );
      }
    }
    
    
    效果图

    最后

    源码地址
    贴一张自己学习Flutter的公众号,感兴趣的小伙伴可以一起学习哦。。。

    相关文章

      网友评论

        本文标题:Flutter 插件开发实践(一)

        本文链接:https://www.haomeiwen.com/subject/ibsloctx.html