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 get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
/**
* 显示Toast
*/
static Future 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 {
@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的公众号,感兴趣的小伙伴可以一起学习哦。。。