Flutter development practice-MethodChannel realizes two-way communication between flutter and iOS

Flutter development practice-MethodChannel realizes two-way communication between flutter and iOS

In the recent development, iOS and flutter need to communicate. The MethodChannel used here

If you need two-way communication between flutter and Android, please see
https://blog.csdn.net/gloryFlow/article/details/132218837

This part is consistent with https://blog.csdn.net/gloryFlow/article/details/132218837 . Here we implement the MethodChannel settings on the iOS side.

1. MethodChannel

MethodChannel: used to pass method calls (method invocation).
The client and host ends of a channel are connected via the channel name passed to the channel constructor

All channel names used in an application must be unique
Prefix channel names with a unique domain prefix, for example: samples.flutter.dev/battery

Official website https://flutter.cn/docs/development/platform-integration/platform-channels

2. Implement MethodChannel on the flutter side

We need to create a channel named "samples.flutter.dev/test".
Realized by invokeNativeMethod and setMethodCallHandler

invokeNativeMethod: Call the code on the Android side
setMethodCallHandler: Set the method callback to receive the parameters on the Android side

code show as below

import 'package:flutter/services.dart';

//MethodChannel
const methodChannel = const MethodChannel('samples.flutter.dev/test');

class FlutterMethodChannel {
    
    
  /*
 * MethodChannel
 * 在方法通道上调用方法invokeMethod
 * methodName 方法名称
 * params 发送给原生的参数
 * return数据 原生发给Flutter的参数
 */
  static Future<Map> invokeNativeMethod(String methodName,
      [Map? params]) async {
    
    
    var res;
    try {
    
    
      if (params == null) {
    
    
        res = await methodChannel.invokeMethod('$methodName');
      } else {
    
    
        res = await methodChannel.invokeMethod('$methodName', params);
      }
    } catch (e) {
    
    
      res = {
    
    'Failed': e.toString()};
    }
    return res;
  }

  /*
 * MethodChannel
 * 接收methodHandler
 * methodName 方法名称
 * params 发送给原生的参数
 * return数据 原生发给Flutter的参数
 */
  static void methodHandlerListener(Future<dynamic> Function(MethodCall call)? handler) {
    
    
    methodChannel.setMethodCallHandler(handler);
  }
}

To use the MethodChannel, we need to use the MethodChannel
code as follows

  
  void initState() {
    
    
    // TODO: implement initState
    super.initState();

    setMethodHandle();
  }

  void setMethodHandle() {
    
    
    FlutterMethodChannel.methodHandlerListener((call) {
    
    
      print("methodHandlerListener call:${
      
      call.toString()}");
      if ("methodToFlutter" == call.method) {
    
    
        print("methodToFlutter arg:${
      
      call.arguments}");
      }
      return Future.value("message from flutter");
    });
  }

  Future<void> invokeNativeMethod() async {
    
    
    var result = await FlutterMethodChannel.invokeNativeMethod("methodTest", {
    
    "param":"params from flutter"});
    print("invokeNativeMethod result:${
      
      result.toString()}");
  }

  void testButtonTouched() {
    
    
    invokeNativeMethod();
  }

  
  void dispose() {
    
    
    // TODO: implement dispose
    super.dispose();
  }

Here we have processed the method methodToFlutter to receive the parameter passing call from the iOS side, and after processing, we will return the result "message from flutter" to the iOS side.
We call the method methodTest on the iOS side, and pass parameters to get the result returned by the iOS side.

3. Implement MethodChannel on the iOS side

In iOS, we also implemented MethodChannel.
To implement MethodChannel on iOS, you need to implement FlutterPlugin and implement registerWithRegistrar.
Here I name a SDFlutterMethodChannelPlugin that inherits NSObject and implements the registerWithRegistrar method.

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
    
    
    FlutterMethodChannel *methodChannel = [FlutterMethodChannel methodChannelWithName:kFlutterMethodChannelName binaryMessenger:[registrar messenger] codec:[FlutterStandardMethodCodec sharedInstance]];
        
    SDFlutterMethodChannelPlugin *instance = [[SDFlutterMethodChannelPlugin alloc] initWithMethodChannel:methodChannel];
    
    // 将插件注册为来自Dart端的传入方法调用的接收者 在指定的“ FlutterMethodChannel”上。
    [registrar addMethodCallDelegate:instance channel:methodChannel];
}

Also set setMethodCallHandler and call Flutter method in the plug-in SDFlutterMethodChannelPlugin

For example

__weak typeof(self) weakSelf = self;
        [self.methodChannel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
    
    
            [weakSelf handleMethodCall:call result:result];
        }];

The method methodTest can be processed through handleMethodCall to process and receive parameters from flutter, and return the result to flutter after processing.

The overall code is as follows

SDFlutterMethodChannelPlugin.h

#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>

@class SDFlutterMethodChannelPlugin;

typedef void (^SDFlutterMethodChannelPluginCompletionBlock)(SDFlutterMethodChannelPlugin *plugin);

@interface SDFlutterMethodChannelPlugin : NSObject<FlutterPlugin>

- (instancetype)initWithMethodChannel:(FlutterMethodChannel *)methodChannel;

@end

SDFlutterMethodChannelPlugin.m

#define kFlutterMethodChannelName @"samples.flutter.dev/test"


@interface SDFlutterMethodChannelPlugin ()<FlutterStreamHandler>

@property (nonatomic, strong) FlutterMethodChannel *methodChannel;

@property (nonatomic, strong) NSTimer *sendMessageTimer;


@end

@implementation SDFlutterMethodChannelPlugin

- (instancetype)initWithMethodChannel:(FlutterMethodChannel *)methodChannel {
    
    
    self = [super init];
    if (self) {
    
    
        self.flutterBridgeConfig = [[DFFlutterBridgeConfig alloc] init];
                
        self.methodChannel = methodChannel;
        __weak typeof(self) weakSelf = self;
        [self.methodChannel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
    
    
            [weakSelf handleMethodCall:call result:result];
        }];
        [self startSendMessageTimer];
    }
    return self;
}

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
    
    
    FlutterMethodChannel *methodChannel = [FlutterMethodChannel methodChannelWithName:kFlutterMethodChannelName binaryMessenger:[registrar messenger] codec:[FlutterStandardMethodCodec sharedInstance]];
        
    SDFlutterMethodChannelPlugin *instance = [[SDFlutterMethodChannelPlugin alloc] initWithMethodChannel:methodChannel];
    
    // 将插件注册为来自Dart端的传入方法调用的接收者 在指定的“ FlutterMethodChannel”上。
    [registrar addMethodCallDelegate:instance channel:methodChannel];
}

#pragma mark - FlutterPlugin协议方法
- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
    
    
    NSLog(@"config handleMethodChannel callmethod:%@,params:%@,result:%@", call.method, call.arguments, result);
    
    // 没有处理,需要单独处理
    NSString *method=call.method;
    if ([method isEqualToString:@"methodTest"]) {
    
    
        
        NSLog(@"flutter 调用到了 ios test");
        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        [dic setObject:@"result.success 返回给flutter的数据" forKey:@"message"];
        [dic setObject: [NSNumber numberWithInt:200] forKey:@"code"];

        result(dic);
        
    } else if ([method isEqualToString:@"test2"]) {
    
    
        NSLog(@"flutter 调用到了 ios test2");
        result(@YES);
    } else {
    
    
        result(FlutterMethodNotImplemented);
    }
}

#pragma mark - 开启定时器
- (void)sendMessageTimerAction {
    
    
    // 开启
    [self.methodChannel invokeMethod:@"methodToFlutter" arguments:@"Params from Android"];
}

/**
 开启定时器
*/
- (void)startSendMessageTimer {
    
    
    if (_sendMessageTimer) {
    
    
        return;
    }
    //开始其实就是开始定时器
    _sendMessageTimer = [NSTimer timerWithTimeInterval:6 target:self selector:@selector(sendMessageTimerAction) userInfo:nil repeats:YES];
    //加到runloop
    [[NSRunLoop currentRunLoop] addTimer:_sendMessageTimer forMode:NSRunLoopCommonModes];
}

/**
 结束定时器
 */
- (void)stopSendMessageTimer {
    
    
    //暂停其实就是销毁计时器
    [_sendMessageTimer invalidate];
    _sendMessageTimer = nil;
}

@end

In iOS, it needs to be set in AppDelegate, implemented in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    
	
[SDFlutterMethodChannelPlugin registerWithRegistrar:[(id)[SDWeakProxy proxyWithTarget:self] registrarForPlugin:@"SDFlutterMethodChannelPlugin"]];

return YES;
}
    

We implement MethodChanel in the iOS code, and regularly call the method methodToFlutter through the timer NSTimer to pass the parameters to the Flutter side. SetMethodCallHandler on the iOS side processes and receives parameters from flutter according to the method methodTest, and returns the result to flutter after processing.

Four. Summary

Flutter development practice-MethodChannel realizes two-way communication between flutter and iOS. Implement MethodChannel to realize mutual communication between flutter and iOS.

https://blog.csdn.net/gloryFlow/article/details/132240415

Learning records, keep improving every day.

Guess you like

Origin blog.csdn.net/gloryFlow/article/details/132240415