_nw_parameters_configure_protocol_disable iOS вызывается напрямую
Я пытаюсь использовать сокет TCP в общем модуле iOS Kotlin/Native.
Согласно документации Apple, чтобы открытьnw_connection_t
, вам просто необходимо:
val connection =
nw_parameters_create_secure_tcp(
NW_PARAMETERS_DISABLE_PROTOCOL, // No TLS
NW_PARAMETERS_DEFAULT_CONFIGURATION // Default TCP config
)
Однако когда я запускаю этот модуль в приложении iOS, я получаю следующую ошибку:
_nw_parameters_configure_protocol_disable_block_invoke _nw_parameters_configure_protocol_disable called directly, dumping backtrace:
[x86_64] libnetcore-1880.120.4
0 libnetwork.dylib 0x00007fff5118d1f8 __nw_create_backtrace_string + 120
1 libnetwork.dylib 0x00007fff5100a898 _nw_parameters_configure_protocol_disable_block_invoke + 120
2 PhoenixShared 0x00000001099af1b5 _70686f656e69783a70686f656e69782d736861726564_knbridge41 + 37
3 PhoenixShared 0x0000000109972eac kfun:fr.acinq.phoenix.io.BlockFunctionImpl16.invoke#internal + 220
4 PhoenixShared 0x0000000109972fbf kfun:fr.acinq.phoenix.io.BlockFunctionImpl16.$<bridge-UNNN>invoke(platform.darwin.NSObject?){}#internal + 95
5 PhoenixShared 0x000000010997342b _70686f656e69783a70686f656e69782d736861726564_knbridge47 + 251
6 libnetwork.dylib 0x00007fff5100d7b6 nw_parameters_create_secure_tcp + 342
...
В parameters.h
заголовок в Apple Network.framework содержит:
#define NW_PARAMETERS_DISABLE_PROTOCOL (_nw_parameters_configure_protocol_disable)
... так что конечно _nw_parameters_configure_protocol_disable
вызывается напрямую.
Есть идеи, что я делаю неправильно?
1 ответ
Итак, оказывается, что ни NW_PARAMETERS_DISABLE_PROTOCOL
ни NW_PARAMETERS_DEFAULT_CONFIGURATION
предназначены для вызова. Хотя они блочного типа^(nw_protocol_options_t)
, то nw_parameters_create_secure_tcp
функция использует их адреса указателей как специальные маркеры и никогда не вызывает их.
Это проблема, потому что уровень взаимодействия Kotlin/Native ObjC:
- Преобразованный
NW_PARAMETERS_DISABLE_PROTOCOL
а такжеNW_PARAMETERS_DEFAULT_CONFIGURATION
блоки в лямбды Котлина. - Оборачивает лямбда-выражения, чтобы преобразовать их обратно в блоки ObjC при передаче их в качестве аргументов (как мы можем видеть в строках трассировки стека вопроса с номерами 3 и 4).
В результате фактический адрес указателя этих специальных блоков теряется, блоки вызываются (чего они не должны делать) и происходит сбой.
В Kotlin нет способа решить эту проблему, так как Kotlin версия nw_parameters_create_secure_tcp
запрашивает лямбда-параметры (а не указатели).
Очень простой обходной путь - создать наш собственный уровень взаимодействия с использованием нашего собственного файла C-interop def:
package = fr.acinq.phoenix.io.network_framework
language = Objective-C
---
#include <Network/Network.h>
NW_RETURNS_RETAINED nw_parameters_t nw_k_parameters_create_secure_tcp(bool withTls) {
return nw_parameters_create_secure_tcp(
withTls ? NW_PARAMETERS_DEFAULT_CONFIGURATION : NW_PARAMETERS_DISABLE_PROTOCOL,
NW_PARAMETERS_DEFAULT_CONFIGURATION
);
}
Это создает Objective-C nw_k_parameters_create_secure_tcp
функция (обратите внимание на nw_k_
префикс), который напрямую вызывает исходный nw_parameters_create_secure_tcp
с правильными параметрами, без уровня Kotlin block-to-lambda-to-block, который можно правильно вызвать из Kotlin.