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

Get started with Mappy SDK

iOS

Install the following:

If you don't have an Xcode project and want to try out a Mappy product, you can download a quick-start sample.

Android

Install the following:

If you don't have an Android project and want to try out a Mappy product, or want to see a code example, you can download or clone this quick-start sample.

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 a Client Id and a secret key associated with your app. Make sure you store them securely.

Add Mappy SDK to your App

iOS

  1. If you don't have Cocoapods installed on your machine, install it by following this guide.
  2. Add pod 'Mappy' to your project's podfile.
  3. Run the pod install command from the root directory of the project.
  4. When finished, open the project's workspace and find the Mappy dependency under the Pod’s project.

Android

dependencies {
    implement("io.mappy.sdk:mappy:0.5.5")
}

Localize the module level build.gradle file where you want the SDK installed and add the dependency full qualified name, you can find an example code at the right.

maven { url = uri("https://esri.jfrog.io/artifactory/arcgis") }
maven {
    name = "GitHubPackages"
    url = uri("https://maven.pkg.github.com/beMappy/Mappy-Kotlin")
    credentials {
        username = <GITHUB_USERNAME>
        password = <GITHUB_PERSONAL_ACCESS_TOKEN>
    }
}

The Mappy Android SDK, for now, is available through Github Packages. So add the following to the project/build.gradle file, you can find an example code at the right.

The SDK is dependant on a special toolkit dependency stored in Jfrog. If you are not familiar to Github Personal Access Token, generate it using this guide

Also, in the code example you will find instructions to exclude duplicated packages to ensure compilation in the Application side is succesfull. These files are just meta data.

android {
    packagingOptions {
        resources.excludes.add("META-INF/INDEX.LIST")
        resources.excludes.add("META-INF/DEPENDENCIES")
        resources.excludes.add("META-INF/io.netty.versions.properties")
    }
}

Initialize Mappy in Your App

Mappy needs to be initialized in your app by adding an initialization code.

iOS

To initialize use this code

import Mappy

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    MappyCore.initialize(clientId: <ClientId>, secret: <ClientSecret>, mappyUserId: <MappyUserId>)
        .sink(receiveCompletion: {
            if case .failure(let error) = $0 {
                print("initialize: error: \(error)")
            }
        }, receiveValue: { [unowned self] in
            print("MappyCore Initialized")
            // $0 - MappyMeta
        })
        .store(in: &cancellables)

  return true
}

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

  1. Import the Mappy module in your UIApplicationDelegate.
  2. Configure a Mappy shared instance, typically in your app's initializer or app delegate's application(_:didFinishLaunchingWithOptions:) method:

This function helps to instantiate the Mappy SDK. Post initialization, SDK APIs can be used internally across the project. This is the static method and 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.

Android

Using Kotlin Coroutines

val mappy = Mappy.createInstance(applicationContext)
CoroutineScope(Dispatchers.IO).launch {
    val userId = mappy.initialize(clientId: <ClientId>, clientSecret: <ClientSecret>, mappyUserId: <String?>)
}

Using Callback

mappy.initialize(clientId: <ClientId>, clientSecret: <ClientSecret>, mappyUserId: <String?>, object: CompletionCallback<String> {
    override fun onSuccess(result: String) {
        //Initialization Success
    }

    override fun onError(throwable: Throwable) {
        //Initialization Error
    }
})
Mappy mappy = Mappy.createInstance(getApplicationContext());

mappy.initialize(clientId: <ClientId>, clientSecret: <ClientSecret>, mappyUserId: <String?>, new CompletionCallback<String>() {
    @Override
    public void onSuccess(String result) {
        //Initialization Success
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Initialization Error
    }
});
  1. Import the Mappy module.
  2. Create a Mappy object instance through the code instruction displayed in the example, be sure to pass a valid context to the createInstance method.

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)

Using Kotlin Coroutines

val venueService = VenueService.createInstance(applicationContext)
CoroutineScope(Dispatchers.IO).launch {      
    val venues = venueService.getVenues()
}

Using Callback

venueService.getVenues(object: CompletionCallback<List<Venue>> {
    override fun onSuccess(result: List<Venue>) {
      //Get Venues Successful
    }

    override fun onError(throwable: Throwable) {
      //Get Venues Error
    }
})
VenueService venueService = VenueService.createInstance(getApplicationContext());
venueService.getVenues(new CompletionCallback<List<Venue>>() {
    @Override
    public void onSuccess(List<Venue> result) {
        //Get Venues Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Get Venues Error
    }
});

This function provides a list of venues associated with a particular Client Id. The data returned includes all details of available venues.

Get a Specific Venue

let venuesService = VenuesService()
venuesService.getVenue(venueId: <VenueId>)
  .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)

Using Kotlin Coroutines

val venueService = VenueService.createInstance(applicationContext);
CoroutineScope(Dispatchers.IO).launch {
    venueService.getVenue(<ID>)
}

Using Callback

venueService.getVenue(<ID>, object: CompletionCallback<Venue> {
    override fun onSuccess(result: Venue) {
        //Get Venue Successful
    }

    override fun onError(throwable: Throwable) {
        //Get Venue Error
    }
})
VenueService venueService = VenueService.createInstance(getApplicationContext());
venueService.getVenue(<ID>, new CompletionCallback<Venue>() {
    @Override
    public void onSuccess(Venue venue) {
        //Get Venue Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Get Venue Error
    }
});

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

Rendering

Map

Map - Load

map = Map(mapInfo: <info>)
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)
val map = Map(venue)
map.load(this, object : CompletionCallback<Map>() {
    fun onSuccess(map: Map) {
        binding.mapView.setMap(map)
    }

    fun onError(throwable: Throwable) {
        // Error Handling
    }
})

Map - Using Jetpack Compose

// must execute load method successfully first on the map object
MapView(
    map = map,
    modifier = Modifier,
    mapController = MapController()
)
Map map = new Map(venue);
map.load(this, new CompletionCallback<Map>() {
    @Override
    public void onSuccess(@NonNull Map map) {
        binding.mapView.setMap(map);
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        // Error Handling
    }
});

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] featues in
        // Received featues
  })
  .store(in: &cancellables)

Get Features - Using Kotlin Coroutines

val map = Map(venue)
CoroutineScope(Dispatchers.IO).launch {     
    val loadedMap = map.load()
    loadedMap.getFeatures()
}

Get Features - Using Callback

// must execute load method successfully first on the map object
loadedMap.getFeatures(object: CompletionCallback<List<Feature>> {
    override fun onSuccess(result: List<Feature>) {
        //Get Features Successful
    }

    override fun onError(throwable: Throwable) {
        //Get Features Error
    }
})
// must execute load method successfully first on the map object
loadedMap.getFeatures(new CompletionCallback<List<Feature>>() {
    @Override
    public void onSuccess(List<Feature> result) {
        //Get Features Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Get Features Error
    }
});

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: <SearchText>)
  .receive(on: DispatchQueue.main)
  .sink(receiveCompletion: { completion in
      switch completion {
      case .finished: break
      case .failure(let error):
          print("error: \(error)")
      }
  }, receiveValue: { [weak self] featues in
        // Received featues
  })
  .store(in: &cancellables)

Search features - Using Kotlin Coroutines

val map = Map(venue)
CoroutineScope(Dispatchers.IO).launch {     
    val loadedMap = map.load()
    loadedMap.getFeatures(<keyword>)
}

Search features - Using Callback

// must execute load method successfully first on the map object
loadedMap.getFeatures(<keyword>, object: CompletionCallback<List<Feature>> {
    override fun onSuccess(result: List<Feature>) {
        //Get Features Successful
    }

    override fun onError(throwable: Throwable) {
        //Get Features Error
    }
})
// must execute load method successfully first on the map object
loadedMap.getFeatures(<keyword>, new CompletionCallback<List<Feature>>() {
    @Override
    public void onSuccess(List<Feature> result) {
        //Get Features Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Get Features Error
    }
});

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>)
  .receive(on: DispatchQueue.main)
  .sink(receiveCompletion: { completion in
      switch completion {
      case .finished: break
      case .failure(let error):
          print("error: \(error)")
      }
  }, receiveValue: { [weak self] featues in
        // Received featues
  })
  .store(in: &cancellables)

Filter features - Using Kotlin Coroutines

val map = Map(venue)
CoroutineScope(Dispatchers.IO).launch {     
    val loadedMap = map.load()
    loadedMap.getFeatures(<classType>)
}

Filter features - Using Callback

// must execute load method successfully first on the map object
loadedMap.getFeatures(<classType>, object: CompletionCallback<List<Feature>> {
    override fun onSuccess(result: List<Feature>) {
        //Get Features Successful
    }

    override fun onError(throwable: Throwable) {
        //Get Features Error
    }
})

/**
* Possible classTypes:
*   - SkiLift::class.java
*   - SkiSlope::class.java
*   - Building::class.java
*   - BuildingAmenity::class.java
*/
// must execute load method successfully first on the map object
loadedMap.getFeatures(<classType>, new CompletionCallback<List<Feature>>() {
    @Override
    public void onSuccess(List<Feature> result) {
        //Get Features Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Get Features Error
    }
});

/**
* Possible classTypes:
*   - SkiLift.class
*   - SkiSlope.class
*   - Building.class
*   - BuildingAmenity.class
*/

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 - Using XML UI

import io.bemappy.sdk.ui.MapView
MapView(context)

MapView - Using Jetpack Compose

import io.bemappy.sdk.ui.compose.MapView 
MapView(map, modifier, mapController)
import io.bemappy.sdk.ui.MapView;
new MapView(context)

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

Rotate - Using XML UI (with View Binding or Data Binding)

binding.mapView.rotateToNorth()

Rotate - Using Jetpack Compose

// must execute load method successfully first on the map object
val mapController = remember { MapController() }

MapView(
    map = loadedMap,
    modifier = Modifier,
    mapController = mapController
)

mapController.rotateToNorth()
binding.mapView.rotateToNorth();

Rotates the map to the default orientation

Set Initial ViewPoint

MapView - Set Initial ViewPoint

mapView.setInitialViewpoint()

Initial ViewPoint - Using XML UI (with View Binding or Data Binding)

binding.mapView.setInitialViewpoint()

Initial ViewPoint - Using Jetpack Compose

mapController.setInitialViewpoint()
binding.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)

Tap Listener - Using XML UI (with View Binding or Data Binding)

binding.mapView.setTapListener(object: TapListener {
        override fun onTouch(feature: Feature?) {
             // handle tap
        }
    }
)

Tap Listener - Using Jetpack Compose

MapView(
    map = loadedMap,
    modifier = Modifier.fillMaxSize(),
    mapController = mapController,
    onTap = { feature -> // handle tap }
)
binding.mapView.setTapListener((feature) -> {
    //handle tap
});

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)

View Point Change Listener - Using XML UI (with View Binding or Data Binding)

binding.mapView.setViewPointChangeListener(object: ViewpointChangeListener {
    override fun onChanged() {
        //handle viewpoint change
    }
})

View Point Change Listener - Using Jetpack Compose

MapView(
    map = loadedMap,
    modifier = Modifier.fillMaxSize(),
    mapController = mapController,
    onViewPointChanged = { 
        //handle viewpoint change
    }
)
// lambda example
binding.mapView.setViewPointChangeListener(() -> {
    //handle viewpoint change
});

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

Select a Feature - Using XML UI (with View Binding or Data Binding)

binding.mapView.selectFeature(<Feature>)

Select a Feature - Using Jetpack Compose

MapView(
    map = loadedMap,
    modifier = Modifier.fillMaxSize(),
    mapController = mapController
)

mapController.selectFeature(<Feature>)

Select a Feature

binding.mapView.selectFeature(<Feature>)

A function that highlights and zooms to the feature provided

Unselect a Feature

Unselect a Feature

mapView.select(feature: nil)

Unselect a Feature - Using XML UI (with View Binding or Data Binding)

binding.mapView.unselectFeature()

Unselect a Feature - Using Jetpack Compose

MapView(
    map = loadedMap,
    modifier = Modifier.fillMaxSize(),
    mapController = mapController
)

mapController.unselectFeature()

Unselect a Feature

binding.mapView.unselectFeature()

A function that removes the highlight from the selected feature

Display User Pins

MapView - Display User Pins

mapView.displayUserPins(using: <[UserPinLocation]>)

MapView - Display User Pins - Using Jetpack Compose

MapView(
    map = loadedMap,
    modifier = Modifier.fillMaxSize(),
    mapController = mapController
)

mapController.displayUserPins(<UserLocation>, <String>, <BitmapDrawable>)

MapView - Display User Pins - Using View Binding

binding.mapView.displayUserPins(<UserLocation>, <String>, <BitmapDrawable>)

MapView - Display User Pins - Using View Binding

binding.mapView.displayUserPins(<UserLocation>, <String>, <BitmapDrawable>)

A function that plots the pins on the map.

Remove User Pins

MapView - Remove User Pins

mapView.displayUserPins(using: [])

MapView - Remove User Pins - Using Jetpack Compose

MapView(
    map = loadedMap,
    modifier = Modifier.fillMaxSize(),
    mapController = mapController
)

mapController.removeUserPins()

MapView - Remove User Pins - Using View Binding

binding.mapView.removeUserPins()

MapView - Remove User Pins - Using View Binding

binding.mapView.removeUserPins()

To remove the pins from the map.

Scene

Scene - Load

scene = Scene(sceneInfo: <info>)
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)

Scene - Using XML UI (with View Binding or Data Binding)

val scene = Scene(venue)
scene.load(this, object : CompletionCallback<Scene>() {
    fun onSuccess(scene: Scene) {
        binding.sceneView.setScene(scene)
    }

    fun onError(throwable: Throwable) {
        // Error Handling
    }
})

Scene - Using Jetpack Compose

// must execute load method successfully first on the scene object
SceneView(
    scene = scene,
    modifier = Modifier,
    sceneController = SceneController()
)
Scene scene = new Scene(venue);
scene.load(this, new CompletionCallback<Scene>() {
    @Override
    public void onSuccess(@NonNull Scene scene) {
        binding.sceneView.setScene(scene);
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        // Error Handling
    }
});

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] featues in
        // Received featues
  })
  .store(in: &cancellables)

Get Features - Using Kotlin Coroutines

val scene = Scene(venue)
CoroutineScope(Dispatchers.IO).launch {     
    val loadedScene = scene.load()
    loadedScene.getFeatures()
}

Get Features - Using Callback

// must execute load method successfully first on the scene object
loadedScene.getFeatures(object: CompletionCallback<List<Feature>> {
    override fun onSuccess(result: List<Feature>) {
        //Get Features Successful
    }

    override fun onError(throwable: Throwable) {
        //Get Features Error
    }
})
// must execute load method successfully first on the map object
loadedScene.getFeatures(new CompletionCallback<List<Feature>>() {
    @Override
    public void onSuccess(List<Feature> result) {
        //Get Features Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Get Features Error
    }
});

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: <SearchText>)
  .receive(on: DispatchQueue.main)
  .sink(receiveCompletion: { completion in
      switch completion {
      case .finished: break
      case .failure(let error):
          print("error: \(error)")
      }
  }, receiveValue: { [weak self] featues in
        // Received featues
  })
  .store(in: &cancellables)

Search features - Using Kotlin Coroutines

val scene = Scene(venue)
CoroutineScope(Dispatchers.IO).launch {     
    val loadedScene = scene.load()
    loadedScene.getFeatures(<keyword>)
}

Search features - Using Callback

// must execute load method successfully first on the scene object
loadedScene.getFeatures(<keyword>, object: CompletionCallback<List<Feature>> {
    override fun onSuccess(result: List<Feature>) {
        //Get Features Successful
    }

    override fun onError(throwable: Throwable) {
        //Get Features Error
    }
})
// must execute load method successfully first on the map object
loadedScene.getFeatures(<keyword>, new CompletionCallback<List<Feature>>() {
    @Override
    public void onSuccess(List<Feature> result) {
        //Get Features Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Get Features Error
    }
});

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] featues in
        // Received featues
  })
  .store(in: &cancellables)

Filter features - Using Kotlin Coroutines

val scene = Scene(venue)
CoroutineScope(Dispatchers.IO).launch {     
    val loadedScene = scene.load()
    loadedScene.getFeatures(<classType>)
}

Filter features - Using Callback

// must execute load method successfully first on the map object
loadedScene.getFeatures(<classType>, object: CompletionCallback<List<Feature>> {
    override fun onSuccess(result: List<Feature>) {
        //Get Features Successful
    }

    override fun onError(throwable: Throwable) {
        //Get Features Error
    }
})

/**
* Possible classTypes:
*   - SkiLift::class.java
*   - SkiSlope::class.java
*   - Building::class.java
*   - BuildingAmenity::class.java
*/
// must execute load method successfully first on the map object
loadedScene.getFeatures(<classType>, new CompletionCallback<List<Feature>>() {
    @Override
    public void onSuccess(List<Feature> result) {
        //Get Features Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Get Features Error
    }
});

/**
* Possible classTypes:
*   - SkiLift.class
*   - SkiSlope.class
*   - Building.class
*   - BuildingAmenity.class
*/

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 - Using XML UI

import io.bemappy.sdk.ui.SceneView
SceneView(context)

SceneView - Using Jetpack Compose

import io.bemappy.sdk.ui.compose.SceneView 
SceneView(scene, modifier, sceneController)
import io.bemappy.sdk.ui.SceneView;
new SceneView(context)

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

Rotate To North - Using XML UI (with View Binding or Data Binding)

binding.sceneView.rotateToNorth()

Rotate To North - Using Jetpack Compose

// must execute load method successfully first on the map object
val sceneController = remember { SceneController() }

SceneView(
    scene = loadedScene,
    modifier = Modifier,
    sceneController = sceneController
)

sceneController.rotateToNorth()
binding.sceneView.rotateToNorth();

Rotates the scene to the default orientation

Set Initial ViewPoint

SceneView - Set Initial ViewPoint

sceneView.setInitialViewpoint()

Set Initial ViewPoint - Using XML UI (with View Binding or Data Binding)

binding.sceneView.setInitialViewpoint()

Set Initial ViewPoint - Using Jetpack Compose

sceneController.setInitialViewpoint()
binding.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)

Tap Listener - Using XML UI (with View Binding or Data Binding)

binding.sceneView.setTapListener(object: TapListener {
        override fun onTouch(feature: Feature?) {
             // handle tap
        }
    }
)

Tap Listener - Using Jetpack Compose

SceneView(
    scene = loadedScene,
    modifier = Modifier.fillMaxSize(),
    sceneController = sceneController,
    onTap = { feature -> // handle tap }
)
binding.sceneView.setTapListener((feature) -> {
    //handle tap
});

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)

View Point Change Listener - Using XML UI (with View Binding or Data Binding)

binding.sceneView.setViewPointChangeListener(object: ViewpointChangeListener {
    override fun onChanged() {
        //handle viewpoint change
    }
})

View Point Change Listener - Using Jetpack Compose

SceneView(
    scene = loadedScene,
    modifier = Modifier.fillMaxSize(),
    sceneController = sceneController,
    onViewPointChanged = { 
        //handle viewpoint change
    }
)
// lambda example
binding.sceneView.setViewPointChangeListener(() -> {
    // handle viewpoint change
});

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

Select a Feature - Using XML UI (with View Binding or Data Binding)

binding.sceneView.selectFeature(<Feature>)

Select a Feature - Using Jetpack Compose

SceneView(
    scene = loadedScene,
    modifier = Modifier.fillMaxSize(),
    sceneController = sceneController
)

sceneController.selectFeature(<Feature>)

Select a Feature - Using Jetpack Compose

binding.sceneView.selectFeature(<Feature>)

A function that highlights and zooms to the feature provided

Unselect a Feature

Unselect a Feature

sceneView.select(feature: nil)

Unselect a Feature - Using XML UI (with View Binding or Data Binding)

binding.sceneView.unselectFeature()

Unselect a Feature - Using Jetpack Compose

SceneView(
    scene = loadedScene,
    modifier = Modifier.fillMaxSize(),
    sceneController = sceneController
)

sceneController.unselectFeature()

Unselect a Feature

binding.sceneView.unselectFeature()

A function that removes the highlight from the selected feature

Display User Pins

SceneView - Display User Pins

sceneView.displayUserPins(using: <[UserPinLocation]>)

SceneView - Display User Pins - Using Jetpack Compose

SceneView(
    scene = loadedScene,
    modifier = Modifier.fillMaxSize(),
    sceneController = sceneController
)

sceneController.displayUserPins(<UserLocation>, <String>, <BitmapDrawable>)

SceneView - Display User Pins - Using View Binding

binding.sceneView.displayUserPins(<UserLocation>, <String>, <BitmapDrawable>)

SceneView - Display User Pins - Using View Binding

binding.sceneView.displayUserPins(<UserLocation>, <String>, <BitmapDrawable>)

A function that plots the pins on the scene.

Remove User Pins

SceneView - Remove User Pins

sceneView.displayUserPins(using: [])

SceneView - Remove User Pins - Using Jetpack Compose

SceneView(
    scene = loadedScene,
    modifier = Modifier.fillMaxSize(),
    sceneController = sceneController
)

sceneController.removeUserPins()

SceneView - Remove User Pins - Using View Binding

binding.sceneView.removeUserPins()

SceneView - Remove User Pins - Using View Binding

binding.sceneView.removeUserPins()

To remove the pins from the scene.

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: <name>)
    .sink(receiveCompletion: {
        if case .failure(let error) = $0 {
            // Error
        }
    }, receiveValue: { [weak self] in
        // $0 - Group Data
    })
    .store(in: &cancellables)

Group CRUD - Create Group

val groupService = GroupService.createInstance(applicationContext)

//Using Kotlin Coroutines
CoroutineScope(Dispatchers.IO).launch {   
    val group = groupService.createGroup(<GroupName>)
}

Group CRUD - Create Group

GroupService groupService = GroupService.createInstance(getApplicationContext());

groupService.createGroup(<GroupName>, new CompletionCallback<List<Group>>() {
    @Override
    public void onSuccess(Group result) {
        //Create group Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Create group Error
    }
});

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)

Group CRUD - Fetch Groups

val groupService = GroupService.createInstance(applicationContext)

//Using Kotlin Coroutines
CoroutineScope(Dispatchers.IO).launch {   
    val groups = groupService.getGroups()
}

Group CRUD - Fetch Groups

GroupService groupService = GroupService.createInstance(getApplicationContext());

groupService.getGroups(new CompletionCallback<List<Group>>() {
    @Override
    public void onSuccess(List<Group> result) {
        //Get groups Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Get groups Error
    }
});

To fetch all the user groups.

Fetch Group Info

Group CRUD - Fetch Groups Info

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

Group CRUD - Fetch Groups Info

val groupService = GroupService.createInstance(applicationContext)

//Using Kotlin Coroutines
CoroutineScope(Dispatchers.IO).launch {   
    val group = groupService.getGroup(<GroupId>)
}

Group CRUD - Fetch Groups Info

GroupService groupService = GroupService.createInstance(getApplicationContext());

groupService.getGroup(<GroupId>, new CompletionCallback<List<Group>>() {
    @Override
    public void onSuccess(Group result) {
        //Get group Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Get group Error
    }
});

To fetch the groups data using its identifier.

Update a Group

Group CRUD - Update Group

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

Group CRUD - Update Group

val groupService = GroupService.createInstance(applicationContext)

//Using Kotlin Coroutines
CoroutineScope(Dispatchers.IO).launch {   
    val group = groupService.updateGroup(<GroupId>, <Name>)
}

Group CRUD - Update Group

GroupService groupService = GroupService.createInstance(getApplicationContext());

groupService.updateGroup(<GroupId>, <Name>, new CompletionCallback<List<Group>>() {
    @Override
    public void onSuccess(Group result) {
        //Update group Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Update group Error
    }
});

To update a group.

Delete a Group

Group CRUD - Delete Group

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

Group CRUD - Delete Group

val groupService = GroupService.createInstance(applicationContext)

//Using Kotlin Coroutines
CoroutineScope(Dispatchers.IO).launch {   
    val group = groupService.deleteGroup(<GroupId>)
}

Group CRUD - Delete Group

GroupService groupService = GroupService.createInstance(getApplicationContext());
groupService.deleteGroup(<GroupId>, new CompletionCallback<List<Group>>() {
    @Override
    public void onSuccess(Group result) {
        //Delete group Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Delete group Error
    }
});

To delete a group.

Add a user

Group CRUD - Add User

groupsService.addUser(userId: <userId>, groupCode: <code>)
    .sink(receiveCompletion: {
        if case .failure(let error) = $0 {
            // Error
        }
    }, receiveValue: { [weak self] in
        // $0 - Group data
    })
    .store(in: &cancellables)

Group CRUD - Add User

val groupService = GroupService.createInstance(applicationContext)

//Using Kotlin Coroutines
CoroutineScope(Dispatchers.IO).launch {   
    val group = groupService.addUserToGroup(<GroupCode>, <UserId>)
}

Group CRUD - Add User

GroupService groupService = GroupService.createInstance(getApplicationContext());
groupService.addUserToGroup(<GroupCode>, <UserId>, new CompletionCallback<List<Group>>() {
    @Override
    public void onSuccess(Group result) {
        //Add user to group Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Add user to group Error
    }
});

To add a user

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)

Group CRUD - Remove User

val groupService = GroupService.createInstance(applicationContext)

//Using Kotlin Coroutines
CoroutineScope(Dispatchers.IO).launch {   
    val group = groupService.deleteUserInGroup(<GroupId>, <UserId>)
}

Group CRUD - Remove User

GroupService groupService = GroupService.createInstance(getApplicationContext());
groupService.deleteUserInGroup(<GroupId>, <UserId>, new CompletionCallback<List<Group>>() {
    @Override
    public void onSuccess(Group result) {
        //Delete user in group Successful
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Delete user in group Error
    }
});

To remove a user

Group Location

The GroupLocationService helps in sharing the user's location to all the user groups and can listen to other group members' location updates.

On Event

Group Location - On Event

groupLocationService.onEvent
    .sink(receiveCompletion: {
        // $0 - Completion
    }, receiveValue: { [weak self] in
        // $0 - The type of the event
    })
    .store(in: &cancellables)

A publisher that will be fired every time whenever some information becomes available in which the application may be interested. For example, curret user's / group member's location updates.

Share User Location

Group Location - Share User Location

groupLocationService.shareUserLocation()
.sink(receiveCompletion: {
    if case .failure(let error) = $0 {
        // Error
    }
}, receiveValue: {
    // Share invocation Success
})
.store(in: &self.cancellables)

Group Location - Share User Location

val locationService = LocationService.createInstance(context)

locationService.startSharingLocation(onError = { throwable ->
    //error handling
})

Group Location - Share User Location

LocationService locationService = LocationService.createInstance(context)

locationService.startSharingLocation(new CompletionCallback<Void>() {
    @Override
    public void onSuccess(Void result) {
        //Sharing Success
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Sharing Error
    }
})

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

Stop Sharing User Location

Group Location - Stop Sharing

groupLocationService.stopSharingUserLocation()

Group Location - Stop Sharing

val locationService = LocationService.createInstance(context)

locationService.stopSharingLocation()

Group Location - Stop Sharing

LocationService locationService = LocationService.createInstance(context)

locationService.stopSharingLocation()

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)

Group Location - Listen To Groups

groupService.startListeningToGroups().catch {
    //Location Flow Error
}.collectLatest { result: UserLocation ->
    //Location Flow Collect Result
}

Group Location - Listen To Groups

groupService.startListeningToGroups(new FlowCallback<UserLocation>() {
    @Override
    public void onCollect(UserLocation result) {
        //Location Callback Collect Result
    }

    @Override
    public void onError(@NonNull Throwable throwable) {
        //Location Callback Error
    }
})

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

Group Location - Stop Listening

groupService.stopListeningToGroups()

Group Location - Stop Listening

groupService.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: <origin>, to: <destination>, skiLevel: <level>)
    .sink(receiveCompletion: {
        if case .failure(let error) = $0 {
            // Error
        }
    }, receiveValue: { [weak self] in
        // $0 - Routes
    }).store(in: &cancellables)

Navigation - Map - Routes

map.getRoutes(<origin>: Feature, <destination>: Feature, <skiLevel>: Level, <callback>: CompletionCallback<List<Route>>)

Navigation - Map - Routes

map.getRoutes(Feature <origin>, Feature <destination>, Level <skiLevel>, CompletionCallback<List<Route>> <callback>: )

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

Navigation - MapView - Display a Route - XML Based UI

mapView.display(<route>: Route)

Navigation - MapView - Display a Route - Jetpack Compose

mapController.display(<route>: Route)

Navigation - MapView - Display a Route

mapView.display(Route <route>)

To display the route on the map.

Start Navigation

Navigation - MapView - Start Navigation

let routeTracker = mapView.startNavigation(route: <RouteResponse>)

Navigation - MapView - Start Navigation - XML Based UI

mapView.startNavigation(<route>, <destinationImage>, <traversedRouteColor>, <remainingRouteColor>, object: NavigationCallback<NavigationTurn> {
    override fun onUpdate(result: NavigationTurn) {

    }

    override fun onError(throwable: Throwable) {

    }
})

Navigation - MapView - Start Navigation - Jetpack Compose

mapController.startNavigation(<route>, <destinationImage>, <traversedRouteColor>, <remainingRouteColor>, object: NavigationCallback<NavigationTurn> {
    override fun onUpdate(result: NavigationTurn) {

    }

    override fun onError(throwable: Throwable) {

    }
})

Note there is not RouteTracker object in android because everything is handled in the callback

Navigation - MapView - Start Navigation

mapView.startNavigation(<route>, <destinationImage>, <traversedRouteColor>, <remainingRouteColor>, new NavigationCallback<NavigationTurn>() {

    @Override
    public void onError(@NonNull Throwable throwable) {

    }

    @Override
    public void onUpdate(NavigationTurn result) {

    }
})

Note there is not RouteTracker object in android because everything is handled in the callback

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

Navigation - MapView - End Navigation - XML Based UI

mapView.stopNavigation()

Navigation - MapView - End Navigation - Jetpack Compose

mapController.stopNavigation()

Navigation - MapView - End Navigation

mapView.stopNavigation()

To end the navigation

Scene

Get Routes

Navigation - Scene - Routes

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

Navigation - Scene - Routes

scene.getRoutes(<origin>: Feature, <destination>: Feature, <skiLevel>: Level, <callback>: CompletionCallback<List<Route>>)

Navigation - Scene - Routes

scene.getRoutes(Feature <origin>, Feature <destination>, Level <skiLevel>, CompletionCallback<List<Route>> <callback>: )

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

Navigation - SceneView - Display a Route - XML Based UI

sceneView.display(<route>: Route)

Navigation - SceneView - Display a Route - Jetpack Compose

sceneController.display(<route>: Route)

Navigation - SceneView - Display a Route

sceneView.display(Route <route>)

To display the route on the scene.

Start Navigation

Navigation - SceneView - Start Navigation

let routeTracker = sceneView.startNavigation(route: <RouteResponse>)

Navigation - SceneView - Start Navigation - XML Based UI

sceneView.startNavigation(<route>, <destinationImage>, <traversedRouteColor>, <remainingRouteColor>, object: NavigationCallback<NavigationTurn> {
    override fun onUpdate(result: NavigationTurn) {

    }

    override fun onError(throwable: Throwable) {

    }
})

Navigation - SceneView - Start Navigation - Jetpack Compose

sceneController.startNavigation(<route>, <destinationImage>, <traversedRouteColor>, <remainingRouteColor>, object: NavigationCallback<NavigationTurn> {
    override fun onUpdate(result: NavigationTurn) {

    }

    override fun onError(throwable: Throwable) {

    }
})

Note there is not RouteTracker object in android because everything is handled in the callback

Navigation - SceneView - Start Navigation

sceneView.startNavigation(<route>, <destinationImage>, <traversedRouteColor>, <remainingRouteColor>, new NavigationCallback<NavigationTurn>() {
    @Override
    public void onError(@NonNull Throwable throwable) {

    }

    @Override
    public void onUpdate(NavigationTurn result) {

    }
})

Note there is not RouteTracker object in android because everything is handled in the callback

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

Navigation - SceneView - End Navigation - XML Based UI

sceneView.stopNavigation()

Navigation - SceneView - End Navigation - Jetpack Compose

sceneController.stopNavigation()

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

routeTracker.voiceDirectionsActive = <true / false>

To toggle the audio navigation.

Mappy Assets