Quick Start

Minimal requirements

  • Android device running API 23 and above
  • Since this is an offline maps-based SDK, sufficent space on internal or external storage is required

Adding the library to your project

Add this piece of code to settings.gradle

dependencyResolutionManagement {
  ..
  repositories {
    ..
        maven {
            url "https://sdk.mapfactor.com/repo/release"
            credentials {
                username "$mavenUsername"
                password "$mavenPassword"
            }
        }
  }
}

or build.gradle for older projects

allprojects {
  repositories {
    ..
      maven {
          url "https://sdk.mapfactor.com/repo/release"
          credentials {
              username "$mavenUsername"
              password "$mavenPassword"
          }
      }
  }
}

Edit your gradle.properties

mavenUsername=askForUsername
mavenPassword=askForPassword

Configure your build.gradle

dependencies {
    implementation "com.mapfactor:sdk:x.y.z"
}

Adding to the layout

Add implementation 'com.google.android.material:material:x.y.z' for back compatibility. Use FragmentActivity instead of a ComponentActivity successor to support our Fragment.

Jetpack Compose

In case of using Jetpack Compose, check Inter-op with XML inter-op docs by Google. Insertion to the layout can be executed either by view or fragment. Our MapView is basically a view containing MapFragment.

MapView element

View plays the role of a wrapper around our MapFragment. Once MapView is inflated, you can access the inner fragment.

AndroidView(
    modifier = Modifier.fillMaxSize(),
    factory = { context ->
        MapView(context).apply {
            //do whatever you want, e.g.

            //set night mode
            this.mapFragment.setNightMode(true)

            //handle map controls visibility
            val mapControls = this.mapFragment.mapControls
            mapControls.setMapControlVisibility(
                MapControls.MapControl.COMPASS,
                true
            )

            //or add listener
            this.mapFragment.addOnMapReadyListener {

            }
        }
    },
    update = {
    }
)

Fragment element

You need to create an XML layout file in res/layout. e.g. fragment_navigation.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragment_container_view"
        android:name="com.mapfactor.sdk.map.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

and then use this layout to inflate in Kotlin like this.

AndroidViewBinding(FragmentNavigationBinding::inflate) {
    val mapFragment = fragmentContainerView.getFragment<MapFragment>()

    //do whatever you want, e.g.

    //set night mode
    mapFragment.setNightMode(true)

    //handle map controls visibility
    val mapControls = mapFragment.mapControls
    mapControls.setMapControlVisibility(
         MapControls.MapControl.COMPASS,
         true
    )

    //or add listener
    mapFragment.addOnMapReadyListener {

    }
}

For more information, check official Google documentation.

View-based system

For layout implementation, there are two options - direct XML view containing MapFragment on background or inserting a MapFragment with FragmentContainerView.

MapView element

<com.mapfactor.sdk.map.MapView
      android:id="@+id/map_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent"/>

Fragment element

<androidx.fragment.app.FragmentContainerView
      android:id="@+id/map_fragment"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:name="com.mapfactor.sdk.map.MapFragment"/>

Initialization

To ensure our SDK works properly, add dependencies to a build.gradle:

implementation "androidx.compose.ui:ui-viewbinding:x.y.z"
implementation "androidx.fragment:fragment-ktx:x.y.z"
implementation 'androidx.constraintlayout:constraintlayout:x.y.z'

buildFeatures {
  viewBinding true
}

You will need to add permissions to access device location to AndroidManifest.xml as follows.

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

The key to run our SDK is MpfcEngine’s init​ method.

// get path
val sdkDataPath = getExternalFilesDir(null).toString()

// get renderer
val rendererName: RendererName = RendererName.HARDWARE

// get map data provider
val mapDataProvider: ProviderName = ProviderName.OSM

//get language
val lang = "en"

MpfcEngine.getInstance().init(this, sdkDataPath, mapDataProvider, rendererName, lang, object :
    MpfcEngine.InitListener {
    override fun onLocationPermissionNotGranted() {
      // notify an activity to make a request for location permission,
      // e.g. using broadcast intent
    }

    override fun onEngineInitStatusChanged(initStatus: MpfcEngine.InitStatus) {
    // log
    }

    override fun onEngineInitFinished(initStatusResult: MpfcEngine.InitResult) {
      if (result == MpfcEngine.InitResult.SUCCESS) {
        //HURAYYY, do whatever you want, e.g.
          initActiveVehicle()
          getAllAvailableVehicles()
          setCurrentLanguage()
      } else if (result == MpfcEngine.InitResult.FAILED_DEVICE_NOT_ACTIVATED
          || result == MpfcEngine.InitResult.FAILED_SDK_NOT_LICENSED) {
         //oops, activate device
          activateDevice()
      }
    }
})

fun activateDevice() {
  MpfcEngine.getInstance().activateDevice(
    getApplication(),
    "AAAAA-BBBBB-CCCCC-DDDDD-EEEEE"
    )  { activationResult: MpfcEngine.ActivationResult ->
          val succeeded =
            activationResult == MpfcEngine.ActivationResult.SUCCEEDED ||
            activationResult == MpfcEngine.ActivationResult.ALREADY_ACTIVATED
            ...
        }
}

From now on theMpfcEngine instance is used for most use cases.

Data download

For downloading map, voice and sound data, use the downloadAppData method of the AppDataManagerModule.

MpfcEngine.getInstance().appDataManagerModule
  .downloadAppData(dataIds, object : DataDownloadListener {
      override fun onDownloadProgress(
          dataId: String,
          dataName: String,
          iFile: Int,
          numFiles: Int,
          curFileProgress: Long,
          curFileSize: Long,
          totProgress: Long,
          totSize: Long
      ) {
          //process current progress
      }

      override fun onDownloadFinished() {

      }

      override fun onDownloadFailed(errorCode: AppDataManager.DownloadErrorCode) {
          //handle error
      }

      override fun onEngineRestarted() {

      }
  })