[Flutter翻译]将Flutter与NativeScript相结合

175 阅读4分钟

本文由 简悦SimpRead 转码,原文地址 blog.nativescript.org

Flutter为使用NativeScript进行创意视图开发提供了另一种选择。让我们来看看......

Flutter为使用NativeScript进行创造性的视图开发提供了另一种选择。让我们来看看如何使用@nativescript-community/ble来丰富Flutter的蓝牙功能。

👉 Demo Repo

这篇文章的灵感来自Sovik Biswas的探索这里

创建一个Flutter模块,与NativeScript一起使用

前提条件:

无论您有一个现有的Flutter应用程序,还是只是想在您的NativeScript应用程序中混入不同的Flutter视图,我们都可以将它们作为Flutter模块使用。

1. 将Flutter添加到一个NativeScript应用程序中

您可以在任何现有的NativeScript应用程序中使用Flutter,或者通过ns create创建一个新的应用程序。

然后我们可以在项目的根目录下创建一个Flutter模块:

flutter create --template module flutter_views

注意: 您可以从这个flutter run --debugflutter build ios文件夹内,像任何正常的Flutter项目一样运行flutter_views来开发它。

这里的Flutter文档了解更多。

2. 配置您的Dart代码,使其具有命名的入口点

命名的入口点允许我们在我们的NativeScript应用程序中使用不同的Flutter视图,通过匹配入口点和视图ID,例如:<Flutter />

  • main.dart
@pragma('vm:entry-point')
void myFlutterView() => runApp(const MyFlutterView());

3. 配置使用的平台

为了简洁起见,我们将在这篇文章中演示iOS,然而你可以看到完整的例子 repo,其中也包括Android。

App_Resources/iOS/Podfile应该包含以下内容来引用我们的Flutter模块。

platform :ios, '14.0'

flutter_application_path = '../../flutter_views'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
install_all_flutter_pods(flutter_application_path)

post_install do |installer|
    flutter_post_install(installer) if defined?(flutter_post_install)
end

App_Resources/iOS/Info.plist中添加Flutter调试权限:

<key>NSLocalNetworkUsageDescription</key>
<string>Allow Flutter tools to debug your views.</string>
<key>NSBonjourServices</key>
<array>
  <string>_dartobservatory._tcp</string>
</array>

4. 安装 @nativescript/flutter

npm install @nativescript/flutter

5. 在需要的地方使用 "Flutter"。

确保在启动你的应用程序之前初始化Flutter引擎,通常在app.tsmain.ts中:

import { init } from '@nativescript/flutter';
init();

// bootstrap app...

在任何地方使用Flutter

<Page xmlns="http://schemas.nativescript.org/tns.xsd"
  xmlns:ui="@nativescript/flutter">
    <ui:Flutter id="myFlutterView"></ui:Flutter>
</Page>

当使用flavors时,你可以直接注册该元素在你的标记中使用:

import { Flutter } from '@nativescript/flutter'

// Angular
import { registerElement } from '@nativescript/angular'
registerElement('Flutter', () => Flutter)

// Solid
import { registerElement } from 'dominative';
registerElement('flutter', Flutter);

// Svelte
import { registerNativeViewElement } from 'svelte-native/dom'
registerNativeViewElement('flutter', () => Flutter);

// React
import { registerElement } from 'react-nativescript';
registerElement('flutter', () => Flutter);

// Vue
import Vue from 'nativescript-vue'
Vue.registerElement('Flutter', () => Flutter)

准备好Flutter的双向NativeScript通信

我们将使用平台通道来设置Flutter和NativeScript之间的双向通信。

在我们的Dart代码中,我们只需要一个单一的nativescript通道来处理我们可能需要的***平台行为。对于json有效载荷的消息传递,我们将用StringCodec设置一个BasicMessageChannel。我们也可以在我们的状态构造函数中设置一个消息处理器。

  • main.dart
import 'package:flutter/services.dart';
import 'dart:convert';

class _MyPageState extends State<MyPage> {
  static const platform = BasicMessageChannel('nativescript', StringCodec());

  _MyPageState() {
    // Receive platform messages from NativeScript
    platform.setMessageHandler((String? message) async {
      Map<String, dynamic> platformMessage = jsonDecode(message!);
      switch (platformMessage['type']) {
        case 'salutation':
          // use any data from the platform
          String hello = platformMessage['data'];
          print(hello);
          break;
      }
      return 'success';
    });
  }
}
  • ns-view.html
<Flutter id="myFlutterView" loaded="loadedFlutter"></Flutter>
  • ns-view.ts
let flutter: Flutter;

export function loadedFlutter(args) {
  flutter = args.object;

  // Send Flutter messages from NativeScript
  flutter.sendMessage('salutation', 'hello');
}

通过NativeScript启用蓝牙

npm install @nativescript-community/ble

App_Resources/iOS/Info.plist中添加蓝牙权限:

<key>UIRequiredDeviceCapabilities</key>
<array>
  <string>bluetooth-le</string>
  <string>location-services</string>
</array>
<key>UIBackgroundModes</key>
<array>
  <string>bluetooth-central</string>
  <string>bluetooth-peripheral</string>
  <string>location</string>
</array>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Use Bluetooth to connect to your devices</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Use Bluetooth to connect to your devices</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Use location with Bluetooth devices</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Use location with Bluetooth devices</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Use location with Bluetooth devices</string>

设置蓝牙插件以开始/停止扫描,同时将发现的设备发送到Flutter。

import { Utils } from "@nativescript/core";
import { Bluetooth, Peripheral } from "@nativescript-community/ble";
import { Flutter, FlutterChannelType } from "@nativescript/flutter";

let flutter: Flutter;
// Flutter can call NativeScript through these channel types
const channel: FlutterChannelType = {
  startScanning: _startScanning,
  stopScanning: _stopScanning,
};

const bluetooth: Bluetooth = new Bluetooth();
const discoveredPeripherals: Array<{ name: string; address: string }> = [];
// reduce extraneous bluetooth scan results when emitting to Flutter
const throttleScanResults = Utils.throttle(_throttleScanResults, 600);

function _throttleScanResults() {
    flutter.sendMessage('scanResults', discoveredPeripherals);
}

function _startScanning() {
  bluetooth.on(Bluetooth.device_discovered_event, result => {
    const peripheral = <Peripheral>result.data;
    if (peripheral?.name) {
      if (!discoveredPeripherals.find((p) => p.address === peripheral.UUID)) {
        discoveredPeripherals.push({
          name: peripheral.name.trim(),
          address: peripheral.UUID?.trim(),
        });
      }
      throttleScanResults();
    }
  });
  bluetooth.startScanning({});
}

function _stopScanning() {
    bluetooth.stopScanning();
    bluetooth.off(Bluetooth.device_discovered_event);
}

我们可以将channel绑定到我们的Flutter组件。这在NativeScript和Flutter之间建立了一个消息类型的契约来进行通信。

<Flutter id="myFlutterView" channel="{{channel}}" />

从NativeScript接收Flutter中的蓝牙数据

在我们的main.dart文件中,我们可以设置消息类型的合同来接收数据。

_MyPageState() {
  platform.setMessageHandler((String? message) async {
    Map<String, dynamic> platformMessage = jsonDecode(message!);
    switch (platformMessage['type']) {
      case 'scanResults':
        // prepare results for presentation in a ListView
        List<BluetoothDevice> devices = platformMessage['data']
            .map<BluetoothDevice>((i) => BluetoothDevice.fromJson(i))
            .toList();
        setState(() {
          _devicesList = devices;
        });
        break;
    }
    return 'success';
  });
}

// Bindable methods for Flutter to communicate to NativeScript
void stopScanning() {
  Map<String, dynamic> message = {'type': 'stopScanning'};
  platform.send(jsonEncode(message));
}

void startScanning() {
  // List<BluetoothDevice> devices = [];
  Map<String, dynamic> message = {'type': 'startScanning'};
  platform.send(jsonEncode(message));
}

我们现在可以设置我们的Widgets来绑定我们的数据。你可以看到一个完整的例子,而不是展示整个Flutter Widget树。

利用物联网和Arduino进一步开展工作

这篇文章在很大程度上受到Sovik Biswas优秀探索的启发这里,你可以挑战自己与Arduino设备对话以获得更多有趣的功能。

干杯 🍻

就像Open Native为框架和平台开发者创造了跨生态系统结合其优势的可能性,Flutter开发者也可以利用NativeScript插件来丰富项目的可能性。

与你的同行合作,无论他们的背景或技能如何,都是富有成效和有意义的。

为一个充满欢乐合作的科技社区干杯 🌸


www.deepl.com 翻译