Documentation portal

Last updated: July 06, 2018

Overview

Matchmore

As the fast-growing world of mobile connected objects computing era is becoming a reality, Matchmore aims at becoming the leading cloud-based software platform supporting the creation of highly dynamic proximity-based applications. At the heart of our vision is the notion of geomatching, which is built on the location-based Publish/Subscribe communication model.

Mission

Our mission is to provide tools that dramatically simplify and accelerate the development, testing and deployment of rich application scenarios based on multiple moving and connected objects, making such applications the new low hanging fruits of the mobile app industry.

Get familiar with the Matchmore products and explore their features:

  Start directly with our quickstart   How it works   Discover our SDKs

Understanding Matchmore

Matchmore helps you to model any geolocated or proximity-based applications, by taking advantage of advanced location-based Publish/Subscribe model. Create any type of interactions for connected objects (Internet of Things) from Smartphones to iBeacons and everything in between.

In-depth Publish/Subscribe

The Publish/Subscribe model is a message-oriented paradigm in which, publishers can publish messages anonymously on a topic and subscribers can receive messages on that topic. The additional layer, namely selector, allows subscribers to filter incoming messages based on the message’s content.

Matchmore Cloud Service

Matchmore is designed to simplify software developer’s life. It is an extension of the Publish/Subscribe model adding user context while remaining message-oriented. Publications and subscriptions are extended with the notion of geographical zone. The zone is defined as a circle with a center at a given location and a range around that location.

Publications and subscriptions are associated with any mobile device (i.e. smartphones and tablets), beacons or pin points and stay linked to it if the device moves. Both the crossing of the range and the correspondance of topic + content lead to the delivery of the message, called, a match.

To ease mobile application development, Matchmore is provided as various Software Development Kits (SDK) for different platforms.

Examples

Please have a look at some applications that have been built with Matchmore:

Matchmore enables you to notify your Application’s users whenever there is someone or something they could be interested in close by. Create proximity detection easily on web or mobile by using the advanced location-based Publish/Subscribe paradigm.

  • Create Smart Geofences

Geofences are used to define virtual areas in the real world, that you are particularly interested in. With smart geofences, you can go further in the filtering process. Thanks to the topic and content filtering it can be used for analytics, for instance to count how many users enter a specific area based on their preference. Or for triggering content displaying matching on your Application. Matchmore works indoor (beacons) and outdoor (GPS).

  • Smart activation with IoT

Activate a connected device when you approach it (for instance a camera).

  • Geochat

Broadcast anonymous message to people around you.

  • Smart checkpoints

Create virtual gates or points to control the passage of users. Example : A trail is validated if the user has passed by every point related to the trail.

 

Interesting, isn’t it ?

You can add any of those features listed above with geomatching. Simply use Matchmore to add location context and tracking to your apps with just a few lines of code.

Matchmore is applicable to many usecases and eases the modelization and deployment of any geolocated applications.

Want to get started quickly? Follow our quickstart guide.

Developer tools

You can integrate Matchmore in your apps using our developer tools: SDKs and the REST API.

SDKs

Integrate the SDK into your iOS or Android applications to start generating matches. The SDKs abstracts away cross-platform differences between location services, allowing you to add location context and proximity detection to your apps with just a few lines of code.

Learn more about the SDKs.

  iOS SDK   Android SDK   Javascript SDK   .Net SDK   Unity 3D SDK

API

You can manage your Matchmore objects, including devices, publications, subscriptions, and matches, using our restful API. For instance, you may use the API to list matches related to a device, or to create some publications programmatically.

Learn more about the   API

 

Questions ?

We are always happy to help you with your code or to answer any other question you might have! Search our documentation and do not hesitate to contact us.

Geomatching

Quickstart

Quickly start geomatching for any type of device.

Follow these four steps to start geomatching:

  1. Create a device to feature geomatching
  2. Create a publication to broadcast the presence of a device
  3. Create a subscription to start discovering nearby devices
  4. Handle the Match, when subscribers and publishers are within range of each other

The devices are core elements of the domain model for geomatching. A Device defines an object that is either virtual or physical. A device without publication or subscription is not detectable nor detecting, so you need to attach Publication or Subscription on a device in order to start either to broadcast presence or to discover nearby devices.

A Match is the event object to notify a device of any geomatching. It is location and content based, in other words a Match event is triggered only if both devices are in the specified range and their Publication/Subscription content match.

STEP 1: Create a device to feature geomatching

To provide geomatching Matchmore relies on different hardware sensors such as GPS, Bluetooth, and others. Each device is unique and offers distinct possibilities:

  • Mobile Device is providing Location updates, thanks to its GPS
  • Beacon Device is made for indoor and outdoor location services. It relies on Bluetooth technology.
  • Pin Device is a virtual (non-physical) device and placed at geographic coordinates.
  • More types of device will be added in the future.

Matchmore SDK can be used in different ways, but the most common way is to have a main device. Usually, this main device is the device on which the app is running, typically it is operated by your actual user: Smartphone (mobile app) or Browser (web app).

The following code demonstrates how to create the main device:

// a. Create the main device
MatchMore.startUsingMainDevice { result in
    // b. Unwrap the result
    guard case .success(let mainDevice) = result else { print(result.errorMessage ?? ""); return }
    print("Using device: \n\(mainDevice.encodeToJSON())")

    // c. Start getting matches
    MatchMore.startPollingMatches()
    // d. Start location track in Matchmore
    MatchMore.startUpdatingLocation()
}
  • a. Use the wrapper MatchMore and call the method startUsingMainDevice() to start the registration of the application running on your device in Matchmore service.
  • b. MatchMore SDK’s methods are generally using an asynchronous callback. To handle it, you need to declare a closure. Callback’s result is an enum, so you need to unwrap it. When it is a success, the callback returns the Device object that has been created, when it is a failure, the callback provides you with an Error object containing a message to describe why it has failed.

In case of success, Matchmore returns a new device object with all of the relevant details:

{
  "id": "84579fd3-58da-433f-a776-ed01c5c3f992",
  "createdAt": 1524214702782,
  "name": "My iphone",
  "platform": "iOs 11",
  "deviceToken": "some-apn-token-for-push",
  "location": {
      "latitude": 46.445015,
      "longitude": 6.908000,
      "altitude": 452
  }
}

Once you have created a device, we advise you to store it’s id value in your own database for later reference. Devices have a universally unique identifier (UUID) that is generated automatically upon device creation.

When creating a device through the API, the response includes an UUID, which you can use to attach a Publication or Subscription to this Device. To attach a Publication/Subscription to an existing device provide it’s UUID in your Matchmore requests. Pass the UUID of the desired device as the deviceId value of the Publication/Subscription parameter.

  • c. When using our SDK, polling the Match in Matchmore cloud service is easy, just one line of code.
  • d. Again, using our SDK will relieve you of many tasks. This single line of code starts informing Matchmore service of the user’s device location.

STEP 2: Create a publication to broadcast the presence of a device

When a Device has a Publication (or a Subscription) attached to it, it will broadcast it’s presence. One can think about a publication as a message, that might store json properties such as a phone number, a name, or any relevant information. Publications can contain customized information for future Match receivers. They are grouped in the properties parameter. You can attach as many Publication and Subscription to a Device as you want. A device can be both publisher and subscriber at the same time. You may define one Publication/Subscription or several hundred, depending on scenarios. Publishers are NOT notified of matches occurrence, if you want your publishers to be notified, they must be subscribing as well.

This code creates a publication via the SDK and the publication will be directly attached to the main device:

// a. Create a Publication, set topic and properties
let publication = Publication(topic: "test", range: 100, duration: 60, properties: ["band": "Metallica",
"tags": ["rock", "metal"],
"price": 400,
"currency": "CHF",
"free_parking": true])
// b. Create a Publication for Main Device
MatchMore.createPublicationForMainDevice(publication: publication, completion: { result in
    switch result {
    case .success(let publication):
        print("Pub was created: \n\(publication.encodeToJSON())")
    case .failure(let error):
        print("\(String(describing: error?.message))")
    }
  })
}
  • a. Create a publication and fill the required parameters.
  • The topic is our first filter. In order to match, both a Publication and a Subscription need to be created on the same unique topic. Here, the topic is test. We use the topic to filter different matches channels.
  • You can select the range of the zone around any publications/subscriptions, it is defined as a circle with a center at the given location and a radial distance around that location. The range is defined in meters.
  • You have to set the duration of your publications. The duration is defined in seconds.
  • Now, you can set some properties to allow finer filtering for the subscribers of your topic. The following data types are allowed in Properties parameters: String, Int, Set and Boolean.
  • b. Use the MatchMore SDK and call the method createPublicationForMainDevice() to send a creation request to the Matchmore service. Don’t forget that we need to handle two cases: in case of success we retrieve the created object, and in case of failure, we retrieve an error. In case of success, Matchmore returns a new Publication object with all the relevant details:
    {
      "id": "c62b5a4f-ce4a-4249-a1fa-33235732ce13",
      "createdAt": 1524212756568,
      "deviceId": "cc8ec61f-913c-4e81-b959-01153f8eb46d",
      "topic": "test",
      "range": 100,
      "duration": 60,
      "properties": {
        "band": "Metallica",
        "tags": [
          "rock",
          "metal"
        ],
        "price": 400,
        "currency": "CHF",
        "free_parking": true
      }
    }
    

    Once you have created the publication, store the id value in your own database for later reference (presumably with user’s deviceId).

STEP 3: Create a subscription to start discovering nearby devices

When a Match occurs, every subscriber receives a message based on their topic and content selection. With the selector parameter, you can filter publications based on the metadata contained within them to discover only the devices that might interest you.

Matchmore offers the ability to simultaneously subscribe a device to multiple topics. This provides additionnal channel to easily include your features in flexible ways. For example, if your service offers multiple features or services based on proximity detection, each could be identified by its own topic and the same device could be subscribed to more than one topic. Imagine an application that has two features: geo-chatting (Broadcast messages to nearby users) and geomatching (discover how many users are nearby). You can create the features on two different topics for example, “geochat” for geochatting and “detection” for geomatching and to completely separate both features.

// a. Create a Subscription, set topic and selector.
let subscription = Subscription(topic: "test", range: 1, duration: 60, selector: "band <> 'Ramstein' AND price < 500")
// b. Create a Subscription for Main Device
MatchMore.createSubscriptionForMainDevice(subscription: subscription, completion: { result in
    switch result {
    case .success(let sub):
        print("Socket Sub was created \n\(sub.encodeToJSON())")
    case .failure(let error):
        print("\(String(describing: error?.message))")
    }
})
  • a. Create a subscription to listen for matches on the test topic.
  • Remember that the topic is the first level of filtering you can use.
  • As for Publications, you can set the desired range and duration for Subscriptions.
  • The selector can be used to granularly filter the publication’s properties. In this example, we want key: band’s value to be different from Ramstein and key: price’s value to be lower than 500. As soon as the two devices will be in range and since this query will be evaluated to True, we will get a match between the previous publication and this subscription.
  • b. Use the wrapper MatchMore and call the method createSubscriptionForMainDevice() to send the creation request to Matchmore service. Don’t forget that we need to handle two cases: in case of success we retrieve the created object, and in case of failure, we retrieve an error.

In case of success, Matchmore returns a new Subscription object with all the relevant details:

{
  "id": "376880ff-52af-4424-8cc7-6033f01ec077",
  "createdAt": 1524232785653,
  "deviceId": "cc8ec61f-913c-4e81-b959-01153f8eb46d",
  "topic": "test",
  "range": 1,
  "duration": 60,
  "selector": "band <> 'Ramstein' AND price < 500",
  "pushers": [
      "localhost"
  ]
}

Once you create a Subscription, we advise you to store it’s id value in your own database for later reference (presumably with the deviceId of the user).

STEP 4: Handle Match, when subscribers and publishers are within range of each other geographically and topic and contents are matching.

A match warns the subscribers of the presence of nearby publishers. In other words, a device that has a subscription attached to it is notified when a Match occurs. It is not the case for devices with publications attached to them.

In order to receive a match, you need to create an instance which is conform to MatchDelegate protocol. All instances that conform to MatchDelegate protocol and that are delegate of MatchMonitor, are going to be notified.

Define an object that is conform to MatchDelegate protocol implementing OnMatchClosure.

class ExampleMatchHandler: MatchDelegate {
    var onMatch: OnMatchClosure?
    init(_ onMatch: @escaping OnMatchClosure) {
        self.onMatch = onMatch
    }
}

In this example we ensure that class ViewController is conform to the MatchDelegate protocol. You also need to add var onMatch which is a closure.

class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, MatchDelegate {
var onMatch: OnMatchClosure?

Next, implement how your matches should be handled:

 // Handle Matches
 self.onMatch = { [weak self] matches, device in
     // a. Get most recent Match
     let mostRecentMatch = matches.max(by: {
         $0.createdAt! < $1.createdAt!
     })

     // b. Unwrap properties
     guard let properties = mostRecentMatch?.publication?.properties else {
         print("No properties.")
         return
     }
     guard let band = properties["band"] as? String else {return}
     guard let tags = properties["tags"] as? Set else {return}
     guard let price = properties["price"] as? Int else {return}
     guard let currency = properties["currency"] as? String else {return}
     guard let free_parking = properties["free_parking"] as? Bool else {return}

     // c. Do something
 }
 // d. Add a new match delegate to Matchmore
 MatchMore.matchDelegates += self

You need to create a delegate function for the onMatch listener. Every onMatchClosure are triggered when there is a new match. The returned callback is composed of an array containing the hundred last matches, plus the device. Then you decide what happens with the matches:

  • a. Filter the Set of hundred returned last matches and get the most recent one.
  • b. Safely unwrap the value you’ll use.
  • c. Use the match information that you need
    {
    "id": "c67dha4f-ce4a-4249-a1fa-33235732ce13",
    "createdAt": 1524232995653,
    "publication": {
      "id": "c62b5a4f-ce4a-4249-a1fa-33235732ce13",
      "createdAt": 1524212756568,
      "deviceId": "cc8ec61f-913c-4e81-b959-01153f8eb46d",
      "topic": "test",
      "range": 100,
      "duration": 60,
      "properties": {
        "band": "Metallica",
        "tags": [
          "rock",
          "metal"
        ],
        "price": 400,
        "currency": "CHF",
        "free_parking": true
      }
    },
    "subscription": {
      "id": "376880ff-52af-4424-8cc7-6033f01ec077",
      "createdAt": 1524232785653,
      "deviceId": "cc8ec61f-913c-4e81-b959-01153f8eb46d",
      "topic": "test",
      "range": 1,
      "duration": 60,
      "selector": "band <> 'Ramstein' AND price < 500",
      "pushers": [
          "localhost"
      ]
      }
    }
    
  • d. Earlier, we have made ViewController conform to MatchDelegate protocol. In order to be informed of every match, you’ll need to add ViewController to Matchmore wrapper match delegates list. Every time Matchmore SDK is notified of a new delegate, it will automatically include this new delegate to the list of objects that are notified for matches.

How it works

We will run through all what you need to know about Matchmore’s service.

Fundamental objects and their interaction are described in details, so you can handle Matchmore on your own.

Matchmore’s geomatching relies on devices, publications and subscriptions. Devices are the central element for geomatching; clients create devices to publish and subscribe, and every geomatching, namely match is broadcasted by Matchmore to the concerned subscribers.

Object id

All objects in Matchmore are generated with a unique identifier, the id.

Besides the id parameter, each type of object have their individual characteristics.

Objects states

Any objects in Matchmore can exist in any of the following states:

  • Creating

A creation has been initiated by sending a request to Matchmore. This is a transient state; it will be followed either by a transitiion to created or failed.

  • Created

Creation has succeeded. At this point, an object is considered being active and alive in Matchmore. It has a unique id generated by Matchmore and a creation datetime property.

  • Deleting

A deletion has been initiated on the object by sending a request to Matchmore. This is a transient state; it will be followed either by a transition to deleted or failed

  • Deleted

The object has been deleted in Matchmore, it is therefore no longer active, nor alive.

  • Failed

The action has failed, see below for details.

 

failed creation or deletion

Matchmore tries to always inform you with error messages when creation or deletion has failed. This state is entered if an error has been received from the Matchmore service (i.e. an attempt to create without the necessary access rights).

Location and Device

The concept of Location and Device is very important to understand how to use Matchmore. In Matchmore, users interact with each other via devices. Each device can be detected by any other devices. Usually, a device is at one location. This location can be static or mobile (changing over time) depending on the type of devices.

Location

A location consists of the geographical coordinates of a Device. An update location is a Location object sent to Matchmore cloud service to update a device position when it has moved.

Device

A device might be either virtual like a pin device or physical like a mobile or a beacon device. In order to publish or subscribe to it, you must first obtain a device instance and then attach your Publication or Subscription to that device. In most case it is unnecessary to explicitly attach to a specific device because the sdk will implicitly use your main device for that purpose. Devices may issue publications and subscriptions at any time; they may also cancel publications and subscriptions issued previously.

In the following examples, you will learn how to obtain each types of device instances.

Mobile

A mobile device is one that potentially moves with its owner and therefore has a geographical location associated with it. A mobile device is typically a location-aware smartphone, which knows its location thanks to GPS or to some other means like cell tower triangulation, etc.

Example: How to obtain a Mobile device

When starting your application, you want to make sure that a Mobile device corresponding to your actual smartphone running your applications already exists in Matchmore’s backend.

By always calling method startUsingMainDevice() when you start your Application, it will automatically either create a new mobile device or reuse the one previously created and stored locally by Matchmore’s sdk.

  1. Use the current mobile device

To use the current mobile device, call function startUsingMainDevice() with empty parameters.

MatchMore.startUsingMainDevice { result in
    guard case .success(let mainDevice) = result else { print("\(String(describing: result.errorMessage))"); return }
    print("Using device: \n\(mainDevice.encodeToJSON())")
}
  1. Use a particular device

If you need to use a specific Device as your main device, you may pass any deviceId to startUsingMainDevice() as shown below.

var myMainDevice : MobileDevice?
MatchMore.mobileDevices.find(byId: "ID stored in your backend", completion: {result in
    if (result != nil){
        myMainDevice = result
        MatchMore.startUsingMainDevice(device: myMainDevice, shouldStartMonitoring: true, completion: {result in
            switch result{
            case .success(let mobile):
                print("Main Device successfully retrieved \n\(mobile.encodeToJSON())")
                myMainDevice = mobile
            case .failure(let error):
                print("\(String(describing: error?.message))")
            }
        })
    } else {
        print("The id used to retrieve a main device does not correspond to any known mobile devices.")
    }
})

Pin

A pin device has geographical coordinates associated with it but is not represented by any object in the physical world; usually its location doesnt change frequently if at all.

Example: How to obtain a Pin device
let locationTest = Location.init(latitude: 46.490513, longitude: 6.430700)
let myPinDevice = PinDevice.init(name: "pin test", location: locationTest)
MatchMore.createPinDevice(pinDevice: myPinDevice, completion: { (result) in
    switch result{
    case .success(let pin):
        print("Pin device was created \n\(pin.encodeToJSON())")
    case .failure(let error):
        print("\(String(describing: error?.message))")
    }
})

Beacon

Beacons are hardware devices that repeatedly broadcast a single signal under the form of an advertising packet. Other devices interact with them through bluetooth and receive their advertising packet which consist of different letters and numbers. With the received information, devices like smartphones know how close they are to a specific beacon. The main purpose of beacons is to handle indoor proximity detection. When developers know how close they are to a specific location, thanks to a nearby beacon, they can do something useful with this information. Geomatching with beacons is done via Bluetooth technology, as a result, the beacons are not geographically located with geographic coordinates. With Matchmore, you are able to attach information to your beacons, thanks to publication’s properties.

Example: How to obtain a Beacon device

Beacon device works slightly differently from Mobile and Pin devices. To operate, they require a pre-registration in our web portal. This pre-registration is mandatory because on most platforms it is only possible to detect known beacons.

  1. Go on Matchmore portal and start registering the beacons that you are going to use. To identify them, we need you to provide us their UUID, major and minor parameters.

  2. Stay on Matchmore portal, and go to your applications view. Assign the beacons to the applications that will use them. When it is done, all registered beacons are accessible with proper credentials via REST API or SDKs.

  3. Get your registered beacons in your app and start publishing to or subscribing to them.

    MatchMore.knownBeacons.findAll(completion: { beacons in
     // store the beacon that you are looking for
    })
    

 

Beacons standard

iBeacon is the standard defined by Apple. There is also other beacons standards like Eddystone by Google or AltBeacons by Kontakt.io. Basically, the content of the advertising packet could vary slightly from one standard to another, but the communication protocol (bluetooth) remains the same. As a consequence, the large majority of beacons on the market support at least the iBeacon standard and the Eddystone standard. IBeacon standard is fully supported by Matchmore.

Publication & Subscription

When devices are created, you can start to attach publications and subscriptions to them. A Publication is a message extended with the notion of a geographical zone. The zone is defined as a circle with a center at the given location of the attached device and a range around that location. Publications and subscriptions do have a definable, finite duration, after which they are deleted from the Matchmore cloud service and don’t participate anymore in the matching process.

Publication
Parameters Description
id The id (UUID) of the publication
createdAt The timestamp of the publication creation in seconds since Jan 01 1970 (UTC)
deviceId The id (UUID) of the device to attach a publication to
topic The topic of the publication. This will act as a first match filter. For a subscription to be able to match a publication they must have the exact same topic
range The range of the publication in meters. This is the range around the device holding the publication in which matches with subscriptions can be triggered
duration The duration of the publication in seconds. If set to ‘0’ it will be instant at the time of publication. Negative values are not allowed
properties The dictionary of key, value pairs. Allowed values are number, boolean, string and array of aforementioned types
Subscription
Parameters Description
id The id (UUID) of the publication
createdAt The timestamp of the publication creation in seconds since Jan 01 1970 (UTC)
deviceId The id (UUID) of the device to attach a publication to
topic The topic of the publication. This will act as a first match filter. For a subscription to be able to match a publication they must have the exact same topic
selector This is an expression to filter the publications. For instance ‘job=’developer’’ will allow matching only with publications containing a ‘job’ key with a value of ‘developer’
range The range of the publication in meters. This is the range around the device holding the publication in which matches with subscriptions can be triggered
duration The duration of the publication in seconds. If set to ‘0’ it will be instant at the time of publication. Negative values are not allowed
pushers When match will occurs, they will be notified on these provided URI(s) address(es) in the pushers array
Topic

The Matchmore service organizes the traffic within any application into named topics. Clients connected to Matchmore can either be publishers (they announce their presence via messages), subscribers (they want to discover nearby information), or both. Publications (messages) are always published over a named topic. Topics are used to filter matches, so whilst billions of devices may cross each other, subscribers will only receive the matches on the topics they subscribe to.

Topics are uniquely identified by a string specified when publishing or subscribing to a topic. Publishers and subscribers are asynchronous:

  • a publisher can publish a message without any subscribers on that particular topic, but later when a Subscription is created on that topic and when the ranges overlap there will be a match;
  • subscribers can listen on topics that don’t have publishers yet, similarly if a Publication is created later on and if both zones overlap there will be a match;
  • arbitrarily many subscribers can match with a single publication published on a topic;
  • the other way around is also possible, many publishers can match with a single subscriber on a topic. In other words, Matchmore topics handle one-to-many, many-to-one, and many-to-many relationships.
Properties & selector

Inside of publications messages and subscriptions, Matchmore allows accurate filtering. Thanks to parameters properties and selector.

  • Publishers :

Publications are customizable, using their properties parameter.

Properties are a Map Data Structure, where you can set keys and values pairs to allow finer filtering. The following data types are allowed in Properties: String, Int, Set and Boolean.

  • Subscribers :

Selector parameter allow the subscribers to filter incoming matches based on the publication’s properties.

Here is a list of operators you can use to filter incoming matches:

Supported SQL operators Description
Comparison Operators  
= Equal to
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to
<> Not equal to
Logical Operators  
ALL TRUE if all of the subquery values meet the condition
AND TRUE if all the conditions separated by AND is TRUE
ANY TRUE if any of the subquery values meet the condition
BETWEEN TRUE if the operand is within the range of comparisons
IN TRUE if the operand is equal to one of a list of expressions
LIKE TRUE if the operand matches a pattern
NOT Displays a record if the condition(s) is NOT TRUE
OR TRUE if any of the conditions separated by OR is TRUE
Range

When publishing or subscribing, you can decide the range in which it is interesting to start being discovered or discovering. The range is defined in meters. Upper limit is 5000 meters and lower limit is 1 meter.

Duration

When publishing or subscribing, you decide how long it is useful for you to be discovered or discovering other devices. The duration is defined in seconds. There is no upper limit to duration and you can’t set negative duration.

Subscription’s Pushers

With pushers, you can choose how and where you want to be notified when matches occur. You can stream matches directly to another queueing service, device or server. For example, you could persist each match of a user to your own database, start counting matches, trigger an event if a device has matched with a location that indicates that it has reached its destination, trigger execution of code on your server and so on. Pushers help to solve many of the challenges associated with consuming matches data server-side or client-side.

Example of use for publications and subscriptions

Imagine a French tourist application in the city of Paris. The tourism office is interested to know how many of their application’s users pass-by the Eiffel tower. This data may, for instance, be useful to anticipate rush hours.

  1. Create a Pin device to represent the Eiffel tower.
    // Monument's location
    let eiffelTowerLocation = Location.init(latitude: 48.858093, longitude: 2.294694)
    var myEiffelPin = PinDevice.init(name: "Eiffel tower", location: eiffelTowerLocation )
    MatchMore.createPinDevice(pinDevice: myEiffelPin, completion: { (result) in
     switch result{
     case .success(let pin):
         // Store this created Pin in the variable myEiffelPin
         myEiffelPin = pin
         // Start monitoring for matches
         MatchMore.startMonitoringMatches(forDevice: pin)
     case .failure(let error):
         print("\(String(describing: error?.message))")
         // make sure your variable myPinDevice doesn't no contain a device that does not exist
         myEiffelPin = nil
     }
    })
    
  2. You know that each of your application’s user has a publication on the topic “eiffel-tower” attached to their main device. Some useful information are known when the users login to your app, let’s save this information in the publication properties for later use.
    MatchMore.startUsingMainDevice { result in
     let userProperties : [String: Any] = ["name":"Jon",
                                           "age": 24,
                                           "gender":"male",
                                           "isTourist": true]
     let publication = Publication.init(topic: "eiffel-tower", range: 10, duration: 5000, properties: userProperties)
     MatchMore.createPublicationForMainDevice(publication: publication, completion: {result in
         switch result {
         case .success(let publication):
             print(publication.encodeToJSON())
         case .failure(let error):
             print("\(String(describing: error?.message))")
         }
     })
    }
    
  3. Finally, you need to attach a subscription to the Eiffel tower itself created above as a pin Device. Each day is 86400 second long so you set that duration to have a daily Subscription. You are now ready to detect any of your app users passing-by the Eiffel-tower.
    let subscription = Subscription.init(topic: "eiffel-tower", range: 50, duration: 86400, selector: "isTourist = true")
    MatchMore.createSubscription(subscription: subscription, forDevice: myEiffelPin, completion: {result in
     switch result{
     case .success(let sub):
         print(sub.encodeToJSON())
     case .failure(let error):
         print("\(String(describing: error?.message))")
     }
    })
    

Match

A match between a Publication and a Subscription occurs when both of the following two conditions hold:

  1. There is a *context match**: when the subscription zone overlaps with the publication zone. It also works with beacons based on the proximity distance detection.

  2. There is a content match: the publication and the subscription match with respect to their properties and selector, i.e., they were issued on the same topic and the evaluation of the selector against the properties returns a True evaluation.

Whenever a match between a Publication and a Subscription occurs, the device owning the subscription receives that match asynchronously via a push notification, if a push endpoint has been defined. A push endpoint is an URI which is able to consume matches. The push endpoint doesn’t necessary point to a mobile device but is rather a very flexible mechanism to define where the matches should be delivered. More than one push endpoint can be active on the same Subscription which means that you can push your matches to different locations at the same time. Look for pushers for more information.

Matches can also be retrieved by issuing a API call for a particular device.

Example: How to handle a match

You need to make the class of your handler conform to MatchDelegate protocol and implement onMatchClosure.

Here is an example of class: MatchHandler.swift

class MatchHandler: MatchDelegate {
    var onMatch: OnMatchClosure?
    init(_ onMatch: @escaping OnMatchClosure) {
        self.onMatch = onMatch
    }
}

Create an instance of MatchHandler class and add it to the match delegates:

let matchHandler = MatchHandler.init({ matches, device in
    print(matches.description)
    print(device)
})
MatchMore.matchDelegates.add(matchHandler)

In this example, for every match there will be a message printed in the console describing all the received matches and their related device.

iOS SDK

This sdk is provided as open-source software:

  iOS SDK on Github

Swift

Get Started

To include Matchmore SDK in your project you need to use CocoaPods.

CocoaPods

If you don’t have CocoaPods installed on your computer, you’ll need to execute this command in the terminal:

sudo gem install cocoapods

When installation is done, open Terminal, locate to your project folder and enter the following command:

pod init

It will create a file named Podfile in the main directory of the project. Open the Podfile and add the following line under use_frameworks.

pod 'Matchmore'

Save the Podfile, and inside Terminal enter the following command:

pod install

Quickstart example

Setup application API key and world, get it for free from http://matchmore.io/.

Our quick sample shows you how to create a first device, a publication, a subscription and get the matches.

import Matchmore // <- Here is our Matchmore module import.
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    var exampleMatchHandler: ExampleMatchHandler!

    func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Start Matchmore by providing the api-key.
        let config = MatchMoreConfig(apiKey: "YOUR_API_KEY")
        Matchmore.configure(config)

        // Create first device, publication and subscription. Please note that we're not caring about errors right now.
        Matchmore.startUsingMainDevice { result in
            guard case let .success(mainDevice) = result else { print(result.errorMessage ?? ""); return }
            print("Using device: \n\(mainDevice.encodeToJSON())")

            // Start Monitoring Matches
            self.exampleMatchHandler = ExampleMatchHandler { matches, _ in
                print("You've got new matches!!! \n\(matches.map { $0.encodeToJSON() })")
            }
            Matchmore.matchDelegates += self.exampleMatchHandler

            // Create New Publication
            Matchmore.createPublicationForMainDevice(publication: Publication(topic: "Test Topic", range: 20, duration: 100, properties: ["test": "true"]), completion: { result in
                switch result {
                case let .success(publication):
                    print("Pub was created: \n\(publication.encodeToJSON())")
                case let .failure(error):
                    print("\(String(describing: error?.message))")
                }
            })

            // Polling
            Matchmore.startPollingMatches(pollingTimeInterval: 5)
            self.createPollingSubscription()

            // Socket (requires world_id)
            Matchmore.startListeningForNewMatches()
            self.createSocketSubscription()

            // APNS (Subscriptions is being created after receiving device token)
            UIApplication.shared.registerForRemoteNotifications()

            Matchmore.startUpdatingLocation()
        }
        return true
    }

    // Subscriptions

    // Create a WebSocket subscription to Matchmore, and get your match notification via WebSocket
    func createSocketSubscription() {
        let subscription = Subscription(topic: "Test Topic", range: 20, duration: 100, selector: "test = true")
        subscription.pushers = ["ws"]
        Matchmore.createSubscriptionForMainDevice(subscription: subscription, completion: { result in
            switch result {
            case let .success(sub):
                print("Socket Sub was created \n\(sub.encodeToJSON())")
            case let .failure(error):
                print("\(String(describing: error?.message))")
            }
        })
    }

    // Create a polling subscription to Matchmore, and get your match notification via polling
    func createPollingSubscription() {
        let subscription = Subscription(topic: "Test Topic", range: 20, duration: 100, selector: "test = true")
        Matchmore.createSubscriptionForMainDevice(subscription: subscription, completion: { result in
            switch result {
            case let .success(sub):
                print("Polling Sub was created \n\(sub.encodeToJSON())")
            case let .failure(error):
                print("\(String(describing: error?.message))")
            }
        })
    }

    // Create a Apple push notification service subscription to Matchmore, and get your match notification via APNS
    func createApnsSubscription(_ deviceToken: String) {
        let subscription = Subscription(topic: "Test Topic", range: 20, duration: 100, selector: "test = true")
        subscription.pushers = ["apns://" + deviceToken]
        Matchmore.createSubscriptionForMainDevice(subscription: subscription, completion: { result in
            switch result {
            case let .success(sub):
                print("APNS Sub was created \n\(sub.encodeToJSON())")
            case let .failure(error):
                print("\(String(describing: error?.message))")
            }
        })
    }

    // MARK: - APNS
    // To add Apple push notification service you need to add these functions
    func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        // Convert token to string
        let deviceTokenString = deviceToken.reduce("", { $0 + String(format: "%02X", $1) })
        Matchmore.registerDeviceToken(deviceToken: deviceTokenString)

        createApnsSubscription(deviceTokenString)
    }

    func application(_: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
        Matchmore.processPushNotification(pushNotification: userInfo)
    }
}

Define an object that’s MatchDelegate implementing OnMatchClosure. This object will handle the matches.

class ExampleMatchHandler: MatchDelegate {
    var onMatch: OnMatchClosure?
    init(_ onMatch: @escaping OnMatchClosure) {
        self.onMatch = onMatch
    }
}

Configuration

Request permission for Location Services

Depending on your needs, your app may require Location Services to work in the background, which means we need to set up Location Services usage description. This description will be shown to the user when asking them about allowing the app to access their location.

Users must grant permission for an app to access personal information, including the current location. Although people appreciate the convenience of using an app that has access to this information, they also expect to have control over their private data.

In the project navigator, find the Info.plist file, right click on it, and select “Open As”, “Source Code”. Then, inside the top-level section, add:

<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>

When opening app for the first time, the system will prompt authorization alert with the filled description. Users can decide wether to accept or reject the request permission.

NSLocationWhenInUseUsageDescription should describe how your app uses Location Services when it’s in use (or “in the foreground”).

NSLocationAlwaysUsageDescription should describe how your app uses Location Services both when in use, and in the background. This description is only for users of your app with iOS 10 or earlier. The user can agree to the “always” authorization, or disable Location Services in the app completely.

NSLocationAlwaysAndWhenInUseUsageDescription should describe how your app use Location Services both when in use, and in the background. This description is only for users of your app with iOS 11. The user can select between the “always” or “only when in use” authorizations, or disable Location Services in the app completely.

 

Good practice

Request permission at launch only when necessary for your app to function. Users won’t be bothered by this request if it’s obvious that your app depends on their personal information to operate. For example, an app might only request access to the current location when activating a location tracking feature.

Add SDK to the project

Matchmore SDKs are very malleable. The SDK is configured by default to work for general cases. But it is possible to configure it according to your needs. First set up Matchmore SDK Cloud credentials, this will allow the SDK to communicate with Matchmore Cloud on your behalf.

You can generate a token API-key for yourself on matchmore.io. When you have your token, create your MatchMoreConfig with your API-key.

// MatchMoreConfig is a structure that defines all variables needed to configure MatchMore SDK.
public struct MatchMoreConfig {
    let apiKey: String
    let serverUrl: String
    let customLocationManager: CLLocationManager?

    public init(apiKey: String,
                serverUrl: String = "https://api.matchmore.io/v5",
                customLocationManager: CLLocationManager? = nil) {
        self.apiKey = apiKey
        self.serverUrl = serverUrl
        self.customLocationManager = customLocationManager
    }
}

Starting with a basic setup. Use MatchmoreSDK with default configuration.

// Basic setup
let config = MatchMoreConfig(apiKey: "YOUR_API_KEY") // create your own app at https://www.matchmore.io
MatchMore.configure(config)

Start/Stop location updates

Both custom and default location managers can be started or stopped by simply calling:

// Start
Matchmore.startUpdatingLocation()

// Stop
Matchmore.stopUpdatingLocation()

Configure custom location manager

Location manager can be easily overwritten by custom configuration like this:

lazy var locationManager: CLLocationManager = {
        let locationManager = CLLocationManager()
        locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
        locationManager.activityType = .fitness
        locationManager.pausesLocationUpdatesAutomatically = true
        locationManager.allowsBackgroundLocationUpdates = true
        return locationManager
    }()

Then make sure you inject your customer manager when configuring Matchmore:

let config = MatchMoreConfig(apiKey: "API_KEY",
              customLocationManager: self.locationManager)

Tutorials

Create a Mobile Device

If you need to create other mobile than device than main mobile device you can do so by:

Matchmore.mobileDevices.create(item: device) { (result) in
    switch result {
    case let .success(device):
        print("Created Mobile Device: \(device.id)")
    case let .failure(error):
        print(error?.localizedDescription)
    }
}

Create a Pin Device

To create new pin device you can simply call:

let location = Location(latitude: 46.519962, longitude: 6.633597, altitude: 0.0, horizontalAccuracy: 0.0, verticalAccuracy: 0.0)
let pin = PinDevice(name: "Pin Device", location: location)
Matchmore.createPinDevice(pinDevice: pin) { result in
    switch result {
    case let .success(device):
        print("Created Pin Device: \(device.id)")
    case let .failure(error):
        print(error?.localizedDescription)
    }
}

Start/Stop Monitoring for device

When creating a main device, it is being monitored automatically. You can monitor any device. For the following example, we monitor a pin device.

let location = Location(latitude: 46.519962, longitude: 6.633597, altitude: 0.0, horizontalAccuracy: 0.0, verticalAccuracy: 0.0)
let pin = PinDevice(name: "Pin Device", location: location)
Matchmore.createPinDevice(pinDevice: pin) { result in
    switch result {
    case let .success(device):
        print("Created Pin Device: \(device.id)")
        Matchmore.startMonitoringMatches(forDevice: device) // <- Start the monitoring of this pin device
    case let .failure(error):
        print(error?.localizedDescription)
    }
}

To stop the monitoring a device :

Matchmore.stopMonitoringMatches(forDevice: device) // <- Stop the monitoring of the instance in variable "device".
Apple Push Notification service

We use Apple Push Notification service (APNs). It allows app developers to propagate information via notifications from servers to iOS, tvOS and macOS devices.

In order to get the certificates and upload them to our portal, **A membership in the Apple iOS developer program is required.**

  1. Enabling the Push Notification Service via Xcode

First, go to App Settings -> General and change Bundle Identifier to something unique.

Right below this, select your development Team. This must be a paid developer account.

After that, you need to create an App ID in your developer account that has the push notification entitlement enabled. Xcode has a simple way to do this. Go to App Settings -> Capabilities and flip the switch for Push Notifications to On.

Note: If any issues occur, visit the Apple Developer Center. You may simply need to agree to a new developer license.

At this point, you should have the App ID created and the push notifications entitlement should be added to your project. You can log into the Apple Developer Center and verify this.

  1. Enable Remote Push Notifications on your App ID

Sign in to your account in the Apple developer center, and then go to Certificates, Identifiers & Profiles

Go to Identifiers -> App IDs. If you followed previous instructions, you should be able to see the App ID of your application( create it if you don’t see it). Click on your application and ensure that the Push Notifications service is enabled.

Click on the Development or Production certificate button and follow the steps. We recommend you for a Production push certificate. It works for most general cases and is the required certificate for Apple store.

Difference between Development and Production certificate

The choice of APNs host depends on which kinds of iOS app you wish to send push notifications to. There are two kinds of iOS app:

Published apps. These are published to the App Store and installed from there. These apps go through the usual App Store publication process, such as code-signing.

Development apps. These are “everything else”, such as apps installed from Xcode, or through private app publication systems.

 

Warning

Do not submit Apps to Apple with Development certificates.

  1. Exporting certificates

After completing the steps to generate a Development SSL or Production SSL certificat and downloading the certificate.

From Finder, double-click the ~/certificate.cer file, or run open ~/certificate.cer. This will open Keychain Access. The certificate should now be added to the list under “My Certificates”.

Right click on the certificate, and select “Export ….”. Select the p12 format and create a password for the file, do not lose this password as you will need it a next step. For now : Leave this password blank.

Upload the generated certificate to Matchmore Portal.

  1. Enable Push Notification in Application

Add the following lines to your appDelegate.

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    // Convert token to string
    let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
    MatchMore.registerDeviceToken(deviceToken: deviceTokenString)
    createApnsSubscription()
}

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
    MatchMore.processPushNotification(pushNotification: userInfo)
}

You can now start sending notifications to your users.

Here is an example of a subscription getting matches with Apple Push Notification service :

// Create a Apple push notification service subscription to Matchmore, and get your match notification via APNS
func createApnsSubscription(_ deviceToken: String) {
    let subscription = Subscription(topic: "Test Topic", range: 20, duration: 100, selector: "test = true")
    subscription.pushers = ["apns://" + deviceToken] // <- Adding "apns://myDeviceToken" in the pushers parameter will activate the Apple Push Notification service
    Matchmore.createSubscriptionForMainDevice(subscription: subscription, completion: { result in
        switch result {
        case let .success(sub):
            print("APNS Sub was created \n\(sub.encodeToJSON())")
        case let .failure(error):
            print("\(String(describing: error?.message))")
        }
    })
}
WebSocket

When it comes to deliver matches, Matchmore SDK uses WebSocket as well to provide alternative solutions to APNs. By initializing this, you inform Matchmore Cloud service that you want to be notified via WebSocket.

    // MARK: - Socket
    func openSocketForMatches()
    func closeSocketForMatches()

Here is an example of a subscription getting matches with WebSocket :

// Create a WebSocket subscription to Matchmore, and get your match notification via WebSocket
func createSocketSubscription() {
    let subscription = Subscription(topic: "Test Topic", range: 20, duration: 100, selector: "test = true")
    subscription.pushers = ["ws"] // <- Adding "ws" in the pushers parameter will activate the WebSocket
    Matchmore.createSubscriptionForMainDevice(subscription: subscription, completion: { result in
        switch result {
        case let .success(sub):
            print("Socket Sub was created \n\(sub.encodeToJSON())")
        case let .failure(error):
            print("\(String(describing: error?.message))")
        }
    })
}
Polling

Use these functions to start or stop polling matches from Matchmore Cloud.

    // MARK: - Polling
    func startPollingMatches(pollingTimeInterval: 10)
    func stopPollingMatches()

Here is an example of a subscription getting matches with polling :

// Create a polling subscription to Matchmore, and get your match notification via polling
func createPollingSubscription() {
    let subscription = Subscription(topic: "Test Topic", range: 20, duration: 100, selector: "test = true")
    Matchmore.createSubscriptionForMainDevice(subscription: subscription, completion: { result in
        switch result {
        case let .success(sub):
            print("Polling Sub was created \n\(sub.encodeToJSON())")
        case let .failure(error):
            print("\(String(describing: error?.message))")
        }
    })
}

Publish

// Create New Publication
var pub = Publication(topic: "Test Topic", range: 100, duration: 30, properties: ["test": "true", "price": 199])
Matchmore.createPublicationForMainDevice(publication: pub, completion: { result in
    switch result {
    case let .success(publication):
        print("Pub was created: \n\(publication.encodeToJSON())")
    case let .failure(error):
        print("\(String(describing: error?.message))")
    }
})

Subscribe

// Create a WebSocket subscription to Matchmore, and get your match notification via WebSocket
func createSocketSubscription() {
    let subscription = Subscription(topic: "Test Topic", range: 100, duration: 30, selector: "test = true")
    subscription.pushers = ["ws"] // <- Adding "ws" in the pushers parameter will activate the WebSocket
    Matchmore.createSubscriptionForMainDevice(subscription: subscription, completion: { result in
        switch result {
        case let .success(sub):
            print("Socket Sub was created \n\(sub.encodeToJSON())")
        case let .failure(error):
            print("\(String(describing: error?.message))")
        }
    })
}

// Create a polling subscription to Matchmore, and get your match notification via polling
func createPollingSubscription() {
    let subscription = Subscription(topic: "Test Topic", range: 20, duration: 100, selector: "test = true")
    Matchmore.createSubscriptionForMainDevice(subscription: subscription, completion: { result in
        switch result {
        case let .success(sub):
            print("Polling Sub was created \n\(sub.encodeToJSON())")
        case let .failure(error):
            print("\(String(describing: error?.message))")
        }
    })
}

// Create a Apple push notification service subscription to Matchmore, and get your match notification via APNS
func createApnsSubscription(_ deviceToken: String) {
    let subscription = Subscription(topic: "Test Topic", range: 20, duration: 100, selector: "test = true")
    subscription.pushers = ["apns://" + deviceToken] // <- Adding "apns://myDeviceToken" in the pushers parameter will activate the Apple Push Notification service
    Matchmore.createSubscriptionForMainDevice(subscription: subscription, completion: { result in
        switch result {
        case let .success(sub):
            print("APNS Sub was created \n\(sub.encodeToJSON())")
        case let .failure(error):
            print("\(String(describing: error?.message))")
        }
    })
}

Get Matches

//you can call to get matches at your leisure, if you don't want to use the monitors. In the end the monitors are calling exactly this method for you.
Matchmore.refreshMatches()

Local States request (Create, Find, FindAll, Delete and DeleteAll)

// You can access locally cached subscriptions, publications and devices
Matchmore.subscriptions
Matchmore.publications
Matchmore.mainDevice
Matchmore.pinDevices
Matchmore.knownBeacons

// you can delete also your sub, pub and device by calling:
Matchmore.subscriptions.delete(item: sub, completion: { error in
                print(error?.message)
            })
Matchmore.publications.delete(item: pub, completion: { error in
                print(error?.message)
            })
Matchmore.pinDevices.delete(item: pin, completion: { (error) in
                print(error?.message)
            })
Matchmore.mobileDevices.delete(item: mobile, completion: { (error) in
                print(error?.message)
            })

Android SDK

Android Matchmore SDK is a contextualized publish/subscribe model which can be used to model any geolocated or proximity based mobile application. Save time and make development easier by using our SDK. We are built on Android Location services and we also provide iBeacons compatibility.

The Matchmore is a static wrapper that provides you all the functions you need to use our SDK. You can access default instance of matchmore by Matchmore.instance.

This sdk is provided as open-source software:

  Android SDK on Github

SDK is written using Kotlin 1.2. Android Matchmore SDK requires Android 4.4+

Kotlin

Get Started

You can install Matchmore SDK using standard Android package managers:

Gradle

Add it in your root build.gradle at the end of repositories:

allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io' }
		}
	}
}

SDK

implementation 'com.github.matchmore.alps-android-sdk:sdk:<latest version>'

Rx Wrapper

implementation 'com.github.matchmore.alps-android-sdk:rx:<latest version>'
Maven
<repositories>
		<repository>
		    <id>jitpack.io</id>
		    <url>https://jitpack.io</url>
		</repository>
</repositories>

SDK

<dependency>
    <groupId>com.github.matchmore.alps-android-sdk</groupId>
    <artifactId>sdk</artifactId>
    <version>latest version</version>
</dependency>

Rx Wrapper

<dependency>
    <groupId>com.github.matchmore.alps-android-sdk</groupId>
    <artifactId>rx</artifactId>
    <version>latest version</version>
</dependency>

Quickstart example

For Kotlin Developers:

package io.matchmore.sdk.example

import android.Manifest
import android.annotation.SuppressLint
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.widget.Toast
import com.gun0912.tedpermission.PermissionListener
import com.gun0912.tedpermission.TedPermission
import io.matchmore.config.SdkConfigTest
import io.matchmore.sdk.Matchmore
import io.matchmore.sdk.MatchmoreSDK
import io.matchmore.sdk.api.models.Publication
import io.matchmore.sdk.api.models.Subscription


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Matchmore.config(this, "Your-api-key", true)
        Matchmore.instance.apply {
            startUsingMainDevice(
                    { device ->
                        Log.i(TAG, "start using device ${device.name}")

                        val publication = Publication("Test Topic", 20.0, 100.0)
                        publication.properties = hashMapOf("test" to "true")
                        createPublicationForMainDevice(publication, { result ->
                            Log.i(TAG, "Publication created ${result.topic}")
                        }, Throwable::printStackTrace)

                        matchMonitor.addOnMatchListener { matches, _ ->
                            Log.i(TAG, "Matches found: ${matches.size}")
                        }
                        createPollingSubscription()
                        checkLocationPermission()
                    }, Throwable::printStackTrace)
        }
    }

    override fun onResume() {
        super.onResume()
        Matchmore.instance.matchMonitor.startPollingMatches()
    }

    override fun onPause() {
        super.onPause()
        Matchmore.instance.matchMonitor.stopPollingMatches()
    }

    override fun onDestroy() {
        super.onDestroy()
        Matchmore.instance.apply {
            stopRanging()
            stopUpdatingLocation()
        }
    }

    private fun MatchmoreSDK.createSocketSubscription() {
        val subscription = Subscription("Test Topic", 20.0, 100.0)
        subscription.selector = "test = 'true'"
				subscription.pushers = mutableListOf("ws")
        createSubscriptionForMainDevice(subscription, { result ->
            Log.i(TAG, "Subscription created ${result.topic}")
        }, Throwable::printStackTrace)
    }

    private fun MatchmoreSDK.createPollingSubscription() {
        val subscription = Subscription("Test Topic", 20.0, 100.0)
        subscription.selector = "test = 'true'"
        createSubscriptionForMainDevice(subscription, { result ->
            Log.i(TAG, "Subscription created ${result.topic}")
        }, Throwable::printStackTrace)
    }

    private fun MatchmoreSDK.createFcmSubscription(deviceToken: String) {
        val subscription = Subscription("Test Topic", 20.0, 100.0)
        subscription.selector = "test = 'true'"
				subscription.pushers = mutableListOf("fcm://" + deviceToken)
        createSubscriptionForMainDevice(subscription, { result ->
            Log.i(TAG, "Subscription created ${result.topic}")
        }, Throwable::printStackTrace)
    }

    private fun checkLocationPermission() {
        val permissionListener = object : PermissionListener {
            @SuppressLint("MissingPermission")
            override fun onPermissionGranted() {
                Matchmore.instance.apply {
                    startUpdatingLocation()
                    startRanging()
                }
            }

            override fun onPermissionDenied(deniedPermissions: ArrayList<String>) {
                Toast.makeText(this@MainActivity, R.string.if_you_reject, Toast.LENGTH_SHORT).show()
            }
        }
        TedPermission.with(this)
                .setPermissionListener(permissionListener)
                .setDeniedMessage(R.string.if_you_reject)
                .setPermissions(Manifest.permission.ACCESS_FINE_LOCATION)
                .check()
    }

    companion object {
        private const val TAG = "MatchMore"
    }
}

Configuration

Request permission for Location Services

Depending on your needs, your app may require Location Services to work in the background, which means we need to set up Location Services usage description. This description will be shown to the user when asking them about allowing the app to access their location.

Users must grant permission for an app to access personal information, including the current location. Although people appreciate the convenience of using an app that has access to this information, they also expect to have control over their private data.

In the project navigator, find the file AndroidManifest.xml (App/manifests), double click on it. Then, inside tag, add the following lines:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

When opening app for the first time, the system will prompt authorization alert with the filled description. Users can decide wether to accept or reject the request permission.

<p><em class="fa fa-thumbs-up"> </em></p>
<h4 class="callout-title" id="good-practice">Good practice</h4>
<p>Request permission at launch only when necessary for your app to function. Users won’t be bothered by this request if it’s obvious that your app depends on their personal information to operate. For example, an app might only request access to the current location when activating a location tracking feature.</p>

Add SDK to the project

Matchmore SDKs are very malleable. The SDK is configured by default to work for general cases. But it is possible to configure it according to your needs. First set up Matchmore SDK Cloud credentials, this will allow the SDK to communicate with Matchmore Cloud on your behalf.

You can generate a token API-key for yourself on matchmore.io. When you have your token, create your MatchMoreConfig with your API-key.

// MatchMoreConfig is a structure that defines all variables needed to configure MatchMore SDK.
data class MatchmoreConfig(
        var context: Context,
        val apiKey: String,
        var debugLog: Boolean
) {

    init {
        context = context.applicationContext
    }
}

Starting with a basic setup. Use MatchmoreSDK with default configuration.

Basic configuration:

class ExampleApp : MultiDexApplication() {
    override fun onCreate() {
        super.onCreate()
        Matchmore.config(this, "YOUR_API_KEY", true)
    }
}

Start/Stop location updates

private fun checkLocationPermission() {
        val permissionListener = object : PermissionListener {
            @SuppressLint("MissingPermission")
            override fun onPermissionGranted() {
                Matchmore.instance.apply {
                    startUpdatingLocation() // <- Start location updates
										stopUpdatingLocation() // <- Stop location udpates
                }
            }

            override fun onPermissionDenied(deniedPermissions: ArrayList<String>) {
                Toast.makeText(this@MainActivity, R.string.if_you_reject, Toast.LENGTH_SHORT).show()
            }
        }
        TedPermission.with(this)
                .setPermissionListener(permissionListener)
                .setDeniedMessage(R.string.if_you_reject)
                .setPermissions(Manifest.permission.ACCESS_FINE_LOCATION)
                .check()
    }

Configure custom location manager

As you already saw MatchmoreConfig plays key role in configuring the SDK, though there’re more custom integrations you can do. For example it’s possible to entirely change location provider:

val locationProvider = object : MatchmoreLocationProvider {
	override fun startUpdatingLocation(sender: LocationSender) {
		sender.sendLocation(MatchmoreLocation(createdAt = System.currentTimeMillis(), latitude = 80.0, longitude = 80.0))
	}
	override fun stopUpdatingLocation() { }
}
// update location
matchMoreSdk.startUpdatingLocation(locationProvider)

Tutorials

Create a Mobile Device

Matchmore.instance.startUsingMainDevice(
                { device ->
                    Log.i(TAG, "start using device ${device.name}")
                }, Throwable::printStackTrace)

Create a Pin Device

val pinDevice = PinDevice("New Pin Device", MatchmoreLocation(latitude = 46.519962, longitude = 6.633597))
Matchmore.instance.devices.create(pinDevice, { device ->
	Log.i(TAG, "Created Pin Device: ${device.id}")
}, Throwable::printStackTrace)

Start/Stop Monitoring for a device

var pinDevice = PinDevice("Pin Device", location = MatchmoreLocation(latitude = 46.519962, longitude = 6.633597))

Matchmore.instance.createPinDevice(pinDevice, { device ->
		Log.i(TAG, "Created Pin Device: ${device.name}")
		Matchmore.instance.matchMonitor.startMonitoringFor(device) // <- Start the monitoring of this pin device
}, Throwable::printStackTrace)

Google Firebase Cloud Notification

To configure push notifications you need to call this code. All token will be propagated to subscriptions created by main device that have fcm:// in pushers.

val token = "FCM_TOKEN"
Matchmore.instance.registerDeviceToken(token)

WebSocket

The other option of getting matches from Matchmore server is a web socket. Note that socket is alternative for push notifications, but it’s more energy consuming. The biggest advantage of using it is permission less configuration. Though this solution will work only when application is active. To make web socket work your subscription’s selector has to contain ws. Then you can open socket connection by calling:

// Opening socket
Matchmore.instance.matchMonitor.openSocketForMatches()

// Closing socket
Matchmore.instance.matchMonitor.closeSocketForMatches()

Polling

Use these functions to start or stop polling matches from Matchmore Cloud.

// Start polling matches every 1000 miliseconds
Matchmore.instance.matchMonitor.startPollingMatches(1000)
// Stop polling
Matchmore.instance.matchMonitor.stopPollingMatches()

Publish

Creating publication on main device:

val publication = Publication("Test Topic", 1000.0, 1000.0)
publication.properties = hashMapOf("isGreen" to true, "name" to "A New Pub")
createPublicationForMainDevice(publication, { result ->
	Log.i(TAG, "Publication created ${result.topic}")
}, Throwable::printStackTrace)

Subscribe

Creating subscription on a pin device:

val subscription = Subscription("Test Topic", 1.0, 0.0)
subscription.selector = "isGreen = true" // Getting matches will all publication that have isGreen property set to true
// Note:
// "ws" is websocket hook
// "fcm://" is push notification hook
subscription.pushers = mutableListOf("ws", "fcm://")
createSubscription(subscription, pinDeviceId, { result ->
	Log.i(TAG, "Subscription created ${result.topic}")
}, Throwable::printStackTrace)

Get Matches

Start and stop listening for new matches by adding listener:

val listener = { matches, device ->
	Log.i(TAG, "Matches found: ${matches.size} on device: ${device}")
}
Matchmore.instance.matchMonitor.addOnMatchListener(listener)

// remove when not needed anymore
Matchmore.instance.matchMonitor.removeOnMatchListener(listener)

Local States request

// You can access locally cached subscriptions, publications and devices
Matchmore.instance.subscriptions
Matchmore.instance.publications
Matchmore.instance.devices
Matchmore.instance.knownBeacons

// you can delete also your sub, pub and device by calling:
Matchmore.instance.subscriptions.delete(sub)
Matchmore.instance.publications.delete(pub)
Matchmore.instance.devices.delete(pin)
Matchmore.instance.devices.delete(mobile)

JavaScript SDK

This sdk is provided as open-source software:

  Javascript SDK on Github

Get started

NPM

In a project backed by npm (like react) you can just type

npm install @matchmore/matchmore --save

Yarn

To include Matchmore SDK in your project you need to use Yarn.

yarn add @matchmore/matchmore

HTML Document

In a HTML document

<script src="../../dist/web/matchmore.js"></script>

Get the API key

Setup application API key and world, get it for free from matchmore.io/.

And then start your application with minimum config, with in memory persistence

import { Manager } from "matchmore";
//...
this.manager = new Manager(
  "<Your api key>"
)

More robust setup

    import { Manager, LocalStoragePersistenceManager } from "matchmore";
    //...
    const localPersistenceManager = new LocalStoragePersistenceManager();
    await localPersistenceManager.load();
    this.manager = new Manager(
      apiKey,
      undefined,
      localPersistenceManager,
      // undefined,
      {
        enableHighAccuracy: false,
        timeout: 60000,
        maximumAge: 60000
      }
    )

Web Setup

Web setup can done inline like this

matchmore.PlatformConfig.storage = {
  save: (key, value) => window.localStorage.setItem(key, value),
  load: (key) => window.localStorage.getItem(key),
  remove: (key) => window.localStorage.removeItem(key),
}

React Native Setup

React Native persistence requires some setup, best if put in its own file and import at the start of the application

const { AsyncStorage } = require('react-native');

const save = async (key, value) => {
  await AsyncStorage.setItem(key, value);
}

const load = async (key) => {
  return await AsyncStorage.getKey(key);
}

const remove = async (key) => {
  return await  AsyncStorage.removeItem(key);
}

module.exports = {
  save,
  load,
  remove
}

Example

 matchmore.PlatformConfig.storage = {
              save: (key, value) => window.localStorage.setItem(key, value),
              load: (key) => window.localStorage.getItem(key),
              remove: (key) => window.localStorage.removeItem(key),
            }
            const localStoragePersistenceManager = new matchmore.LocalStoragePersistenceManager();

            let manager = new matchmore.Manager(
              apiKey,
              undefined,
              localStoragePersistenceManager
            );
            manager.createMobileDevice("me", "browser", "").then(device => {
                manager.startMonitoringMatches();
                manager.onMatch = (match) => {
                    writeToScreen(match.publication.properties.name + " matched!");
                };
                return device;
            }).then(device => {
                //lets wait for the current location
                let location = new Promise(resolve => {
                    manager.onLocationUpdate = (loc) => {
                        writeToScreen("Got Location");
                        resolve(loc);
                    };
                    manager.startUpdatingLocation();

                });

                location.then(location => {
                  const { latitude, longitude, altitude } = location.coords;
                  const coords = {
                    latitude,
                    longitude,
                    altitude: altitude || 0,
                  }
                    let publication = manager.createPinDevice(
                        "Our test pin",
                        coords,
                    ).then(pin => {
                        let p1 = manager.createPublication(
                            "my-topic",
                            100 /* m */,
                            20 /* s */,
                            { "age": 20, "name": "Clara" },
                            pin.id);
                        let p2 = manager.createPublication(
                            "my-topic",
                            100 /* m */,
                            20 /* s */,
                            { "age": 18, "name": "Justine" },
                            pin.id);
                        let p3 = manager.createPublication(
                            "my-topic",
                            100 /* m */,
                            20 /* s */,
                            { "age": 17, "name": "Alex" },
                            pin.id);
                        return Promise.all([p1, p2, p3]);
                    });
                }).then(_ => {
                    let subscription = manager.createSubscription(
                        "my-topic",
                        100 /* m */,
                        20 /* s */,
                        "age >= 18"
                    );
                    return subscription;
                });

            });

Developers are also free to use async/await syntax

async multiplePublications(){
   await manager.createPublication(
       "my-topic",
       100 /* m */,
       20 /* s */,
       { "age": 20, "name": "Clara" },
       pin.id);
   await manager.createPublication(
       "my-topic",
       100 /* m */,
       20 /* s */,
       { "age": 18, "name": "Justine" },
       pin.id);
   await manager.createPublication(
       "my-topic",
       100 /* m */,
       20 /* s */,
       { "age": 17, "name": "Alex" },
       pin.id);
   return;
}

Developer is free to mix and match the styles

Configuration

Request permission for Location Services

Add SDK to the project

import { Manager } from "matchmore";
//...
this.manager = new Manager(
  "<Your api key>"
)

More robust setup

    import { Manager, LocalStoragePersistenceManager } from "matchmore";
    //...
    const localPersistenceManager = new LocalStoragePersistenceManager();
    await localPersistenceManager.load();
    this.manager = new Manager(
      apiKey,
      undefined,
      localPersistenceManager,
      // undefined,
      {
        enableHighAccuracy: false,
        timeout: 60000,
        maximumAge: 60000
      }
    )

Start/Stop location updates

manager.startUpdatingLocation();
manager.stopUpdatingLocation();

Configure custom location manager

Manual update locations
await manager.updateLocation({
    latitude = 54.414662,
    longitude = 18.625498
});
await manager.updateLocation({
    latitude = 54.414662,
    longitude = 18.625498
}, deviceId);

Tutorials

Create a Mobile Device

First you need to create the main device

//use your own application specific names
//device token can be kept empty, but it is used for third party match delivery mechanics which we will introduce to the sdk soon, it can be considered also optional
await manager.createMobileDevice("my mobile device", "iOS", "<device_token>");
manager.startMonitoringMatches();
manager.onMatch = (match) => {
                    console.log(match.publication.properties.name + " matched!");
                };

Create a Pin Device

let newDevice = await manager.createPinDevice("pin", {
    latitude = 54.414662,
    longitude = 18.625498
});

Start/Stop Monitoring for a device

Apple Push Notification service

Google Firebase Cloud Notification

WebSocket

Polling

Publish

let publication =  await manager.createPublication(
      "my-topic",
      100 /* m */,
      20 /* s */,
      { "age": 20, "name": "Clara" });

Subscribe

let subscription = await this.manager.createSubscription(
      "my-topic",
      99999 /* m */,
      20 /* s */,
      "age >= 18"
    );

Get Matches

let matches = await manager.getAllMatches();
let otherDeviceMatches = await manager.getAllMatches(deviceId);
let specificMatch = await manager.getMatch(matchId);

Local States request

To access the local persisted entities you can just call them direct from the manager, they are regular array so you can query them whatever way you likes

let devices = this.manager.devices;
let publications = this.manager.publications;
let subscriptions = this.manager.subscriptions;

Demo

Couple of demos to be found in Javascript github.

Changelog

Supported Platform

.NET SDK

This sdk is provided as open-source software:

  .NET SDK on Github

Getting started

Creating your project

For Xamarin projects using the Shared Code strategy for sharing code use the Matchmore.Xamarin.SDK.

For web services or Xamarin.Forms applications using .NET Standard use the Matchmore.SDK. Refer to Customization

Installation

NuGet package

You can integrate Matchmore to your project via NuGet.

A NuGet-walkthrough can be found here https://docs.microsoft.com/en-us/visualstudio/mac/nuget-walkthrough

Configuration

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

Add SDK to project

Setup application API key and world, get it for free from http://matchmore.io/.

async Task SetupMatchmore()
{
    await Matchmore.SDK.Matchmore.ConfigureAsync("YOUR_API_KEY");
}

QuickStart example

Create main mobile device, publication and subscription. Please note that we’re not caring about errors right now.

// Configure Matchmore with your credentials
await Matchmore.SDK.Matchmore.ConfigureAsync("YOUR_API_KEY");
//you can access the device later by calling Matchmore.SDK.Matchmore.Instance.MainDevice
await Matchmore.SDK.Matchmore.Instance.SetupMainDeviceAsync();
//this will start a simple polling based service which queries the local location services frequently, there are iOS and Android implementation available, but for other platforms check the Customization Section
Matchmore.SDK.Matchmore.Instance.StartLocationService();

// Create the subscription
var sub = new Subscription
{
    Topic = "Test Topic",
    Duration = 30,
    Range = 100,
    Selector = "test = true and price <= 200"
};
// Start the creation of your subscription in Matchmore service
var createdSub = await Matchmore.SDK.Matchmore.Instance.CreateSubscriptionAsync(sub);
Console.WriteLine($"created subscription {createdSub.Id}");
var pubDevice = await Matchmore.SDK.Matchmore.Instance.CreateDeviceAsync(new PinDevice
{
    Name = "Publisher"
});
var pub = new Publication
{
    Topic = "Test Topic",
    Duration = 30,
    Range = 100,
    Properties = new Dictionary<string, object> {
        {"test", true},
        {"price", 199}
    }
};
//you can pass explicitly the device you would want to use, here we use a "virtual" second device for publication, like a pin
var createdPub = await Matchmore.SDK.Matchmore.Instance.CreatePublicationAsync(pub, pubDevice);
Console.WriteLine($"created publication {createdPub.Id}");
// To receive matches, you need to create a monitor
//default params of .SubscribeMatches() use your main device, Polling and Websocket as a channel delivery mechanism
var monitor = Matchmore.SDK.Matchmore.Instance.SubscribeMatches();
monitor.MatchReceived += (object sender, MatchReceivedEventArgs e) =>
{
    Console.WriteLine($"Got match from {e.Channel}, {e.Matches[0].Id}");
};
//if  you don't have access to your monitor, you can attach the event handler on the Matchmore Instance
Matchmore.SDK.Matchmore.Instance.MatchReceived += (object sender, MatchReceivedEventArgs e) =>
{
    Console.WriteLine($"Got match using global event handler {e.Matches[0].Id}");
};
//lets update locations for both devices, in real life the published would pass
await Matchmore.SDK.Matchmore.Instance.UpdateLocationAsync(new Location
{
    Latitude = 54.414662,
    Longitude = 18.625498
});
await Matchmore.SDK.Matchmore.Instance.UpdateLocationAsync(new Location
{
    Latitude = 54.414662,
    Longitude = 18.625498
}, pubDevice);

{: #net-tutorials}
### Tutorials

{: #net-start-stop}

Start/stop Matchmore

//Reset will stop monitors and location updates
Matchmore.SDK.Matchmore.Reset();

Start/Stop updating location

//this will start a simple polling based service which queries the local location services frequently, there are iOS and Android implementation available, but for other platforms check the Customization Section
Matchmore.SDK.Matchmore.Instance.StartLocationService();

Customization

The shown ConfigureAsync method is a shorthand, you can pass config object contain more information, like implementations for location services, state repositories

await Matchmore.SDK.Matchmore.ConfigureAsync(new GenericConfig{
                ApiKey = "YOUR_API_KEY",
                LocationService = myLocationService, //implements ILocationService
                StateManager = myStateManager, // implements IStateRepository
            });

The location service is crucial for automated location updates for your device

Manual update locations
await Matchmore.SDK.Matchmore.Instance.UpdateLocationAsync(new Location
{
    Latitude = 54.414662,
    Longitude = 18.625498
});

Create a Mobile Device

var pubDevice = await Matchmore.SDK.Matchmore.Instance.CreateDeviceAsync(new MobileDevice
{
    Name = "Publisher"
});

{: #net-pin-device}

Create a Pin Device

var pubDevice = await Matchmore.SDK.Matchmore.Instance.CreateDeviceAsync(new PinDevice
{
    Name = "Publisher"
});

Publish

var pub = new Publication
		{
			Topic = "Test Topic",
			Duration = 30,
			Range = 100,
			Properties = new Dictionary<string, object>(){
				{"test", true},
				{"price", 199}
			}
		};
//you can pass explicitly the device you would want to use
var createdPub = await Matchmore.SDK.Matchmore.Instance.CreatePublicationAsync(pub, pubDevice);

{: #net-subscribe}

Subscribe

var sub = new Subscription
        {
            Topic = "Test Topic",
            Duration = 30,
            Range = 100,
            Selector = "test = true and price <= 200"
        };

var createdSub = await Matchmore.SDK.Matchmore.Instance.CreateSubscriptionAsync(sub);

GetMatches

//you can call to get matches at your leisure, if you don't want to use the monitors. In the end the monitors are calling exactly this method
var matches = await Matchmore.SDK.Matchmore.Instance.GetMatches();

Match monitoring

The SDK provide a simple way to create monitor which works of both websocket and polling

var monitor = Matchmore.SDK.Matchmore.Instance.SubscribeMatches();
monitor.MatchReceived += (sender, e) => {
            LogLine(string.Format("Received match {0} from device {1} with channel {2} directly from monitor", e.Matches[0].Id, e.Device.Id, e.Channel));
        };

.SubscribeMatches() takes an optional value which lets you choose a specific match delivery mechanism

Matches from static instance

Matchmore.Instance.MatchReceived += (sender, e) => {
    LogLine(string.Format("Received match {0} from device {1} with channel {2}", e.Matches[0].Id, e.Device.Id, e.Channel));
};

Local States request

foreach (var _pub in Matchmore.SDK.Matchmore.Instance.ActivePublications)
{
    LogLine(string.Format("Pub {0} existings for another {1} seconds", _pub.Id, _pub.SecondsRemaining()));
}

foreach (var _sub in Matchmore.SDK.Matchmore.Instance.ActiveSubscriptions)
{
    LogLine(string.Format("Sub {0} existing for another {1} seconds", _sub.Id, _sub.SecondsRemaining()));
}

Third party match providers (APNS and FCM)

To use your match provider of your choice, you need to wire it differently depending on the platform.

First you need to provide the token for the platform (FCM or APNS) to Matchmore so we know where to route the match id

//fcm
Matchmore.SDK.Matchmore.Instance.UpdateDeviceCommunicationAsync(new Matchmore.SDK.Communication.FCMTokenUpdate("token taken from FCM"));
//basing of https://docs.microsoft.com/en-us/xamarin/android/data-cloud/google-messaging/remote-notifications-with-fcm?tabs=vswin

[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class MyFirebaseIIDService : FirebaseInstanceIdService
{
    const string TAG = "MyFirebaseIIDService";
    public override void OnTokenRefresh()
    {
        var refreshedToken = FirebaseInstanceId.Instance.Token;
        Log.Debug(TAG, "Refreshed token: " + refreshedToken);
        Matchmore.SDK.Matchmore.Instance.UpdateDeviceCommunicationAsync(new Matchmore.SDK.Communication.FCMTokenUpdate(refreshedToken));
    }
}

//apns
Matchmore.SDK.Matchmore.Instance.UpdateDeviceCommunicationAsync(new Matchmore.SDK.Communication.APNSTokenUpdate("token taken from APNS"));
//basing of https://github.com/xamarin/ios-samples/blob/master/Notifications/AppDelegate.cs
public override void RegisteredForRemoteNotifications (UIApplication application, NSData deviceToken)
{
	Matchmore.SDK.Matchmore.Instance.UpdateDeviceCommunicationAsync(new Matchmore.SDK.Communication.APNSTokenUpdate(deviceToken.ToString()));
}

Then you need to tell Matchmore whenever you will get a match id to retrieve.

//android fcm
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class MyFirebaseMessagingService : FirebaseMessagingService
{

    IMatchProviderMonitor matchProviderMonitor = Matchmore.SDK.Matchmore.Instance.SubscribeMatchesWithThirdParty();
    const string TAG = "MyFirebaseMsgService";
    public override void OnMessageReceived(RemoteMessage message)
    {
        matchProviderMonitor.ProvideMatchIdAsync(MatchId.Make(message.GetNotification().Body));
    }
}

//ios apns in your AppDelegate
public override void ReceivedRemoteNotification (UIApplication application, NSDictionary userInfo)
{
    IMatchProviderMonitor matchProviderMonitor = Matchmore.SDK.Matchmore.Instance.SubscribeMatchesWithThirdParty();
    var matchId = userInfo["matchId"].ToString();
    matchProviderMonitor.ProvideMatchIdAsync(MatchId.Make(matchId));
}

Additional info you might find useful

Local States request (Create, Find, FindAll, Delete and DeleteAll)

//You can access locally cached publications and subscriptions by calling, these are IEnumerables which you can easily query with LINQ
Matchmore.SDK.Matchmore.Instance.ActiveSubscriptions;
Matchmore.SDK.Matchmore.Instance.ActivePublications;

//you can delete also your sub and pub calling
await Matchmore.SDK.Matchmore.Instance.DeleteSubscriptionAsync(sub.Id);
await Matchmore.SDK.Matchmore.Instance.DeletePublicationAsync(pub.Id);
await Matchmore.SDK.Matchmore.Instance.DeleteDeviceAsync(device.Id)

DEMO

A console app demo is available in our .NET SDK github.

Unity 3D SDK

 

Unity vs .NET

Just recently Unity released support for newer version of C# in Unity 2018. We are working on making the .NET work with Unity. But for now you are free to use this version of the SDK

This sdk is provided as open-source software:

  Unity 3D SDK on Github

Installation

Clone and copy contents Assets/Matchmore of the repository into Assets/Matchmore. You can change the target folder

Quickstart sample

        //make sure new TLS is enabled, this is only available in .NET 4.x Equivalent
        System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12 | System.Net.SecurityProtocolType.Tls11;

        //get the api key from our portal
        var config = Matchmore.Config.WithApiKey(apiKey);
        Matchmore.Configure(config);
	    // we register the device as the main device
        var mainDevice = Matchmore.Instance.MainDevice;

        //methods interacting with devices by default use the main device, but there are overloads to provide other devices
        var pub = Matchmore.Instance.CreatePublication(new Publication
        {
            Topic = "Unity",
            Duration = 30,
            Range = 100,
            Properties = new Dictionary<string, object>(){
                {"test", true},
                {"price", 199}
            }
        });

        var sub = Matchmore.Instance.CreateSubscription(new Subscription
        {
            Topic = "Unity",
            Duration = 30,
            Range = 100,
            Selector = "test = true and price <= 200",
            Pushers = new List<string>() { "ws" }
        });

        foreach (var _pub in Matchmore.Instance.ActivePublications)
        {
            LogLine(string.Format("Pub {0} existings for another {1} seconds", _pub.Id, _pub.SecondsRemaining()));
        }

        foreach (var _sub in Matchmore.Instance.ActiveSubscriptions)
        {
            LogLine(string.Format("Sub {0} existing for another {1} seconds", _sub.Id, _sub.SecondsRemaining()));
        }

        //this method is available but we run a coroutine in the background which starts the unity location service and runs this call every time the location was changed
        Matchmore.Instance.UpdateLocation(new Location
        {
            Latitude = 54.414662,
            Longitude = 18.625498
        });

        //query for available matches via a single request
        var matches = Matchmore.Instance.GetMatches();
        matches.ForEach(m =>
        {
            LogLine("Got Match " + m.Id + " single call");
        });

        //creates a monitor on a single device which has an event handler(by default the main one)
        var socketMonitor = Matchmore.Instance.SubscribeMatches(Matchmore.MatchChannel.Websocket);

        //creates a monitor on a single device which has an event handler(by default the main one)
        var pollingMonitor = Matchmore.Instance.SubscribeMatches(Matchmore.MatchChannel.Polling);

        //this event handler fires only for a single device
        socketMonitor.MatchReceived += (sender, e) => {
            LogLine(string.Format("Received match {0} from device {1} with channel {2} directly from monitor", e.Matches[0].Id, e.Device.Id, e.Channel));
        };

        pollingMonitor.MatchReceived += (sender, e) => {
            LogLine(string.Format("Received match {0} from device {1} with channel {2} directly from monitor", e.Matches[0].Id, e.Device.Id, e.Channel));
        };

        //this event handler fires for all devices created
        Matchmore.Instance.MatchReceived += (sender, e) => {
            LogLine(string.Format("Received match {0} from device {1} with channel {2}", e.Matches[0].Id, e.Device.Id, e.Channel));
        };

Tutorials

Start/stop Matchmore

//Reset will stop monitors and location updates
Matchmore.Reset();

Start/Stop updating location

Matchmore.Instance.StartLocationService();
Manual update locations
Matchmore.Instance.UpdateLocation(new Location
        {
            Latitude = 54.414662,
            Longitude = 18.625498
        });

Create a Mobile Device

var pubDevice = Matchmore.Instance.CreateDevice(new MobileDevice
{
    Name = "Publisher"
});

{: #unity-pin-device}

Create a Pin Device

var pubDevice = Matchmore.Instance.CreateDevice(new PinDevice
{
    Name = "Publisher"
});

Publish

var pub = new Publication
		{
			Topic = "Test Topic",
			Duration = 30,
			Range = 100,
			Properties = new Dictionary<string, object>(){
				{"test", true},
				{"price", 199}
			}
		};
//you can pass explicitly the device you would want to use
var createdPub = Matchmore.Instance.CreatePublication(pub, pubDevice);

Subscribe

var sub = new Subscription
        {
            Topic = "Test Topic",
            Duration = 30,
            Range = 100,
            Selector = "test = true and price <= 200"
        };

var createdSub = Matchmore.Instance.CreatePublicationCreateSubscription(sub);

GetMatches

//you can call to get matches at your leisure, if you don't want to use the monitors. In the end the monitors are calling exactly this method
var matches = Matchmore.Instance.GetMatches();

Polling

var pollingMonitor = Matchmore.Instance.SubscribeMatches(Matchmore.MatchChannel.polling);
pollingMonitor.MatchReceived += (sender, e) => {
            LogLine(string.Format("Received match {0} from device {1} with channel {2} directly from monitor", e.Matches[0].Id, e.Device.Id, e.Channel));
        };

Websocket

var socketMonitor = Matchmore.Instance.SubscribeMatches(Matchmore.MatchChannel.websocket);
socketMonitor.MatchReceived += (sender, e) => {
            LogLine(string.Format("Received match {0} from device {1} with channel {2} directly from monitor", e.Matches[0].Id, e.Device.Id, e.Channel));
        };

Matches from static instance

Matchmore.Instance.MatchReceived += (sender, e) => {
    LogLine(string.Format("Received match {0} from device {1} with channel {2}", e.Matches[0].Id, e.Device.Id, e.Channel));
};

Local States request

foreach (var _pub in Matchmore.Instance.ActivePublications)
{
    LogLine(string.Format("Pub {0} existings for another {1} seconds", _pub.Id, _pub.SecondsRemaining()));
}

foreach (var _sub in Matchmore.Instance.ActiveSubscriptions)
{
    LogLine(string.Format("Sub {0} existing for another {1} seconds", _sub.Id, _sub.SecondsRemaining()));
}

TLS 1.1 and 1.2

We have moved to support newer cyphers as Apple stopped support most of TLS 1.0 cyphers. Some version of Unity might not support this but here is a trick which might make it work.

  1. Set Scripting Runtime Version to .NET 4.x Equivalent If this didn’t work
  2. Unzip the SystemSecurity.zip into a folder called plugins which can exist anywhere in the solution.

Demo

A Unity demo is available in our Unity github.