Quick Start On this page The SDK library is always improving. For the latest developments and features please check Release Notes .
Minimal requirements# Android Studio Android device or emulator running API 23 and above Since this is an offline maps-based SDK, sufficient space on internal or external storage is required Adding the library to your project# Please check Release Notes to find out the current version of the library.
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 () {
}
})
TIP: If using Kotlin, you can take advantage of callbackFlow
.
Beware of executing methods related to MpfcEngine instance
repeatedly. You can call them again once onEngineRestarted
callback is invoked.