forked from jbagg/QtZeroConf
Move Android part to use native Android mDNS API
Signed-off-by: Jonathan Bagg <drwho@infidigm.net>
This commit is contained in:
committed by
Jonathan Bagg
parent
473d8520f9
commit
24debe31b0
180
QZeroConfNsdManager.java
Normal file
180
QZeroConfNsdManager.java
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
/**************************************************************************************************
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2015 Jonathan Bagg
|
||||||
|
This file is part of QtZeroConf.
|
||||||
|
|
||||||
|
QtZeroConf is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
QtZeroConf is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with QtZeroConf. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
Project name : QtZeroConf
|
||||||
|
File name : QZeroConfNsdManager.java
|
||||||
|
Created : 10 Spetember 2021
|
||||||
|
Author(s) : Michael Zanetti
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
NsdManager wrapper for use on Android devices
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
**************************************************************************************************/
|
||||||
|
|
||||||
|
package qtzeroconf;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import android.net.nsd.NsdServiceInfo;
|
||||||
|
import android.net.nsd.NsdManager;
|
||||||
|
|
||||||
|
public class QZeroConfNsdManager {
|
||||||
|
|
||||||
|
public static native void onServiceResolvedJNI(int id, String name, String type, String hostname, String address, int port, Map<String, byte[]> txtRecords);
|
||||||
|
public static native void onServiceRemovedJNI(int id, String name);
|
||||||
|
public static native void onBrowserStateChangedJNI(int id, boolean running, boolean error);
|
||||||
|
public static native void onPublisherStateChangedJNI(int id, boolean running, boolean error);
|
||||||
|
public static native void onServiceNameChangedJNI(int id, String newName);
|
||||||
|
|
||||||
|
private static String TAG = "QZeroConfNsdManager";
|
||||||
|
private int id;
|
||||||
|
private Context context;
|
||||||
|
private NsdManager nsdManager;
|
||||||
|
private NsdManager.DiscoveryListener discoveryListener;
|
||||||
|
private NsdManager.RegistrationListener registrationListener;
|
||||||
|
private String registrationName; // The original service name that was given for registration, it might change on collisions
|
||||||
|
|
||||||
|
public QZeroConfNsdManager(int id, Context context) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
this.context = context;
|
||||||
|
|
||||||
|
nsdManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE);
|
||||||
|
discoveryListener = initializeDiscoveryListener();
|
||||||
|
registrationListener = initializeRegistrationListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerService(String name, String type, int port, Map<String, String> txtRecords) {
|
||||||
|
registrationName = name;
|
||||||
|
|
||||||
|
NsdServiceInfo serviceInfo = new NsdServiceInfo();
|
||||||
|
serviceInfo.setServiceName(name);
|
||||||
|
serviceInfo.setServiceType(type);
|
||||||
|
serviceInfo.setPort(port);
|
||||||
|
for (Map.Entry<String, String> entry: txtRecords.entrySet()) {
|
||||||
|
serviceInfo.setAttribute(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
nsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.w(TAG, "Error registering service: " + e.toString());
|
||||||
|
onPublisherStateChangedJNI(id, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregisterService() {
|
||||||
|
nsdManager.unregisterService(registrationListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void discoverServices(String serviceType) {
|
||||||
|
nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopServiceDiscovery() {
|
||||||
|
nsdManager.stopServiceDiscovery(discoveryListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NsdManager.DiscoveryListener initializeDiscoveryListener() {
|
||||||
|
return new NsdManager.DiscoveryListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDiscoveryStarted(String regType) {
|
||||||
|
QZeroConfNsdManager.onBrowserStateChangedJNI(id, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceFound(NsdServiceInfo service) {
|
||||||
|
nsdManager.resolveService(service, initializeResolveListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceLost(NsdServiceInfo serviceInfo) {
|
||||||
|
QZeroConfNsdManager.onServiceRemovedJNI(id, serviceInfo.getServiceName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDiscoveryStopped(String serviceType) {
|
||||||
|
QZeroConfNsdManager.onBrowserStateChangedJNI(id, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
|
||||||
|
QZeroConfNsdManager.onBrowserStateChangedJNI(id, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
|
||||||
|
QZeroConfNsdManager.onBrowserStateChangedJNI(id, false, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private NsdManager.ResolveListener initializeResolveListener() {
|
||||||
|
return new NsdManager.ResolveListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
||||||
|
Log.d(TAG, "Resolving failed for: " + serviceInfo.getServiceName() + " " + serviceInfo.getServiceType() + ": " + errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceResolved(NsdServiceInfo serviceInfo) {
|
||||||
|
QZeroConfNsdManager.onServiceResolvedJNI(id,
|
||||||
|
serviceInfo.getServiceName(),
|
||||||
|
serviceInfo.getServiceType(),
|
||||||
|
serviceInfo.getHost().getHostName(),
|
||||||
|
serviceInfo.getHost().getHostAddress(),
|
||||||
|
serviceInfo.getPort(),
|
||||||
|
serviceInfo.getAttributes()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public NsdManager.RegistrationListener initializeRegistrationListener() {
|
||||||
|
return new NsdManager.RegistrationListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceRegistered(NsdServiceInfo serviceInfo) {
|
||||||
|
QZeroConfNsdManager.onPublisherStateChangedJNI(id, true, false);
|
||||||
|
if (!serviceInfo.getServiceName().equals(registrationName)) {
|
||||||
|
onServiceNameChangedJNI(id, serviceInfo.getServiceName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
||||||
|
QZeroConfNsdManager.onPublisherStateChangedJNI(id, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceUnregistered(NsdServiceInfo arg0) {
|
||||||
|
QZeroConfNsdManager.onPublisherStateChangedJNI(id, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
||||||
|
QZeroConfNsdManager.onPublisherStateChangedJNI(id, false, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
322
androidnsd.cpp
Normal file
322
androidnsd.cpp
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
/**************************************************************************************************
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2015-2021 Jonathan Bagg
|
||||||
|
This file is part of QtZeroConf.
|
||||||
|
|
||||||
|
QtZeroConf is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
QtZeroConf is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with QtZeroConf. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
Project name : QtZeroConf
|
||||||
|
File name : androidnsd.cpp
|
||||||
|
Created : 10 Spetember 2021
|
||||||
|
Author(s) : Michael Zanetti
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
NsdManager wrapper for use on Android devices
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
**************************************************************************************************/
|
||||||
|
#include "androidnsd_p.h"
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QHostAddress)
|
||||||
|
|
||||||
|
static QMutex s_instancesMutex;
|
||||||
|
static QList<QZeroConfPrivate*> s_instances;
|
||||||
|
|
||||||
|
|
||||||
|
QZeroConfPrivate::QZeroConfPrivate(QZeroConf *parent)
|
||||||
|
{
|
||||||
|
qRegisterMetaType<QHostAddress>();
|
||||||
|
qRegisterMetaType<TxtRecordMap>("TxtRecordMap");
|
||||||
|
|
||||||
|
pub = parent;
|
||||||
|
|
||||||
|
QAndroidJniEnvironment env;
|
||||||
|
|
||||||
|
JNINativeMethod methods[] {
|
||||||
|
{ "onServiceResolvedJNI", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/util/Map;)V", (void*)QZeroConfPrivate::onServiceResolvedJNI },
|
||||||
|
{ "onServiceRemovedJNI", "(ILjava/lang/String;)V", (void*)QZeroConfPrivate::onServiceRemovedJNI },
|
||||||
|
{ "onBrowserStateChangedJNI", "(IZZ)V", (void*)QZeroConfPrivate::onBrowserStateChangedJNI },
|
||||||
|
{ "onPublisherStateChangedJNI", "(IZZ)V", (void*)QZeroConfPrivate::onPublisherStateChangedJNI },
|
||||||
|
{ "onServiceNameChangedJNI", "(ILjava/lang/String;)V", (void*)QZeroConfPrivate::onServiceNameChangedJNI }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Passing "this" as ID down to Java so we can access "this" in callbacks.
|
||||||
|
// There seems to be no straight forward way to match the "thiz" pointer from JNI calls to our pointer of the Java class
|
||||||
|
nsdManager = QAndroidJniObject("qtzeroconf/QZeroConfNsdManager", "(ILandroid/content/Context;)V", reinterpret_cast<int>(this), QtAndroid::androidActivity().object());
|
||||||
|
if (nsdManager.isValid()) {
|
||||||
|
jclass objectClass = env->GetObjectClass(nsdManager.object<jobject>());
|
||||||
|
env->RegisterNatives(objectClass, methods, sizeof(methods) / sizeof(methods[0]));
|
||||||
|
env->DeleteLocalRef(objectClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMutexLocker locker(&s_instancesMutex);
|
||||||
|
s_instances.append(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QZeroConfPrivate::~QZeroConfPrivate()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&s_instancesMutex);
|
||||||
|
s_instances.removeAll(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In order to not having to pay attention to only use thread safe methods on the java side, we're only running
|
||||||
|
// Java calls on the Android thread.
|
||||||
|
// To make sure the Java object is not going out of scope and being garbage collected when the QZeroConf object
|
||||||
|
// is deleted before the worker thread actually starts, keep a new QAndroidJniObject to nsdManager
|
||||||
|
// which will increase the ref counter in the JVM.
|
||||||
|
void QZeroConfPrivate::startServicePublish(const char *name, const char *type, quint16 port)
|
||||||
|
{
|
||||||
|
QAndroidJniObject ref(nsdManager);
|
||||||
|
QtAndroid::runOnAndroidThread([=](){
|
||||||
|
QAndroidJniObject txtMap("java/util/HashMap");
|
||||||
|
foreach (const QByteArray &key, txtRecords.keys()) {
|
||||||
|
txtMap.callObjectMethod("put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||||
|
QAndroidJniObject::fromString(key).object<jstring>(),
|
||||||
|
QAndroidJniObject::fromString(txtRecords.value(key)).object<jstring>());
|
||||||
|
}
|
||||||
|
|
||||||
|
ref.callMethod<void>("registerService", "(Ljava/lang/String;Ljava/lang/String;ILjava/util/Map;)V",
|
||||||
|
QAndroidJniObject::fromString(QString(name)).object<jstring>(),
|
||||||
|
QAndroidJniObject::fromString(QString(type)).object<jstring>(),
|
||||||
|
port,
|
||||||
|
txtMap.object());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConfPrivate::stopServicePublish()
|
||||||
|
{
|
||||||
|
QAndroidJniObject ref(nsdManager);
|
||||||
|
QtAndroid::runOnAndroidThread([ref]() {
|
||||||
|
ref.callMethod<void>("unregisterService");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConfPrivate::startBrowser(QString type, QAbstractSocket::NetworkLayerProtocol protocol)
|
||||||
|
{
|
||||||
|
Q_UNUSED(protocol)
|
||||||
|
QAndroidJniObject ref(nsdManager);
|
||||||
|
QtAndroid::runOnAndroidThread([ref, type]() {
|
||||||
|
ref.callMethod<void>("discoverServices", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(type).object<jstring>());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConfPrivate::stopBrowser()
|
||||||
|
{
|
||||||
|
QAndroidJniObject ref(nsdManager);
|
||||||
|
QtAndroid::runOnAndroidThread([ref]() {
|
||||||
|
ref.callMethod<void>("stopServiceDiscovery");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks will come in from the android thread. So we're never accessing any of our members directly but instead
|
||||||
|
// propagate callbacks through Qt::QueuedConnection invokes into the Qt thread. Be sure to check if the instance is still
|
||||||
|
// alive by checking s_instances while holding the mutex before scheduling the invokation.
|
||||||
|
void QZeroConfPrivate::onServiceResolvedJNI(JNIEnv */*env*/, jobject /*thiz*/, jint id, jstring name, jstring type, jstring hostname, jstring address, jint port, jobject txtRecords)
|
||||||
|
{
|
||||||
|
QMap<QByteArray, QByteArray> txtMap;
|
||||||
|
QAndroidJniObject txt(txtRecords);
|
||||||
|
QAndroidJniObject txtKeys = txt.callObjectMethod("keySet", "()Ljava/util/Set;").callObjectMethod("toArray", "()[Ljava/lang/Object;");
|
||||||
|
|
||||||
|
QAndroidJniEnvironment env;
|
||||||
|
for (int i = 0; i < txt.callMethod<jint>("size"); i++) {
|
||||||
|
QAndroidJniObject key = QAndroidJniObject(env->GetObjectArrayElement(txtKeys.object<jobjectArray>(), i));
|
||||||
|
QAndroidJniObject valueObj = txt.callObjectMethod("get", "(Ljava/lang/Object;)Ljava/lang/Object;", key.object<jstring>());
|
||||||
|
if (valueObj.isValid()) {
|
||||||
|
jboolean isCopy;
|
||||||
|
jbyte* b = env->GetByteArrayElements(valueObj.object<jbyteArray>(), &isCopy);
|
||||||
|
QByteArray value((char *)b, env->GetArrayLength(valueObj.object<jbyteArray>()));
|
||||||
|
env->ReleaseByteArrayElements(valueObj.object<jbyteArray>(), b, JNI_ABORT);
|
||||||
|
txtMap.insert(key.toString().toUtf8(), value);
|
||||||
|
} else {
|
||||||
|
txtMap.insert(key.toString().toUtf8(), QByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QZeroConfPrivate *ref = reinterpret_cast<QZeroConfPrivate*>(id);
|
||||||
|
QMutexLocker locker(&s_instancesMutex);
|
||||||
|
if (!s_instances.contains(ref)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QMetaObject::invokeMethod(ref, "onServiceResolved", Qt::QueuedConnection,
|
||||||
|
Q_ARG(QString, QAndroidJniObject(name).toString()),
|
||||||
|
Q_ARG(QString, QAndroidJniObject(type).toString()),
|
||||||
|
Q_ARG(QString, QAndroidJniObject(hostname).toString()),
|
||||||
|
Q_ARG(QHostAddress, QHostAddress(QAndroidJniObject(address).toString())),
|
||||||
|
Q_ARG(int, port),
|
||||||
|
Q_ARG(TxtRecordMap, txtMap)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConfPrivate::onServiceRemovedJNI(JNIEnv */*env*/, jobject /*this*/, jint id, jstring name)
|
||||||
|
{
|
||||||
|
QZeroConfPrivate *ref = reinterpret_cast<QZeroConfPrivate*>(id);
|
||||||
|
QMutexLocker locker(&s_instancesMutex);
|
||||||
|
if (!s_instances.contains(ref)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QMetaObject::invokeMethod(ref, "onServiceRemoved", Qt::QueuedConnection, Q_ARG(QString, QAndroidJniObject(name).toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QZeroConfPrivate::onBrowserStateChangedJNI(JNIEnv */*env*/, jobject /*thiz*/, jint id, jboolean running, jboolean error)
|
||||||
|
{
|
||||||
|
QZeroConfPrivate *ref = reinterpret_cast<QZeroConfPrivate*>(id);
|
||||||
|
QMutexLocker locker(&s_instancesMutex);
|
||||||
|
if (!s_instances.contains(ref)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QMetaObject::invokeMethod(ref, "onBrowserStateChanged", Qt::QueuedConnection, Q_ARG(bool, running), Q_ARG(bool, error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConfPrivate::onPublisherStateChangedJNI(JNIEnv */*env*/, jobject /*this*/, jint id, jboolean running, jboolean error)
|
||||||
|
{
|
||||||
|
QZeroConfPrivate *ref = reinterpret_cast<QZeroConfPrivate*>(id);
|
||||||
|
QMutexLocker locker(&s_instancesMutex);
|
||||||
|
if (!s_instances.contains(ref)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QMetaObject::invokeMethod(ref, "onPublisherStateChanged", Qt::QueuedConnection, Q_ARG(bool, running), Q_ARG(bool, error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConfPrivate::onServiceNameChangedJNI(JNIEnv */*env*/, jobject /*thiz*/, jint id, jstring newName)
|
||||||
|
{
|
||||||
|
QZeroConfPrivate *ref = reinterpret_cast<QZeroConfPrivate*>(id);
|
||||||
|
QMutexLocker locker(&s_instancesMutex);
|
||||||
|
if (!s_instances.contains(ref)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QMetaObject::invokeMethod(ref, "onServiceNameChanged", Qt::QueuedConnection, Q_ARG(QString, QAndroidJniObject(newName).toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConfPrivate::onServiceResolved(const QString &name, const QString &type, const QString &hostname, const QHostAddress &address, int port, const TxtRecordMap &txtRecords)
|
||||||
|
{
|
||||||
|
QZeroConfService zcs;
|
||||||
|
bool newRecord = false;
|
||||||
|
if (pub->services.contains(name)) {
|
||||||
|
zcs = pub->services.value(name);
|
||||||
|
} else {
|
||||||
|
zcs = QZeroConfService(new QZeroConfServiceData);
|
||||||
|
newRecord = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
zcs->m_name = name;
|
||||||
|
zcs->m_type = type;
|
||||||
|
// A previous implementation (based on avahi) returned service type as "_http._tcp" but Android API return "._http._tcp"
|
||||||
|
// Stripping leading dot for backwards compatibility. FIXME: Still not in line with bonjour, which adds a trailing dot.
|
||||||
|
zcs->m_type.remove(QRegExp("^."));
|
||||||
|
zcs->m_host = hostname;
|
||||||
|
zcs->m_port = port;
|
||||||
|
zcs->m_ip = address;
|
||||||
|
zcs->m_txt = txtRecords;
|
||||||
|
|
||||||
|
// Those are not available on Androids NsdManager
|
||||||
|
// zcs->m_domain = domain;
|
||||||
|
// zcs->m_interfaceIndex = interface;
|
||||||
|
|
||||||
|
if (newRecord) {
|
||||||
|
pub->services.insert(name, zcs);
|
||||||
|
emit pub->serviceAdded(zcs);
|
||||||
|
} else {
|
||||||
|
emit pub->serviceUpdated(zcs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConfPrivate::onServiceRemoved(const QString &name)
|
||||||
|
{
|
||||||
|
if (pub->services.contains(name)) {
|
||||||
|
QZeroConfService service = pub->services.take(name);
|
||||||
|
emit pub->serviceRemoved(service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConfPrivate::onBrowserStateChanged(bool running, bool error)
|
||||||
|
{
|
||||||
|
browserExists = running;
|
||||||
|
if (error) {
|
||||||
|
emit pub->error(QZeroConf::browserFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConfPrivate::onPublisherStateChanged(bool running, bool error)
|
||||||
|
{
|
||||||
|
publisherExists = running;
|
||||||
|
if (running) {
|
||||||
|
emit pub->servicePublished();
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
emit pub->error(QZeroConf::serviceRegistrationFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConfPrivate::onServiceNameChanged(const QString &newName)
|
||||||
|
{
|
||||||
|
emit pub->serviceNameChanged(newName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QZeroConf::QZeroConf(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
pri = new QZeroConfPrivate(this);
|
||||||
|
qRegisterMetaType<QZeroConfService>("QZeroConfService");
|
||||||
|
}
|
||||||
|
|
||||||
|
QZeroConf::~QZeroConf()
|
||||||
|
{
|
||||||
|
delete pri;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConf::startServicePublish(const char *name, const char *type, const char *domain, quint16 port)
|
||||||
|
{
|
||||||
|
Q_UNUSED(domain) // Not supported on Android API
|
||||||
|
pri->startServicePublish(name, type, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConf::stopServicePublish(void)
|
||||||
|
{
|
||||||
|
pri->stopServicePublish();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QZeroConf::publishExists(void)
|
||||||
|
{
|
||||||
|
return pri->publisherExists;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConf::addServiceTxtRecord(QString nameOnly)
|
||||||
|
{
|
||||||
|
pri->txtRecords.insert(nameOnly.toUtf8(), QByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConf::addServiceTxtRecord(QString name, QString value)
|
||||||
|
{
|
||||||
|
pri->txtRecords.insert(name.toUtf8(), value.toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConf::clearServiceTxtRecords()
|
||||||
|
{
|
||||||
|
pri->txtRecords.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConf::startBrowser(QString type, QAbstractSocket::NetworkLayerProtocol protocol)
|
||||||
|
{
|
||||||
|
pri->startBrowser(type, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QZeroConf::stopBrowser(void)
|
||||||
|
{
|
||||||
|
pri->stopBrowser();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QZeroConf::browserExists(void)
|
||||||
|
{
|
||||||
|
return pri->browserExists;
|
||||||
|
}
|
65
androidnsd_p.h
Normal file
65
androidnsd_p.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/**************************************************************************************************
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2015-2021 Jonathan Bagg
|
||||||
|
This file is part of QtZeroConf.
|
||||||
|
|
||||||
|
QtZeroConf is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
QtZeroConf is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with QtZeroConf. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
Project name : QtZeroConf
|
||||||
|
File name : androidnsd_p.h
|
||||||
|
Created : 10 Spetember 2021
|
||||||
|
Author(s) : Michael Zanetti
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
NsdManager wrapper for use on Android devices
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
**************************************************************************************************/
|
||||||
|
#include "qzeroconf.h"
|
||||||
|
|
||||||
|
#include <QtAndroid>
|
||||||
|
#include <QtAndroidExtras>
|
||||||
|
#include <QAndroidJniObject>
|
||||||
|
|
||||||
|
class QZeroConfPrivate: QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
typedef QMap<QByteArray, QByteArray> TxtRecordMap;
|
||||||
|
|
||||||
|
QZeroConfPrivate(QZeroConf *parent);
|
||||||
|
~QZeroConfPrivate();
|
||||||
|
void startServicePublish(const char *name, const char *type, quint16 port);
|
||||||
|
void stopServicePublish();
|
||||||
|
void startBrowser(QString type, QAbstractSocket::NetworkLayerProtocol protocol);
|
||||||
|
void stopBrowser();
|
||||||
|
static void onServiceResolvedJNI(JNIEnv */*env*/, jobject /*this*/, jint id, jstring name, jstring type, jstring hostname, jstring address, jint port, jobject txtRecords);
|
||||||
|
static void onServiceRemovedJNI(JNIEnv */*env*/, jobject /*this*/, jint id, jstring name);
|
||||||
|
static void onBrowserStateChangedJNI(JNIEnv */*env*/, jobject /*thiz*/, jint id, jboolean running, jboolean error);
|
||||||
|
static void onPublisherStateChangedJNI(JNIEnv */*env*/, jobject /*thiz*/, jint id, jboolean running, jboolean error);
|
||||||
|
static void onServiceNameChangedJNI(JNIEnv */*env*/, jobject /*thiz*/, jint id, jstring newName);
|
||||||
|
|
||||||
|
QZeroConf *pub;
|
||||||
|
QAndroidJniObject nsdManager;
|
||||||
|
|
||||||
|
bool browserExists = false;
|
||||||
|
bool publisherExists = false;
|
||||||
|
QMap<QByteArray, QByteArray> txtRecords;
|
||||||
|
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onServiceResolved(const QString &name, const QString &type, const QString &hostname, const QHostAddress &address, int port, const TxtRecordMap &txtRecords);
|
||||||
|
void onServiceRemoved(const QString &name);
|
||||||
|
void onBrowserStateChanged(bool running, bool error);
|
||||||
|
void onPublisherStateChanged(bool running, bool error);
|
||||||
|
void onServiceNameChanged(const QString &newName);
|
||||||
|
};
|
@ -57,7 +57,7 @@ ios {
|
|||||||
QMAKE_CXXFLAGS+= -I$$PWD
|
QMAKE_CXXFLAGS+= -I$$PWD
|
||||||
}
|
}
|
||||||
|
|
||||||
ubports|android: {
|
ubports: {
|
||||||
QMAKE_CXXFLAGS+= -I$$PWD
|
QMAKE_CXXFLAGS+= -I$$PWD
|
||||||
QMAKE_CFLAGS+= -I$$PWD
|
QMAKE_CFLAGS+= -I$$PWD
|
||||||
ACM = $$PWD/avahi-common
|
ACM = $$PWD/avahi-common
|
||||||
@ -121,6 +121,13 @@ ubports|android: {
|
|||||||
#avahi-core/iface-none.c avahi-core/iface-pfroute.c avahi-core/avahi-reflector.c
|
#avahi-core/iface-none.c avahi-core/iface-pfroute.c avahi-core/avahi-reflector.c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
android: {
|
||||||
|
QT += androidextras
|
||||||
|
HEADERS += $$PWD/qzeroconf.h $$PWD/androidnsd_p.h
|
||||||
|
SOURCES += $$PWD/androidnsd.cpp
|
||||||
|
DISTFILES += $$PWD/QZeroConfNsdManager.java
|
||||||
|
}
|
||||||
|
|
||||||
HEADERS+= $$PWD/qzeroconfservice.h $$PWD/qzeroconfglobal.h
|
HEADERS+= $$PWD/qzeroconfservice.h $$PWD/qzeroconfglobal.h
|
||||||
|
|
||||||
SOURCES+= $$PWD/qzeroconfservice.cpp
|
SOURCES+= $$PWD/qzeroconfservice.cpp
|
||||||
|
@ -66,6 +66,7 @@ public:
|
|||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void servicePublished(void);
|
void servicePublished(void);
|
||||||
|
void serviceNameChanged(const QString &newName);
|
||||||
void error(QZeroConf::error_t);
|
void error(QZeroConf::error_t);
|
||||||
void serviceAdded(QZeroConfService);
|
void serviceAdded(QZeroConfService);
|
||||||
void serviceUpdated(QZeroConfService);
|
void serviceUpdated(QZeroConfService);
|
||||||
|
Reference in New Issue
Block a user