We have previously covered SDKs for Swift, Kotlin and Javascript. Now we will cover Xamarin, the favorite tool in the .NET developers tool-belt for mobile applications! We will create an app for localized borrowing of items. As for example, if you want to install a shelf and you need a drill just for this project. Maybe somebody nearby has one which you can borrow, and will lend it to you for a beer or a hug?

Requirements

  • Visual Studio installed on your computer. Download Visual Studio for free here.
  • Good knowledge of C# and Xamarin.
  • A Matchmore account to start using the service. You can register for free here.
  • If you want to test the app in real life, you'll need at least two devices, any Android or iOS should be good enough.
  • Willingness to learn new stuff.

The examples will be done in Visual Studio for Mac, but most steps should be similar in case of the classical Visual Studio for Windows.

Getting started

Create a new multiplatform Forms App.

create-project

Let's opt in for use of .NET Standard and skip generating the mobile backend. We want to use Matchmore for this.

create-project-2

Follow the wizard until you get to your created project.

Install Matchmore SDK

The Matchmore SDK is available as a NUGET package.

NuGet package

A NuGet-walkthrough can be found here.

Make sure to choose the pure .NET Standard, Matchmore.SDK not, Matchmore.Xamarin.SDK. The latter is useful for older projects using Shared Code and contain some bridging code but we will show you how to circumvent it in this blog post.

Running the app

Let's run the app for the first time. I've selected the iOS version as the startup project and hit Command + Enter.

4-emulator-list

We will update the template to leverage Matchmore!

Let's create a borrowing app!

Get API key

Now let's create a new application on the Matchmore Portal and obtain the API key that we will use to configure SDK later on. After logging in (register for free here) you will do the following:

alt text

And now let's use the key in the application. A good place to put the key is in the App.xaml.cs file in the Project. This file is shared for both platforms.

protected override void OnStart()
        {
            //1
            Matchmore.SDK.Matchmore.ConfigureAsync(new GenericConfig
            {
                ApiKey = "<YOUR API KEY>"
            }).GetAwaiter().GetResult();

            //2
            Matchmore.SDK.Matchmore.Instance.SetupMainDeviceAsync().GetAwaiter().GetResult();

            //3
            Matchmore.SDK.Matchmore.Instance.StartLocationService();
        }

The commented lines mean the following:

  1. Setting up the general static instance of the SDK. Remember to replace the placeholder with your own API Key.

  2. Setting up the default device of the SDK. I will persist some metadata locally on the client device as well create a device in the Matchmore service.

  3. Starting the location service. And here there are couple of caveats we need to touch upon.

We mentioned earlier the Xamarin specific version of the SDK, and that we use the .NET Standard, and due to this we must fill in some pieces. This gives more control over the SDK in your application.

We implement the ILocationService interface.

    public class MyLocationService : ILocationService
    {

        public event EventHandler<LocationUpdatedEventArgs> LocationUpdated;

        public void Start()
        {
            
        }

        public void Stop()
        {
            
        }
    }
    

Let's use a class we already implemented, so let's use the Geolocator plugin written for Xamarin. Add the the geolocator via the nuget, and try to search for Xam.Plugin.Geolocator. This is one example how to do it, if your application already has some infrastructure for obtaining location, you can adapt it and plug it into the Matchmore SDK.

The last step is to use the Location Service.

Matchmore.SDK.Matchmore.ConfigureAsync(new GenericConfig
            {
                ApiKey = "<YOUR API KEY>",
                LocationService = new MyLocationService()
            }).GetAwaiter().GetResult();

In similar fashion you might want to implement your own persistence mechanisms, just implement the IStateRepository and wire it in. Example implementation specific for Xamarin

Device privileges

Configure project (Request permission)

iOS info.plist

In iOS 10, developers have to declare ahead of time any access to a user's private data in their Info.plist.

You must add the follow privacy settings into the Info.plist file to get access to location data:

<key>NSLocationWhenInUseUsageDescription</key>
<string>MyApp will show you detected nearby devices.</string>

<!-- iOS 10 or earlier -->
<key>NSLocationAlwaysUsageDescription</key>
<string>MyApp will show you detected nearby devices, and alert you via
notifications if you don't have the app open.</string>

<!-- iOS 11 -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>MyApp will show you detected nearby devices in the app. With the "always" option,
we can also alert you via notifications if you don't have the app open.</string>
Android request permission

In Android, you need to add the following lines of code in your MainActivity.cs file inside of onCreate() function:

const string p1 = Android.Manifest.Permission.AccessFineLocation;
const string p2 = Android.Manifest.Permission.AccessCoarseLocation;
RequestPermissions(new string[] { p1, p2 }, 0);

Also, find your AndroidManifest.xml file in the properties folder and tick the followings:

Required permissions :

  • ACCESS_COARSE_LOCATION
  • ACCESS_FINE_LOCATION

Visit our official documentation if you need more details on this!

Using Matchmore

We got here! We are wired up and ready to roll!

Let's start by adding ability to tell people that we have as a lendable item.

Navigate to MockDataSource.cs and rename it to MatchmoreDataSource.cs and continue refactoring it to leverage Matchmore. Remove the mocking code and create a monitor to get matches.

        List<Item> items;
        private Matchmore.SDK.Matchmore matchmore;

        public MatchmoreDataStore()
        {
            items = new List<Item>();
            matchmore = Matchmore.SDK.Matchmore.Instance;
            var monitor = matchmore.SubscribeMatches();
            monitor.MatchReceived += (sender, e) =>
            {
                //fill here later
            };
        }

To avoid producing too much boilerplate for our example, let's hijack the Item class and make it do some more work for us.

Change the List to a HashSet to handle duplication and modify the Item class accordingly.

    public class Item
    {
        public string Id { get; set; }
        public string Text { get; set; }
        public string Description { get; set; }
        Publication _publication;

        public Publication Publication
        {
            get
            {
                return _publication;
            }

            set
            {
                _publication = value;
                this.Id = value.Id;
            }
        }

        public Item() {
        }

        public Item(Publication publication){
            this.Publication = publication;
            this.Id = Publication.Id;
            this.Description = Publication.Properties["description"].ToString();
            this.Text = Publication.Properties["name"].ToString();
        }

        public override int GetHashCode()
        {
            return Id.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Item))
                return false;
            var i = obj as Item;
           return  i.Id == this.Id;
        }
    }

And then we modify the event delegate to add Items.

monitor.MatchReceived += (sender, e) =>
            {
                foreach (var match in e.Matches)
                {
                    items.Add(new Item(match.Publication));
                }
            };
monitor.Start();

Create Publications

Now let's modify the storage to create a Publication when we add an Item.

        public async Task<bool> AddItemAsync(Item item)
        {
            var pub = await matchmore.CreatePublicationAsync(new Publication
            {
                Range = 1000,
                Duration = 24 * 60  * 60,
                Properties = new Dictionary<string, object>{
                    {"name", item.Text},
                    {"description", item.Description}
                },
                Topic = "shared-economy-app"
            });

            item.Publication = pub;

            items.Add(item);

            return await Task.FromResult(true);
        }

We added Publication Ids to track these entities later in an easer fashion.

Similarly we can update other CRUD methods, for example getting all matches.

 public async Task<IEnumerable<Item>> GetItemsAsync(bool forceRefresh = false)
        {
            var matches = await matchmore.GetMatchesAsync();
            foreach (var match in matches)
            {
                items.Add(new Item(match.Publication));
            }
            return await Task.FromResult(items);
        }

Creating Subscriptions

Great, now we need to subscribe to other postings.

For now let's add a simple subscription, let's get everything published in our vicinity.

In the App.xaml.cs, OnStart method add:

if (!Matchmore.SDK.Matchmore.Instance.ActiveSubscriptions.Any()){
               var sub = Matchmore.SDK.Matchmore.Instance.CreateSubscriptionAsync(new Subscription
                {
                    Range = 1000,
                    Duration = 24 * 60 * 60,
                    Topic = "shared-economy-app",
                    Selector = ""
                }).GetAwaiter().GetResult();  
            }

Here you can immediately notice that adding a new publication will get you a match, you were matched with your own publication. Since we are using a HashSet we are worry-free.

Ok, we got a simple sharing app done and ready, but now we need to search for everything. In order to do that, we have to add a functionality to narrow down the lendable items.

In the ItemsPage.xaml in the outer StackLayout add:

<SearchBar x:Name="SearchBar" SearchCommand="{Binding SearchCommand}" SearchCommandParameter="{Binding Text, Source={x:Reference SearchBar}}"></SearchBar>

And in the ItemsViewModel.cs add the bounded search command:

        private ICommand _searchCommand;
        public ICommand SearchCommand
        {
            get
            {
                return _searchCommand ?? (_searchCommand = new Command<string>(async(text) => await UpdateSearch(text)));
            }
        }

And then the method:

 private async Task UpdateSearch(String text) {
            //1
            var searchSub = Matchmore.SDK.Matchmore.Instance.ActiveSubscriptions.FirstOrDefault();
            if (searchSub != null)
            {
                await Matchmore.SDK.Matchmore.Instance.DeleteSubscriptionAsync(searchSub.Id);
            }
            //2
            var selector = "";

            //3
            var sub = await Matchmore.SDK.Matchmore.Instance.CreateSubscriptionAsync(new Subscription
            {
                Range = 1000,
                Duration = 24 * 60 * 60,
                Topic = "shared-economy-app",
                Selector = selector
            });
        }

1 is about removing the old subscription.
2 is the Selector and (3) creating subscription.

The Selector is a SQL conditional following the SQL92 specification.

So let's write a query to find publications where the term is in the name or description.

var selector = $"name LIKE \"{text}\" OR description LIKE \"{text}\"";

Great, now we can subscribe for other publications and borrow stuff from our neighbors!

5-list

That's it for today! From here we can extrapolate and create an awesome application using Xamarin and Matchmore!