为了账号安全,请及时绑定邮箱和手机立即绑定

[-Flutter插件篇 1-] 从自定义插件开始说起

标签:
Android

Flutter可以为你提供一个强大华丽简洁高效的跨平台UI界面,
但无论外表多么绚丽美女,没有内在也只是空壳,你会喜欢她吗?(还用问,当然会)
使用插件可以让Flutter轻松与当前平台进行联系,调用平台中的方法。
这篇先不虚头巴脑的介绍一堆MethodChannel的概念,先看怎么用。本文你将了解:

[1].如何创建一个Flutter插件的 [2].Flutter中如何和Android以及iOS交互(本文使用Kotlin和Swift) [3].Flutter插件的使用 复制代码

1.Flutter插件创建与结构简析

1.1:创建一个Flutter插件

File-->new-->new Flutter Project...


5d48393000010a5212800623.jpg


  • 填写信息


5d4839310001ffd112800561.jpg


  • 包名及语言选择




1.2:Flutter插件项目结构

写代码的地方有三块:

android下面写Android原生代码,使用Java或Kotlin,如果用JNI还可能涉及C++ ios文件夹下面写iOS原生代码,使用Object-c或Swift lib文件夹下面写Flutter代码,使用Dart语言 复制代码

也就是说一个插件可能涉及到6种语言,哈哈,颤抖吧人类...


5d483931000137e212800290.jpg



1.3:运行插件示例

虽然复杂,但是简单必有简单的成本,复杂必有复杂的价值。


5d4839310001d2d712800508.jpg


注意有个坑点:mac上需要装cocoapods

---->[本机信息]---- toly:~ mac$ ruby -v ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin18] toly:~ mac$ gem -v 2.5.2.3 toly:~ mac$ gem sources -l  *** CURRENT SOURCES *** https://rubygems.org/ ---->[替换ruby源]---- gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/ ---->[替换ruby源完成]---- toly:~ mac$ gem sources -l *** CURRENT SOURCES *** https://gems.ruby-china.com ---->[安装cocoapods]---- toly:~ mac$ sudo gem install -n /usr/local/bin cocoapods toly:~ mac$ pod setup 复制代码

2.第一个插件代码分析

这里创建一个ia_version的项目专门看看示例的插件是如何完成的。

2.1:Flutter代码:

可以看到ia_version.dart中定义了一个类IaVersion,其中有一个MethodChannel类型静态常量_channel,接受一个字符串,在静态方法platformVersion中使用异步调用_channel的getPlatformVersion方法获取版本进行返回。

---->[lib/ia_version.dart]---- class IaVersion {   static const MethodChannel _channel =       const MethodChannel('ia_version');   static Future<String> get platformVersion async {     final String version = await _channel.invokeMethod('getPlatformVersion');     return version;   } } 复制代码

2.2:Android方Kotlin代码:
[1].定义IaVersionPlugin类继承自MethodCallHandler。 [2].创建静态方法registerWith,传入一个Registrar类型变量registrar。   [3].通过registrar的messenger和标识符创建MethodChannel对象,   [4].将IaVersionPlugin对象设置给MethodChannel进行回调处理。   [5].覆写了onMethodCall方法,回调MethodCall和Result对象, 在方法体中根据方法名`getPlatformVersion`来用result对象执行方法传入Android版本信息。 ---->[com.toly1994.ia_version.IaVersionPlugin]---- class IaVersionPlugin: MethodCallHandler {   companion object {     @JvmStatic     fun registerWith(registrar: Registrar) {       val channel = MethodChannel(registrar.messenger(), "ia_version")       channel.setMethodCallHandler(IaVersionPlugin())     }   }   override fun onMethodCall(call: MethodCall, result: Result) {     if (call.method == "getPlatformVersion") {       result.success("Android ${android.os.Build.VERSION.RELEASE}")     } else {       result.notImplemented()     }   } } 复制代码

2.3:iOS方Swift代码
[1].定义SwiftIaVersionPlugin类继承自NSObject, FlutterPlugin   [2].创建静态方法register,传入一个FlutterPluginRegistrar类型变量registrar。 [3].通过registrar的messenger和标识符创建FlutterMethodChannel对象,   [4].将SwiftIaVersionPlugin对象设置给MethodChannel进行回调处理。   [5].handle方法,回调FlutterMethodCall和FlutterResult对象, 用result对象执行方法传入iOS版本信息。 ---->[ios/Classes/SwiftIaVersionPlugin.swift]---- public class SwiftIaVersionPlugin: NSObject, FlutterPlugin {   public static func register(with registrar: FlutterPluginRegistrar) {     let channel = FlutterMethodChannel(name: "ia_version", binaryMessenger: registrar.messenger())     let instance = SwiftIaVersionPlugin()     registrar.addMethodCallDelegate(instance, channel: channel)   }   public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {     result("iOS " + UIDevice.current.systemVersion)   } } 复制代码

还有两个文件使用OC写的,关于OC我不是太懂,下面是Flutter群里一位朋友的介绍


5d4839310001ca2012800489.jpg


---->[ios/Classes/IaVersionPlugin.h]---- @interface IaVersionPlugin : NSObject<FlutterPlugin> @end ---->[ios/Classes/IaVersionPlugin.m]---- @implementation IaVersionPlugin + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {   [SwiftIaVersionPlugin registerWithRegistrar:registrar]; } @end 复制代码

2.4:使用插件

使用的时候就很方便了,调用一下就ok。

import 'package:flutter/material.dart'; import 'dart:async'; import 'package:flutter/services.dart'; import 'package:ia_version/ia_version.dart'; void main() => runApp(MyApp()); class MyApp extends StatefulWidget {   @override   _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> {   String _platformVersion = 'Unknown';   @override   void initState() {     super.initState();     initPlatformState();   }   Future<void> initPlatformState() async {//异步初始化平台状态     String platformVersion;     try {//捕捉PlatformException.       platformVersion = await IaVersion.platformVersion;//通过插件获取平台版本     } on PlatformException {       platformVersion = 'Failed to get platform version.';     }     // 如果在异步平台消息运行期间widget从树中删除,     // 我们希望丢弃响应,而不是调用setState来更新不存在的外观。     if (!mounted) return;     setState(() {//更新状态       _platformVersion = platformVersion;     });   }   @override   Widget build(BuildContext context) {     return MaterialApp(       home: Scaffold(         appBar: AppBar(           title: const Text('Plugin example app'),         ),         body: Center(           child: Text('Running on: $_platformVersion\n'),         ),       ),     );   } } 复制代码

3.获取缓存文件夹

相信大家都用过path_provider,感觉很方便就可以在Flutter中获取文件路径
下面我们看一下如何让一个插件获取缓存文件夹,如果前面看明白了,应该so easy


5d483932000151f312800386.jpg



3.1:dart插件文件
import 'dart:async'; import 'dart:io'; import 'package:flutter/services.dart'; class IaPath {   static const MethodChannel _channel =//插件的渠道标识名       const MethodChannel('com.toly1994.ia_path');   Future<Directory> getTemporaryDirectory() async {     final String path =     await _channel.invokeMethod<String>('getTemporaryDirectory');     if (path == null) {       return null;     }     return Directory(path);   } } 复制代码

3.2:Android文件
class IaPathPlugin(registrar: Registrar) : MethodCallHandler {   private var mRegistrar: Registrar? = registrar      companion object {     @JvmStatic     fun registerWith(registrar: Registrar) {       val channel = MethodChannel(registrar.messenger(), "com.toly1994.ia_path")       val instance = IaPathPlugin(registrar)       channel.setMethodCallHandler(instance)     }   }      override fun onMethodCall(call: MethodCall, result: Result) {     when(call.method){       "getTemporaryDirectory"->{         result.success(geTemporaryDirectory())       }     }   }   private fun geTemporaryDirectory(): String {    return mRegistrar!!.context().cacheDir.path;   } } 复制代码

3.3:iOS的文件
public class SwiftIaPathPlugin: NSObject, FlutterPlugin {   public static func register(with registrar: FlutterPluginRegistrar) {     let channel = FlutterMethodChannel(name: "com.toly1994.ia_path", binaryMessenger: registrar.messenger())     let instance = SwiftIaPathPlugin()     registrar.addMethodCallDelegate(instance, channel: channel)   }   public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {     switch call.method {        case "getTemporaryDirectory"  :           result(NSTemporaryDirectory())        default :           result("UnKnown")     }   } } 复制代码

3.4:使用
import 'package:flutter/material.dart'; import 'package:ia_path/ia_path.dart'; void main() => runApp(MyApp()); class MyApp extends StatefulWidget {   @override   _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> {   String _str = 'CacheDir:\n';   @override   void initState() {     super.initState();     IaPath().getTemporaryDirectory().then((dir){       setState(() {         _str+=dir.path;       });     });   }   @override   Widget build(BuildContext context) {     return MaterialApp(       home: Scaffold(         appBar: AppBar(           title: const Text('Plugin example app'),         ),         body: Container(           child: Text('Running on: $_str\n'),         ),       ),     );   } } 复制代码

4.其他工程引用插件

4.1:发布到公网

有道墙隔着,发不发得了就看你自己了。

---->[发布]---- flutter packages pub publish ---->[使用]---- dependencies:   ia_path: ^0.0.1 复制代码

4.2:本地使用

经测试,使用无误

dependencies:   ia_path:     path: /Volumes/coder/Project/Flutter/plugins/ia_path 复制代码

当然你也可以直接在本项目中调用Android和iOS方法,就像插件里做的那样。
本文讲了一下插件的自定义和在两个平台上的代码处理,
下一篇将详细讲述MethodChannel,让你在Flutter中无后顾之忧。



点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消