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
- Xcode
14.2
or later installed - Cocoapods or Swift Package Manager can be used to include the Mappy SDK.
- Optionally CocoaPods can be installed using any of these guides:
- official guide. This guide is usually the simplest. If you run into problems, try the sudo-less installation or [troubleshooting installing CocoaPods] sections.
- using Homebrew. CocoaPods recommends using the system Ruby, but if you run into problems with the official guides then, especially if you already use Homebrew, this is probably your best option. You will have to install homebrew first, if you don't already have it installed.
- Xcode Project settings:
- Targets iOS platform versions
14.0
or later
- Targets iOS platform versions
- A physical Apple device is preferred.
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
- Android Studio, with Android SDK. Latest versions are recommended.
- A physical Android device with Android version 6 (Marshmallow) or later.
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
- Open your project in Xcode
- From the File menu choose
Add Packages...
- Search for
https://github.com/beMappy/Mappy-Swift
- Select
Mappy-Swift
- Select Dependency Rule
Up to Next Major Version
- Verify that the version range is from at least version
0.8.11
- Click
Add Package
- 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
- Close your project
- From a command line go to your project's root directory i.e.
cd <MappyProject>
. - Create a Podfile for your project with the command
pod init
. - Edit your project's newly created
Podfile
file, and addpod 'Mappy'
after the# Pods for ...
line. - Set the platform to iOS 14 by adding or uncommenting the line
platform :ios, '14.0'
at the top of the Podfile. - Install Mappy into your project with the command
pod install
. - 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. - 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 inPods -> Pods -> Mappy
. - 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:
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
import UIKit
import Mappy
import Combine
...
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.
- Import
Mappy
,UIKit
, andCombine
modules in your UIApplicationDelegate. - Configure a Mappy shared instance, by calling MappyCore.initialize typically in your app's initializer or app delegate's
application(_:didFinishLaunchingWithOptions:)
method: - 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
- Import the Mappy module.
- Create a Mappy instance with Mappy.createInstance(context: Context). Be sure to pass a valid context.
- 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
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
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
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
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
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
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
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
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
mapView.rotateToNorth()
Rotates the map to the default orientation.
Set Initial ViewPoint
MapView - Set Initial ViewPoint
mapView.setInitialViewpoint()
Restores the map to its initial state where the venue is entirely visible
Tap on a Feature
Tap on a Feature
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
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
mapView.select(feature: <#Feature#>)
A function that highlights and zooms to the feature provided
Unselect a Feature
Unselect a Feature
mapView.select(feature: nil)
A function that removes the highlight from the selected feature
Display User Pins
MapView - Display User Pins
mapView.displayUserPins(using: <#[UserPinLocation]#>)
A function that plots the pins on the map.
Remove User Pins
MapView - Remove User Pins
mapView.displayUserPins(using: [])
To remove the pins from the map.
Tracks
Render User's Tracks
MapView - Render user's tracks
// 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
self.mapView.removeUserTrack()
Removes the user's tracks from the map.
Hide user's tracks
MapView - Hide user's tracks
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
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
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
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
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
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
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
sceneView.rotateToNorth()
Rotates the scene to the default orientation
Set Initial ViewPoint
SceneView - Set Initial ViewPoint
sceneView.setInitialViewpoint()
Restores the scene to its initial state where the venue is entirely visible.
Tap on a Feature
Tap on a Feature
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
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
sceneView.select(feature: <#Feature?#>)
A function that highlights and zooms to the feature provided
Unselect a Feature
Unselect a Feature
sceneView.select(feature: nil)
A function that removes the highlight from the selected feature
Display User Pins
SceneView - Display User Pins
sceneView.displayUserPins(using: <#[UserPinLocation]#>)
A function that plots the pins on the scene.
Remove User Pins
SceneView - Remove User Pins
sceneView.displayUserPins(using: [])
To remove the pins from the scene.
Tracks
Render user's tracks
SceneView - Render user's tracks
// 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
self.sceneView.removeUserTrack()
Removes the user's tracks from the scene.
Hide user's tracks
SceneView - Hide user's tracks
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
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
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
TrackingService.current.suspend()
To suspend the user's location tracking.
Update tracking payload
Location Tracking - Update App Info
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
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
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
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
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
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
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
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
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
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
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
groupLocationService.stopSharingUserLocation()
To stop sharing the user's location with the user's groups.
Listen To Groups
Group Location - Listen To Groups
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
groupLocationService.stopListeningToGroups()
To stop listening to other users' locations who are part of the user's groups.
Navigation
Map
Get Routes
Navigation - Map - Routes
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
mapView.display(route: <#RouteResponse?#>)
To display the route on the map.
Start Navigation
Navigation - MapView - Start Navigation
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
mapView.stopNavigation()
To end the navigation
Scene
Get Routes
Navigation - Scene - Routes
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
sceneView.display(route: <#RouteResponse?#>)
To display the route on the scene.
Start Navigation
Navigation - SceneView - Start Navigation
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
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
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
routeTracker.voiceDirectionsActive = <true / false>
To toggle the audio navigation.
Mappy Assets
- Download iOS Assets
- Download Android Assets
Icon Asset Name accommodation hotel accommodation condo accommodation location Icon Asset Name events health event entertainment events sport events meeting events festival Icon Asset Name first aid medical clinic first aid location aeds first aid ski patrol first aid fire hydrant Icon Asset Name food restaurant food bar food casual dining food location Icon Asset Name guest services information guest services lost and found guest services ski school kid zone guest services lockers guest services restroom guest services zip tours guest services ticket office guest services location Icon Asset Name other fountain other playground area other ice rink other atm other racing village summit other post office interactive building other restroom other location other ada accessible other elevator other terrain park other statue building Icon Asset Name retail art gallery retail store retail shop retail bank retail spa retail repair shop retail location retail ticket office Icon Asset Name service corporate tours service atm service health service real estate service location service post office service construction service ticket office Icon Asset Name ski features racing ski features slow zone ski features kid zone ski features ski valet ski features location ski features terrain park Icon Asset Name transportation bus transportation location transportation parking Icon Asset Name avatar 1 avatar 2 avatar 3 avatar 4 avatar 5 avatar 6 avatar 7 avatar 8 avatar 9 avatar 10 avatar 11 avatar 12 avatar 13 avatar 14 avatar 15 avatar 16 avatar 17 avatar 18 avatar 19 avatar 20 avatar 21 avatar 22 avatar 23 avatar 24 avatar 25 avatar 26 avatar 27 avatar 28 avatar 29 avatar 30 avatar 31 avatar 32 avatar 33 avatar 34 avatar 35 avatar grey 1 avatar 36 avatar grey 4 avatar grey 3 avatar grey 2 Icon Asset Name alert avatar directions building Icon Asset Name gondola tram chair lift 6 towrope chair lift 3 chair lift 4 magic carpet chair lift 5 chair lift 2 Icon Asset Name rotate settings home sign close zoom in north layers sort chevron down measurement gallery show website basemap gallery close 1 about collapse more hide search mountain view 3d view edit zoom out chevron right grid view card view elevation phone compass find location 1 current position 2d view pan Share search 1 Icon Asset Name settings 3d meet artist tutorial location sharing map legend ski patrol crew user tips coming soon stats Icon Asset Name beginner intermediate advanced expert beginner intermediate intermediate advanced expert extreme Icon Asset Name rotate pan zoom in zoom out tilt