Quick Start
Caution
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
Username and password will be provided by our sales department.
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
...
}
}
License key will be provided by our sales department.
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.