前言

61、Flutter插件通信原理<一>_风雨「83」的博客-CSDN博客Flutter与原生通讯 - Flutter Plugin - 知乎前言Flutter优势主要体现在UI上--高性能且跨平台表现一致。但是针对平台(Android、IOS)的实现,如:获取电量、判断WiFi使用、调起WebView加载网页等,得调用特定平台的API包。Flutter Plugin就是为调用平台API而生。下文中所提及到的"平台"指的是Android、IOS两端。介绍Flutter Plugin包含针对Android(Java或Kotlin代码)或iOS(Objectihttps://blog.csdn.net/wywinstonwy/article/details/123925721?spm=1001.2014.3001.5502Flutter中已经具体提到了Flutter与iOS,Android的通信原理。Flutter通信是靠MethodChannel进行通信的。

假设Flutter需要一个第三方的授权登录,而第三方目前没有支持到Flutter的版本,只支持Android,iOS版本,这个时候就需要自己开发Flutter与原生的通信插件。

通信插件的开发过程

1、创建Flutter_Plugin项目

新建flutter_plugin工程,选择工程类型,选项语言类型,并点击finish完成工程的创建。

2、Flutter_Plugin目录介绍

Android 就是我们开发安卓部分的位置

iOS 就是我们开发 iOS 的位置

lib 是与 Android 、iOS 联调的位置。也可以理解为Flutter 实现通信的位置

example 是测试的位置,当我们写完插件 可以直接运行 插件,example 可以理解为一个Flutter项目,只不过这个项目只给你写的插件服务  。

3、Flutter部分开发

1、添加原生、Flutter交互渠道

我们打开插件,找到lib ,在lib下面会有一个文件 test_flutter_plugin_demo.dart,在这个基础上我们进行扩展,更加灵活

import 'dart:async';import 'package:flutter/services.dart';typedef void TestViewCreatedCallback(TestFlutterPluginDemo controller);
class TestFlutterPluginDemo {late MethodChannel _channel;TestFlutterPluginDemo.init(int id){// 原生与Flutter 交互渠道_channel = new MethodChannel('test_flutter_plugin_demo');_channel.setMethodCallHandler(platformCallHandler);///设置原生参数监听}///Flutter 调用原生///这里我传了一个 字符串 当然也可以传MapFuture<List<dynamic>?> changeNativeTitle(String str) async{return _channel.invokeListMethod('changeNativeTitle',str);}///实现监听原生方法回调Future<dynamic> platformCallHandler(MethodCall call) async {switch (call.method) {case "clickAciton":print('收到原生回调 ---- $call.arguments');return ;break;}}
}

这样就实现了 原生与Flutter之间的交互,等后续iOS,Android端代码完成就可以进行两端调试。

2、Flutter界面开发以及调用

在example/lib下创建view.dart 文件,并在example/lib/main.dart中引入视图view.dart并调用。

view.dart全部代码


import 'package:flutter/cupertino.dart';
import 'package:test_flutter_plugin_demo/test_flutter_plugin_demo.dart';
import 'package:flutter/services.dart';
import 'dart:io';/// @Author wywinstonwy
/// @Date 2022/4/15 10:58 上午
/// @Description: ///我是使用的 StatefulWidget 使用StatelessWidget 也是一样
class TestView extends StatefulWidget {///根据自己的需求创建初始化参数final TestViewCreatedCallback ? onCreated; ///是上面创建的回调final String ? titleStr;TestView({required Key key,this.onCreated,this.titleStr,});@override_TestViewState createState() => _TestViewState();
}class _TestViewState extends State<TestView> {@overrideWidget build(BuildContext context) {return Container(child: _loadNativeView(),);}///加载原生视图Widget _loadNativeView(){///根据不同的平台显示相应的视图if(Platform.isAndroid){ ///加载安卓原生视图return AndroidView(viewType: 'testView',///视图标识符 要和原生 保持一致 要不然加载不到视图onPlatformViewCreated:onPlatformViewCreated,///原生视图创建成功的回调creationParams: <String, dynamic>{ ///给原生传递初始化参数 就是上面定义的初始化参数'titleStr':widget.titleStr,},/// 用来编码 creationParams 的形式,可选 [StandardMessageCodec], [JSONMessageCodec], [StringCodec], or [BinaryCodec]/// 如果存在 creationParams,则该值不能为nullcreationParamsCodec: const StandardMessageCodec(),);}else if(Platform.isIOS){///加载iOS原生视图return UiKitView(viewType: 'testView',///视图标识符 要和原生 保持一致 要不然加载不到视图onPlatformViewCreated:onPlatformViewCreated,///原生视图创建成功的回调creationParams: <String, dynamic>{ ///给原生传递初始化参数 就是上面定义的初始化参数'titleStr':widget.titleStr,},/// 用来编码 creationParams 的形式,可选 [StandardMessageCodec], [JSONMessageCodec], [StringCodec], or [BinaryCodec]/// 如果存在 creationParams,则该值不能为nullcreationParamsCodec: const StandardMessageCodec(),);}else{return Text('这个平台老子不支持');}}///这个基本上是固定写法 Future<void> onPlatformViewCreated(id) async {if (widget.onCreated == null) {return;}widget.onCreated!(new TestFlutterPluginDemo.init(id));}
}

example/lib/main.dart中调用view.dart

import 'package:flutter/material.dart';
import 'dart:async';import 'package:flutter/services.dart';
import 'package:test_flutter_plugin_demo/test_flutter_plugin_demo.dart';
import 'package:test_flutter_plugin_demo_example/view.dart';
void main() {runApp(const MyApp());
}class MyApp extends StatefulWidget {const MyApp({Key? key}) : super(key: key);@overrideState<MyApp> createState() => _MyAppState();
}class _MyAppState extends State<MyApp> {String _platformVersion = 'Unknown';///定义一个测试类的属性 用来调用原生方法 和原生交互var testFlutterPluginDemo;@overridevoid initState() {super.initState();initPlatformState();}// Platform messages are asynchronous, so we initialize in an async method.Future<void> initPlatformState() async {String platformVersion ='是是是';// try {//   platformVersion =//       await TestFlutterPluginDemo.platformVersion ?? 'Unknown platform version';// } on PlatformException {//   platformVersion = 'Failed to get platform version.';// }if (!mounted) return;setState(() {_platformVersion = platformVersion;});}@overrideWidget build(BuildContext context) {///初始化 测试视图的类TestView testView =  TestView(onCreated: onTestViewCreated, key: ValueKey('testView'),titleStr: 'flutter给原生的参数',);return MaterialApp(home: Scaffold(appBar: AppBar(title: const Text('Plugin example app'),),body: Column(children: [Container(height: 200,width: 400,child: testView,),FloatingActionButton(onPressed: onNativeMethon)],),),);}void onNativeMethon(){this.testFlutterPluginDemo.changeNativeTitle('Flutter 调用原生成功了');}void onTestViewCreated(testFlutterPluginDemo){this.testFlutterPluginDemo = testFlutterPluginDemo;}
}

4、iOS、Android介绍

1、iOS部分代码开发

iOS 找到 ios 目录,选择Reveal in Finder,因为现在这个ios 部分还没有pod install,我们这要先进行pod install,成功后直接打开项目即可,效果如下

在这里我们找到TestFlutterPluginDemoPlugin,这个类隐藏的很深,他是Flutter 与原生交互的核心,在这了我们可以接收到Flutter的内容。

在此目录下分别创建TestFlutterPluginViewTestFlutterPluginViewFactory

//
//  TestFlutterPluginView.h
//  Pods
//
//  Created by wangyun on 2022/4/15.
//#import <Foundation/Foundation.h>
#include <Flutter/Flutter.h>@interface TestFlutterPluginView : NSObject<FlutterPlatformView>
- (id)initWithFrame:(CGRect)frameviewId:(int64_t)viewIdargs:(id)argsmessager:(NSObject<FlutterBinaryMessenger>*)messenger;
@end
//
//  TestFlutterPluginView.m
//  Pods
//
//  Created by wangyun on 2022/4/15.
//#import "TestFlutterPluginView.h"@interface TestFlutterPluginView ()
/** channel*/
@property (nonatomic, strong)  FlutterMethodChannel  *channel;
@property (nonatomic, strong)  UIButton  *button;
@property (nonatomic, strong)  UITextField  *textField;
@property (nonatomic, strong)  UILabel  *lblText;
@property (nonatomic, assign)  NSInteger  count;
@end@implementation TestFlutterPluginView
{CGRect _frame;int64_t _viewId;id _args;}- (id)initWithFrame:(CGRect)frameviewId:(int64_t)viewIdargs:(id)args
messager:(NSObject<FlutterBinaryMessenger>*)messenger
{if (self = [super init]){_frame = frame;_viewId = viewId;_args = args;NSLog(@"%@",args[@"titleStr"]);///建立通信通道 用来 监听Flutter 的调用和 调用Fluttter 方法 这里的名称要和Flutter 端保持一致_channel = [FlutterMethodChannel methodChannelWithName:@"test_flutter_plugin_demo" binaryMessenger:messenger];__weak __typeof__(self) weakSelf = self;[_channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {[weakSelf onMethodCall:call result:result];}];}return self;
}- (UIView *)view{UIView *nativeView = [[UIView alloc] initWithFrame:_frame];nativeView.backgroundColor = [UIColor redColor];_button = [UIButton buttonWithType:UIButtonTypeSystem];[_button setTitle:@"我是按钮" forState:UIControlStateNormal];[_button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];[_button setBackgroundColor:[UIColor blueColor]];_button.frame = CGRectMake(10, 20, 100, 44);[nativeView addSubview:_button];self.lblText = [[UILabel alloc] initWithFrame:CGRectMake(140, 20, 200, 44)];self.lblText.text =_args[@"titleStr"];self.lblText.backgroundColor =[UIColor blueColor];self.lblText.textColor =[UIColor whiteColor];[nativeView addSubview:self.lblText];[_button addTarget:self action:@selector(flutterMethod) forControlEvents:UIControlEventTouchUpInside];_textField = [[UITextField alloc] initWithFrame:CGRectMake(100, 125, 200, 44)];[_textField setText: [NSString stringWithFormat:@"这个数据是原生控制 %d",_count] ];[nativeView addSubview:_textField];return nativeView;}
#pragma mark -- Flutter 交互监听
-(void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result{//监听Fluterif ([[call method] isEqualToString:@"changeNativeTitle"]) {[_button setTitle:call.arguments forState:UIControlStateNormal];}}
//调用Flutter
- (void)flutterMethod{self.count = self.count+1;NSString *str = [NSString stringWithFormat:@"原生给flutter的参数 %ld",(long)self.count];[self.channel invokeMethod:@"clickAciton" arguments:str];[_textField setText: [NSString stringWithFormat:@"这个数据是原生控制 %ld",(long)_count] ];if(_count%2==0){self.lblText.backgroundColor =[UIColor blueColor];self.lblText.textColor =[UIColor whiteColor];}else{self.lblText.backgroundColor =[UIColor orangeColor];self.lblText.textColor =[UIColor blackColor];}}
@end
//
//  TestFlutterPluginViewFactory.h
//  Pods
//
//  Created by wangyun on 2022/4/15.
//#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN@interface TestFlutterPluginViewFactory : NSObject<FlutterPlatformViewFactory>
/// 重写一个构造方法 来接收 Flutter 相关蚕食
/// @param messenger Flutter类 包含回调方法等信息
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
@endNS_ASSUME_NONNULL_END
//
//  TestFlutterPluginViewFactory.m
//  Pods
//
//  Created by wangyun on 2022/4/15.
//#import "TestFlutterPluginViewFactory.h"
#import "TestFlutterPluginView.h"
@interface TestFlutterPluginViewFactory ()@property(nonatomic)NSObject<FlutterBinaryMessenger>* messenger;@end@implementation TestFlutterPluginViewFactory- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {self = [super init];if (self) {self.messenger = messenger;}return self;
}#pragma mark -- 实现FlutterPlatformViewFactory 的代理方法
- (NSObject<FlutterMessageCodec>*)createArgsCodec {return [FlutterStandardMessageCodec sharedInstance];
}/// FlutterPlatformViewFactory 代理方法 返回过去一个类来布局 原生视图
/// @param frame frame
/// @param viewId view的id
/// @param args 初始化的参数
- (NSObject<FlutterPlatformView> *)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id)args{TestFlutterPluginView *testFlutterPluginView = [[TestFlutterPluginView alloc] initWithFrame:frame viewId:viewId args:args messager:self.messenger];return testFlutterPluginView;}@end

2、Android 部分代码开发

Android 这部分和iOS 是同一个道理,没有丝毫区别,Android 我们也右键在工具中打开,然后如下图找到位置,Android 所有的代码都在这里进行

Android TestFlutterPluginView全部代码
package com.example.test_flutter_plugin_demo;import android.content.Context;
import android.graphics.Color;
import android.graphics.SurfaceTexture;
import android.provider.CalendarContract;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;import androidx.annotation.NonNull;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.platform.PlatformView;/*** Created by sunyd on 1/25/22*/
public class TestFlutterPluginView extends TextView implements PlatformView, MethodChannel.MethodCallHandler, TextureView.SurfaceTextureListener{@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {return false;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture surface) {}public  Context context;/*** 通道*/private  MethodChannel methodChannel = null;public TestFlutterPluginView(Context context, int viewId, Object args, BinaryMessenger messenger) {super(context);this.context = context;Toast.makeText(context, "创建关联成功", Toast.LENGTH_SHORT).show();setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));setBackgroundColor(Color.argb(255,79,79,79));  //0完全透明  255不透明//注册methodChannel = new MethodChannel(messenger, "test_flutter_plugin_demo");methodChannel.setMethodCallHandler(this);}@Overridepublic void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {handleCall(call, result);}private void handleCall(MethodCall methodCall, MethodChannel.Result result) {switch (methodCall.method) {//开始预览case "changeNativeTitle":Toast.makeText(context, (String)methodCall.arguments, Toast.LENGTH_SHORT).show();break;default:}}@Overridepublic View getView() {return this;}@Overridepublic void dispose() {}
}
Android TestFlutterPluginViewFactory全部代码
package com.example.test_flutter_plugin_demo;
import android.content.Context;import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MessageCodec;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;public class TestFlutterPluginViewFactory extends PlatformViewFactory {private BinaryMessenger messenger = null;public TestFlutterPluginViewFactory(BinaryMessenger messenger) {super(StandardMessageCodec.INSTANCE);this.messenger = messenger;}/*** @param createArgsCodec the codec used to decode the args parameter of {@link #create}.*/public TestFlutterPluginViewFactory(MessageCodec<Object> createArgsCodec) {super(createArgsCodec);}@Overridepublic PlatformView create(Context context, int viewId, Object args) {return new TestFlutterPluginView(context, viewId, args, this.messenger);}
}

到此,插件的开发就算是完事了。实现的效果(iOS,Android)如下:

下面就是使用这个插件了,我们如何集成到 别的项目里,在这里 我们只介绍 本地 使用

其实本地使用非常简单。

1、打开我们的项目

2、打开pubspec.yaml

dependencies:flutter:sdk: fluttertest_flutter_plugin_demo:path: /Users/yunwang/Documents/flutterStudy/flutter_plugin_demo

flutter_plugin_demo 位插件的名称,就是我们创建插件时候的文件名称,path就是路径了,我们找到插件位置 将路径 粘贴到这里即可

3、pub get

到此就引用完成了。

4、使用我们就和example 里面一摸一样就可以了。

源码demo地址:test_flutter_plugin_demo: flutter插件开发,Android,iOS端通信。

62、Flutter插件通信iOS,Android实现过程<二>相关推荐

  1. Flutter插件(Plugin)开发 - Android视角,flutter安装视频

    // 上报播放器的状态的EventChannel EventChannel status_channel = new EventChannel(registrar.messenger(), " ...

  2. 【Flutter】Flutter 开发环境搭建 ( Android Studio 下 Flutter / Dart 插件安装 | Flutter SDK 安装 | 环境变量配置 | 开发环境检查 )

    文章目录 一.Flutter 学习资料 二.Flutter 开发环境搭建 三.Android Studio 环境安装 Flutter / Dart 插件 四.下载 Flutter SDK 五.设置 F ...

  3. 【Flutter】开发 Flutter 包和插件 ( Flutter 包和插件简介 | 创建 Flutter 插件 | 创建 Dart 包 )

    文章目录 一.Flutter 包和插件简介 二.创建 Flutter 插件 1.Android Studio 中可视化创建 2.命令行创建 三.创建 Dart 包 1.Android Studio 中 ...

  4. Flutter学习:高德地图flutter插件增加中英文切换

    高德官方已经有Flutter插件,但在使用过程中发现并没有将中英文切换接口,所以只能在本地修改插件代码. Flutter插件修改 修改文件amap_flutter_map.dart,增加属性mapLa ...

  5. Flutter插件汇总

    ❀ ❀ 尽可能收集好用的插件以便更快的开发效率,85%亲测,持续添加中 如果有好的插件或者建议,可以直接评论 ❀❀ Github地址:https://github.com/jahnli/awesome ...

  6. 【Flutter】Flutter 拍照示例 ( Flutter 插件配置 | Flutter 插件源码示例 | iOS 应用配置 | Android 应用配置 )

    文章目录 一.Flutter 插件配置 二.Flutter 插件源码示例 三.iOS 应用配置 四.Android 应用配置 五.相关资源 一.Flutter 插件配置 Flutter 拍照示例中 , ...

  7. 谷歌插件之蓝湖代码生成器,iOS,Android,Swift,Flutter

    这是一个谷歌插件,当打开蓝湖网站时,可识别出蓝湖生成的html代码并显示插件面板,可生成iOS,Android,Swift,Flutter代码,非常方便 效果请看下方GIF 如何下载插件 路径1:Gi ...

  8. 【Flutter】友盟智能认证Android Flutter插件集成

    目录 介绍 入手 问题:报错600017, 提示Appkey 密钥不对. 介绍 友盟官方的文档不齐全, 且文档和Demo均未与SDK版本同步. 目前SDK版本已经出到 umeng-common-9.1 ...

  9. Flutter 打包APP (Android IOS)

    打包Android apk 参考 https://flutter.dev/docs/deployment/android https://flutterchina.club/android-relea ...

最新文章

  1. 将横排文本变成竖排文本
  2. 二分图最大匹配的König定理及其证明
  3. [转]资深CTO:关于技术团队打造与管理的10问10答
  4. CSS3的box-sizing:向外撑content-box向内挤border-box 外撑的padding算自己的盒子会变大 内挤的padding会缩小自己
  5. 高效的数据压缩编码方式 Protobuf
  6. asp.net 2.0中允许一次上传多个文件的设计
  7. (转载) AT指令详解
  8. HDU 1596 find the safest road (最短路)
  9. 使用Native API查询Windows硬盘分区系统设备名称
  10. 乾颐堂军哥HCNP真题(科目221)解析,含2017年最新更新后题库,61到75题
  11. MD4、MD5、SHA1、HMAC、HMAC_SHA1区别
  12. 【处理手记】VS2010SP1安装不上Visual Studio 2010 SP1 SDK的解决办法
  13. 数据分析 告诉你《飞驰人生》为什么这么燃?
  14. mysqldump参数之-A -B
  15. 苹果手机怎么信任软件_苹果安装未受信任软件如何设置信任企业APP证书
  16. 如何买到货真价实的OA产品?
  17. linux系统清理命令行,告诉你Ubuntu系统较全面清理的方法及命令
  18. 反转链表(Java)
  19. 迷你csgo饰品租赁系统
  20. elementUI Drawer 抽屉打开时表单自动聚焦问题解决

热门文章

  1. 3000字计算机领域技术发展,计算机应用技术专业毕业论文3000字
  2. 【话剧观后感】情不重,不生娑婆
  3. 华为ENSP 模拟器免费下载及安装指南
  4. 【招聘贴】美资外企Java开发工程师-城市:北上广深+苏州+成都
  5. 使用ieee会议模板字体无法加粗问题
  6. 第六十六篇:单目三维重建点云
  7. 解决G13无法刷机的问题。
  8. “个人知识管理”百科
  9. Atlas 200DK 开发环境配置总结(Ubuntu 18.04)
  10. 世界国家省份城市县区街道村地址邮编常用通用功能最全API - 多级联动 - 淘宝天猫阿里巴巴技术赏析...