如何在 Flutter 中绕过 Platform Channels 直接使用 Objective-C/Swift Interop

807 阅读1分钟

在Dart 2.18中,Dart团队引入了Objective-C/Swift互操作。允许使用dart ffi 和 C 作为互操作性层,直接从 Dart 代码库调用 iOS 上的本机代码。这意味着可以绕开 platform method channel 直接调用 iOS 上的原生功能。

一、背景需求

  • 获取操作系统以及设备信息,如电池、蓝牙、NFC、权限等

  • 可使用 ffi 替换 method channel 封装的一些原生库,提升效率

二、什么是 Objective-C/Swift Interop?

允许直接从 Dart 代码调用 Swift/Object-C 代码,Objective-C/Swift Interop 将从 Swift/Objective-C代码创建 C 代码绑定,然后可以直接从Dart- code使用 Dart FFI(外部函数接口)调用。

三、实践

1、创建demo 工程 $ flutter create -i swift -a kotlin native_info_demo

2、切换到工程目录添加 ffigen 以及 ffi 插件

$ dart pub add ffi
$ dart pub add --dev ffigen

3、在 pubspec.yaml 中添加 ffigen config  信息

ffigen:  name: UIDevice  description: Bindings for UIDevice.  language: objc  output: './lib/src/uidevice_bindings.dart' ## 指定生成绑定代码所在文件目录  exclude-all-by-default: true  objc-interfaces:    include:      - 'UIDevice'  headers:    entry-points:      - '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/iOSSupport/System/Library/Frameworks/UIKit.framework/Headers/UIDevice.h'

添加完成如下图:

如果使用 swift 语言需要生成一个Objective-C包装头文件。可以使用Xcode,或者Swift命令行编译器swiftc。如使用命令行:

swiftc -c swift_api.swift             \
    -module-name swift_module           \
    -emit-objc-header-path swift_api.h  \
    -emit-library -o libswiftapi.dylib

该命令编译Swift文件swift_api.swift,并生成一个头文件swift_api.h、以及后面需要加载的动态库 libswiftapi.dylib

使用swift_api.swift 的 ffigen 配置文件需修改如下

ffigen:
  name: SwiftLibrary
  description: Bindings for swift_api.
  language: objc
  output: 'swift_api_bindings.dart'
  exclude-all-by-default: true
  objc-interfaces:
    include:
      - 'SwiftClass'
    module:
      'SwiftClass': 'swift_module'
  headers:
    entry-points:
      - 'swift_api.h'
  preamble: |
    // ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field, return_of_invalid_type, void_checks, annotate_overrides, no_leading_underscores_for_local_identifiers, library_private_types_in_public_api

4、生成绑定代码

$ dart run ffigen

生成过程中如有命名冲突,可能会用类名1原来的类名,如UIDevice1替换UIDevice绑定代码生成完结构如图:

5、在Flutter项目中使用绑定代码

import 'src/uidevice_bindings.dart';import 'dart:ffi';...

  @override  void initState() {    super.initState();    getNativeDeviceInfo();  }  void getNativeDeviceInfo() {    final lib = UIDevice1(DynamicLibrary.process());    final device = UIDevice.new1(lib);    _systemName = '${device.systemName}${device.systemVersion}';    if (device.batteryMonitoringEnabled) {      final batteryLevel = device.batteryLevel;      _batteryLevel = batteryLevel;      print('Battery level: $batteryLevel');    }  }...

显示效果:

到这里基本已完成整个 ffi 调用 iOS 的过程了,iOS的小伙伴可愉快的使用起来了~

参考链接:

api.dart.dev/stable/3.2.…

dart.dev/interop/obj…

github.com/dart-lang/f…