Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ package final class WebViewManager: NSObject {

let configuration = WKWebViewConfiguration()
configuration.userContentController = makeUserContentController()
configuration.allowsInlineMediaPlayback = true

webView = WKWebView(frame: frame, configuration: configuration)
webView?.navigationDelegate = self
webView?.scrollView.contentInsetAdjustmentBehavior = .never

webView?.load(request)
}
}
Expand Down
17 changes: 16 additions & 1 deletion Sources/MapTilerSDK/Commands/Style/AddSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ package struct AddSource: MTCommand {
return handleGeoJSONSource(source)
} else if let source = source as? MTImageSource {
return handleImageSource(source)
} else if let source = source as? MTVideoSource {
return handleVideoSource(source)
}

return emptyReturnValue
Expand Down Expand Up @@ -126,11 +128,24 @@ package struct AddSource: MTCommand {

private func handleImageSource(_ source: MTImageSource) -> JSString {
guard let url = source.url else { return emptyReturnValue }
let coords = source.coordinates.map { [$0.longitude, $0.latitude] }
return """
\(MTBridge.mapObject).addSource('\(source.identifier)', {
type: '\(source.type.rawValue)',
url: '\(url.absoluteString)',
coordinates: \(source.coordinates)
coordinates: \(coords)
});
"""
}

private func handleVideoSource(_ source: MTVideoSource) -> JSString {
let urls = source.urls.map { $0.absoluteString }
let coords = source.coordinates.map { [$0.longitude, $0.latitude] }
return """
\(MTBridge.mapObject).addSource('\(source.identifier)', {
type: '\(source.type.rawValue)',
urls: \(urls),
coordinates: \(coords)
});
"""
}
Expand Down
18 changes: 18 additions & 0 deletions Sources/MapTilerSDK/Commands/Style/PauseVideoSource.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Copyright (c) 2025, MapTiler
// All rights reserved.
// SPDX-License-Identifier: BSD 3-Clause
//
// PauseVideoSource.swift
// MapTilerSDK
//

import Foundation

package struct PauseVideoSource: MTCommand {
var source: MTSource

package func toJS() -> JSString {
return "\(MTBridge.mapObject).getSource('\(source.identifier)').pause();"
}
}
35 changes: 35 additions & 0 deletions Sources/MapTilerSDK/Commands/Style/PlayVideoSource.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright (c) 2025, MapTiler
// All rights reserved.
// SPDX-License-Identifier: BSD 3-Clause
//
// PlayVideoSource.swift
// MapTilerSDK
//

import Foundation

package struct PlayVideoSource: MTCommand {
var source: MTSource

package func toJS() -> JSString {
return """
(function(){
const src = \(MTBridge.mapObject).getSource('\(source.identifier)');
if (!src) { return; }
// Try to get the underlying HTMLVideoElement used by the VideoSource
const v = src._video || (typeof src.getVideo === 'function' ? src.getVideo() : null);
if (v) {
try {
v.setAttribute('playsinline', '');
v.setAttribute('webkit-playsinline', '');
v.playsInline = true;
v.muted = true;
v.controls = false;
} catch(e) { /* no-op */ }
}
if (typeof src.play === 'function') { src.play(); }
})();
"""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Copyright (c) 2026, MapTiler
// All rights reserved.
// SPDX-License-Identifier: BSD 3-Clause
//
// SetCoordinatesToVideoSource.swift
// MapTilerSDK
//

import Foundation

package struct SetCoordinatesToVideoSource: MTCommand {
var source: MTSource
var coordinates: [[Double]]

package func toJS() -> JSString {
return "\(MTBridge.mapObject).getSource('\(source.identifier)').setCoordinates(\(coordinates));"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//

import UIKit
import CoreLocation

extension MTMapView: MTStylable {
/// Sets the value of the style's glyphs property.
Expand Down Expand Up @@ -649,24 +650,45 @@ extension MTMapView: MTStylable {

// MARK: - Image source helpers
package func setCoordinates(
_ coordinates: [[Double]],
_ coordinates: [CLLocationCoordinate2D],
to source: MTImageSource,
completionHandler: ((Result<Void, MTError>) -> Void)? = nil
) {
runCommand(SetCoordinatesToImageSource(source: source, coordinates: coordinates), completion: completionHandler)
let coords = coordinates.map { [$0.longitude, $0.latitude] }
runCommand(SetCoordinatesToImageSource(source: source, coordinates: coords), completion: completionHandler)
}

package func updateImage(
url: URL,
coordinates: [[Double]],
coordinates: [CLLocationCoordinate2D],
to source: MTImageSource,
completionHandler: ((Result<Void, MTError>) -> Void)? = nil
) {
let coords = coordinates.map { [$0.longitude, $0.latitude] }
runCommand(
UpdateImageInSource(source: source, url: url, coordinates: coordinates),
UpdateImageInSource(source: source, url: url, coordinates: coords),
completion: completionHandler
)
}

// MARK: - Video source helpers
package func setCoordinates(
_ coordinates: [CLLocationCoordinate2D],
to source: MTVideoSource,
completionHandler: ((Result<Void, MTError>) -> Void)? = nil
) {
let coords = coordinates.map { [$0.longitude, $0.latitude] }
runCommand(SetCoordinatesToVideoSource(source: source, coordinates: coords), completion: completionHandler)
}

// Control playback on a video source
package func play(_ source: MTVideoSource, completionHandler: ((Result<Void, MTError>) -> Void)? = nil) {
runCommand(PlayVideoSource(source: source), completion: completionHandler)
}

package func pause(_ source: MTVideoSource, completionHandler: ((Result<Void, MTError>) -> Void)? = nil) {
runCommand(PauseVideoSource(source: source), completion: completionHandler)
}
}

// Concurrency: style property setters
Expand Down
25 changes: 13 additions & 12 deletions Sources/MapTilerSDK/Map/Style/Source/MTImageSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//

import Foundation
import CoreLocation

/// An image source.
///
Expand All @@ -21,9 +22,9 @@ public class MTImageSource: MTSource, @unchecked Sendable {
/// URL that points to an image.
public var url: URL?

/// Corners of image specified in longitude, latitude pairs.
/// Corners of image specified as `CLLocationCoordinate2D`.
/// Clockwise order: top-left, top-right, bottom-right, bottom-left.
public var coordinates: [[Double]]
public var coordinates: [CLLocationCoordinate2D]

/// Type of the source.
public private(set) var type: MTSourceType = .image
Expand All @@ -32,8 +33,8 @@ public class MTImageSource: MTSource, @unchecked Sendable {
/// - Parameters:
/// - identifier: Unique id of the source.
/// - url: URL to the image resource.
/// - coordinates: Corners of image in [lng, lat] clockwise order.
public init(identifier: String, url: URL, coordinates: [[Double]]) {
/// - coordinates: Corners of image in clockwise order using `CLLocationCoordinate2D`.
public init(identifier: String, url: URL, coordinates: [CLLocationCoordinate2D]) {
self.identifier = identifier
self.url = url
self.coordinates = coordinates
Expand All @@ -44,13 +45,13 @@ public class MTImageSource: MTSource, @unchecked Sendable {
extension MTImageSource {
/// Updates the coordinates of the image source.
/// - Parameters:
/// - coordinates: New corners of the image specified in [lng, lat] pairs.
/// - coordinates: New corners of the image using `CLLocationCoordinate2D`.
/// - mapView: MTMapView which holds the source.
/// - completionHandler: A handler block to execute when function finishes.
@MainActor
@available(iOS, deprecated: 16.0, message: "Prefer the async version for modern concurrency handling")
public func setCoordinates(
_ coordinates: [[Double]],
_ coordinates: [CLLocationCoordinate2D],
in mapView: MTMapView,
completionHandler: ((Result<Void, MTError>) -> Void)? = nil
) {
Expand All @@ -60,14 +61,14 @@ extension MTImageSource {
/// Updates the image URL and coordinates simultaneously.
/// - Parameters:
/// - url: New image URL.
/// - coordinates: New corners of the image specified in [lng, lat] pairs.
/// - coordinates: New corners of the image using `CLLocationCoordinate2D`.
/// - mapView: MTMapView which holds the source.
/// - completionHandler: A handler block to execute when function finishes.
@MainActor
@available(iOS, deprecated: 16.0, message: "Prefer the async version for modern concurrency handling")
public func updateImage(
url: URL,
coordinates: [[Double]],
coordinates: [CLLocationCoordinate2D],
in mapView: MTMapView,
completionHandler: ((Result<Void, MTError>) -> Void)? = nil
) {
Expand All @@ -79,10 +80,10 @@ extension MTImageSource {
extension MTImageSource {
/// Updates the coordinates of the image source.
/// - Parameters:
/// - coordinates: New corners of the image specified in [lng, lat] pairs.
/// - coordinates: New corners of the image using `CLLocationCoordinate2D`.
/// - mapView: MTMapView which holds the source.
@MainActor
public func setCoordinates(_ coordinates: [[Double]], in mapView: MTMapView) async {
public func setCoordinates(_ coordinates: [CLLocationCoordinate2D], in mapView: MTMapView) async {
await withCheckedContinuation { continuation in
setCoordinates(coordinates, in: mapView) { _ in
continuation.resume()
Expand All @@ -93,10 +94,10 @@ extension MTImageSource {
/// Updates the image URL and coordinates simultaneously.
/// - Parameters:
/// - url: New image URL.
/// - coordinates: New corners of the image specified in [lng, lat] pairs.
/// - coordinates: New corners of the image using `CLLocationCoordinate2D`.
/// - mapView: MTMapView which holds the source.
@MainActor
public func updateImage(url: URL, coordinates: [[Double]], in mapView: MTMapView) async {
public func updateImage(url: URL, coordinates: [CLLocationCoordinate2D], in mapView: MTMapView) async {
await withCheckedContinuation { continuation in
updateImage(url: url, coordinates: coordinates, in: mapView) { _ in
continuation.resume()
Expand Down
Loading
Loading