NAV
swift kotlin java

Introduction


Welcome to Mappy.

We build geospatial platforms connecting venues to their guests. Our turnkey solutions (developer tools, including the Mappy API and Mappy SDK, for mobile apps), improve the guest experience using interactive and social custom maps. Our data analytics platform and operations dashboards are designed to inform data driven decisions.

Mappy SDKs provide an elegant and composable interface for mapping, geocoding, and routing.

The Mappy SDKs leverages the power of best in class technology, including ESRI using the ArcGIS Runtime SDKs as dependencies.

This Implementation Documentation describes how to use the latest version of the Mappy SDK for iOS and Android for ski resorts. Terms of Service for our developer tools, data analytics platform, and mapping services portal are found here.

We also have Technical Documentation for Swift and Technical Documentation for Kotlin which describes individual components of the SDK.

Register your App with Mappy

Your app needs to be registered with Mappy to use the Mappy SDK in your app. For a quote, please email info@beMappy.io. Mappy will provide customers an Id and Secret. Be sure to store them securely.

Prepare Development Requirements

iOS Development Requirements

If you have registered and received your Client ID and Secret Key, we have a quick-start sample you can download or clone in case you want to see some code examples in action before starting a new Xcode project.

Android Development Requirements

If you have registered and received your Client ID and Secret Key, we have a quick-start sample you can download or clone in case you want to see some code examples in action before starting a new Android project.

Add Mappy SDK to your App

iOS

Include Mappy in your project using either Swift Package Manager or CocoaPods as follows:

Use Swift Package Manager to include Mappy in your project

  1. Open your project in Xcode
  2. From the File menu choose Add Packages...
  3. Search for https://github.com/beMappy/Mappy-Swift
  4. Select Mappy-Swift
  5. Select Dependency Rule Up to Next Major Version
  6. Verify that the version range is from at least version 0.8.11
  7. Click Add Package
  8. Verify the Mappy SDK version: in the Project navigator under Package Dependencies, find Mappy and verify the grey version text is 0.8.4 or greater.

Use CocoaPods to include Mappy in your project

  1. Close your project
  2. From a command line go to your project's root directory i.e. cd <MappyProject>.
  3. Create a Podfile for your project with the command pod init.
  4. Edit your project's newly created Podfile file, and add pod 'Mappy' after the # Pods for ... line.
  5. Set the platform to iOS 14 by adding or uncommenting the line platform :ios, '14.0' at the top of the Podfile.
  6. Install Mappy into your project with the command pod install.
  7. During the install process the versions of the dependencies will be listed to the terminal, they will also be listed in the Podfile.lock file. Verify that the Mappy version is 0.8.3 or later.
  8. After the installation completes, open the new .xcworkspace file (not the ".xcodeproj" file), and verify that the Mappy dependancy is in the Pods project. It will be in Pods -> Pods -> Mappy.
  9. Later, to update to the latest Mappy SDK version available for the specified platform, from the project directory run the command pod update.

Android

maven

In the settings.gradle (Project Settings) file add the Jfrog and Maven Central to dependencyResolutionManagement { repositories {} } list.

dependencies

In the build.gradle (Module :app) file, for the project where you want the SDK installed, add the io.github.bemappy:mappy to dependencies {} list. You can find the latest version from here: Maven Central

Exclude Duplicated Packages

In the build.gradle (Module :app) file, in android {} add these settings to exclude duplicated packages. Otherwise duplicated packages may prevent compilation.

Initialize Mappy in Your App

Before using Mappy in your app, it needs to be initialized.

iOS

To initialize use this code

Copy to Clipboard
import UIKit import Mappy import Combine

...

Copy to Clipboard
let mappyUserIdKey: String = "mappyUserId" var mappyInitCancellable: AnyCancellable? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // UserDefaults used for demonstration purpose only. mappyInitCancellable = MappyCore.initialize( clientId: <#String#>, secret: <#String#> /* ClientSecret */, mappyUserId: UserDefaults.standard.string(forKey: self.mappyUserIdKey) deferTracking: false, // true - if the application doesn't want to track the user's location. Note: User statistics and visual tracks depend on the tracking. appTrackingInfo: <AppTrackingInfo> // App specific information tracked along with the user location. ) .sink(receiveCompletion: { if case .failure(let error) = $0 { // TODO: handle error print("initialize: error: \(error)") } }, receiveValue: { mappyMeta in // !!!: sometimes the Mappy SDK can successfully return a MappyMeta object even though there was an error. In that case the MappyMeta object will contain error data, and no error will be passed to the receiveCompletion block. guard let mappyUserId = mappyMeta.mappyUserId else { // TODO: handle error print("errorDescription: \(mappyMeta.error?.errorDescription ?? "")") return } UserDefaults.standard.setValue(mappyUserId, forKey: self.mappyUserIdKey) // Override point for customization after MappyCore Initialized. }) // Override point for customization after application launch. return true }

Make sure to replace `ClientId` and `ClientSecret` with your credentials.

  1. Import Mappy, UIKit, and Combine modules in your UIApplicationDelegate.
  2. Configure a Mappy shared instance, by calling MappyCore.initialize typically in your app's initializer or app delegate's application(_:didFinishLaunchingWithOptions:) method:
  3. Make sure that you app stores the mappyUserId String on it's first launch, and passes that value to the initialize method on subsequent launches.

This function instantiates the Mappy SDK, so the SDK APIs can be used across the project. This static method requires a Client ID, Client Secret, an a returning user's Mappy User ID. In the first invocation the User ID is not required, and will be generated and passed to the app in the receiveValue: block.

It is the application's responsibility to store the Mappy User ID accros user sessions, and to use it to initialize Mappy in subsequent sessions.

The Mappy User ID is associated with the Client ID and Client Secret credentials, and cannot be used with another set of Client credentials. When switching between development credentials and production credentials care should be taken to use a Mappy User ID which is associated with the credentials used to initialize Mappy.

Android

  1. Import the Mappy module.
  2. Create a Mappy instance with Mappy.createInstance(context: Context). Be sure to pass a valid context.
  3. And initialize your Mappy instance with either:

This function helps to instantiate the Mappy SDK. Post initialization, SDK APIs can be used internally across the project. This method requires a Client Id, a secret and the user Id. The user Id is generated by Mappy. In the first invocation, you can pass nil as the User Id. The SDK will then generate a new user Id and send it back to the app in the completion block. It is the application's responsibility to store and pass that user Id across user sessions.

Venues

Get All Venues

Copy to Clipboard
let venuesService = VenuesService() venuesService.getVenues() .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { [weak self] venues in // Received venues }) .store(in: &cancellables)

This function provides a list of venues associated with a particular Client Id. The data returned includes all details of available venues. You can get these IDs from a venue returned by VenueService().getVenues().

Get a Specific Venue

Copy to Clipboard
let venuesService = VenuesService() venuesService.getVenue(venueId: <#String#> /* from the venueId property of a Venue */) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { [weak self] venue in // Received Venue }) .store(in: &cancellables)

This function helps to get the details for a specific venue using its identifier.

Parameters

Parameter DataType Description
VenueId String The ID of the venue to retrieve

User Statistics

Get User's Statistics

StatsService - GetUserStats

Copy to Clipboard
self.statsService = StatsService() self.statsService.getUserStats(userId: <userId>, venueId: <venueId>, startTime: <startTime>, endTime: <endTime>) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { userStats in print("maximumAltitudeInMetres: \(userStats.maximumAltitudeInMetres)") }) .store(in: &cancellables)

This function retrieves the statistics for a user. Optionally the results can be restricted to stats from specific venu, and within a specified date range.

The list of stats availible can be found in the technical documentation at iOS - UserStats, and Android - Stats

Parameters

Parameter DataType Description
userId String The ID of any particular venue in which the user Skied, or null to use the current user ID.
venueId String The ID of any particular venue in which the user Skied, or null to retrieve statistics for all venues.
startTime Long A Unix time (iOS: in seconds; Android: in milliseconds). This restricts the retrieved results to only those created after startTime. When set to nil/null it will retrieve: all results before the endTime parameter, or all results if endTime is also null.
endTime Long A Unix time (iOS: in seconds; Android: in milliseconds). This restricts the retrieved results to only those created before endTime. When set to nil/null it will retrieve: all results after the startTime parameter, or all results if startTime is also null.

Rendering

Map

Map - Load

Copy to Clipboard
map = Map(mapInfo: <#Venue#>) map.load() .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { [weak self, weak map, weak mapView] _ in // Map has been loaded if let map = map { self?.mapView?.map = map } }) .store(in: &cancellables)

A Map is a class that represents the 2D map. You need to inject all the required data associated with a venue to instantiate and load a Map.

Get Features

Map - Get Features

Copy to Clipboard
map.getFeatures() .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { [weak self] features in // Received features }) .store(in: &cancellables)

Get all the available features in the map like Ski run, lift, buidling, amenity, bookmarks, etc.

Search features by keyword

Map - Search Features

Copy to Clipboard
map.getFeatures(text: <#String#> /* search text */) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { [weak self] features in // Received features }) .store(in: &cancellables)

Get all the available features in the map like Ski run, lift, buidling, amenity, bookmarks, etc. that contains a given keyword.

Filter features by type

Map - Filter Features

Copy to Clipboard
map.getFeatures(category: .<#FeatureCategory#>(.any)) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { [weak self] features in // Received features }) .store(in: &cancellables)

Get all the available features in the map like Ski run, lift, buidling, amenity, bookmarks, etc. that matches a given type.

Map Features

  • Attribute Name: objectid
  • Data Type: ObjectID
  • Recommended Uses: Unique Identifier of feature
  • Attribute Name: name
  • Data Type: String
  • Length: 60
  • Recommended Uses: Search, list, badge name, selection, network routing, sort by alphabetical
  • Attribute Name: length
  • Data Type: Single
  • Recommended Uses: In the badge and selection
  • Attribute Name: trav_time
  • Data Type: single
  • Attribute Name: Length_feet
  • Data Type: integer
  • Attribute Name: pass_pos
  • Data Type: string
  • Length: 255
  • Recommended Uses: Stand / Sit
  • Attribute Name: type
  • Data Type: string
  • Length: 255
  • Recommended Uses: Notates the type of lift e.g. 4 person chairlift that signifies which graphic to show. Included in the list, badge, selection, network routing
  • Value List: lift_type
  • Coded Values: Magic Carpet, Tow Rope, 2 Chairlift, 3 Chair Lift, 4 Chair Lift, 5 Chair Lift, 6 Chair Lift, Gondola, Tram
  • Attribute Name: lift_number
  • Data Type: Small integer
  • Recommended Uses: search, list, badge name, in addition to a name the lifts have numbers, only used at some large resorts, not applicable for smaller resorts
  • Attribute Name: objectid
  • Data Type: ObjectID
  • Recommended Uses: Unique Identifier of feature
  • Attribute Name: name
  • Data Type: string
  • Length: 100
  • Recommended Uses: Search, badge name, selection, network routing, sort by alphabetical
  • Attribute Name: skill_level
  • Data Type: intiger
  • Recommended Uses: Notates the level of run that signifies which graphic to show per run e.g. Advanced
  • Value List: skill_level
  • Coded Values: 1 (Beginner), 2 (Intermediate), 3 (Advanced), 4 (Expert), 5 (Beginner Intermediate), 6 (Intermediate Advanced), 7 (Advanced Expert)
  • Attribute Name: slope
  • Data Type: Single
  • Recommended Uses: Search, badge name, selection
  • Attribute Name: avg_spd
  • Data Type: Single
  • Attribute Name: length
  • Data Type: single
  • Attribute Name: run_type
  • Data Type: string
  • Length: 255
  • Recommended Uses: Turn by turn navigation
  • Value List: run_type
  • Coded Values: Main Run, Connector, Walking Path, Nordic Trail, Hike to Terrain, Tunnel, Private Skiway, Catwalk
  • Attribute Name: trav_time
  • Data Type: single
  • Attribute Name: generalized_level
  • Data Type: intiger
  • Recommended Uses: Notates the level for user login and network routing (turn by turn directions by skill level)
  • Value List: skill_level_gen
  • Coded Values: 1 (Beginner), 2 (Intermediate), 3 (Advanced), 4 (Expert)
  • Attribute Name: complexity
  • Data Type: string
  • Length: 255
  • Value List: complexity
  • Coded Values: Glades, Moguls
  • Attribute Name: extreme_conditions
  • Data Type: string
  • Length: 255
  • Value List: y_n
  • Coded Values: Yes, No
  • Attribute Name: objectid
  • Data Type: ObjectID
  • Recommended Uses: Unique Identifier of feature
  • Attribute Name: objectid
  • Data Type: ObjectID
  • Recommended Uses: Unique Identifier of feature
  • Attribute Name: building_name
  • Data Type: string
  • Length: 255
  • Recommended Uses: In the badge name as a subtitle to the amenity in the list view and selection, amenities will be within a building and show the building name, or if it is an amenity like terrain park or kid zone (point features temporarily in this feature class) it will be 'On Mountain'
  • Attribute Name: amenity_class
  • Data Type: string
  • Length: 255
  • Recommended Uses: Search filter
  • Value List: amenity_class
  • Coded Values: Food and Beverage, Guest Services, Retail, Ski Features, Service, First Aid, Other, Accommodation, Transportation, Event, Label
  • Attribute Name: amenity_type
  • Data Type: string
  • Length: 255
  • Recommended Uses: Search filter
  • Value List: amenity_type
  • Coded Values: Bar, Casual Dining, Full Service Restaurant, Childcare, Information, Lockers, Other, Restroom, Ski School, Ski Valet, Ticket Office, Art Gallery, Bank, Grocery, Rental Shop, Repair Shop, Retail Store, Bowl, Kid Zone, Racing Zone, Slow Zone, Terrain Park, Tubing Area, Unspecified Ski Feature, ATM, Health and Wellness, Postal, Recreation, Construction, Corporate, Miscellaneous, Postal, Real Estate, Recreation, Medical Clinic, Ski Patrol, Elevator, Fountain, Ice Rink, Playground, Statue, Condo, Hotel, Bus Stop, Parking, Entertainment, Festival, Wellness, Meeting, Sporting Event, Base Area, Peak Elevation, Plaza
  • Attribute Name: name
  • Data Type: string
  • Length: 255
  • Recommended Uses: Name of the amenity on the list, search, badge name, selection, network routing, sort alphabetical
  • Attribute Name: phone
  • Data Type: string
  • Length: 255
  • Recommended Uses: In the badge name during selection
  • Attribute Name: website
  • Data Type: string
  • Length: 10000
  • Recommended Uses: In the badge name, selection
  • Attribute Name: foreign_id
  • Data Type: string
  • Length: 255
  • Attribute Name: foreign_source
  • Data Type: string
  • Length: 255
  • Attribute Name: unique_id
  • Data Type: string
  • Length: 255
  • Attribute Name: objectid
  • Data Type: ObjectID
  • Recommended Uses: Unique Identifier of feature
  • Attribute Name: name
  • Data Type: string
  • Length: 100
  • Recommended Uses: Search, badge name, selection, network routing, sort by alphabetical

MapView

MapView - Initialize

Copy to Clipboard
MapView()

MapView is an UI class that helps in rendering the 2D map. Once the map is loaded, add the map to MapView and then you can add the same to your UI hierarchy.

Rotate To North

MapView - Rotate To North

Copy to Clipboard
mapView.rotateToNorth()

Rotates the map to the default orientation.

Set Initial ViewPoint

MapView - Set Initial ViewPoint

Copy to Clipboard
mapView.setInitialViewpoint()

Restores the map to its initial state where the venue is entirely visible

Tap on a Feature

Tap on a Feature

Copy to Clipboard
mapView.event .receive(on: DispatchQueue.main) .sink(receiveValue: { switch $0 { case .onTap(let feature): // Handle the tap event default: break } }) .store(in: &cancellables)

A callback that will be invoked with the feature the user taps on.

View Point Change

MapView - View Point Change

Copy to Clipboard
mapView.event .receive(on: DispatchQueue.main) .sink(receiveValue: { switch $0 { case .onViewpointChange: // Handle the event default: break } }) .store(in: &cancellables)

A callback that will be invoked every time when the user interacts with the Map except in the case of a tap.

Select a Feature

Select a Feature

Copy to Clipboard
mapView.select(feature: <#Feature#>)

A function that highlights and zooms to the feature provided

Unselect a Feature

Unselect a Feature

Copy to Clipboard
mapView.select(feature: nil)

A function that removes the highlight from the selected feature

Display User Pins

MapView - Display User Pins

Copy to Clipboard
mapView.displayUserPins(using: <#[UserPinLocation]#>)

A function that plots the pins on the map.

Remove User Pins

MapView - Remove User Pins

Copy to Clipboard
mapView.displayUserPins(using: [])

To remove the pins from the map.

Tracks

Render User's Tracks

MapView - Render user's tracks

Copy to Clipboard
// Current day range let startTime = Calendar.current.startOfDay(for: Date()).timeIntervalSince1970 let endTime = Date(timeIntervalSince1970: Calendar.current.startOfDay(for: Date()).timeIntervalSince1970 + (86400 - 1)).timeIntervalSince1970 // 86400 -> 1 day in seconds self.mapView.renderUserTrack(startTime: startTime, endTime: endTime) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { status in print("status: \(status)") }) .store(in: &cancellables)

Renders the user's tracks on the map.

Remove user's tracks

MapView - Remove user's tracks

Copy to Clipboard
self.mapView.removeUserTrack()

Removes the user's tracks from the map.

Hide user's tracks

MapView - Hide user's tracks

Copy to Clipboard
self.mapView.hideUserTrack()

Make the user's tracks on the map invisible if already rendered.

To check user's tracks rendering status

MapView - Track's Redering Status

Copy to Clipboard
self.mapView.isUserTrackRendered

Determines whether the user's tracks has been rendered on the map.

Check user's tracks visibility

Determines whether the user's tracks is currently visible on the map.

Scene

Scene - Load

Copy to Clipboard
scene = Scene(sceneInfo: <#Venue#>) scene.load() .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { [weak self, weak scene, weak sceneView] _ in // Scene has been loaded if let scene = scene { self?.sceneView?.scene = scene } }) .store(in: &cancellables)

A scene is a class that represents the 3D map. You need to inject in all the required data associated with a venue to instantiate and load a Scene.

Get Features

Scene - Get Features

Copy to Clipboard
scene.getFeatures() .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { [weak self] features in // Received features }) .store(in: &cancellables)

Get all the available features in the scene like Ski run, lift, buidling, amenity, bookmarks, etc.

Search features by keyword

Scene - Search Features

Copy to Clipboard
scene.getFeatures(text: <#String#>) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { [weak self] features in // Received features }) .store(in: &cancellables)

Get all the available features in the scene like Ski run, lift, buidling, amenity, bookmarks, etc. that contains a given keyword.

Filter features by type

Scene - Filter Features

Copy to Clipboard
scene.getFeatures(category: <#FeatureCategory#>) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { [weak self] features in // Received features }) .store(in: &cancellables)

Get all the available features in the scene like Ski run, lift, buidling, amenity, bookmarks, etc. that matches a given type.

SceneView

SceneView - Initialize

Copy to Clipboard
SceneView()

SceneView is an UI class that helps in rendering the 3D map. Once the scene is loaded, add the scene to SceneView and then you can add the same to your UI hierarchy.

Rotate To North

SceneView - Rotate To North

Copy to Clipboard
sceneView.rotateToNorth()

Rotates the scene to the default orientation

Set Initial ViewPoint

SceneView - Set Initial ViewPoint

Copy to Clipboard
sceneView.setInitialViewpoint()

Restores the scene to its initial state where the venue is entirely visible.

Tap on a Feature

Tap on a Feature

Copy to Clipboard
sceneView.event .receive(on: DispatchQueue.main) .sink(receiveValue: { switch $0 { case .onTap(let feature): // Handle the tap event default: break } }) .store(in: &cancellables)

A callback that will be invoked with the feature the user taps on.

View Point Change

SceneView - View Point Change

Copy to Clipboard
sceneView.event .receive(on: DispatchQueue.main) .sink(receiveValue: { switch $0 { case .onViewpointChange: // Handle the event default: break } }) .store(in: &cancellables)

A callback that will be invoked every time when the user interacts with the Scene except in the case of a tap.

Select a Feature

Select a Feature

Copy to Clipboard
sceneView.select(feature: <#Feature?#>)

A function that highlights and zooms to the feature provided

Unselect a Feature

Unselect a Feature

Copy to Clipboard
sceneView.select(feature: nil)

A function that removes the highlight from the selected feature

Display User Pins

SceneView - Display User Pins

Copy to Clipboard
sceneView.displayUserPins(using: <#[UserPinLocation]#>)

A function that plots the pins on the scene.

Remove User Pins

SceneView - Remove User Pins

Copy to Clipboard
sceneView.displayUserPins(using: [])

To remove the pins from the scene.

Tracks

Render user's tracks

SceneView - Render user's tracks

Copy to Clipboard
// Current day range let startTime = Calendar.current.startOfDay(for: Date()).timeIntervalSince1970 let endTime = Date(timeIntervalSince1970: Calendar.current.startOfDay(for: Date()).timeIntervalSince1970 + (86400 - 1)).timeIntervalSince1970 // 86400 -> 1 day in seconds self.sceneView.renderUserTrack(startTime: startTime, endTime: endTime) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { case .finished: break case .failure(let error): print("error: \(error)") } }, receiveValue: { status in print("status: \(status)") }) .store(in: &cancellables)

Renders the user's tracks on the scene.

Remove user's tracks

SceneView - Remove user's tracks

Copy to Clipboard
self.sceneView.removeUserTrack()

Removes the user's tracks from the scene.

Hide user's tracks

SceneView - Hide user's tracks

Copy to Clipboard
self.sceneView.hideUserTrack()

Make the user's tracks on the scene invisible if already rendered.

To check user's tracks rendering status

SceneView - Track's Redering Status

Copy to Clipboard
self.sceneView.isUserTrackRendered

Determines whether the user's tracks have been rendered on the scene.

Check user's tracks visibility

Determines whether the user's tracks are currently visible on the scene.

Location Tracking

Start location tracking

Location Tracking - Start

Copy to Clipboard
TrackingService.current.resume(appTrackingInfo: <AppTrackingInfo>)

To start/resume the user's location tracking. NOTE: By default the Tracking service starts tracking when the SDK is initialized. This invocation would be useful when we want to toggle the tracking process.

Suspend tracking

Location Tracking - Stop

Copy to Clipboard
TrackingService.current.suspend()

To suspend the user's location tracking.

Update tracking payload

Location Tracking - Update App Info

Copy to Clipboard
TrackingService.current.appTrackingInfo = <AppTrackingInfo>

To update the current tracking payload. It is necessary that the application updates the tracking service with necessary app specific information at least once. Please refer to the code snippets on how to update the current tracking payload.

To check tracking status

Location Tracking - Status

Copy to Clipboard
TrackingService.current.isTracking

Check if tracking is currently active. Returns true if tracking is active, false otherwise.

Location Sharing

Group CRUD

The GroupsService helps in creating, reading, updating and deleting groups. It can also add or remove users to and from the groups. It is mandatory to initialize the SDK before creating the instance and invoking the functions of this service.

Create a Group

Group CRUD - Create Group

Copy to Clipboard
groupsService.createGroup(name: <#String#>) .sink(receiveCompletion: { if case .failure(let error) = $0 { // Error } }, receiveValue: { [weak self] in // $0 - Group Data }) .store(in: &cancellables)

To create a group.

Fetch Groups

Group CRUD - Fetch Groups

Copy to Clipboard
groupsService.fetchGroups() .sink(receiveCompletion: { if case .failure(let error) = $0 { // Error } }, receiveValue: { [weak self] in // $0 - Groups }) .store(in: &cancellables)

To fetch all the user groups.

Fetch Group Info

Group CRUD - Fetch Groups Info

Copy to Clipboard
groupsService.fetchGroupInfo(groupId: <#String#>) .sink(receiveCompletion: { if case .failure(let error) = $0 { // Error } }, receiveValue: { [weak self] in // $0 - Group Data }) .store(in: &cancellables)

To fetch the groups data using its identifier.

Update a Group

Group CRUD - Update Group

Copy to Clipboard
groupsService.updateGroup(groupId: <#String#>, name: <#String#> /* new name */) .sink(receiveCompletion: { if case .failure(let error) = $0 { // Error } }, receiveValue: { [weak self] in // $0 - Group Data }) .store(in: &cancellables)

To update a group.

Delete a Group

Group CRUD - Delete Group

Copy to Clipboard
groupsService.deleteGroup(groupId: <#String#>) .sink(receiveCompletion: { if case .failure(let error) = $0 { // Error } }, receiveValue: { [weak self] // $0 - Group Data }) .store(in: &cancellables)

To delete a group.

Add a user

Group CRUD - Add User

Copy to Clipboard
groupsService.addUser(userId: <#String#>, groupCode: <#String#>) .sink(receiveCompletion: { completion in if case .failure(let error) = completion { // failure condition } }, receiveValue: { [weak self] group in // success condition // “group” is a Group instance of the group the user for "userId" was added to. }) .store(in: &cancellables)

To add a user.

The current limit is 50 users per group. Once a group reaches its users limit, the error message 'groupUserLimitExceeded' will be returned. Please contact support@bemappy.io to increase the limit for number of users per group.

Remove a user

Group CRUD - Remove User

Copy to Clipboard
groupsService.removeUser(userId: user.userId, groupId: groupID) .sink(receiveCompletion: { if case .failure(let error) = $0 { // Error } }, receiveValue: { [weak self] in // $0 - Group data }) .store(in: &cancellables)

To remove a user

Group Location

Receive group members' locations and location updates, and share a user's location with group members

To use group location features an instance of GroupLocationService must be initialized and kept. There must only be one instance of GroupLocationService for the lifetime of the app.

On Event

Group Location - On Event

Copy to Clipboard
groupLocationService.onEvent .sink(receiveCompletion: { if case .failure(let error) = $0 { // handle error print(error.localizedDescription) } }, receiveValue: { [weak self] groupEvent in switch groupEvent { case .userLocation(let userLocation) : print(userLocation); case .userAddedToGroup(groupId: let groupId, userId: let userId) print("\(groupId) \(userId)") case .userRemovedFromGroup(groupId: let groupId, userId: let userId) print("\(groupId) \(userId)") } }) .store(in: &cancellables)

After inializing a GroupLocationService instance, the next thing that needs to be set up is an onEvent callback to receive group location service notifications. If listenToGroups has been run, the receiveValue block of onEvent will be called when any group member's location updates, or a user is added or removed from the group.

When a group member's location update is received it can be updated or added to an array/list of user pins and displayed in a mapView or displayed in a sceneView

Share User Location

Group Location - Share User Location

Copy to Clipboard
groupLocationService.shareUserLocation() .sink(receiveCompletion: { if case .failure(let error) = $0 { // Error } }, receiveValue: { // This is called when this user's device location changes. This may never be called. }) .store(in: &self.cancellables)

The startSharingLocation() method of a GroupLocationService starts sending real-time location updates to other members of the user’s groups. It is required so other members of the user’s group can receive live location updates for this user.

Other users in the group will receive updates for this user's location in the callback to onEvent (only on iOS) or startListeningToGroups.

In case you also want to do something on this user’s device each time this user’s location is sent to the group, the onMessage(event: Location) callback is called each time this user’s new location is sent to the group.

Stop Sharing User Location

Group Location - Stop Sharing

Copy to Clipboard
groupLocationService.stopSharingUserLocation()

To stop sharing the user's location with the user's groups.

Listen To Groups

Group Location - Listen To Groups

Copy to Clipboard
groupLocationService.listenToGroups() .sink(receiveCompletion: { if case .failure(let error) = $0 { // Error } }, receiveValue: { // Started listening }) .store(in: &self.cancellables)

To start listening to other users' locations who are part of the user's groups.

Stop Listening To Groups

Group Location - Stop Listening

Copy to Clipboard
groupLocationService.stopListeningToGroups()

To stop listening to other users' locations who are part of the user's groups.

Navigation

Map

Get Routes

Navigation - Map - Routes

Copy to Clipboard
map.getRoutes(from: <#Feature#>, to: <#Feature#>, skiLevel: <#SkiSlope.Level#>) .sink(receiveCompletion: { if case .failure(let error) = $0 { // Error } }, receiveValue: { [weak self] in // $0 - Routes }).store(in: &cancellables)

To find possible routes from one feature(origin) to another(destination) using the difficulty level.

MapView

Display a Route

Navigation - MapView - Display a Route

Copy to Clipboard
mapView.display(route: <#RouteResponse?#>)

To display the route on the map.

Start Navigation

Navigation - MapView - Start Navigation

Copy to Clipboard
let routeTracker = mapView.startNavigation(route: <#RouteResponse#>)

To start the turn by turn navigation using a route. This function returns a RouteTracker using which the application user interface can be updated during the navigation.

End Navigation

Navigation - MapView - End Navigation

Copy to Clipboard
mapView.stopNavigation()

To end the navigation

Scene

Get Routes

Navigation - Scene - Routes

Copy to Clipboard
scene.getRoutes(from: <#Feature#>, to: <#Feature#>, skiLevel: <#SkiSlope.Level#>) .sink(receiveCompletion: { if case .failure(let error) = $0 { // Error } }, receiveValue: { [weak self] in // $0 - Routes }).store(in: &cancellables)

To find possible routes from one feature(origin) to another(destination) using the difficulty level.

SceneView

Display a Route

Navigation - SceneView - Display a Route

Copy to Clipboard
sceneView.display(route: <#RouteResponse?#>)

To display the route on the scene.

Start Navigation

Navigation - SceneView - Start Navigation

Copy to Clipboard
let routeTracker = sceneView.startNavigation(route: <#RouteResponse#>)

To start the turn by turn navigation using a route. This function returns a RouteTracker using which the application user interface can be updated during the navigation.

End Navigation

Navigation - SceneView - End Navigation

Copy to Clipboard
sceneView.stopNavigation()

To end the navigation

RouteTracker

Uses a location to provide status and progress updates as a route is traversed (by a moving vehicle, for example).

RouteTracker can give the time or distance to the next maneuver, notify if the location is off-route, and regenerate a new route if necessary.

Routing Events

Navigation - RouteTracker - Routing Events

Copy to Clipboard
routeTracker.onEvent .sink(receiveValue: { switch $0 { case .onError(let error): // Error case .onTurnByTurnNavigationResponse(let response): // Navigation status update case .didReroute(let routeResponse): // New route case .didReachDestination: // Reached destination - Navigation Ended } }).store(in: &cancellables)

To listen to the events related to the route that is being navigated.

Audio Navigation

Navigation - RouteTracker - Enable / Disable voice directions

Copy to Clipboard
routeTracker.voiceDirectionsActive = <true / false>

To toggle the audio navigation.

Mappy Assets