我正在用Windows VISUAL Studio 2022测试Platform-Channels.

我可以在获得电池电池值的同时,从Ffltter用户界面传递单个值,但我想要将Ffltter中的多个数据发送到Windows代码. 以下是我的测试代码,我将遵循Fighting教程:

class _MyHomePageState extends State<MyHomePage> {
  static const MethodChannel platform =
      MethodChannel('samples.flutter.dev/battery');

  String _batteryLevel = 'Unknown battery level.';
  int value = 100;
  Future<void> _getBatteryLevel(int fluval) async {
    String batteryLevel;
    try {
      final int result = await platform.invokeMethod('getBatteryLevel', fluval);
      batteryLevel = 'Battery level at $result % .';
    } on PlatformException catch (e) {
      batteryLevel = "Failed to get battery level: '${e.message}'.";
    }
    setState(() {
      _batteryLevel = batteryLevel;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            ElevatedButton(
              onPressed: () {
                _getBatteryLevel(100);
              },
              child: const Text('Get Battery Level'),
            ),
            Text(_batteryLevel),
          ],
        ),
      ),
    );
  }
}

和窗边:

void initMethodChannel(flutter::FlutterEngine* flutter_instance) {
    const static std::string channel_name("samples.flutter.dev/battery");
    auto channel =
        std::make_unique<flutter::MethodChannel<>>(
            flutter_instance->messenger(), channel_name,
            &flutter::StandardMethodCodec::GetInstance());
    channel->SetMethodCallHandler(
        [](const flutter::MethodCall<>& call,
            std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {

                // cheack method name called from dart
                if (call.method_name().compare("getBatteryLevel") == 0) {
                    int battery_level = GetBatteryLevel();
                    const auto* flu_value = std::get_if<int>(call.arguments());
                    std::cout << typeid(flu_value).name() << std::endl;

                    if (!flu_value) {
                        result->Error("Missing required type parameter","Expected int");
                    }
                    std::cout << "From Flutter: " << *flu_value << std::endl;

                    if (battery_level != -1) {
                        result->Success(battery_level);
                    }
                    else {
                        result->Error("UNAVAILABLE", "Battery level not available.");
                    }
                }
                else {
                    result->NotImplemented();
                }
        });
}

如果我想像这样发送多个数据:

Future<void> _getBatteryLevel(int fluval, int data2,...,...) ...

当调用一次invkeMethod时,我应该如何处理或解析这两个值:Fluval和Data2?

有什么我可以参考的例子吗?或者是WindowsUI设计的小贴士?

我试着搜索,但大多数答案是针对Android或iOS应用程序的,Android的答案是使用call.argument("value"),你可以 Select 特定的数据值来使用,但Windows只有call.arguments();个函数调用,我不知道如何获得我想要的特定数据.

============================================================ [更新] 从@Richard Tips and Example, 我做了一个测试,它起作用了,谢谢你,理查德!

下面是Flutter 用户界面示例代码:(在Stateful Widget State类中),Fluval=100,flval2=87

  String _getBackV1 = 'Unknown Value 1.';
  String _getBackV2 = 'Unknown Value 2.';
  int value = 100;
  Future<void> _testMapPassValue(int fluval, int fluval2) async {
    String backValue1, backValue2;
    try {
      final Map<String, dynamic>? getReply = await platform
          .invokeMapMethod<String, dynamic>('testPass',
              <String, dynamic>{"fluval": fluval, "fluval2": fluval2});
      backValue1 = "Get Back Value 1 from windows: ${getReply!["fluval"]}";
      backValue2 = "Get Back Value 2 from windows: ${getReply!["fluval2"]}";
    } on PlatformException catch (e) {
      backValue1 = "Failed to get Value 1: '${e.message}'.";
      backValue2 = "Failed to get Value 2: '${e.message}'.";
    }
    setState(() {
      _getBackV1 = backValue1;
      _getBackV2 = backValue2;
    });
  }

在Windows端的示例代码中:

using flutter::EncodableList;
using flutter::EncodableMap;
using flutter::EncodableValue;
constexpr char testMapPassValue[] = "testPass";

constexpr char passKey1[] = "fluval";
constexpr char passKey2[] = "fluval2";

方法调用处理程序:

if (call.method_name().compare(testMapPassValue) == 0) {
  const auto* getArguments_flu = std::get_if<flutter::EncodableMap>(call.arguments());
  assert(getArguments_flu);
  return Flu_2_Win_MethodHandler(*getArguments_flu, std::move(result));
}

void Flu_2_Win_MethodHandler(
    const EncodableMap& args, std::unique_ptr<flutter::MethodResult<>> result) {
    // Parse enableAudio argument.
    int wins2fluValue1;
    int wins2fluValue2;
    EncodableMap win2fluMap;

    const auto* flu2winsValue1 =
        std::get_if<int>(ValueOrNull(args, passKey1));
    if (!flu2winsValue1) {
        return result->Error("argument_error",
            std::string(passKey1) + " argument missing");
    }
    wins2fluValue1 = *flu2winsValue1;
    std::cout << "From Flutter value1: " << *flu2winsValue1 << std::endl;
    wins2fluValue1 = wins2fluValue1 + 10;
    std::cout << "After calculate value1: " << wins2fluValue1 << std::endl;

    const auto* flu2winsValue2 =
        std::get_if<int>(ValueOrNull(args, passKey2));
    if (!flu2winsValue2) {
        return result->Error("argument_error",
            std::string(passKey2) + " argument missing");
    }
    wins2fluValue2 = *flu2winsValue2;
    std::cout << "From Flutter value1: " << *flu2winsValue2 << std::endl;
    wins2fluValue2 = wins2fluValue2 + 20;
    std::cout << "After calculate value2: " << wins2fluValue2 << std::endl;

    win2fluMap.insert(std::pair<std::string, int>("fluval", wins2fluValue1));
    win2fluMap.insert(std::pair<std::string, int>("fluval2", wins2fluValue2));
    
    return result->Success(std::move(EncodableValue(win2fluMap)));
}

最后的结果是:

FlutterUI Result

谢谢!

推荐答案

您只能将单个实体作为参数或结果进行传递,但该实体可以是任何受支持的类型(无论是Primitive-int、Double等,还是Complex-List或map).

DART和C++(Windows本机)类型之间的映射为:

// std::monostate       -> null
// bool                 -> bool
// int32_t              -> int
// int64_t              -> int
// double               -> double
// std::string          -> String
// std::vector<uint8_t> -> Uint8List
// std::vector<int32_t> -> Int32List
// std::vector<int64_t> -> Int64List
// std::vector<float>   -> Float32List
// std::vector<double>  -> Float64List
// EncodableList        -> List
// EncodableMap         -> Map

(见encodable_value.h)

因此,要发送两个整数(fluvaldata2),您可以 Select 将它们放入DART列表(例如<int>[123, 456])或DART映射(例如{'fluval':123, 'data2':456})中.在本机端,参数将是EncodableListEncodableMap.

下面是一个复杂的DART struct 如何在本机端显示的示例:

//   {
//     'flag': true,
//     'name': 'Thing',
//     'values': [1, 2.0, 4],
//   }
// would correspond to:
//   EncodableValue(EncodableMap{
//       {EncodableValue("flag"), EncodableValue(true)},
//       {EncodableValue("name"), EncodableValue("Thing")},
//       {EncodableValue("values"), EncodableValue(EncodableList{
//                                      EncodableValue(1),
//                                      EncodableValue(2.0),
//                                      EncodableValue(4),
//                                  })},
//   })

camera插件有一些用法示例(以映射形式获取参数):

const auto* arguments = std::get_if<flutter::EncodableMap>(method_call.arguments());

在同一文件中,签出两个实用程序函数:

// Looks for |key| in |map|, returning the associated value if it is present, or
// a nullptr if not.
const EncodableValue* ValueOrNull(const EncodableMap& map, const char* key) {
  auto it = map.find(EncodableValue(key));
  if (it == map.end()) {
    return nullptr;
  }
  return &(it->second);
}

// Looks for |key| in |map|, returning the associated int64 value if it is
// present, or std::nullopt if not.
std::optional<int64_t> GetInt64ValueOrNull(const EncodableMap& map,
                                           const char* key) {
  auto value = ValueOrNull(map, key);
  if (!value) {
    return std::nullopt;
  }

  if (std::holds_alternative<int32_t>(*value)) {
    return static_cast<int64_t>(std::get<int32_t>(*value));
  }
  auto val64 = std::get_if<int64_t>(value);
  if (!val64) {
    return std::nullopt;
  }
  return *val64;
}

以及它们的典型用法:

  const auto* camera_name =
      std::get_if<std::string>(ValueOrNull(args, kCameraNameKey));

  auto camera_id = GetInt64ValueOrNull(args, kCameraIdKey);

Flutter相关问答推荐

我如何才能收到每天重复的预定通知?

关闭模式,但再次打开时微件条件相同

有没有可能不在BlocBuilder中重新构建内容?

轻松本地化包翻译在底部导航栏项目标签Flutter 翼dart 中不起作用

使用持久的侧边菜单和顶部栏在Ffltter Web应用程序中的页面之间导航

FittedBox叠加技术在Flutter 中的应用

如何使用providerContainer监听/写入FutureProvider?

Flutter中不使用Container是否可以做margin

Flutter:在 pubspec.yaml 中找不到assets资源

Flutter:我应该使用哪种应用内购买服务?

Flutter 中的区域不匹配

Flutter如何从深入嵌套的小部件中打开抽屉?

使用Flutter项目设置Firebase遇到困难?这些解决方案或许能帮到你!

Flutter开发中,如何通过'nfc_manager'插件在Android设备上避免默认的New Tag Scanned弹出窗口?

Flutter列顶部和底部出现不必要的边距问题

如何从 Flutter 中的 App2 远程点击 App1 中的按钮

我想在一个屏幕上有两个相同区域的列表视图,我该如何设置?

如何在Flutter中制作带有波浪边框的圆圈来显示图像?

为什么 Flutter riverpod 直接分配不起作用但方法可以

gridview 的所有按钮都应该在Flutter 中适合其父容器