当前位置:   article > 正文

62、Flutter插件通信iOS,Android实现过程<二>_flutter ios view demo地址

flutter ios view demo地址

前言

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,在这个基础上我们进行扩展,更加灵活

  1. import 'dart:async';
  2. import 'package:flutter/services.dart';
  3. typedef void TestViewCreatedCallback(TestFlutterPluginDemo controller);
  4. class TestFlutterPluginDemo {
  5. late MethodChannel _channel;
  6. TestFlutterPluginDemo.init(int id){
  7. // 原生与Flutter 交互渠道
  8. _channel = new MethodChannel('test_flutter_plugin_demo');
  9. _channel.setMethodCallHandler(platformCallHandler);///设置原生参数监听
  10. }
  11. ///Flutter 调用原生
  12. ///这里我传了一个 字符串 当然也可以传Map
  13. Future<List<dynamic>?> changeNativeTitle(String str) async{
  14. return _channel.invokeListMethod('changeNativeTitle',str);
  15. }
  16. ///实现监听原生方法回调
  17. Future<dynamic> platformCallHandler(MethodCall call) async {
  18. switch (call.method) {
  19. case "clickAciton":
  20. print('收到原生回调 ---- $call.arguments');
  21. return ;
  22. break;
  23. }
  24. }
  25. }

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

2、Flutter界面开发以及调用

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

view.dart全部代码

  1. import 'package:flutter/cupertino.dart';
  2. import 'package:test_flutter_plugin_demo/test_flutter_plugin_demo.dart';
  3. import 'package:flutter/services.dart';
  4. import 'dart:io';
  5. /// @Author wywinstonwy
  6. /// @Date 2022/4/15 10:58 上午
  7. /// @Description:
  8. ///我是使用的 StatefulWidget 使用StatelessWidget 也是一样
  9. class TestView extends StatefulWidget {
  10. ///根据自己的需求创建初始化参数
  11. final TestViewCreatedCallback ? onCreated; ///是上面创建的回调
  12. final String ? titleStr;
  13. TestView({
  14. required Key key,
  15. this.onCreated,
  16. this.titleStr,
  17. });
  18. @override
  19. _TestViewState createState() => _TestViewState();
  20. }
  21. class _TestViewState extends State<TestView> {
  22. @override
  23. Widget build(BuildContext context) {
  24. return Container(
  25. child: _loadNativeView(),
  26. );
  27. }
  28. ///加载原生视图
  29. Widget _loadNativeView(){
  30. ///根据不同的平台显示相应的视图
  31. if(Platform.isAndroid){ ///加载安卓原生视图
  32. return AndroidView(
  33. viewType: 'testView',///视图标识符 要和原生 保持一致 要不然加载不到视图
  34. onPlatformViewCreated:onPlatformViewCreated,///原生视图创建成功的回调
  35. creationParams: <String, dynamic>{ ///给原生传递初始化参数 就是上面定义的初始化参数
  36. 'titleStr':widget.titleStr,
  37. },
  38. /// 用来编码 creationParams 的形式,可选 [StandardMessageCodec], [JSONMessageCodec], [StringCodec], or [BinaryCodec]
  39. /// 如果存在 creationParams,则该值不能为null
  40. creationParamsCodec: const StandardMessageCodec(),
  41. );
  42. }else if(Platform.isIOS){///加载iOS原生视图
  43. return UiKitView(
  44. viewType: 'testView',///视图标识符 要和原生 保持一致 要不然加载不到视图
  45. onPlatformViewCreated:onPlatformViewCreated,///原生视图创建成功的回调
  46. creationParams: <String, dynamic>{ ///给原生传递初始化参数 就是上面定义的初始化参数
  47. 'titleStr':widget.titleStr,
  48. },
  49. /// 用来编码 creationParams 的形式,可选 [StandardMessageCodec], [JSONMessageCodec], [StringCodec], or [BinaryCodec]
  50. /// 如果存在 creationParams,则该值不能为null
  51. creationParamsCodec: const StandardMessageCodec(),
  52. );
  53. }else{
  54. return Text('这个平台老子不支持');
  55. }
  56. }
  57. ///这个基本上是固定写法
  58. Future<void> onPlatformViewCreated(id) async {
  59. if (widget.onCreated == null) {
  60. return;
  61. }
  62. widget.onCreated!(new TestFlutterPluginDemo.init(id));
  63. }
  64. }

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

  1. import 'package:flutter/material.dart';
  2. import 'dart:async';
  3. import 'package:flutter/services.dart';
  4. import 'package:test_flutter_plugin_demo/test_flutter_plugin_demo.dart';
  5. import 'package:test_flutter_plugin_demo_example/view.dart';
  6. void main() {
  7. runApp(const MyApp());
  8. }
  9. class MyApp extends StatefulWidget {
  10. const MyApp({Key? key}) : super(key: key);
  11. @override
  12. State<MyApp> createState() => _MyAppState();
  13. }
  14. class _MyAppState extends State<MyApp> {
  15. String _platformVersion = 'Unknown';
  16. ///定义一个测试类的属性 用来调用原生方法 和原生交互
  17. var testFlutterPluginDemo;
  18. @override
  19. void initState() {
  20. super.initState();
  21. initPlatformState();
  22. }
  23. // Platform messages are asynchronous, so we initialize in an async method.
  24. Future<void> initPlatformState() async {
  25. String platformVersion ='是是是';
  26. // try {
  27. // platformVersion =
  28. // await TestFlutterPluginDemo.platformVersion ?? 'Unknown platform version';
  29. // } on PlatformException {
  30. // platformVersion = 'Failed to get platform version.';
  31. // }
  32. if (!mounted) return;
  33. setState(() {
  34. _platformVersion = platformVersion;
  35. });
  36. }
  37. @override
  38. Widget build(BuildContext context) {
  39. ///初始化 测试视图的类
  40. TestView testView = TestView(
  41. onCreated: onTestViewCreated, key: ValueKey('testView'),
  42. titleStr: 'flutter给原生的参数',
  43. );
  44. return MaterialApp(
  45. home: Scaffold(
  46. appBar: AppBar(
  47. title: const Text('Plugin example app'),
  48. ),
  49. body: Column(children: [
  50. Container(height: 200,width: 400,child: testView,),
  51. FloatingActionButton(onPressed: onNativeMethon)
  52. ],),
  53. ),
  54. );
  55. }
  56. void onNativeMethon(){
  57. this.testFlutterPluginDemo.changeNativeTitle('Flutter 调用原生成功了');
  58. }
  59. void onTestViewCreated(testFlutterPluginDemo){
  60. this.testFlutterPluginDemo = testFlutterPluginDemo;
  61. }
  62. }

4、iOS、Android介绍

1、iOS部分代码开发

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

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

在此目录下分别创建TestFlutterPluginViewTestFlutterPluginViewFactory

  1. //
  2. // TestFlutterPluginView.h
  3. // Pods
  4. //
  5. // Created by wangyun on 2022/4/15.
  6. //
  7. #import <Foundation/Foundation.h>
  8. #include <Flutter/Flutter.h>
  9. @interface TestFlutterPluginView : NSObject<FlutterPlatformView>
  10. - (id)initWithFrame:(CGRect)frame
  11. viewId:(int64_t)viewId
  12. args:(id)args
  13. messager:(NSObject<FlutterBinaryMessenger>*)messenger;
  14. @end
  1. //
  2. // TestFlutterPluginView.m
  3. // Pods
  4. //
  5. // Created by wangyun on 2022/4/15.
  6. //
  7. #import "TestFlutterPluginView.h"
  8. @interface TestFlutterPluginView ()
  9. /** channel*/
  10. @property (nonatomic, strong) FlutterMethodChannel *channel;
  11. @property (nonatomic, strong) UIButton *button;
  12. @property (nonatomic, strong) UITextField *textField;
  13. @property (nonatomic, strong) UILabel *lblText;
  14. @property (nonatomic, assign) NSInteger count;
  15. @end
  16. @implementation TestFlutterPluginView
  17. {
  18. CGRect _frame;
  19. int64_t _viewId;
  20. id _args;
  21. }
  22. - (id)initWithFrame:(CGRect)frame
  23. viewId:(int64_t)viewId
  24. args:(id)args
  25. messager:(NSObject<FlutterBinaryMessenger>*)messenger
  26. {
  27. if (self = [super init])
  28. {
  29. _frame = frame;
  30. _viewId = viewId;
  31. _args = args;
  32. NSLog(@"%@",args[@"titleStr"]);
  33. ///建立通信通道 用来 监听Flutter 的调用和 调用Fluttter 方法 这里的名称要和Flutter 端保持一致
  34. _channel = [FlutterMethodChannel methodChannelWithName:@"test_flutter_plugin_demo" binaryMessenger:messenger];
  35. __weak __typeof__(self) weakSelf = self;
  36. [_channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
  37. [weakSelf onMethodCall:call result:result];
  38. }];
  39. }
  40. return self;
  41. }
  42. - (UIView *)view{
  43. UIView *nativeView = [[UIView alloc] initWithFrame:_frame];
  44. nativeView.backgroundColor = [UIColor redColor];
  45. _button = [UIButton buttonWithType:UIButtonTypeSystem];
  46. [_button setTitle:@"我是按钮" forState:UIControlStateNormal];
  47. [_button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  48. [_button setBackgroundColor:[UIColor blueColor]];
  49. _button.frame = CGRectMake(10, 20, 100, 44);
  50. [nativeView addSubview:_button];
  51. self.lblText = [[UILabel alloc] initWithFrame:CGRectMake(140, 20, 200, 44)];
  52. self.lblText.text =_args[@"titleStr"];
  53. self.lblText.backgroundColor =[UIColor blueColor];
  54. self.lblText.textColor =[UIColor whiteColor];
  55. [nativeView addSubview:self.lblText];
  56. [_button addTarget:self action:@selector(flutterMethod) forControlEvents:UIControlEventTouchUpInside];
  57. _textField = [[UITextField alloc] initWithFrame:CGRectMake(100, 125, 200, 44)];
  58. [_textField setText: [NSString stringWithFormat:@"这个数据是原生控制 %d",_count] ];
  59. [nativeView addSubview:_textField];
  60. return nativeView;
  61. }
  62. #pragma mark -- Flutter 交互监听
  63. -(void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result{
  64. //监听Fluter
  65. if ([[call method] isEqualToString:@"changeNativeTitle"]) {
  66. [_button setTitle:call.arguments forState:UIControlStateNormal];
  67. }
  68. }
  69. //调用Flutter
  70. - (void)flutterMethod{
  71. self.count = self.count+1;
  72. NSString *str = [NSString stringWithFormat:@"原生给flutter的参数 %ld",(long)self.count];
  73. [self.channel invokeMethod:@"clickAciton" arguments:str];
  74. [_textField setText: [NSString stringWithFormat:@"这个数据是原生控制 %ld",(long)_count] ];
  75. if(_count%2==0){
  76. self.lblText.backgroundColor =[UIColor blueColor];
  77. self.lblText.textColor =[UIColor whiteColor];
  78. }else{
  79. self.lblText.backgroundColor =[UIColor orangeColor];
  80. self.lblText.textColor =[UIColor blackColor];
  81. }
  82. }
  83. @end
  1. //
  2. // TestFlutterPluginViewFactory.h
  3. // Pods
  4. //
  5. // Created by wangyun on 2022/4/15.
  6. //
  7. #import <Foundation/Foundation.h>
  8. #import <Flutter/Flutter.h>
  9. NS_ASSUME_NONNULL_BEGIN
  10. @interface TestFlutterPluginViewFactory : NSObject<FlutterPlatformViewFactory>
  11. /// 重写一个构造方法 来接收 Flutter 相关蚕食
  12. /// @param messenger Flutter类 包含回调方法等信息
  13. - (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
  14. @end
  15. NS_ASSUME_NONNULL_END
  1. //
  2. // TestFlutterPluginViewFactory.m
  3. // Pods
  4. //
  5. // Created by wangyun on 2022/4/15.
  6. //
  7. #import "TestFlutterPluginViewFactory.h"
  8. #import "TestFlutterPluginView.h"
  9. @interface TestFlutterPluginViewFactory ()
  10. @property(nonatomic)NSObject<FlutterBinaryMessenger>* messenger;
  11. @end
  12. @implementation TestFlutterPluginViewFactory
  13. - (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
  14. self = [super init];
  15. if (self) {
  16. self.messenger = messenger;
  17. }
  18. return self;
  19. }
  20. #pragma mark -- 实现FlutterPlatformViewFactory 的代理方法
  21. - (NSObject<FlutterMessageCodec>*)createArgsCodec {
  22. return [FlutterStandardMessageCodec sharedInstance];
  23. }
  24. /// FlutterPlatformViewFactory 代理方法 返回过去一个类来布局 原生视图
  25. /// @param frame frame
  26. /// @param viewId view的id
  27. /// @param args 初始化的参数
  28. - (NSObject<FlutterPlatformView> *)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id)args{
  29. TestFlutterPluginView *testFlutterPluginView = [[TestFlutterPluginView alloc] initWithFrame:frame viewId:viewId args:args messager:self.messenger];
  30. return testFlutterPluginView;
  31. }
  32. @end

2、Android 部分代码开发

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

Android TestFlutterPluginView全部代码
  1. package com.example.test_flutter_plugin_demo;
  2. import android.content.Context;
  3. import android.graphics.Color;
  4. import android.graphics.SurfaceTexture;
  5. import android.provider.CalendarContract;
  6. import android.view.TextureView;
  7. import android.view.View;
  8. import android.view.ViewGroup;
  9. import android.widget.FrameLayout;
  10. import android.widget.TextView;
  11. import android.widget.Toast;
  12. import androidx.annotation.NonNull;
  13. import io.flutter.plugin.common.BinaryMessenger;
  14. import io.flutter.plugin.common.MethodCall;
  15. import io.flutter.plugin.common.MethodChannel;
  16. import io.flutter.plugin.platform.PlatformView;
  17. /**
  18. * Created by sunyd on 1/25/22
  19. */
  20. public class TestFlutterPluginView extends TextView implements PlatformView, MethodChannel.MethodCallHandler, TextureView.SurfaceTextureListener{
  21. @Override
  22. public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
  23. }
  24. @Override
  25. public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
  26. }
  27. @Override
  28. public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
  29. return false;
  30. }
  31. @Override
  32. public void onSurfaceTextureUpdated(SurfaceTexture surface) {
  33. }
  34. public Context context;
  35. /**
  36. * 通道
  37. */
  38. private MethodChannel methodChannel = null;
  39. public TestFlutterPluginView(Context context, int viewId, Object args, BinaryMessenger messenger) {
  40. super(context);
  41. this.context = context;
  42. Toast.makeText(context, "创建关联成功", Toast.LENGTH_SHORT).show();
  43. setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
  44. setBackgroundColor(Color.argb(255,79,79,79)); //0完全透明 255不透明
  45. //注册
  46. methodChannel = new MethodChannel(messenger, "test_flutter_plugin_demo");
  47. methodChannel.setMethodCallHandler(this);
  48. }
  49. @Override
  50. public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
  51. handleCall(call, result);
  52. }
  53. private void handleCall(MethodCall methodCall, MethodChannel.Result result) {
  54. switch (methodCall.method) {
  55. //开始预览
  56. case "changeNativeTitle":
  57. Toast.makeText(context, (String)methodCall.arguments, Toast.LENGTH_SHORT).show();
  58. break;
  59. default:
  60. }
  61. }
  62. @Override
  63. public View getView() {
  64. return this;
  65. }
  66. @Override
  67. public void dispose() {
  68. }
  69. }
Android TestFlutterPluginViewFactory全部代码
  1. package com.example.test_flutter_plugin_demo;
  2. import android.content.Context;
  3. import io.flutter.plugin.common.BinaryMessenger;
  4. import io.flutter.plugin.common.MessageCodec;
  5. import io.flutter.plugin.common.StandardMessageCodec;
  6. import io.flutter.plugin.platform.PlatformView;
  7. import io.flutter.plugin.platform.PlatformViewFactory;
  8. public class TestFlutterPluginViewFactory extends PlatformViewFactory {
  9. private BinaryMessenger messenger = null;
  10. public TestFlutterPluginViewFactory(BinaryMessenger messenger) {
  11. super(StandardMessageCodec.INSTANCE);
  12. this.messenger = messenger;
  13. }
  14. /**
  15. * @param createArgsCodec the codec used to decode the args parameter of {@link #create}.
  16. */
  17. public TestFlutterPluginViewFactory(MessageCodec<Object> createArgsCodec) {
  18. super(createArgsCodec);
  19. }
  20. @Override
  21. public PlatformView create(Context context, int viewId, Object args) {
  22. return new TestFlutterPluginView(context, viewId, args, this.messenger);
  23. }
  24. }

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

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

其实本地使用非常简单。

1、打开我们的项目

 2、打开pubspec.yaml

  1. dependencies:
  2. flutter:
  3. sdk: flutter
  4. test_flutter_plugin_demo:
  5. 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端通信。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/383282
推荐阅读
相关标签
  

闽ICP备14008679号