flutter 和ios平台混合开发

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

Flutter平台特定的API支持不依赖于代码生成,而是依赖于灵活的消息传递的方式:

  • 应用的Flutter部分通过平台通道(platform channel)将消息发送到其应用程序的所在的宿主(iOS或Android)。
  • 宿主监听平台通道,并接收该消息。然后它会调用特定于该平台的API(使用原生编程语言) - 并将响应发送回客户端,即应用程序的Flutter部分。

框架概述: 平台通道

使用平台通道在客户端(Flutter UI)和宿主(平台)之间传递消息,如下图所示:

平台通道

注意消息和响应是异步传递的,以确保用户界面保持响应(不会挂起)。

在客户端,MethodChannel (API)可以发送与方法调用相对应的消息。 在宿主平台上,MethodChannel 在Android((API) 和 FlutterMethodChannel iOS (API) 可以接收方法调用并返回结果。这些类允许您用很少的“脚手架”代码开发平台插件。

  • 注意: 如果需要,方法调用也可以反向发送,宿主作为客户端调用Dart中实现的API。 这个quick_actions插件就是一个具体的例子

平台通道数据类型支持和解码器

标准平台通道使用标准消息编解码器,以支持简单的类似JSON值的高效二进制序列化,例如 booleans,numbers, Strings, byte buffers, List, Maps(请参阅StandardMessageCodec了解详细信息)。

    • 当您发送和接收值时,这些值在消息中的序列化和反序列化会自动进行。*

下表显示了如何在宿主上接收Dart值,反之亦然:

Dart Android iOS
null null nil (NSNull when nested)
bool java.lang.Boolean NSNumber numberWithBool:
int java.lang.Integer NSNumber numberWithInt:
int, if 32 bits not enough java.lang.Long NSNumber numberWithLong:
int, if 64 bits not enough java.math.BigInteger FlutterStandardBigInteger
double java.lang.Double NSNumber numberWithDouble:
String java.lang.String NSString
Uint8List byte[] FlutterStandardTypedData typedDataWithBytes:
Int32List int[] FlutterStandardTypedData typedDataWithInt32:
Int64List long[] FlutterStandardTypedData typedDataWithInt64:
Float64List double[] FlutterStandardTypedData typedDataWithFloat64:
List java.util.ArrayList NSArray
Map java.util.HashMap NSDictionary

举例

1打开终端随便cd一个目录下,生成flutterIosMix 目录

 mkdir flutterIosMix |ls

2 进入该目录并且创建一个新的应用程序

cd flutterIosMix 
flutter create flutteriosmix

这个时候的目录结构如下


目录结构

3.用vscode 打开该工程并运行该工程

结果如下:


image.png

这个时候有默认工程的代码

4.修改main.dart 代码

修改main.dart 代码如下

import 'package:flutter/material.dart';
import 'dart:async';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: PlatformChannel(),
    );
  }
}

class PlatformChannel extends StatefulWidget {
  @override
  _PlatformChannelState createState() => _PlatformChannelState();
}



class _PlatformChannelState extends State<PlatformChannel> {

  int _hitNum = 0;
  int _time = 0;

  Future<void> _hitEvent() async{

  }

 @override
  Widget build(BuildContext context) {
    return Material(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text("当前点击次数:$_hitNum", key: const Key('hitEvent')),
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: RaisedButton(
                  child: const Text('hit'),
                  onPressed: _hitEvent,
                ),
              ),
            ],
          ),
          Text("计时器时间${_time}s"),
        ],
      ),
    );
  }
}

运行上述代码结果如下


这是准备好的工程基本工程.接下来我们就准备flutter 和ios平台的混合开发代码。我们准备开发的内容如下

  • 1 点击hit按钮,我们从ios平台获取已经点击的次数
  • 2.我们从ios平台的计时器中获取回调给flutter的计时时间。

我们调用ios平台的方法是通过MethodChannel 类来实现的
我们监听来自ios的调用是通过EventChannel 类来实现的

5. 实现点击hit 按钮获取ios平台回传回来的点击次数

<1> 添加引用文件
import 'package:flutter/services.dart';

在main.dart 文件中头部添加上述代码。

<2>类_PlatformChannelState增加一个成员变量
class _PlatformChannelState extends State<PlatformChannel> {
  static const MethodChannel methodChannel =
      MethodChannel('hit.flutter.io/count');
...
}

这里我们生成一个MethodChannel类型的变量methodChannel 并且实例化

"hit.flutter.io/count" 这里需要注意,这是与ios平台桥接的key,可以随便命名,但是必须和ios平台接受时候的key 一致。

<3> 在_hitEvent 函数中添加如下函数
  Future<void> _hitEvent() async{
  int hitNum;
  try {
      final int result = await methodChannel.invokeMethod('getBatteryLevel');
      hitNum =result;
    } on PlatformException {
    }
    if (hitNum !=null) {
    setState(() {
      _hitNum = hitNum;
    });  
    } 
  }

这个时候保存main.dart 代码。点击hit按钮是崩溃的

<4> 打开ios工程代码

打开ios工程ios->右键reveal in finder -> xcode 打开该工程

image.png
<5>编辑ios工程代码

打开appdelegate.m 文件,修改文件如下

#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
#import <Flutter/Flutter.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
    FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
    ///hit.flutter.io/count 必须与flutter 请求的key一样才会调用到函数中
    FlutterMethodChannel* batteryChannel = [FlutterMethodChannel methodChannelWithName:@"hit.flutter.io/count" binaryMessenger:controller];
    [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
        ///这个是flutter 请求的事件
        if ([@"hitCount" isEqualToString:call.method]) {
            static int count =0;
            return result(@(++count));
        }
        
        
    }];
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

@end

这个时候,我们就实现了flutter 平台调用ios平台的函数了

停止应用,重新启动app。保证app对ios平台的代码进行了重新编译。

运行结果如下


6.实现ios平台调用flutter平台的方法

ios 平台调用flutter 是通过flutter监听事件来完成的

<1> 引入头文件
import 'package:flutter/services.dart';

<2>添加成员变量
class _PlatformChannelState extends State<PlatformChannel> {
  static const EventChannel eventChannel =
      EventChannel('time.flutter.io/count');
...
}
<3>添加监听事件
 @override
  void initState() {
    super.initState();
    eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
  }

  void _onEvent(Object event) {
    setState(() {
      print("{$event}");
      _chargingStatus =
          "Battery status: ${event}";
    });
  }

  void _onError(Object error) {
    setState(() {
      _chargingStatus = 'Battery status: unknown.';
    });
  }

<4>打开ios工程代码 并添加代码如下
- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];

···
    FlutterEventChannel* chargingChannel = [FlutterEventChannel eventChannelWithName:@"time.flutter.io/count" binaryMessenger:controller];
    [chargingChannel setStreamHandler:self];
    
 ···
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

给appdelegate类添加成员变量

@interface AppDelegate()
{
    FlutterEventSink _eventSink;

}
@end

增加代理函数

- (FlutterError*)onListenWithArguments:(id)arguments
                             eventSink:(FlutterEventSink)eventSink {
    _eventSink = eventSink;
    static int mm = 0;
    [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        if (!_eventSink) return;
        _eventSink(@(++mm));
    }];
    return nil;
}


- (FlutterError*)onCancelWithArguments:(id)arguments {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    _eventSink = nil;
    return nil;
}

这样就实现了ios 调用flutter函数


flutter 中文网相关文章

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容