Xamarin.Forms using Mqtt
We can using of course mqtt in Xamarin.Form via dependency service / Xamarin.Forms.MessagingCenter, event or simply create a class instance. We are following the last option.
First step, we need to install the MQTTnet NuGet Package for the Solution. (So in each project.)
.NET Standard Library:
We need to create an MqttClientRepository class in the .NET Standard Library.
public class MqttClientRepository
{
Dictionary<string, TopicFilter> _topicFilter;
private static IMqttClient client;
public IMqttClient Create(string server, int? port, string userName, string password, List<string> topics)
{
_topicFilter = new Dictionary<string, TopicFilter>();
foreach (var topic in topics)
{
TopicFilter topicFilter = new TopicFilter
{
Topic = topic,
QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce
};
_topicFilter.Add(topic, topicFilter);
}
Task.Run(() => MqttClientRunAsync(server, port, userName, password)).Wait();
return client;
}
private async Task MqttClientRunAsync(string server, int? port, string userName, string password)
{
try
{
var options = new MqttClientOptions
{
ClientId = "YOURCLIENTID",
CleanSession = true,
ChannelOptions = new MqttClientTcpOptions
{
Server = server,
Port = port
},
Credentials = new MqttClientCredentials
{
Username = userName,
Password = Encoding.UTF8.GetBytes(password)
}
};
var factory = new MqttFactory();
client = factory.CreateMqttClient();
client.ConnectedHandler = new MqttConnectedHandler(_topicFilter, client);
client.DisconnectedHandler = new MqttDisconnectedHandler(options, client);
try
{
await client.ConnectAsync(options);
}
catch //(Exception ex)
{
}
}
catch //(Exception ex)
{
}
}
}
public class MqttDisconnectedHandler : IMqttClientDisconnectedHandler
{
private IMqttClient _client;
private MqttClientOptions _options;
public MqttDisconnectedHandler(MqttClientOptions options, IMqttClient client)
{
_options = options;
_client = client;
}
public async Task HandleDisconnectedAsync(MqttClientDisconnectedEventArgs eventArgs)
{
await Task.Delay(TimeSpan.FromSeconds(5));
try
{
}
catch
{
}
}
}
public class MqttConnectedHandler : IMqttClientConnectedHandler
{
private IMqttClient _client;
private Dictionary<string, TopicFilter> _topicFilter;
public MqttConnectedHandler(Dictionary<string, TopicFilter> topicFilter, IMqttClient client)
{
_topicFilter = topicFilter;
_client = client;
}
public async Task HandleConnectedAsync(MqttClientConnectedEventArgs eventArgs)
{
await _client.SubscribeAsync(_topicFilter.Values.ToArray());
}
}
}
Next step the platform specific implementations.
Android:
We need to create a MqttTaskService class in the Android Project.
public class MqttTaskService
{
private IMqttClient _mqttClient;
private readonly string _sessionPayedTopic;
public MqttTaskService()
{
_sessionPayedTopic = "YOUR TOPIC";
_mqttClient = new MqttClientRepository().Create(
"MqttServer",
MqttPort IN INTEGER,
"MqttUserName",
"MqttPassword",
new List<string> { _sessionPayedTopic });
_mqttClient.ApplicationMessageReceivedHandler = new SubscribeCallback(_sessionPayedTopic);
}
public void UnSubscribe()
{
_mqttClient.ApplicationMessageReceivedHandler = null;
}
}
public class SubscribeCallback : IMqttApplicationMessageReceivedHandler
{
private readonly string _sessionPayedTopic;
public SubscribeCallback(string sessionPayedTopic)
{
_sessionPayedTopic = sessionPayedTopic;
}
public Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs e)
{
string message = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
if (e.ApplicationMessage.Topic == _sessionPayedTopic)
{
}
return Task.CompletedTask;
}
}
We need to create an instance in the Android project, maybe in the MainActivity at the end in the OnCreate function.
MqttTaskService mqttTaskService = new MqttTaskService();
If we want to unsubscribe:
mqttTaskService.UnSubscribe(); call this
iOS
The same. We need to create a MqttTaskService class in the iOS Project.
public class MqttTaskService
{
private IMqttClient _mqttClient;
private readonly string _sessionPayedTopic;
public MqttTaskService()
{
_sessionPayedTopic = "YOUR TOPIC";
_mqttClient = new MqttClientRepository().Create(
"MqttServer",
MqttPort IN INTEGER,
"MqttUserName",
"MqttPassword",
new List<string> { _sessionPayedTopic });
_mqttClient.ApplicationMessageReceivedHandler = new SubscribeCallback(_sessionPayedTopic);
}
public void UnSubscribe()
{
_mqttClient.ApplicationMessageReceivedHandler = null;
}
}
public class SubscribeCallback : IMqttApplicationMessageReceivedHandler
{
private readonly string _sessionPayedTopic;
public SubscribeCallback(string sessionPayedTopic)
{
_sessionPayedTopic = sessionPayedTopic;
}
public Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs e)
{
string message = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
if (e.ApplicationMessage.Topic == _sessionPayedTopic)
{
}
return Task.CompletedTask;
}
}
We need to create an instance in the iOS Project, maybe in the MainActivity at the end in the OnCreate function.
MqttTaskService mqttTaskService = new MqttTaskService();
If we want to unsubscribe:
mqttTaskService.UnSubscribe(); call this
Okay, okay, we know if a message got, but how can we indicate to the .NET Standard Library? We have to create an event or through MessagingCenter. Use this, if you got a message in the various platform codes:
MessagingCenter.Send("SessionPayed", "SessionPayed", message);
And use this code in the .NET Standard Library, if you want to be notified, when a message got:
MessagingCenter.Subscribe<string, string>("SessionPayed", "SessionPayed", (sender, args) =>
{
Device.BeginInvokeOnMainThread(()=>
{
//You got a message from Mqtt, do something.
});
});
Be wary, in the Subscribe section, your code will run in the background thred, so if you want to do some UI thing, you have to do in the main thread! (above)