Skip to content

Commit 9ef8b36

Browse files
committed
Location sharing: don't hardcode API key
In an effort to make it easier for forks to (a) use their own API keys (b) change map styles or maybe even providers, move the MapTiler key out of the source code and pass it in via env var or property. Also refactor the utility classes slightly to keep all the URL related functions together, to reduce the chance of collisions when maintaining such forks.
1 parent ee56821 commit 9ef8b36

File tree

9 files changed

+128
-218
lines changed

9 files changed

+128
-218
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ jobs:
3838
with:
3939
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
4040
- name: Assemble debug APK
41+
env:
42+
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
4143
run: ./gradlew assembleDebug $CI_GRADLE_ARG_PROPERTIES
4244
- name: Upload debug APKs
4345
uses: actions/upload-artifact@v3

.github/workflows/nightly.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ jobs:
3535
run: |
3636
./gradlew assembleNightly appDistributionUploadNightly $CI_GRADLE_ARG_PROPERTIES
3737
env:
38+
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
3839
ELEMENT_ANDROID_NIGHTLY_KEYID: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYID }}
3940
ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD }}
4041
ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD }}

docs/maps.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Use of maps
2+
3+
<!--- TOC -->
4+
5+
* [Overview](#overview)
6+
* [Local development with MapTiler](#local-development-with-maptiler)
7+
* [Making releasable builds with MapTiler](#making-releasable-builds-with-maptiler)
8+
* [Using other map sources or MapTiler styles](#using-other-map-sources-or-maptiler-styles)
9+
10+
<!--- END -->
11+
12+
## Overview
13+
14+
Element Android uses [MapTiler](https://www.maptiler.com/) to provide map
15+
imagery where required. MapTiler requires an API key, which we bake in to
16+
the app at release time.
17+
18+
## Local development with MapTiler
19+
20+
If you're developing the application and want maps to render properly you can
21+
sign up for the [MapTiler free tier](https://www.maptiler.com/cloud/pricing/).
22+
23+
Place your API key in `local.properties` with the key
24+
`services.maptiler.apikey`, e.g.:
25+
26+
```properties
27+
services.maptiler.apikey=abCd3fGhijK1mN0pQr5t
28+
```
29+
30+
## Making releasable builds with MapTiler
31+
32+
To insert the MapTiler API key when building an APK, set the
33+
`ELEMENT_ANDROID_MAPTILER_API_KEY` environment variable in your build
34+
environment.
35+
36+
## Using other map sources or MapTiler styles
37+
38+
If you wish to use an alternative map provider, or custom MapTiler styles,
39+
you can customise the functions in
40+
`features/location/api/src/main/kotlin/io/element/android/features/location/api/internal/MapUrls.kt`.
41+
We've kept this file small and self contained to minimise the chances of merge
42+
collisions in forks.

features/location/api/build.gradle.kts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,33 @@
1414
* limitations under the License.
1515
*/
1616

17+
import java.util.Properties
18+
1719
plugins {
1820
id("io.element.android-compose-library")
1921
alias(libs.plugins.ksp)
2022
id("kotlin-parcelize")
2123
}
2224

25+
fun readLocalProperty(name: String) = Properties().apply {
26+
try {
27+
load(rootProject.file("local.properties").reader())
28+
} catch (ignored: java.io.IOException) {
29+
}
30+
}[name]
31+
2332
android {
2433
namespace = "io.element.android.features.location.api"
34+
35+
defaultConfig {
36+
resValue(
37+
type = "string",
38+
name = "maptiler_api_key",
39+
value = System.getenv("ELEMENT_ANDROID_MAPTILER_API_KEY")
40+
?: readLocalProperty("services.maptiler.apikey") as? String
41+
?: ""
42+
)
43+
}
2544
}
2645

2746
dependencies {

features/location/api/src/main/kotlin/io/element/android/features/location/api/StaticMapView.kt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,8 @@ import androidx.compose.ui.unit.dp
3434
import coil.compose.AsyncImagePainter
3535
import coil.compose.rememberAsyncImagePainter
3636
import coil.request.ImageRequest
37-
import io.element.android.features.location.api.internal.AttributionPlacement
3837
import io.element.android.features.location.api.internal.StaticMapPlaceholder
39-
import io.element.android.features.location.api.internal.buildStaticMapsApiUrl
38+
import io.element.android.features.location.api.internal.staticMapUrl
4039
import io.element.android.libraries.designsystem.preview.DayNightPreviews
4140
import io.element.android.libraries.designsystem.preview.ElementPreview
4241
import io.element.android.libraries.designsystem.text.toDp
@@ -64,6 +63,7 @@ fun StaticMapView(
6463
modifier = modifier,
6564
contentAlignment = Alignment.Center
6665
) {
66+
val context = LocalContext.current
6767
var retryHash by remember { mutableStateOf(0) }
6868
val painter = rememberAsyncImagePainter(
6969
model = if (constraints.isZero) {
@@ -72,17 +72,16 @@ fun StaticMapView(
7272
} else {
7373
ImageRequest.Builder(LocalContext.current)
7474
.data(
75-
buildStaticMapsApiUrl(
75+
staticMapUrl(
76+
context = context,
7677
lat = lat,
7778
lon = lon,
78-
desiredZoom = zoom,
79+
zoom = zoom,
7980
darkMode = darkMode,
80-
attributionPlacement = AttributionPlacement.BottomLeft,
8181
// Size the map based on DP rather than pixels, as otherwise the features and attribution
8282
// end up being illegibly tiny on high density displays.
83-
desiredWidth = constraints.maxWidth.toDp().value.toInt(),
84-
desiredHeight = constraints.maxHeight.toDp().value.toInt(),
85-
doubleScale = true,
83+
width = constraints.maxWidth.toDp().value.toInt(),
84+
height = constraints.maxHeight.toDp().value.toInt(),
8685
)
8786
)
8887
.size(width = constraints.maxWidth, height = constraints.maxHeight)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) 2023 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.element.android.features.location.api.internal
18+
19+
import android.content.Context
20+
import io.element.android.features.location.api.R
21+
22+
/**
23+
* Provides the URL to an image that contains a statically-generated map of the given location.
24+
*/
25+
fun staticMapUrl(
26+
context: Context,
27+
lat: Double,
28+
lon: Double,
29+
zoom: Double,
30+
width: Int,
31+
height: Int,
32+
darkMode: Boolean,
33+
): String {
34+
return "${baseUrl(darkMode)}/static/${lon},${lat},${zoom}/${width}x${height}@2x.webp?key=${context.apiKey}&attribution=bottomleft"
35+
}
36+
37+
/**
38+
* Provides the URL to a MapLibre style document, used for rendering dynamic maps.
39+
*/
40+
fun tileStyleUrl(
41+
context: Context,
42+
darkMode: Boolean,
43+
): String {
44+
return "${baseUrl(darkMode)}/style.json?key=${context.apiKey}"
45+
}
46+
47+
private fun baseUrl(darkMode: Boolean) =
48+
"https://api.maptiler.com/maps/" +
49+
if (darkMode)
50+
"dea61faf-292b-4774-9660-58fcef89a7f3"
51+
else
52+
"9bc819c8-e627-474a-a348-ec144fe3d810"
53+
54+
private val Context.apiKey: String
55+
get() = getString(R.string.maptiler_api_key)

features/location/api/src/main/kotlin/io/element/android/features/location/api/internal/MapsUtils.kt

Lines changed: 0 additions & 91 deletions
This file was deleted.

0 commit comments

Comments
 (0)