diff --git a/platform/android/MapLibreAndroidTestApp/src/main/AndroidManifest.xml b/platform/android/MapLibreAndroidTestApp/src/main/AndroidManifest.xml index e12347751..7cdedd553 100644 --- a/platform/android/MapLibreAndroidTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapLibreAndroidTestApp/src/main/AndroidManifest.xml @@ -769,6 +769,18 @@ + + + + + // --8<-- [start:loadStyle] + map.setStyle("https://demotiles.maplibre.org/pmtiles/raster/style-imagery.json") { style -> + map.cameraPosition = CameraPosition.Builder() + .target(LatLng(47.5, 12.0)) + .zoom(9.0) + .build() + // --8<-- [end:loadStyle] + addPlaces(style) + } + } + } + + private fun addPlaces(style: Style) { + // --8<-- [start:addSource] + val overtureSource = VectorSource( + "overture-places", + "pmtiles://https://overturemaps-tiles-us-west-2-beta.s3.amazonaws.com/2026-01-21/places.pmtiles" + ) + style.addSource(overtureSource) + val overtureLayer = CircleLayer("overture-layer", "overture-places") + overtureLayer.setSourceLayer("place") + overtureLayer.setProperties( + PropertyFactory.circleColor(Color.parseColor("#f5c800")), + PropertyFactory.circleRadius(4f), + PropertyFactory.circleOpacity(0.6f) + ) + style.addLayer(overtureLayer) + // --8<-- [end:addSource] + + val foursquareSource = VectorSource( + "foursquare-places", + "pmtiles://https://oliverwipfli.ch/data/foursquare-os-places-10M-2024-11-20.pmtiles" + ) + style.addSource(foursquareSource) + val foursquareLayer = CircleLayer("foursquare-layer", "foursquare-places") + foursquareLayer.setSourceLayer("place") + foursquareLayer.setProperties( + PropertyFactory.circleColor(Color.parseColor("#2dd9fe")), + PropertyFactory.circleRadius(4f), + PropertyFactory.circleOpacity(0.6f) + ) + style.addLayer(foursquareLayer) + } + + @Suppress("unused") + private fun addLocalRasterSource(style: Style) { + // --8<-- [start:loadFromFile] + val path = getExternalFilesDir(null)?.absolutePath + "/watercolor.pmtiles" + val source = RasterSource( + "watercolor", + "pmtiles://file://$path", + 256 + ) + style.addSource(source) + style.addLayer(RasterLayer("watercolor", "watercolor")) + // --8<-- [end:loadFromFile] + } + + override fun onStart() { super.onStart(); mapView.onStart() } + override fun onResume() { super.onResume(); mapView.onResume() } + override fun onPause() { super.onPause(); mapView.onPause() } + override fun onStop() { super.onStop(); mapView.onStop() } + override fun onLowMemory() { super.onLowMemory(); mapView.onLowMemory() } + override fun onDestroy() { super.onDestroy(); mapView.onDestroy() } +} diff --git a/platform/android/MapLibreAndroidTestApp/src/main/res/layout/activity_pmtiles.xml b/platform/android/MapLibreAndroidTestApp/src/main/res/layout/activity_pmtiles.xml new file mode 100644 index 000000000..9ac9f0bcc --- /dev/null +++ b/platform/android/MapLibreAndroidTestApp/src/main/res/layout/activity_pmtiles.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/platform/android/MapLibreAndroidTestApp/src/main/res/values/descriptions.xml b/platform/android/MapLibreAndroidTestApp/src/main/res/values/descriptions.xml index 53faf92ba..663c890ca 100644 --- a/platform/android/MapLibreAndroidTestApp/src/main/res/values/descriptions.xml +++ b/platform/android/MapLibreAndroidTestApp/src/main/res/values/descriptions.xml @@ -85,6 +85,7 @@ Example Custom Geometry Source Load a map without providing a style URI or JSON Load MVT data + Load PMTiles data Suzhou using Droid Sans for Chinese glyphs Example raster-dem source and hillshade layer Use HeatmapLayer to visualise earthquakes diff --git a/platform/android/MapLibreAndroidTestApp/src/main/res/values/titles.xml b/platform/android/MapLibreAndroidTestApp/src/main/res/values/titles.xml index c8c5a6e8c..30fbaf929 100644 --- a/platform/android/MapLibreAndroidTestApp/src/main/res/values/titles.xml +++ b/platform/android/MapLibreAndroidTestApp/src/main/res/values/titles.xml @@ -81,6 +81,7 @@ Grid Source No Style URI/JSON Vector Tile source + PMTiles Local CJK glyph generation Hillshade Heatmap layer diff --git a/platform/android/buildSrc/src/main/kotlin/Versions.kt b/platform/android/buildSrc/src/main/kotlin/Versions.kt index 294872c09..047ca2342 100644 --- a/platform/android/buildSrc/src/main/kotlin/Versions.kt +++ b/platform/android/buildSrc/src/main/kotlin/Versions.kt @@ -1,4 +1,4 @@ object Versions { - const val ndkVersion = "28.1.13356709" + const val ndkVersion = "28.2.13676358" const val cmakeVersion = "3.24.0+" } diff --git a/platform/android/docs/data/PMTiles.md b/platform/android/docs/data/PMTiles.md index 1800c8ce7..23ec857a6 100644 --- a/platform/android/docs/data/PMTiles.md +++ b/platform/android/docs/data/PMTiles.md @@ -1,17 +1,44 @@ # PMTiles -Starting MapLibre Android 11.7.0, using [PMTiles](https://docs.protomaps.com/pmtiles/) as a data source is supported. You can prefix your vector tile source with `pmtiles://` to load a PMTiles file. The rest of the URL continue with be `https://` to load a remote PMTiles file, `asset://` to load an asset or `file://` to load a local PMTiles file. +{{ activity_source_note("PMTilesActivity.kt") }} -> Note: PMTiles sources do not currently support offline pack downloads. +Starting MapLibre Android 11.7.0, [PMTiles](https://docs.protomaps.com/pmtiles/) archives are supported as tile sources. Prefix any tile source URL with `pmtiles://` to read from a PMTiles archive: -Oliver Wipfli has made a style available that combines a [Protomaps]() basemap togehter with Foursquare's POI dataset. It is available in the [wipfli/foursquare-os-places-pmtiles](https://github.com/wipfli/foursquare-os-places-pmtiles) repository on GitHub. The style to use is +- `pmtiles://https://` — stream tiles from a remote file +- `pmtiles://file://` — read a file from device storage (use `getExternalFilesDir` or `filesDir` for the path) -``` -https://raw.githubusercontent.com/wipfli/foursquare-os-places-pmtiles/refs/heads/main/style.json +The `pmtiles://` prefix works with any [tile source type](https://maplibre.org/maplibre-style-spec/sources/) (e.g. `vector`, `raster`, `raster-dem`, etc.), from a style JSON or dynamically. + +Unlike MapLibre GL JS, which resolves relative URLs against the style's base URL, MapLibre Native requires the URL inside `pmtiles://` to be fully specified (e.g. `pmtiles://https://example.com/tiles.pmtiles`, not `pmtiles://tiles.pmtiles`). + +> Note: PMTiles sources do not support offline pack downloads or caching. + +## Loading a style that uses PMTiles sources + +Load a style JSON that references `pmtiles://` sources. The example below loads a satellite imagery basemap of the Central Alps and sets the initial camera position: + +```kotlin +--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/sources/PMTilesActivity.kt:loadStyle" ``` -The neat thing about this style is that it only uses PMTiles vector sources. PMTiles can be hosted with a relatively simple file server (or file hosting service) instead of a more complex specialized tile server. +## Adding a PMTiles source directly -
- ![Screenshot of PMTiles based style using Protomaps basemap with Foursquare POIs]({{ s3_url("pmtiles-demo.png") }}){ width="300" } -
+Add `vector` sources from PMTiles archives to an already-loaded style. The example overlays two places datasets — [Overture Maps](https://overturemaps.org/) (yellow) and [Foursquare OS Places](https://opensource.foursquare.com/os-places/) (blue) — both using `CircleLayer`. The `setSourceLayer` call names the layer within the archive to render: + +```kotlin +--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/sources/PMTilesActivity.kt:addSource" +``` + +The same pattern works for `raster` archives using `RasterSource` and `RasterLayer`. + +> Note: `raster-dem` sources added programmatically cannot specify `encoding` via the current Android API. Define `raster-dem` sources with terrarium encoding in the style JSON instead, where the `encoding` field is fully supported. + +## Loading a local PMTiles file + +For files on device storage, use `file://` with an absolute path. The example below uses `getExternalFilesDir(null)` to locate a file downloaded to the app's external files directory: + +```kotlin +--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/sources/PMTilesActivity.kt:loadFromFile" +``` + +> Note: `pmtiles://asset://` (files in `src/main/assets/`) is not currently supported. `AssetManagerFileSource` does not implement byte-range reads, which PMTiles requires to read its header and metadata. Use `file://` from device storage instead. See the [open issue](https://github.com/maplibre/maplibre-native/issues/4360) for status. diff --git a/platform/ios/MapLibre.docc/ActionJournalExample.md b/platform/ios/MapLibre.docc/ActionJournalExample.md index 8d33785b3..07f677b74 100644 --- a/platform/ios/MapLibre.docc/ActionJournalExample.md +++ b/platform/ios/MapLibre.docc/ActionJournalExample.md @@ -65,6 +65,7 @@ Enabling the action journal. ```swift let options = MLNMapOptions() options.actionJournalOptions.enabled = true + options.actionJournalOptions.renderingStatsReportInterval = 10 options.styleURL = AMERICANA_STYLE mapView = MLNMapView(frame: view.bounds, options: options) ``` diff --git a/platform/ios/MapLibre.docc/CustomStyleLayerExample.md b/platform/ios/MapLibre.docc/CustomStyleLayerExample.md index 7a7c8337d..6b3fcae89 100644 --- a/platform/ios/MapLibre.docc/CustomStyleLayerExample.md +++ b/platform/ios/MapLibre.docc/CustomStyleLayerExample.md @@ -89,10 +89,15 @@ class CustomStyleLayer: MLNCustomStyleLayer { } """ - var error: NSError? let device = resource.device - let library = try? device?.makeLibrary(source: shaderSource, options: nil) - assert(library != nil, "Error compiling shaders: \(String(describing: error))") + var library: MTLLibrary? = nil + var shaderError: Error? = nil + do { + library = try device?.makeLibrary(source: shaderSource, options: nil) + } catch { + shaderError = error + } + assert(library != nil, "Error compiling shaders: \(String(describing: shaderError))") let vertexFunction = library?.makeFunction(name: "vertexShader") let fragmentFunction = library?.makeFunction(name: "fragmentShader") diff --git a/platform/ios/MapLibre.docc/ExampleStyles.md b/platform/ios/MapLibre.docc/ExampleStyles.md index b0f2dc03d..09026765a 100644 --- a/platform/ios/MapLibre.docc/ExampleStyles.md +++ b/platform/ios/MapLibre.docc/ExampleStyles.md @@ -5,8 +5,9 @@ The following styles are used in the examples: ```swift -let AMERICANA_STYLE = URL(string: - "https://americanamap.org/style.json") - +let DEMOTILES_STYLE = URL(string: "https://demotiles.maplibre.org/style.json") +let AMERICANA_STYLE = URL(string: "https://americanamap.org/style.json") +let OPENFREEMAP_LIBERTY_STYLE = URL(string: "https://tiles.openfreemap.org/styles/liberty") +let OPENFREEMAP_BRIGHT_STYLE = URL(string: "https://tiles.openfreemap.org/styles/bright") let VERSATILES_COLORFUL_STYLE = URL(string: "https://tiles.versatiles.org/assets/styles/colorful.json") ``` diff --git a/platform/ios/MapLibre.docc/LocationPrivacyExample.md b/platform/ios/MapLibre.docc/LocationPrivacyExample.md index 32a1981f9..99f8cb906 100644 --- a/platform/ios/MapLibre.docc/LocationPrivacyExample.md +++ b/platform/ios/MapLibre.docc/LocationPrivacyExample.md @@ -64,7 +64,7 @@ class PrivacyExampleCoordinator: NSObject, MLNMapViewDelegate { super.init() } - @MainActor func mapView(_: MLNMapView, didChangeLocationManagerAuthorization manager: MLNLocationManager) { + func mapView(_: MLNMapView, didChangeLocationManagerAuthorization manager: MLNLocationManager) { guard let accuracySetting = manager.accuracyAuthorization else { return } diff --git a/platform/ios/MapLibre.docc/ObserverExample.md b/platform/ios/MapLibre.docc/ObserverExample.md index f5fdc148c..b9782b2e3 100644 --- a/platform/ios/MapLibre.docc/ObserverExample.md +++ b/platform/ios/MapLibre.docc/ObserverExample.md @@ -13,9 +13,7 @@ Observe frame rendering statistics with ``MLNMapViewDelegate/mapViewDidFinishRen ```swift -func mapViewDidFinishRenderingFrame(_: MLNMapView, fullyRendered: Bool, renderingStats: MLNRenderingStats) { - - } +func mapViewDidFinishRenderingFrame(_: MLNMapView, fullyRendered _: Bool, renderingStats _: MLNRenderingStats) {} ``` See also: ``MLNMapViewDelegate/mapViewDidFinishRenderingFrame:fullyRendered:`` and ``MLNMapViewDelegate/mapViewDidFinishRenderingFrame:fullyRendered:frameEncodingTime:frameRenderingTime:`` diff --git a/platform/ios/MapLibre.docc/PMTiles.md b/platform/ios/MapLibre.docc/PMTiles.md index f5b4585ff..c6b04f8e8 100644 --- a/platform/ios/MapLibre.docc/PMTiles.md +++ b/platform/ios/MapLibre.docc/PMTiles.md @@ -2,16 +2,133 @@ Working with PMTiles -Starting MapLibre iOS 6.10.0, using [PMTiles](https://docs.protomaps.com/pmtiles/) as a data source is supported. You can prefix your vector tile source with `pmtiles://` to load a PMTiles file. The rest of the URL continue with be `https://` to load a remote PMTiles file, `asset://` to load an asset or `file://` to load a local PMTiles file. +Starting MapLibre iOS 6.10.0, [PMTiles](https://docs.protomaps.com/pmtiles/) archives are supported as tile sources. Prefix any tile source URL with `pmtiles://` to read from a PMTiles archive: -> Note: PMTiles sources do not currently support offline pack downloads. +- `pmtiles://https://` — stream tiles from a remote file +- `pmtiles://file://` — read a file from the device filesystem, including the app bundle -Oliver Wipfli has made a style available that combines a [Protomaps]() basemap togehter with Foursquare's POI dataset. It is available in the [wipfli/foursquare-os-places-pmtiles](https://github.com/wipfli/foursquare-os-places-pmtiles) repository on GitHub. The style to use is +The `pmtiles://` prefix works with any [tile source type](https://maplibre.org/maplibre-style-spec/sources/) (e.g. `vector`, `raster`, `raster-dem`, etc.), from a style JSON or dynamically. -``` -https://raw.githubusercontent.com/wipfli/foursquare-os-places-pmtiles/refs/heads/main/style.json +> Note: PMTiles sources do not support offline pack downloads or caching. + +## Loading a style that uses PMTiles sources + +Load a style JSON that references `pmtiles://` sources. The example below loads a satellite imagery basemap of the Central Alps and sets the initial camera position: + + + +```swift +class PMTilesStyleURL: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + let mapView = MLNMapView( + frame: view.bounds, + styleURL: URL(string: "https://demotiles.maplibre.org/pmtiles/raster/style-imagery.json")! + ) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + mapView.setCenter(CLLocationCoordinate2D(latitude: 47.5, longitude: 12.0), zoomLevel: 9, animated: false) + view.addSubview(mapView) + } +} ``` -The neat thing about this style is that it only uses PMTiles vector sources. PMTiles can be hosted with a relatively simple file server (or file hosting service) instead of a more complex specialized tile server. +## Adding a PMTiles source directly -![](pmtiles-demo.png) +Add `vector` sources from PMTiles archives to an already-loaded style. The example overlays two places datasets — [Overture Maps](https://overturemaps.org/) (yellow) and [Foursquare OS Places](https://opensource.foursquare.com/os-places/) (blue) — both using `MLNCircleStyleLayer`. The `sourceLayerIdentifier` names the layer within the archive to render: + + + +```swift +class PMTilesAddSource: UIViewController, MLNMapViewDelegate { + var mapView: MLNMapView! + + override func viewDidLoad() { + super.viewDidLoad() + mapView = MLNMapView(frame: view.bounds) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + mapView.delegate = self + view.addSubview(mapView) + } + + func mapView(_: MLNMapView, didFinishLoading style: MLNStyle) { + let overtureURL = URL(string: "pmtiles://https://overturemaps-tiles-us-west-2-beta.s3.amazonaws.com/2026-01-21/places.pmtiles")! + let overtureSource = MLNVectorTileSource(identifier: "overture-places", configurationURL: overtureURL) + style.addSource(overtureSource) + let overtureLayer = MLNCircleStyleLayer(identifier: "overture-layer", source: overtureSource) + overtureLayer.sourceLayerIdentifier = "place" + overtureLayer.circleColor = NSExpression(forConstantValue: UIColor(red: 0.96, green: 0.78, blue: 0.0, alpha: 1)) + overtureLayer.circleRadius = NSExpression(forConstantValue: 4) + overtureLayer.circleOpacity = NSExpression(forConstantValue: 0.6) + style.addLayer(overtureLayer) + + let foursquareURL = URL(string: "pmtiles://https://oliverwipfli.ch/data/foursquare-os-places-10M-2024-11-20.pmtiles")! + let foursquareSource = MLNVectorTileSource(identifier: "foursquare-places", configurationURL: foursquareURL) + style.addSource(foursquareSource) + let foursquareLayer = MLNCircleStyleLayer(identifier: "foursquare-layer", source: foursquareSource) + foursquareLayer.sourceLayerIdentifier = "place" + foursquareLayer.circleColor = NSExpression(forConstantValue: UIColor(red: 0.18, green: 0.85, blue: 1.0, alpha: 1)) + foursquareLayer.circleRadius = NSExpression(forConstantValue: 4) + foursquareLayer.circleOpacity = NSExpression(forConstantValue: 0.6) + style.addLayer(foursquareLayer) + } +} +``` + +The same pattern works for `raster` archives using `MLNRasterTileSource` and `MLNRasterStyleLayer`: + + + +```swift +class PMTilesRasterSource: UIViewController, MLNMapViewDelegate { + var mapView: MLNMapView! + + override func viewDidLoad() { + super.viewDidLoad() + mapView = MLNMapView(frame: view.bounds) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + mapView.delegate = self + view.addSubview(mapView) + } + + func mapView(_: MLNMapView, didFinishLoading style: MLNStyle) { + let url = URL(string: "pmtiles://https://demotiles.maplibre.org/pmtiles/raster/imagery.pmtiles")! + let source = MLNRasterTileSource(identifier: "imagery", configurationURL: url, tileSize: 256) + style.addSource(source) + let layer = MLNRasterStyleLayer(identifier: "imagery", source: source) + style.addLayer(layer) + } +} +``` + +> Note: `raster-dem` sources added programmatically cannot specify `encoding` via the current iOS API. Define `raster-dem` sources with terrarium encoding in the style JSON instead, where the `encoding` field is fully supported. + +## Loading a local PMTiles file + +Bundle a `.pmtiles` file in your app target and reference it using its bundle URL. iOS app bundle files are accessible via `file://`, so no special handling is needed: + + + +```swift +class PMTilesLocalFile: UIViewController, MLNMapViewDelegate { + var mapView: MLNMapView! + + override func viewDidLoad() { + super.viewDidLoad() + mapView = MLNMapView(frame: view.bounds) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + mapView.delegate = self + view.addSubview(mapView) + } + + func mapView(_: MLNMapView, didFinishLoading style: MLNStyle) { + guard let fileURL = Bundle.main.url(forResource: "world", withExtension: "pmtiles") else { return } + let url = URL(string: "pmtiles://\(fileURL.absoluteString)")! + let source = MLNVectorTileSource(identifier: "world", configurationURL: url) + style.addSource(source) + let layer = MLNFillStyleLayer(identifier: "countries", source: source) + layer.sourceLayerIdentifier = "countries" + layer.fillColor = NSExpression(forConstantValue: UIColor(red: 0.67, green: 0.83, blue: 0.87, alpha: 1)) + style.addLayer(layer) + } +} +``` diff --git a/platform/ios/app-swift/Sources/PMTilesExample.swift b/platform/ios/app-swift/Sources/PMTilesExample.swift new file mode 100644 index 000000000..33207e968 --- /dev/null +++ b/platform/ios/app-swift/Sources/PMTilesExample.swift @@ -0,0 +1,125 @@ +import MapLibre +import SwiftUI +import UIKit + +// #-example-code(PMTilesStyleURL) +class PMTilesStyleURL: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + let mapView = MLNMapView( + frame: view.bounds, + styleURL: URL(string: "https://demotiles.maplibre.org/pmtiles/raster/style-imagery.json")! + ) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + mapView.setCenter(CLLocationCoordinate2D(latitude: 47.5, longitude: 12.0), zoomLevel: 9, animated: false) + view.addSubview(mapView) + } +} + +// #-end-example-code + +// #-example-code(PMTilesAddSource) +class PMTilesAddSource: UIViewController, MLNMapViewDelegate { + var mapView: MLNMapView! + + override func viewDidLoad() { + super.viewDidLoad() + mapView = MLNMapView(frame: view.bounds) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + mapView.delegate = self + view.addSubview(mapView) + } + + func mapView(_: MLNMapView, didFinishLoading style: MLNStyle) { + let overtureURL = URL(string: "pmtiles://https://overturemaps-tiles-us-west-2-beta.s3.amazonaws.com/2026-01-21/places.pmtiles")! + let overtureSource = MLNVectorTileSource(identifier: "overture-places", configurationURL: overtureURL) + style.addSource(overtureSource) + let overtureLayer = MLNCircleStyleLayer(identifier: "overture-layer", source: overtureSource) + overtureLayer.sourceLayerIdentifier = "place" + overtureLayer.circleColor = NSExpression(forConstantValue: UIColor(red: 0.96, green: 0.78, blue: 0.0, alpha: 1)) + overtureLayer.circleRadius = NSExpression(forConstantValue: 4) + overtureLayer.circleOpacity = NSExpression(forConstantValue: 0.6) + style.addLayer(overtureLayer) + + let foursquareURL = URL(string: "pmtiles://https://oliverwipfli.ch/data/foursquare-os-places-10M-2024-11-20.pmtiles")! + let foursquareSource = MLNVectorTileSource(identifier: "foursquare-places", configurationURL: foursquareURL) + style.addSource(foursquareSource) + let foursquareLayer = MLNCircleStyleLayer(identifier: "foursquare-layer", source: foursquareSource) + foursquareLayer.sourceLayerIdentifier = "place" + foursquareLayer.circleColor = NSExpression(forConstantValue: UIColor(red: 0.18, green: 0.85, blue: 1.0, alpha: 1)) + foursquareLayer.circleRadius = NSExpression(forConstantValue: 4) + foursquareLayer.circleOpacity = NSExpression(forConstantValue: 0.6) + style.addLayer(foursquareLayer) + } +} + +// #-end-example-code + +// #-example-code(PMTilesRasterSource) +class PMTilesRasterSource: UIViewController, MLNMapViewDelegate { + var mapView: MLNMapView! + + override func viewDidLoad() { + super.viewDidLoad() + mapView = MLNMapView(frame: view.bounds) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + mapView.delegate = self + view.addSubview(mapView) + } + + func mapView(_: MLNMapView, didFinishLoading style: MLNStyle) { + let url = URL(string: "pmtiles://https://demotiles.maplibre.org/pmtiles/raster/imagery.pmtiles")! + let source = MLNRasterTileSource(identifier: "imagery", configurationURL: url, tileSize: 256) + style.addSource(source) + let layer = MLNRasterStyleLayer(identifier: "imagery", source: source) + style.addLayer(layer) + } +} + +// #-end-example-code + +// #-example-code(PMTilesLocalFile) +class PMTilesLocalFile: UIViewController, MLNMapViewDelegate { + var mapView: MLNMapView! + + override func viewDidLoad() { + super.viewDidLoad() + mapView = MLNMapView(frame: view.bounds) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + mapView.delegate = self + view.addSubview(mapView) + } + + func mapView(_: MLNMapView, didFinishLoading style: MLNStyle) { + guard let fileURL = Bundle.main.url(forResource: "world", withExtension: "pmtiles") else { return } + let url = URL(string: "pmtiles://\(fileURL.absoluteString)")! + let source = MLNVectorTileSource(identifier: "world", configurationURL: url) + style.addSource(source) + let layer = MLNFillStyleLayer(identifier: "countries", source: source) + layer.sourceLayerIdentifier = "countries" + layer.fillColor = NSExpression(forConstantValue: UIColor(red: 0.67, green: 0.83, blue: 0.87, alpha: 1)) + style.addLayer(layer) + } +} + +// #-end-example-code + +struct PMTilesStyleURLRepresentable: UIViewControllerRepresentable { + func makeUIViewController(context _: Context) -> PMTilesStyleURL { PMTilesStyleURL() } + func updateUIViewController(_: PMTilesStyleURL, context _: Context) {} +} + +struct PMTilesAddSourceRepresentable: UIViewControllerRepresentable { + func makeUIViewController(context _: Context) -> PMTilesAddSource { PMTilesAddSource() } + func updateUIViewController(_: PMTilesAddSource, context _: Context) {} +} + +struct PMTilesRasterSourceRepresentable: UIViewControllerRepresentable { + func makeUIViewController(context _: Context) -> PMTilesRasterSource { PMTilesRasterSource() } + func updateUIViewController(_: PMTilesRasterSource, context _: Context) {} +} + +struct PMTilesLocalFileRepresentable: UIViewControllerRepresentable { + func makeUIViewController(context _: Context) -> PMTilesLocalFile { PMTilesLocalFile() } + func updateUIViewController(_: PMTilesLocalFile, context _: Context) {} +} diff --git a/render-test/android/app/build.gradle.kts b/render-test/android/app/build.gradle.kts index aca56f883..a01878a8c 100644 --- a/render-test/android/app/build.gradle.kts +++ b/render-test/android/app/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } android { - ndkVersion = "28.1.13356709" + ndkVersion = "28.2.13676358" sourceSets { getByName("test") {