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)

4 thoughts on “Xamarin.Forms using Mqtt”

Leave a Reply

Your email address will not be published. Required fields are marked *