- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
514 lines
18 KiB
Python
514 lines
18 KiB
Python
"""
|
|
Android NsdManager API — NsdManager, NsdServiceInfo, DiscoveryListener, RegistrationListener, ResolveListener
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
import socket
|
|
import uuid
|
|
import threading
|
|
from typing import Any, Dict, List, Optional, Set, Tuple, Callable
|
|
|
|
from .._core import Stub, AndroidOnlyError
|
|
from ..java.lang import RuntimeException
|
|
|
|
IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# 常量
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
# PROTOCOL_* 常量
|
|
PROTOCOL_DNS_SD = 0
|
|
|
|
# FAILURE_* 常量
|
|
FAILURE_ALREADY_ACTIVE = 3
|
|
FAILURE_INTERNAL_ERROR = 0
|
|
FAILURE_MAX_LIMIT = 4
|
|
FAILURE_SERVICE_NOT_FOUND = 1
|
|
FAILURE_SERVICE_NOT_RUNNING = 2
|
|
|
|
# DNS_* 常量
|
|
DNS_A = 1
|
|
DNS_AAAA = 28
|
|
DNS_CNAME = 5
|
|
DNS_HINFO = 13
|
|
DNS_MX = 15
|
|
DNS_NS = 2
|
|
DNS_PTR = 12
|
|
DNS_SOA = 6
|
|
DNS_SRV = 33
|
|
DNS_TXT = 16
|
|
DNS_WKS = 11
|
|
DNS_ANY = 255
|
|
|
|
# SERVICE_TYPE 常量
|
|
SERVICE_TYPE_HTTP = "_http._tcp"
|
|
SERVICE_TYPE_HTTPS = "_https._tcp"
|
|
SERVICE_TYPE_FTP = "_ftp._tcp"
|
|
SERVICE_TYPE_SSH = "_ssh._tcp"
|
|
SERVICE_TYPE_SMTP = "_smtp._tcp"
|
|
SERVICE_TYPE_IMAP = "_imap._tcp"
|
|
SERVICE_TYPE_AIRPLAY = "_airplay._tcp"
|
|
SERVICE_TYPE_GOOGLECAST = "_googlecast._tcp"
|
|
SERVICE_TYPE_DEVICE_INFO = "_device-info._tcp"
|
|
SERVICE_TYPE_PRINTER = "_printer._tcp"
|
|
SERVICE_TYPE_SCANNER = "_scanner._tcp"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# NsdServiceInfo
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class NsdServiceInfo(Stub):
|
|
"""NsdServiceInfo — NSD 服务信息"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._service_name: Optional[str] = None
|
|
self._service_type: Optional[str] = None
|
|
self._host: Optional[str] = None
|
|
self._port: int = 0
|
|
self._txt_records: Dict[str, bytes] = {}
|
|
self._attributes: Dict[str, str] = {}
|
|
self._network: Optional[Any] = None
|
|
self._interface_index = 0
|
|
self._service_id = str(uuid.uuid4())
|
|
self._ttl = 120
|
|
self._priority = 0
|
|
self._weight = 0
|
|
self._is_resolved = False
|
|
self._addresses: List[str] = []
|
|
|
|
def getServiceName(self) -> Optional[str]:
|
|
return self._service_name
|
|
|
|
def setServiceName(self, serviceName: str) -> None:
|
|
self._service_name = serviceName
|
|
|
|
def getServiceType(self) -> Optional[str]:
|
|
return self._service_type
|
|
|
|
def setServiceType(self, serviceType: str) -> None:
|
|
self._service_type = serviceType
|
|
|
|
def getHost(self) -> Optional[str]:
|
|
return self._host
|
|
|
|
def setHost(self, host: str) -> None:
|
|
self._host = host
|
|
|
|
def getPort(self) -> int:
|
|
return self._port
|
|
|
|
def setPort(self, port: int) -> None:
|
|
self._port = port
|
|
|
|
def getTxtRecords(self) -> Dict[str, bytes]:
|
|
return dict(self._txt_records)
|
|
|
|
def setTxtRecords(self, txtRecords: Dict[str, bytes]) -> None:
|
|
self._txt_records = dict(txtRecords)
|
|
|
|
def getAttributes(self) -> Dict[str, str]:
|
|
return dict(self._attributes)
|
|
|
|
def setAttribute(self, key: str, value: str) -> None:
|
|
self._attributes[key] = value
|
|
|
|
def removeAttribute(self, key: str) -> None:
|
|
self._attributes.pop(key, None)
|
|
|
|
def getNetwork(self) -> Optional[Any]:
|
|
return self._network
|
|
|
|
def setNetwork(self, network: Any) -> None:
|
|
self._network = network
|
|
|
|
def getInterfaceIndex(self) -> int:
|
|
return self._interface_index
|
|
|
|
def setInterfaceIndex(self, index: int) -> None:
|
|
self._interface_index = index
|
|
|
|
def getHostAddresses(self) -> List[str]:
|
|
return list(self._addresses)
|
|
|
|
def addHostAddress(self, address: str) -> None:
|
|
if address not in self._addresses:
|
|
self._addresses.append(address)
|
|
|
|
def getServiceId(self) -> str:
|
|
return self._service_id
|
|
|
|
def getTtl(self) -> int:
|
|
return self._ttl
|
|
|
|
def setTtl(self, ttl: int) -> None:
|
|
self._ttl = ttl
|
|
|
|
def getPriority(self) -> int:
|
|
return self._priority
|
|
|
|
def setPriority(self, priority: int) -> None:
|
|
self._priority = priority
|
|
|
|
def getWeight(self) -> int:
|
|
return self._weight
|
|
|
|
def setWeight(self, weight: int) -> None:
|
|
self._weight = weight
|
|
|
|
def isResolved(self) -> bool:
|
|
return self._is_resolved
|
|
|
|
def setResolved(self, resolved: bool) -> None:
|
|
self._is_resolved = resolved
|
|
|
|
def getHostAddress(self) -> Optional[str]:
|
|
if self._addresses:
|
|
return self._addresses[0]
|
|
return self._host
|
|
|
|
def toString(self) -> str:
|
|
return (
|
|
f"NsdServiceInfo(name={self._service_name}, "
|
|
f"type={self._service_type}, "
|
|
f"host={self._host}, "
|
|
f"port={self._port})"
|
|
)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# NsdManager 内部 Listener 类
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class NsdManagerDiscoveryListener(Stub):
|
|
"""NsdManager.DiscoveryListener — 服务发现监听器"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def onDiscoveryStarted(self, serviceType: str) -> None:
|
|
pass
|
|
|
|
def onDiscoveryStopped(self, serviceType: str) -> None:
|
|
pass
|
|
|
|
def onServiceFound(self, serviceInfo: "NsdServiceInfo") -> None:
|
|
pass
|
|
|
|
def onServiceLost(self, serviceInfo: "NsdServiceInfo") -> None:
|
|
pass
|
|
|
|
def onStartDiscoveryFailed(self, serviceType: str, errorCode: int) -> None:
|
|
pass
|
|
|
|
def onStopDiscoveryFailed(self, serviceType: str, errorCode: int) -> None:
|
|
pass
|
|
|
|
def onDiscoveryStopped(self, serviceType: str) -> None:
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return "NsdManager.DiscoveryListener"
|
|
|
|
|
|
class NsdManagerRegistrationListener(Stub):
|
|
"""NsdManager.RegistrationListener — 服务注册监听器"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def onRegistrationFailed(self, serviceInfo: "NsdServiceInfo", errorCode: int) -> None:
|
|
pass
|
|
|
|
def onUnregistrationFailed(self, serviceInfo: "NsdServiceInfo", errorCode: int) -> None:
|
|
pass
|
|
|
|
def onServiceRegistered(self, serviceInfo: "NsdServiceInfo") -> None:
|
|
pass
|
|
|
|
def onServiceUnregistered(self, serviceInfo: "NsdServiceInfo") -> None:
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return "NsdManager.RegistrationListener"
|
|
|
|
|
|
class NsdManagerResolveListener(Stub):
|
|
"""NsdManager.ResolveListener — 服务解析监听器"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def onResolveFailed(self, serviceInfo: "NsdServiceInfo", errorCode: int) -> None:
|
|
pass
|
|
|
|
def onServiceResolved(self, serviceInfo: "NsdServiceInfo") -> None:
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return "NsdManager.ResolveListener"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# NsdManager
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class NsdManager(Stub):
|
|
"""NsdManager — 网络服务发现管理器 (桌面存根)"""
|
|
|
|
PROTOCOL_DNS_SD = PROTOCOL_DNS_SD
|
|
|
|
FAILURE_ALREADY_ACTIVE = FAILURE_ALREADY_ACTIVE
|
|
FAILURE_INTERNAL_ERROR = FAILURE_INTERNAL_ERROR
|
|
FAILURE_MAX_LIMIT = FAILURE_MAX_LIMIT
|
|
FAILURE_SERVICE_NOT_FOUND = FAILURE_SERVICE_NOT_FOUND
|
|
FAILURE_SERVICE_NOT_RUNNING = FAILURE_SERVICE_NOT_RUNNING
|
|
|
|
DiscoveryListener = NsdManagerDiscoveryListener
|
|
RegistrationListener = NsdManagerRegistrationListener
|
|
ResolveListener = NsdManagerResolveListener
|
|
|
|
def __init__(self, context: Any = None):
|
|
super().__init__()
|
|
self._context = context
|
|
self._lock = threading.Lock()
|
|
self._registered_services: Dict[str, NsdServiceInfo] = {}
|
|
self._discovery_listeners: Dict[str, NsdManagerDiscoveryListener] = {}
|
|
self._discovery_active: Set[str] = set()
|
|
self._resolved_services: Dict[str, NsdServiceInfo] = {}
|
|
self._discovered_services: Dict[str, List[NsdServiceInfo]] = {}
|
|
self._network_interface: Optional[str] = None
|
|
self._socket_family = socket.AF_INET
|
|
self._discovery_timeout = 5000
|
|
self._is_available = True
|
|
|
|
def discoverServices(
|
|
self, serviceType: str, protocolType: int, listener: NsdManagerDiscoveryListener
|
|
) -> None:
|
|
"""发现指定类型的服务"""
|
|
with self._lock:
|
|
if serviceType in self._discovery_active:
|
|
listener.onStartDiscoveryFailed(serviceType, FAILURE_ALREADY_ACTIVE)
|
|
return
|
|
self._discovery_active.add(serviceType)
|
|
self._discovery_listeners[serviceType] = listener
|
|
listener.onDiscoveryStarted(serviceType)
|
|
# 模拟发现
|
|
for srv_id, info in self._registered_services.items():
|
|
if info.getServiceType() == serviceType:
|
|
listener.onServiceFound(info)
|
|
|
|
def stopServiceDiscovery(self, listener: NsdManagerDiscoveryListener) -> None:
|
|
"""停止服务发现"""
|
|
with self._lock:
|
|
to_remove = []
|
|
for stype, lst in self._discovery_listeners.items():
|
|
if lst is listener:
|
|
to_remove.append(stype)
|
|
for stype in to_remove:
|
|
self._discovery_active.discard(stype)
|
|
del self._discovery_listeners[stype]
|
|
listener.onDiscoveryStopped(stype)
|
|
|
|
def registerService(
|
|
self, serviceInfo: NsdServiceInfo, protocolType: int, listener: NsdManagerRegistrationListener
|
|
) -> None:
|
|
"""注册本地服务"""
|
|
with self._lock:
|
|
srv_id = f"{serviceInfo.getServiceName()}:{serviceInfo.getServiceType()}"
|
|
if srv_id in self._registered_services:
|
|
listener.onRegistrationFailed(serviceInfo, FAILURE_ALREADY_ACTIVE)
|
|
return
|
|
self._registered_services[srv_id] = serviceInfo
|
|
listener.onServiceRegistered(serviceInfo)
|
|
|
|
def unregisterService(self, listener: NsdManagerRegistrationListener) -> None:
|
|
"""注销本地服务"""
|
|
with self._lock:
|
|
to_remove = []
|
|
for srv_id, info in self._registered_services.items():
|
|
to_remove.append(srv_id)
|
|
for srv_id in to_remove:
|
|
info = self._registered_services.pop(srv_id)
|
|
listener.onServiceUnregistered(info)
|
|
|
|
def resolveService(
|
|
self, serviceInfo: NsdServiceInfo, listener: NsdManagerResolveListener
|
|
) -> None:
|
|
"""解析服务(获取主机和端口)"""
|
|
with self._lock:
|
|
srv_id = f"{serviceInfo.getServiceName()}:{serviceInfo.getServiceType()}"
|
|
if srv_id in self._registered_services:
|
|
resolved = self._registered_services[srv_id]
|
|
resolved.setResolved(True)
|
|
if not resolved.getHost():
|
|
resolved.setHost("127.0.0.1")
|
|
if resolved.getPort() == 0:
|
|
resolved.setPort(8080)
|
|
self._resolved_services[srv_id] = resolved
|
|
listener.onServiceResolved(resolved)
|
|
else:
|
|
listener.onResolveFailed(serviceInfo, FAILURE_SERVICE_NOT_FOUND)
|
|
|
|
def getDiscoveredServices(self, serviceType: str) -> List[NsdServiceInfo]:
|
|
"""获取已发现的服务列表"""
|
|
with self._lock:
|
|
return [
|
|
info for info in self._registered_services.values()
|
|
if info.getServiceType() == serviceType
|
|
]
|
|
|
|
def getRegisteredServices(self) -> List[NsdServiceInfo]:
|
|
"""获取所有已注册的服务"""
|
|
with self._lock:
|
|
return list(self._registered_services.values())
|
|
|
|
def isDiscoveryActive(self, serviceType: str) -> bool:
|
|
"""检查指定类型的发现是否活跃"""
|
|
with self._lock:
|
|
return serviceType in self._discovery_active
|
|
|
|
def setNetworkInterface(self, iface: str) -> None:
|
|
"""设置网络接口"""
|
|
self._network_interface = iface
|
|
|
|
def getNetworkInterface(self) -> Optional[str]:
|
|
return self._network_interface
|
|
|
|
def setDiscoveryTimeout(self, timeoutMs: int) -> None:
|
|
self._discovery_timeout = timeoutMs
|
|
|
|
def getDiscoveryTimeout(self) -> int:
|
|
return self._discovery_timeout
|
|
|
|
def isAvailable(self) -> bool:
|
|
return self._is_available
|
|
|
|
def destroy(self) -> None:
|
|
with self._lock:
|
|
self._discovery_active.clear()
|
|
self._discovery_listeners.clear()
|
|
self._registered_services.clear()
|
|
self._resolved_services.clear()
|
|
self._is_available = False
|
|
|
|
def toString(self) -> str:
|
|
with self._lock:
|
|
return (
|
|
f"NsdManager(registered={len(self._registered_services)}, "
|
|
f"active_discoveries={len(self._discovery_active)})"
|
|
)
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# NsdManager 补充功能
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
def getServiceInfo(self, serviceName: str) -> Optional[NsdServiceInfo]:
|
|
"""通过名称获取已注册的服务信息"""
|
|
with self._lock:
|
|
for srv_id, info in self._registered_services.items():
|
|
if info.getServiceName() == serviceName:
|
|
return info
|
|
return None
|
|
|
|
def removeService(self, serviceName: str) -> bool:
|
|
"""移除已注册的服务"""
|
|
with self._lock:
|
|
to_remove = [
|
|
srv_id for srv_id, info in self._registered_services.items()
|
|
if info.getServiceName() == serviceName
|
|
]
|
|
for srv_id in to_remove:
|
|
del self._registered_services[srv_id]
|
|
return len(to_remove) > 0
|
|
|
|
def getResolvedService(self, serviceName: str) -> Optional[NsdServiceInfo]:
|
|
"""获取已解析的服务"""
|
|
with self._lock:
|
|
for srv_id, info in self._resolved_services.items():
|
|
if info.getServiceName() == serviceName:
|
|
return info
|
|
return None
|
|
|
|
def getResolvedServices(self) -> List[NsdServiceInfo]:
|
|
"""获取所有已解析的服务"""
|
|
with self._lock:
|
|
return list(self._resolved_services.values())
|
|
|
|
def getAllDiscoveredServices(self) -> List[NsdServiceInfo]:
|
|
"""获取所有已发现的服务"""
|
|
with self._lock:
|
|
return [
|
|
info for info in self._registered_services.values()
|
|
if info.isResolved()
|
|
]
|
|
|
|
def getActiveDiscoveryCount(self) -> int:
|
|
"""获取活跃发现数量"""
|
|
with self._lock:
|
|
return len(self._discovery_active)
|
|
|
|
def getActiveDiscoveryTypes(self) -> List[str]:
|
|
"""获取正在发现的服务类型列表"""
|
|
with self._lock:
|
|
return list(self._discovery_active)
|
|
|
|
def createServiceInfo(
|
|
self, serviceName: str, serviceType: str, port: int = 0
|
|
) -> NsdServiceInfo:
|
|
"""创建服务信息对象"""
|
|
info = NsdServiceInfo()
|
|
info.setServiceName(serviceName)
|
|
info.setServiceType(serviceType)
|
|
info.setPort(port)
|
|
info.setHost("127.0.0.1")
|
|
return info
|
|
|
|
|
|
class NsdServiceInfoBuilder(Stub):
|
|
"""NsdServiceInfo.Builder — 服务信息构建器"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._info = NsdServiceInfo()
|
|
|
|
def setServiceName(self, name: str) -> "NsdServiceInfoBuilder":
|
|
self._info.setServiceName(name)
|
|
return self
|
|
|
|
def setServiceType(self, serviceType: str) -> "NsdServiceInfoBuilder":
|
|
self._info.setServiceType(serviceType)
|
|
return self
|
|
|
|
def setHost(self, host: str) -> "NsdServiceInfoBuilder":
|
|
self._info.setHost(host)
|
|
return self
|
|
|
|
def setPort(self, port: int) -> "NsdServiceInfoBuilder":
|
|
self._info.setPort(port)
|
|
return self
|
|
|
|
def setTxtRecords(self, records: Dict[str, bytes]) -> "NsdServiceInfoBuilder":
|
|
self._info.setTxtRecords(records)
|
|
return self
|
|
|
|
def addAttribute(self, key: str, value: str) -> "NsdServiceInfoBuilder":
|
|
self._info.setAttribute(key, value)
|
|
return self
|
|
|
|
def setNetwork(self, network: Any) -> "NsdServiceInfoBuilder":
|
|
self._info.setNetwork(network)
|
|
return self
|
|
|
|
def build(self) -> NsdServiceInfo:
|
|
return self._info
|
|
|
|
def toString(self) -> str:
|
|
return f"NsdServiceInfoBuilder(name={self._info.getServiceName()})" |