美文网首页
flutter调用原生

flutter调用原生

作者: 沉江小鱼 | 来源:发表于2019-09-26 10:05 被阅读0次

    “平台特定”或“特定平台”中的平台指的就是Flutter应用程序运行的平台,如Android或iOS。我们知道一个完整的Flutter应用程序实际上包括原生代码和Flutter代码两部分。由于Flutter本身只是一个UI系统,它本身是无法提供一些系统能力,比如使用蓝牙、相机、GPS等,因此要在Flutter APP中调用这些能力就必须和原生平台进行通信。
    为此,Flutter中提供了一个平台通道(platform channel),用于Flutter和原生平台的通信。平台通道正是Flutter和原生之间通信的桥梁,它也是Flutter插件的底层基础设施。

    Flutter 使用了一个灵活的系统,允许调用特定平台的API,无论在Android上的Java或Kotlin代码中,还是iOS上的ObjectiveC或Swift代码中均可用。

    Flutter与原生之间的通信依赖灵活的消息传递方式:

    • 应用的Flutter部分通过平台通道(platform channel)将消息发送到其应用程序的所在的宿主(iOS或Android)应用(原生应用)。
    • 宿主监听平台通道,并接受该消息。然后它会调用该平台的API,并将相应发送回应用程序的Flutter部分。

    平台通道

    使用平台通道在Flutter和原生之间传递消息,如下:


    屏幕快照 2019-09-17 上午10.31.18.png

    在Flutter中调用原生方法时,调用信息通过平台通道传递到原生,原生收到调用信息后可以执行指定的操作,如果需要返回数据,则原生会将数据再通过平台通道传递给Flutter。这里的消息传递是异步的,这确保了用户在消息传递时不会被挂起。

    在Flutter,MethodChannel API 可以发送与方法调用相对应的消息。在宿主平台上,MethodChannelAndroid APIFlutterMethodChannel iOS API可以接收方法调用并返回结果。这些类可以帮助我们用很少的代码就能开发平台插件。

    注意: 如果需要,方法调用(消息传递)可以是反向的,即宿主作为客户端调用Dart中实现的API。 quick_actions插件就是一个具体的例子。

    平台通道数据类型支持

    平台通道使用标准消息编/解码器对消息进行编解码,它可以高效的对消息进行二进制序列化与反序列化。由于Dart与原生平台之间数据类型有所差异,下面我们列出数据类型之间的映射关系。


    屏幕快照 2019-09-17 上午10.35.43.png

    自定义编解码器

    除了上面提到的MethodChannel,还可以使用BasicMessageChannel,它支持使用自定义消息编解码器进行基本的异步消息传递。 此外,可以使用专门的BinaryCodecStringCodecJSONMessageCodec类,或创建自己的编解码器。

    如何获取平台信息

    Flutter中提供了一个全局变量 defultTargetPlatform 来获取当前应用的平台信息,defaultTargetPlatform定义在 “platform.dart”中,它的类型是TargetPlatform,这是一个枚举类,定义如下:

    enum TargetPlatform {
      android,
      fuchsia,
      iOS,
    }
    

    可以看到目前Flutter只支持这三个平台。我们可以通过如下代码判断平台:

    if(defaultTargetPlatform==TargetPlatform.android){
      // 是安卓系统,do something
      ...
    }
    ...
    

    由于不同平台有它们各自的交互规范,Flutter Material库中的一些组件都针对相应的平台做了一些适配,比如路由组件MaterialPageRoute,它在android和ios中会应用各自平台规范的切换动画。那如果我们想让我们的APP在所有平台都表现一致,比如希望在所有平台路由切换动画都按照ios平台一致的左右滑动切换风格该怎么做?Flutter中提供了一种覆盖默认平台的机制,我们可以通过显式指定debugDefaultTargetPlatformOverride全局变量的值来指定应用平台。比如:

    debugDefaultTargetPlatformOverride=TargetPlatform.iOS;
    print(defaultTargetPlatform); // 会输出TargetPlatform.iOS
    

    上面代码即在Android中运行后,Flutter APP就会认为是当前系统是iOS,Material组件库中所有组件交互方式都会和iOS平台对齐,defaultTargetPlatform的值也会变为TargetPlatform.iOS。

    下面以一个获取电池电量的插件来介绍一下,通过在Dart中通过 getBatteryLevel 调用 iOS device.batteryLevel API。

    Flutter部分:

    • 导入import 'package:flutter/services.dart';
    • 创建通道名称,单个应用使用的所有通道名称必须是唯一的:
      static const platform = const MethodChannel('samples.flutter.io/battery');
    • 调用方法,这里是异步的 final int result = await platform.invokeMethod('getBatteryLevel');

    iOS部分:
    在application didFinishLaunchingWithOptions:方法内部创建一个FlutterMethodChannel,并添加一个处理方法。 确保与在Flutter客户端使用的通道名称相同。

    - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
      FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
    
      FlutterMethodChannel* batteryChannel = [FlutterMethodChannel
                                              methodChannelWithName:@"samples.flutter.io/battery"
                                              binaryMessenger:controller];
    
      [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
        // TODO
      }];
    
      return [super application:application didFinishLaunchingWithOptions:launchOptions];
    }
    

    在AppDelegate类中添加以下新的方法:

    - (int)getBatteryLevel {
      UIDevice* device = UIDevice.currentDevice;
      device.batteryMonitoringEnabled = YES;
      if (device.batteryState == UIDeviceBatteryStateUnknown) {
        return -1;
      } else {
        return (int)(device.batteryLevel * 100);
      }
    }
    

    最后,我们完成之前添加的setMethodCallHandler方法。我们需要处理的平台方法名为getBatteryLevel,所以我们在call参数中需要先判断是否为getBatteryLevel。 这个平台方法的实现只需调用我们在前一步中编写的iOS代码,并使用result参数返回成功或错误的响应。如果调用了未定义的API,我们也会通知返回:

    [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
      if ([@"getBatteryLevel" isEqualToString:call.method]) {
        int batteryLevel = [self getBatteryLevel];
    
        if (batteryLevel == -1) {
          result([FlutterError errorWithCode:@"UNAVAILABLE"
                                     message:@"电池信息不可用"
                                     details:nil]);
        } else {
          result(@(batteryLevel));
        }
      } else {
        result(FlutterMethodNotImplemented);
      }
    }];
    

    至此,就可以了。

    相关文章

      网友评论

          本文标题:flutter调用原生

          本文链接:https://www.haomeiwen.com/subject/dhmquctx.html