Gtel Maps iOS SDK
GtelMap iOS SDK provides a map integration API suite for iOS applications, featuring a centralized interaction architecture centered on GtelMapView. The SDK enables applications to initialize and manage maps, execute operations via apply(input:), and receive status updates, operation results, and map-related events through GtelMapViewDelegate.GtelMap SDK iOS cung cấp bộ API tích hợp bản đồ dành cho ứng dụng iOS, với kiến trúc tương tác tập trung thông qua GtelMapView. SDK hỗ trợ ứng dụng khởi tạo và quản lý bản đồ, thực hiện các thao tác thông qua apply(input:), đồng thời tiếp nhận trạng thái, kết quả xử lý và các sự kiện liên quan đến bản đồ thông qua GtelMapViewDelegate.
| InfoThông tin | ValueGiá trị | Integration notesGhi chú tích hợp |
|---|---|---|
| SDKSDK | GtelMapSDK |
Add GtelMapSDK to your application target, then import the SDK with import GtelMapSDK to use its APIs.Thêm GtelMapSDK vào target của ứng dụng, sau đó import SDK bằng import GtelMapSDK để sử dụng các API của SDK. |
| Guide versionPhiên bản guide | 1.1 |
Added: GtelRouteNavigationViewController for navigation; POI interaction and display APIs; Map Style customization APIs; camera control utilities; door-to-door routing support; and implementation examples for Geofencing and Isochrone.Bổ sung: GtelRouteNavigationViewController cho chức năng dẫn đường; API thao tác và hiển thị POI; API tùy biến kiểu hiển thị bản đồ (Map Style); các tiện ích điều khiển camera; hỗ trợ dẫn đường từ điểm xuất phát đến điểm đích (door-to-door routing); cùng các ví dụ triển khai Geofencing và Isochrone. |
| PlatformNền tảng | iOS 14.0 or lateriOS 14.0 trở lên | The package currently declares iOS 14.0 as the minimum deployment target.SDK tương thích với iOS 14.0 trở lên. |
| UI frameworkUI framework | UIKit, SwiftUI | Use GtelMapView directly in UIKit or GtelMapSwiftUIView in SwiftUI.Dùng GtelMapView trực tiếp trong UIKit hoặc GtelMapSwiftUIView trong SwiftUI. |
| Installation methodCách cài đặt | Vendor binary packageVendor binary package | See details in Installation.Xem chi tiết tại phần Cài đặt. |
What the SDK doesCác tính năng được SDK hỗ trợ
apply(input:).Gửi lệnh và tham số đến bản đồ thông qua hàm apply(input:).GtelMapClient.shared.autocomplete.Màn hình tìm kiếm địa điểm có sẵn của SDK.
Recommended pathTrình tự tích hợp SDK
- Add
GtelMapSDK.xcframeworkto the app target and set it toEmbed & Sign.ThêmGtelMapSDK.xcframeworkvào target ứng dụng và thiết lậpEmbed & Sign. - Configure the SDK before the first
GtelMapViewis created.Cấu hình SDK trước khi tạoGtelMapViewđầu tiên. - Create
GtelMapView, assigngtelMapDelegate, then send feature requests throughapply(input:).TạoGtelMapView, gắngtelMapDelegate, rồi gửi yêu cầu bằngapply(input:). - Use
GtelMapClient.sharedfor service calls that feed host-owned UI or background workflows.DùngGtelMapClient.sharedkhi ứng dụng cần lấy dữ liệu cho giao diện riêng hoặc xử lý nền.
GtelMapView, GtelMapViewDelegate, and GtelMapClient. Internal implementation details and backend credentials are excluded for security.Tài liệu này chỉ hướng dẫn các API công khai qua GtelMapView, GtelMapViewDelegate và GtelMapClient. Chi tiết máy chủ và thông tin bảo mật không được đưa vào guide.
InstallationCài đặt
Use the provided vendor binary package. The host app only adds GtelMapSDK.xcframework to the app target. All internal SDK content needed at runtime is packaged inside the framework.Dùng gói binary được cung cấp. Ứng dụng chỉ cần thêm GtelMapSDK.xcframework vào app target; mọi nội dung nội bộ mà SDK cần khi chạy đều đã được đóng gói sẵn trong framework.
Binary package layoutCấu trúc binary package
GtelMapSDKVendor/
GtelMapSDK.xcframework
README.md
manifest.json
Add GtelMapSDK.xcframeworkThêm GtelMapSDK.xcframework
- Open the host app project or workspace in Xcode.Mở project hoặc workspace của ứng dụng trong Xcode.
- Drag
GtelMapSDKVendor/GtelMapSDK.xcframeworkinto the project navigator.KéoGtelMapSDKVendor/GtelMapSDK.xcframeworkvào project navigator. - In Xcode's add-file dialog, enable
Copy items if neededand tick the host app target inAdd to targets.Trong hộp thoại thêm file của Xcode, bậtCopy items if neededvà tích chọn app target ở mụcAdd to targets. - Open the app target
General > Frameworks, Libraries, and Embedded Contentand setGtelMapSDK.xcframeworktoEmbed & Sign.Mở app targetGeneral > Frameworks, Libraries, and Embedded Contentvà đặtGtelMapSDK.xcframeworklàEmbed & Sign.
| Package itemThành phần package | Handled byXử lý bởi | Build destinationĐích trong build output |
|---|---|---|
GtelMapSDK.xcframework | Host adds to app targetHost thêm vào app target | Frameworks, Libraries, and Embedded Content |
| Internal runtime contentNội dung runtime nội bộ | GtelMapSDK.xcframework | Linked and embedded inside GtelMapSDK.frameworkĐã link và nhúng bên trong GtelMapSDK.framework |
Import SDKKhai báo module SDK
import UIKit
import GtelMapSDK
Runtime configuration valuesCác giá trị cấu hình runtime
Keep real values outside committed source. The public guide shows only where the host app supplies configuration.Không commit giá trị thật vào source. Guide chỉ chỉ ra nơi ứng dụng truyền cấu hình cho SDK.
| KeyKey | RequiredBắt buộc | DescriptionMô tả |
|---|---|---|
GTELMapAccessToken | YesCó | Read from the host app Info.plist by GtelMapConfig.GtelMapConfig đọc giá trị này từ Info.plist của ứng dụng. |
weatherApiKey | Only for weatherChỉ khi dùng weather | Set via GtelMapConfiguration(weatherApiKey:) in AppDelegate. Required only when the host app calls weather helpers.Truyền qua GtelMapConfiguration(weatherApiKey:) trong AppDelegate. Chỉ cần khi ứng dụng dùng tính năng thời tiết. |
apiVersion | NoKhông | Set via GtelMapConfiguration(apiVersion:) in AppDelegate. Defaults to "1.1" when not provided.Set qua GtelMapConfiguration(apiVersion:) trong AppDelegate. Mặc định "1.1" nếu không cung cấp. |
Location permissionQuyền vị trí
Only declare the location usage description if the host app uses the user's location, focuses the camera on the current location, or uses navigation.Chỉ khai báo mô tả quyền vị trí nếu ứng dụng dùng vị trí người dùng, đưa camera tới vị trí hiện tại hoặc dùng dẫn đường.
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs your location to display the map and provide directions.</string>
Initialization & configKhởi tạo & cấu hình
Configure the SDK once during the app launch phase, before any screen creates a GtelMapView.Cấu hình SDK một lần trong giai đoạn app launch, trước khi bất kỳ màn hình nào tạo GtelMapView.
import UIKit
import GtelMapSDK
@main
final class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GtelMapConfig.configure(GtelMapConfiguration(
apiVersion: "1.1",
weatherApiKey: "YOUR_WEATHER_API_KEY",
ui: GtelMapUIConfiguration(
titleColor: .black,
titleSize: 13,
subTitleColor: .gray,
subTitleSize: 11,
backgroundColor: .white
),
size: GtelMapSizeConfiguration(
closeButtonSize: 30,
iconSize: 48,
inset: 16
)
))
return true
}
}
import SwiftUI
import GtelMapSDK
@main
struct YourApp: App {
init() {
GtelMapConfig.configure(GtelMapConfiguration(
apiVersion: "1.1",
weatherApiKey: "YOUR_WEATHER_API_KEY",
ui: GtelMapUIConfiguration(
titleColor: .black,
titleSize: 13,
subTitleColor: .gray,
subTitleSize: 11,
backgroundColor: .white
),
size: GtelMapSizeConfiguration(
closeButtonSize: 30,
iconSize: 48,
inset: 16
)
))
}
var body: some Scene {
WindowGroup {
MapScreen()
}
}
}
GtelMapConfiguration referenceTham chiếu GtelMapConfiguration
| FieldTrường | DefaultMặc định | DescriptionMô tả |
|---|---|---|
apiVersion | "1.1" | API version used in SDK requests. Defaults to "1.1" when not provided.Phiên bản API SDK sử dụng. Mặc định là "1.1" nếu không truyền. |
weatherApiKey | nil | Required when the host app uses weather features. Supply via GtelMapConfig.configure in AppDelegate.Cần khi ứng dụng dùng tính năng thời tiết. Truyền qua GtelMapConfig.configure trong AppDelegate. |
baseURL | SDK defaultMặc định SDK | Optional environment override provided by the SDK team.Tùy chọn override môi trường do đội SDK cung cấp. |
ui | GtelMapUIConfiguration.default | Optional theme for SDK-provided UIKit components: title color and size, subtitle color and size, and component background color.Giao diện tùy chọn cho UIKit component của SDK: màu/cỡ chữ tiêu đề, màu/cỡ chữ phụ và màu nền. |
size | GtelMapSizeConfiguration.default | Optional sizing for SDK-provided UIKit components: close button size, icon size, and layout inset.Kích thước tùy chọn cho UIKit component của SDK: nút đóng, icon và khoảng cách lề. |
GtelMapUIConfiguration referenceTham chiếu GtelMapUIConfiguration
| FieldTrường | DefaultMặc định | DescriptionMô tả |
|---|---|---|
titleColor | .black | Text color for primary labels in SDK UIKit components.Màu chữ cho nhãn chính trong UIKit component của SDK. |
titleSize | 13 | Font size for primary labels.Cỡ chữ cho label chính. |
subTitleColor | .gray | Text color for secondary/detail labels.Màu chữ cho label phụ/detail. |
subTitleSize | 11 | Font size for secondary/detail labels.Cỡ chữ cho label phụ/detail. |
backgroundColor | .white | Background color for SDK UIKit component containers, table views, collection views, and reusable cells.Màu nền cho container, table view, collection view và cell dùng lại của UIKit component trong SDK. |
GtelMapSizeConfiguration referenceTham chiếu GtelMapSizeConfiguration
| FieldTrường | DefaultMặc định | DescriptionMô tả |
|---|---|---|
closeButtonSize | 30 | Width and height for close buttons in SDK UIKit sheets.Chiều rộng và chiều cao của nút đóng trong UIKit sheet của SDK. |
iconSize | 48 | Size for primary icons in SDK UIKit components.Kích thước icon chính trong UIKit component của SDK. |
inset | 16 | Leading/trailing content inset used by SDK UIKit components.Khoảng cách trái/phải cho nội dung trong UIKit component của SDK. |
Update configuration at runtimeCập nhật cấu hình khi đang chạy
Call apply(configuration:) on an existing GtelMapView instance to apply a new configuration without recreating the view.Gọi apply(configuration:) trên GtelMapView đang có để đổi cấu hình mà không cần tạo lại view.
mapView.apply(configuration: GtelMapConfiguration(baseURL: stagingURL))
Info.plist key & GtelMapConfig helpersKey Info.plist & hàm hỗ trợ GtelMapConfig
Only GTELMapAccessToken is read from Info.plist. All other values (apiVersion, weatherApiKey, baseURL, ui, size) are supplied via GtelMapConfig.configure in AppDelegate.Chỉ GTELMapAccessToken được đọc từ Info.plist. Các giá trị còn lại (apiVersion, weatherApiKey, baseURL, ui, size) được cung cấp qua GtelMapConfig.configure trong AppDelegate.
| ConstantHằng số | Info.plist keyKey Info.plist |
|---|---|
GtelMapInfoDictionaryKey.accessToken | GTELMapAccessToken |
Use GtelMapConfig static helpers at app launch to guard against missing keys before creating the map view.Dùng các hàm static của GtelMapConfig khi mở app để phòng trường hợp thiếu key trước khi tạo bản đồ.
guard GtelMapConfig.hasAPIKey else {
fatalError("GTELMapAccessToken missing in Info.plist")
}
GtelMapConfig.configure(GtelMapConfiguration(
apiVersion: "1.1",
weatherApiKey: "YOUR_WEATHER_API_KEY",
ui: .default,
size: .default
))
| HelperHelper | DescriptionMô tả |
|---|---|
GtelMapConfig.hasAPIKey | Returns true when GTELMapAccessToken is non-empty.Trả true khi GTELMapAccessToken không rỗng. |
GtelMapConfig.hasWeatherApiKey | Returns true when weatherApiKey was supplied via GtelMapConfig.configure.Trả true khi weatherApiKey đã được cung cấp qua GtelMapConfig.configure. |
GtelMapConfig.apiKey | Reads GTELMapAccessToken from main bundle Info.plist.Đọc GTELMapAccessToken từ Info.plist của main bundle. |
GtelMapConfig.apiVersion | Returns the active API version (configured or SDK default "1.1").Trả API version đang dùng (đã cấu hình hoặc mặc định SDK "1.1"). |
GtelMapConfig.baseURL | Returns the active base URL (overridden or SDK default maps.ots.vn).Trả URL gốc đang dùng (override hoặc mặc định SDK maps.ots.vn). |
GtelMapConfig.ui | Returns the active UIKit component theme.Trả theme đang áp dụng cho UIKit component của SDK. |
GtelMapConfig.size | Returns the active UIKit component sizing.Trả cấu hình kích thước đang áp dụng cho UIKit component của SDK. |
init(apiKey:weatherApiKey:apiVersion:baseURL:ui:size:) constructor is deprecated. Use init(apiVersion:weatherApiKey:baseURL:ui:size:) instead.Constructor init(apiKey:weatherApiKey:apiVersion:baseURL:ui:size:) đã deprecated. Dùng init(apiVersion:weatherApiKey:baseURL:ui:size:) thay thế.
Map ViewHiển thị bản đồ
Create GtelMapView, assign the delegate, and add it to the layout. All subsequent tasks in this guide assume the host app holds a mapView instance.Tạo GtelMapView, gắn delegate và thêm vào layout. Các phần sau giả định màn hình đã có biến mapView.
final class MapViewController: UIViewController {
private let mapView = GtelMapView()
override func viewDidLoad() {
super.viewDidLoad()
mapView.gtelMapDelegate = self
mapView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(mapView)
NSLayoutConstraint.activate([
mapView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
mapView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
mapView.topAnchor.constraint(equalTo: view.topAnchor),
mapView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
}
extension MapViewController: GtelMapViewDelegate {
func gtelMapViewDidFinishLoading(_ mapView: GtelMapView) {
mapView.setCameraBoundsInVietNam()
}
}
struct MapScreen: View {
var body: some View {
GtelMapContainer()
.ignoresSafeArea()
}
}
struct GtelMapContainer: UIViewRepresentable {
func makeUIView(context: Context) -> GtelMapView {
let mapView = GtelMapView()
mapView.gtelMapDelegate = context.coordinator
return mapView
}
func updateUIView(_ mapView: GtelMapView, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator()
}
}
final class Coordinator: NSObject, GtelMapViewDelegate {
func gtelMapViewDidFinishLoading(_ mapView: GtelMapView) {
mapView.setCameraBoundsInVietNam()
}
}
CameraCamera
The camera is controlled through public helpers on GtelMapView. The host app should store the updated viewport via delegate to use for search, nearby, or UI that depends on the visible map region.Điều khiển camera bằng các hàm public của GtelMapView. Ứng dụng nên lưu vùng bản đồ mới từ delegate để dùng cho tìm kiếm, nearby hoặc giao diện phụ thuộc vị trí đang xem.
| APIAPI | When to useKhi dùng |
|---|---|
setCameraZoomToAt(coordinate:edgePadding:completed:) | Zoom to a marker, search result, or a host-chosen coordinate.Zoom tới marker, kết quả tìm kiếm hoặc tọa độ do ứng dụng chọn. |
setCameraToUserLocation(coordinate:zoomLevel:completed:) | Focus the camera on the user's location after the host app has a valid coordinate.Đưa camera tới vị trí người dùng sau khi ứng dụng có tọa độ hợp lệ. |
setCameraBoundsInVietNam(completed:) | Return to the default viewport when no location is available.Đưa bản đồ về vùng mặc định khi chưa có vị trí. |
setCameraDefaultMap(sw:ne:edgePadding:) | Fit camera to a custom SW/NE bounds with optional edge padding. Use when the host app has its own bounding box.Căn chỉnh camera vừa vặn vùng bao tọa độ SW/NE do ứng dụng cung cấp (Fit Bounds). |
currentZoomLevel | Keep the current zoom when changing focus.Giữ mức zoom hiện tại khi đổi vị trí xem. |
defaultZoomLevel | The SDK default zoom level (read-only). Use as fallback when currentZoomLevel is not yet available.Mức zoom mặc định của SDK. Dùng khi chưa có currentZoomLevel. |
visiableBounds | Returns the current visible bounds (topLeft, bottomRight, center) synchronously without waiting for a delegate callback.Trả vùng bản đồ đang thấy, gồm topLeft, bottomRight và center — trả về ngay, không cần chờ callback delegate. |
onSetVisiableBounds(annotations:) | Fit the camera to show all annotations.Căn chỉnh camera vừa vặn vùng bao tất cả điểm đánh dấu (Fit to Markers). |
onSetVisiableBounds(points:[CLLocationCoordinate2D]) | Same as above but accepts raw coordinates instead of annotation models.Tương tự, nhưng truyền trực tiếp danh sách tọa độ. |
gtelMapView(_:didChangeRegion:) | Receive updated bounds after the viewport changes.Nhận vùng bản đồ mới sau khi camera thay đổi. |
func focusPlace(_ coordinate: CLLocationCoordinate2D) {
guard mapView.isValidCoordinate(coordinate) else {
mapView.setCameraBoundsInVietNam()
return
}
mapView.setCameraZoomToAt(coordinate: coordinate, edgePadding: .zero)
}
func fitCustomBounds(sw: CLLocationCoordinate2D, ne: CLLocationCoordinate2D) {
mapView.setCameraDefaultMap(sw: sw, ne: ne)
}
func gtelMapView(_ mapView: GtelMapView, didChangeRegion bounds: MapVisibleBounds) {
currentMapCenter = bounds.center
}
GtelMapCameraChangeReasonGtelMapCameraChangeReason
The regionWillChangeWith and regionDidChangeWith delegate callbacks receive a GtelMapCameraChangeReason OptionSet. Use it to distinguish user gestures from programmatic camera moves.Các callback regionWillChangeWith và regionDidChangeWith nhận GtelMapCameraChangeReason. Dùng giá trị này để biết camera đổi do người dùng thao tác hay do code gọi.
| CaseTrường hợp | MeaningÝ nghĩa |
|---|---|
.programmatic | Camera moved by an SDK or host app API call.Camera di chuyển do SDK hoặc ứng dụng gọi API. |
.gesturePan | User dragged the map.Người dùng kéo bản đồ. |
.gesturePinch | User pinched to zoom.Người dùng pinch để zoom. |
.gestureZoomIn / .gestureZoomOut | Double-tap or two-finger tap zoom.Chạm hai lần hoặc chạm hai ngón để zoom. |
.gestureOneFingerZoom | One-finger drag zoom gesture.Drag một ngón để zoom. |
.gestureTilt | Two-finger vertical drag to tilt.Kéo dọc bằng hai ngón để nghiêng bản đồ. |
.transitionCancelled | A programmatic animation was interrupted.Animation programmatic bị ngắt giữa chừng. |
func gtelMapView(_ mapView: GtelMapView, regionDidChangeWith reason: GtelMapCameraChangeReason, animated: Bool) {
if reason.contains(.gesturePan) || reason.contains(.gesturePinch) {
dismissSearchPanel()
}
}
Style & LayerStyle & lớp
The host app reads the style catalog and applies the item the user selects via GtelMapViewInput.Ứng dụng lấy danh sách style, áp dụng style người dùng chọn qua GtelMapViewInput.
func loadStyles() {
// Option A: read the local catalog synchronously
styleItems = GtelMapClient.shared.mapStyles
// Option B: receive it via the delegate through GtelMapViewInput
mapView.apply(input: .mapStyles)
}
func applyStyle(_ style: GtelMapStyleModel) {
mapView.apply(input: .mapStyle(style))
}
func applyExternalStyle(_ source: GtelMapStyleSource) {
mapView.apply(input: .mapStyleSource(source))
}
Built-in styles (GtelMapStyle)Style dựng sẵn (GtelMapStyle)
Switch a built-in style with mapView.apply(style:). Existing markers and routes re-attach once the new style has loaded.Đổi style dựng sẵn bằng mapView.apply(style:). Marker và tuyến đường hiện có sẽ tự gắn lại sau khi style mới tải xong.
// Create the map already set to a built-in style
let mapView = GtelMapView(style: .STREETS)
// Or switch style at any time
mapView.apply(style: .STREETS)
// Resolve a style from a raw id (nil for an unknown id)
if let style = GtelMapStyle.fromId("dark") {
mapView.apply(style: style)
}
GtelMapStyle | GtelMapStyle | GtelMapStyle | GtelMapStyle |
|---|---|---|---|
.STREETS | .BASIC | .LIGHT | .DARK |
.SATELLITE | .SATELLITE_STREETS | .NAVIGATION_DAY | .NAVIGATION_NIGHT |
.ONLY_TRAFFIC | .ONLY_TRAFFIC_DARK |
GtelMapStyle exposes styleId (e.g. gtelmaps-streets-v1) and model (a GtelMapStyleModel). Use .mapStyle(GtelMapStyleModel) for catalog items and .mapStyleSource(_:) for external styles.Mỗi GtelMapStyle cung cấp styleId (vd gtelmaps-streets-v1) và model (một GtelMapStyleModel). Dùng .mapStyle(GtelMapStyleModel) cho style trong danh sách và .mapStyleSource(_:) cho style bên ngoài.
Custom style contentCustom style content
Use custom style content when the host app already has GeoJSON-like content, images, layer ids, or filters to control on the current style.Dùng custom style content khi ứng dụng đã có dữ liệu dạng GeoJSON, hình ảnh, layer id hoặc bộ lọc cần hiển thị trên style hiện tại.
host_ to avoid collisions with SDK-internal identifiers.Tất cả content id, source id, layer id và tên hình do ứng dụng đặt phải bắt đầu bằng host_ để tránh trùng với id nội bộ của SDK.
| InputInput | DescriptionMô tả |
|---|---|
.customStyleImage(name:image:), .removeCustomStyleImage(name:) | Register or remove reusable images for custom style layers.Thêm hoặc xóa hình dùng cho layer tùy chỉnh. |
.customStyleContent(content:) | Add a new GtelMapCustomStyleContent (sources + layers + features). Use once per content id; update individual features with granular inputs.Thêm một GtelMapCustomStyleContent. Mỗi content id chỉ thêm một lần; khi dữ liệu đổi thì cập nhật từng feature. |
.updateCustomStyleSource(contentId:source:) | Replace all features in an existing source without removing the whole content block.Thay toàn bộ feature trong source đã có mà không xóa cả content. |
.updateCustomStyleFeature(contentId:sourceId:feature:) | Update a single feature by id within an existing source.Cập nhật một feature theo id. |
.removeCustomStyleFeature(contentId:sourceId:featureId:) | Remove a single feature by id from an existing source.Xóa một feature theo id. |
.removeCustomStyleContentById(contentId:) | Remove an entire content block (all its sources, layers, and features) by content id.Xóa toàn bộ content theo content id. |
.removeCustomStyleContent(layerIds:sourceIds:) | Remove specific layers and sources by id lists.Xóa layer và source theo danh sách id. |
.clearCustomStyleContent | Remove all host-owned custom content at once.Xóa toàn bộ custom content của ứng dụng. |
.setCustomStyleLayerVisibility(layerIds:isVisible:) | Show or hide custom layers by id list.Bật hoặc tắt layer theo danh sách id. |
.setCustomStyleLayerFilter(layerId:propertyKey:allowedValues:), .clearCustomStyleLayerFilter(layerId:) | Filter visible features by a property value list, or clear the filter.Lọc feature được hiển thị theo giá trị, hoặc xóa bộ lọc. |
Custom style typesCác type của custom style
GtelMapCustomLayerKind
.symbol · .circle · .line · .fill
GtelMapCustomLayerPosition
.top · .above(layerId) · .below(layerId)
GtelMapCustomLayerStyle controls visual appearance. Key fields: color, strokeColor, opacity, width (line), radius (circle), iconScale (symbol), showsTitle, allowsOverlap.GtelMapCustomLayerStyle điều khiển cách layer hiển thị. Các trường thường dùng gồm color, strokeColor, opacity, width, radius, iconScale, showsTitle và allowsOverlap.
Read-back helpersHàm đọc trạng thái
Use these to inspect the current custom style state without tracking it separately in the host app.Dùng các hàm này để kiểm tra custom style hiện tại mà ứng dụng không cần tự lưu thêm.
| Property / MethodThuộc tính / Phương thức | ReturnsKiểu trả về |
|---|---|
customStyleContentIds | [String] — all active content ids.— tất cả content id đang active. |
customStyleLayerIds | [String] — all active custom layer ids.— tất cả custom layer id đang active. |
customStyleSourceIds | [String] — all active custom source ids.— tất cả custom source id đang active. |
customStyleImageNames | [String] — registered custom image names.— tên image custom đã đăng ký. |
customStyleFilters | [GtelMapCustomLayerFilter] — active layer filters.— filter layer đang active. |
customStyleContent(id:) | GtelMapCustomStyleContent? |
customStyleSource(contentId:sourceId:) | GtelMapCustomSource? |
customStyleFeature(contentId:sourceId:featureId:) | GtelMapCustomFeature? |
customStyleFeatures(contentId:sourceId:where:) | [GtelMapCustomFeature] — filtered by predicate.— lọc theo predicate. |
visibleCustomStyleFeatures() | [GtelMapCustomFeature] — features currently visible on screen.— các feature đang hiển thị trên màn hình. |
Custom feature tapTap vào custom feature
When the user taps a feature in a host-owned custom layer, the SDK fires didTapCustomFeature. The layerId parameter identifies which layer was tapped.Khi người dùng chạm vào feature trong custom layer của ứng dụng, SDK gọi didTapCustomFeature. Tham số layerId cho biết layer nào được chạm.
func gtelMapView(_ mapView: GtelMapView, didTapCustomFeature feature: GtelMapCustomFeature, layerId: String?) {
guard let id = feature.id else { return }
showDetail(for: id, layer: layerId)
}
Custom style errorsLỗi custom style
The delegate has two didFailCustomStyleContent overloads: one with ResponseMessage (network/general) and one with typed GtelMapCustomStyleContentError (validation). Common validation errors:Delegate có hai hàm didFailCustomStyleContent: một hàm trả ResponseMessage cho lỗi chung, một hàm trả GtelMapCustomStyleContentError cho lỗi dữ liệu đầu vào. Các lỗi thường gặp:
| ErrorLỗi | CauseNguyên nhân |
|---|---|
.invalidSourceId / .invalidLayerId / .invalidImageName | Id or name does not start with host_.Id hoặc name không bắt đầu bằng host_. |
.duplicateSourceId / .duplicateLayerId | Two sources or layers with the same id in one content block.Hai source hoặc layer có cùng id trong một content block. |
.missingLayerSource | A layer references a source id not declared in the same content block.Layer tham chiếu source id chưa khai báo trong cùng content block. |
.rendererNotReady | Map style is not yet loaded. Wait for gtelMapViewDidFinishLoading before adding custom content.Style bản đồ chưa tải xong. Chờ gtelMapViewDidFinishLoading rồi mới thêm custom content. |



Marker & CalloutMarker & Callout
The host app creates an AnnotationModel and renders a single marker or multiple annotations. Icons, annotation views, and callouts are customised via the delegate.Ứng dụng tạo AnnotationModel để hiển thị một hoặc nhiều marker. Icon, view marker và callout được tùy biến qua delegate.
func showFocusedMarker(_ annotation: AnnotationModel) {
mapView.apply(input: .marker(annotation, iconScale: 1.0, zoomLevel: 16))
}
func showMarkers(_ annotations: [AnnotationModel]) {
mapView.apply(input: .annotations(annotations, layerId: "places", visibleLayerIds: ["places"], iconScale: 1.0))
}
func clearMarkers() {
mapView.removeAllAnnotations()
mapView.deselectAllCallout()
}
func gtelMapView(_ mapView: GtelMapView, didTouchAnnotation annotation: AnnotationModel) {
selectedAnnotation = annotation
}
func gtelMapView(_ mapView: GtelMapView, markerImageFor annotation: AnnotationModel) -> UIImage? {
markerIcon(for: annotation)
}
Custom annotation viewView annotation tùy chỉnh
Return a UIView from annotationViewFor to render a fully custom annotation instead of an icon image. The view is pinned to the annotation coordinate.Trả UIView từ annotationViewFor để hiển thị marker tùy chỉnh thay vì chỉ dùng icon. View sẽ được đặt tại tọa độ của marker.
func gtelMapView(_ mapView: GtelMapView, annotationViewFor annotation: AnnotationModel) -> UIView? {
guard annotation.type == "highlight" else { return nil }
let badge = PulsingBadgeView()
badge.tintColor = .systemRed
return badge
}
Callout lifecycleVòng đời hiển thị của khung bóng thoại thông tin (Callout View) (Callout Lifecycle)
| Callback / HelperCallback / Helper | DescriptionMô tả |
|---|---|
canShowCalloutFor | Return whether an annotation should open a callout.Quyết định annotation có được mở callout hay không. |
leftCalloutAccessoryViewFor, rightCalloutAccessoryViewFor | Provide host-owned callout accessory views.Cung cấp view phụ trong callout do ứng dụng tự tạo. |
didShowCallout | Fired when callout becomes visible. isLoadingSubtitle is true while the SDK is resolving the subtitle asynchronously.Được gọi khi callout hiển thị. isLoadingSubtitle là true khi SDK đang tải subtitle. |
didUpdateCalloutSubtitle | Fired when the subtitle string is resolved. Update the host preview panel to show the address.Được gọi khi đã có subtitle. Cập nhật phần xem trước để hiển thị địa chỉ. |
didUpdateCalloutCategory | Fired when the SDK resolves the place category type string (e.g. "restaurant"). Use to update the category icon in the callout.Được gọi khi đã có loại địa điểm. Dùng để cập nhật icon trong callout. |
gtelMapViewDidRemoveCallout | Fired when the callout is dismissed. Use to reset host preview panels.Được gọi khi callout đóng. Dùng để reset phần xem trước. |
deselectAllCallout(), removeAllAnnotations() | Clear selected callout or all annotations when leaving the flow.Xóa callout đang chọn hoặc toàn bộ marker khi rời màn hình. |
Callout positioning helpersHàm căn chỉnh callout
When the host app places a custom overlay anchored to the callout (e.g. a bottom sheet pinned above it), use these helpers to keep it aligned after layout changes.Khi ứng dụng đặt một overlay gắn với callout, ví dụ bottom sheet nằm phía trên callout, dùng các hàm này để giữ đúng vị trí sau khi layout thay đổi.
| APIAPI | DescriptionMô tả |
|---|---|
calloutAnchorPoint(for:) | Returns the anchor CGPoint in the GtelMapView coordinate space for a given annotation. Returns nil if the annotation is not visible.Trả CGPoint của marker trong GtelMapView. Trả nil nếu marker không hiển thị. |
scheduleOverlayPositionUpdate(notifiesCalloutPositionUpdate:animated:) | Ask the SDK to recalculate overlay positions. Set notifiesCalloutPositionUpdate: true to trigger didRequestCalloutPositionUpdate on the delegate.Yêu cầu SDK tính lại vị trí overlay. Đặt notifiesCalloutPositionUpdate: true để gọi didRequestCalloutPositionUpdate trên delegate. |
didRequestCalloutPositionUpdate(animated:) | Delegate callback to reposition host-owned views aligned to the callout.Callback để ứng dụng đặt lại vị trí các view gắn với callout. |
GtelMapView public API.Android có mục clustering tự động. iOS guide public chưa document clustering cho tới khi tính năng này được expose qua public API của GtelMapView.



RouteVẽ tuyến
A route can be loaded via a navigation input or rendered from a RouteResponseModel the host app already received via delegate.Có thể tải tuyến đường bằng navigation input, hoặc hiển thị từ RouteResponseModel mà ứng dụng đã nhận qua delegate.
func requestRoute(from origin: LocationDataRequest, to destination: LocationDataRequest, costing: TransportType) {
mapView.apply(input: .navigationRoute(locations: [origin, destination], costing: costing))
}
func renderRoute(_ response: RouteResponseModel) {
mapView.apply(input: .route(response))
}
func clearRoute() {
mapView.apply(input: .clearRoute)
}
func gtelMapView(_ mapView: GtelMapView, didLoadNavigationRoute route: RouteResponseModel, selectedTrip: TripModel?) {
routeSummary = selectedTrip
}
Alternative and candidate routesTuyến đường thay thế và các tuyến đề xuất (Alternative & Candidate Routes)
For A/B alternatives, request the candidate route data through the host flow, then render the public response set with .matrixCandidateRoutes. Use delegate route-selection callbacks to keep host UI in sync.Với nhiều tuyến thay thế, ứng dụng lấy dữ liệu tuyến trước, rồi hiển thị bằng .matrixCandidateRoutes. Dùng callback chọn tuyến để cập nhật giao diện.
func renderCandidateRoutes(_ routes: [RouteResponseModel?], colors: [UIColor], sources: [MatrixRouteSourceMarker], targets: [MatrixRouteTargetMarker]) {
mapView.apply(input: .matrixCandidateRoutes(
responses: routes,
colors: colors,
sourceMarkers: sources,
targetMarkers: targets,
optimalIndex: 0,
optimalTargetIndex: 0
))
}
func gtelMapView(_ mapView: GtelMapView, didSelectNavigationRoute route: RouteResponseModel, selectedTrip: TripModel?) {
selectedRoute = route
}
Direct route API helpersHàm lấy dữ liệu tuyến đường
Use these when the host app needs route data without rendering it on the map (e.g. to display a distance summary before the user confirms).Dùng khi ứng dụng cần dữ liệu tuyến đường nhưng chưa cần hiển thị lên bản đồ, ví dụ để xem trước khoảng cách trước khi người dùng xác nhận.
| MethodPhương thức | Use caseTrường hợp sử dụng |
|---|---|
GtelMapClient.shared.getRoutes(request:callback:) | Fetch a route response without rendering. Returns RouteResponseModel? via callback. Ideal for showing ETA before starting navigation.Lấy tuyến đường mà chưa hiển thị lên bản đồ. Trả RouteResponseModel? qua callback. Phù hợp để hiển thị ETA trước khi dẫn đường. |
GtelMapClient.shared.getDoorToDoorRoute(request:callback:) | Fetch a door-to-door route (includes last-mile walking segments). Returns RouteResponseModel? via callback.Định tuyến điểm đầu - điểm cuối toàn diện (Door-to-Door Routing), tự động bổ sung đoạn đi bộ kết nối. Trả RouteResponseModel? qua callback. |
let req = EstimateTimeDataRequest(
origin: LocationDataRequest(lat: 10.776, lng: 106.701, address: "Point A"),
destination: LocationDataRequest(lat: 10.800, lng: 106.720, address: "Point B"),
costing: .auto
)
GtelMapClient.shared.getRoutes(request: req) { response, message in
guard message.onCheckSuccess(), let trip = response?.trip else { return }
showSummary(distance: trip.summary?.length, time: trip.summary?.time)
}
GtelMapClient.shared.getDoorToDoorRoute(request: req) { response, message in
guard message.onCheckSuccess() else { return }
renderDoorToDoorResult(response)
}
Overlay (boundary)Lớp phủ (ranh giới)
Use polygon or custom style content when the host app has region data to display. This guide does not describe backend details for generating region data.Dùng polygon hoặc custom style content khi ứng dụng có sẵn dữ liệu vùng cần hiển thị. Guide không mô tả chi tiết hệ thống tạo dữ liệu vùng.
func showBoundary(_ coordinates: [CLLocationCoordinate2D]) {
guard coordinates.count >= 3 else { return }
mapView.apply(input: .polygon(coordinates: coordinates))
}
func clearBoundary() {
mapView.apply(input: .clearPolygon)
}



Map EventsSự kiện bản đồ
Map events flow through GtelMapViewDelegate. The host app only implements the callbacks it needs; all callbacks have empty default implementations.Sự kiện bản đồ được gửi qua GtelMapViewDelegate. Ứng dụng chỉ cần cài đặt các callback đang dùng; callback còn lại đã có mặc định rỗng.
| CallbackCallback | When firedKhi kích hoạt |
|---|---|
gtelMapViewDidFinishLoading(_:) | Map is fully initialized and ready for inputs. Send first actions here.Bản đồ đã sẵn sàng nhận input. Gửi lệnh đầu tiên tại đây. |
gtelMapViewDidFinishLoadingStyle(_:) | Fired every time a style finishes loading, including after .mapStyle / .mapStyleSource switches. Re-apply host-owned custom style content here if needed.Được gọi mỗi khi style tải xong, kể cả sau khi đổi style. Nếu cần giữ custom style content, hãy gửi lại tại đây. |
gtelMapViewRegionIsChanging(_:) | Fires continuously while the camera is in motion. Use sparingly — avoid expensive UI updates here.Được gọi liên tục khi camera đang di chuyển. Chỉ nên cập nhật giao diện nhẹ tại đây. |
regionWillChangeWith(reason:animated:) | Camera is about to move. reason is a GtelMapCameraChangeReason OptionSet.Camera sắp di chuyển. reason là GtelMapCameraChangeReason OptionSet. |
regionDidChangeWith(reason:animated:) | Camera finished moving.Camera đã dừng. |
didChangeRegion(bounds:) | Returns the new MapVisibleBounds (topLeft, bottomRight, center). Store bounds.center for search focus.Trả MapVisibleBounds mới. Lưu bounds.center để ưu tiên tìm kiếm quanh khu vực đang xem. |
didTapCoordinate(_:coordinate:) | User tapped an empty area of the map (no annotation or POI).Người dùng chạm vào vùng trống trên bản đồ. |
didPinCoordinate(_:coordinate:) | User long-pressed the map. Typically trigger a .reversePoint input here.Người dùng nhấn giữ trên bản đồ. Thường gửi .reversePoint tại đây. |
gtelMapViewDidBeginGesturePan / gtelMapViewDidEndGesturePan | Pan gesture started or ended. Use to show/hide search bar or floating UI.Người dùng bắt đầu hoặc dừng kéo bản đồ. Có thể dùng để ẩn/hiện thanh tìm kiếm. |
extension MapViewController: GtelMapViewDelegate {
func gtelMapViewDidFinishLoadingStyle(_ mapView: GtelMapView) {
// re-apply custom content after each style reload
if let content = pendingCustomContent {
mapView.apply(input: .customStyleContent(content: content))
}
}
func gtelMapViewRegionIsChanging(_ mapView: GtelMapView) {
// lightweight: update a loading indicator only
mapView.scheduleOverlayPositionUpdate()
}
func gtelMapView(_ mapView: GtelMapView, didTapCoordinate coordinate: CLLocationCoordinate2D) {
tappedCoordinate = coordinate
}
func gtelMapView(_ mapView: GtelMapView, didPinCoordinate coordinate: CLLocationCoordinate2D) {
mapView.apply(input: .reversePoint(coordinate: coordinate, showMarker: true, zoom: 18, size: 1))
}
func gtelMapView(_ mapView: GtelMapView, regionWillChangeWith reason: GtelMapCameraChangeReason, animated: Bool) {
if reason.contains(.gesturePan) { dismissSearchPanel() }
}
func gtelMapView(_ mapView: GtelMapView, regionDidChangeWith reason: GtelMapCameraChangeReason, animated: Bool) {}
func gtelMapViewDidBeginGesturePan(_ mapView: GtelMapView) {}
func gtelMapViewDidEndGesturePan(_ mapView: GtelMapView) {}
}
User LocationVị trí người dùng
The host app is responsible for requesting location permission and obtaining coordinates via CLLocationManager. Once a valid coordinate is available, pass it to the camera helper on GtelMapView.Ứng dụng tự xin quyền vị trí và lấy tọa độ bằng CLLocationManager. Sau khi có tọa độ hợp lệ, truyền vào hàm camera của GtelMapView.
func handleLocation(_ coordinate: CLLocationCoordinate2D?) {
guard let coordinate, mapView.isValidCoordinate(coordinate) else {
mapView.setCameraBoundsInVietNam()
return
}
mapView.setCameraToUserLocation(coordinate: coordinate, zoomLevel: mapView.currentZoomLevel)
mapView.showUserCurrentLocation()
}
POI InteractionTương tác POI trên bản đồ
When the user taps a built-in map POI (restaurants, fuel stations, hospitals, etc.), the SDK automatically shows a callout and loads place details. The host app receives data through delegate callbacks and can respond to callout button taps via public helpers.Khi người dùng chạm vào POI có sẵn trên bản đồ như nhà hàng, trạm xăng hoặc bệnh viện, SDK tự hiển thị callout và tải chi tiết địa điểm. Ứng dụng nhận dữ liệu qua delegate callback và xử lý nút trong callout bằng các hàm public.
POI delegate flowLuồng delegate của POI
| CallbackCallback | When firedKhi kích hoạt |
|---|---|
didTouchAnnotation(_:annotation:) | Fired immediately when the user taps any annotation or POI. Provides the initial AnnotationModel with title and category.Được gọi ngay khi người dùng chạm vào marker hoặc POI. Trả AnnotationModel ban đầu gồm tiêu đề và loại địa điểm. |
didShowCallout(_:annotation:isLoadingSubtitle:) | Fired when the callout bubble appears. isLoadingSubtitle: true means the address is still resolving.Được gọi khi callout xuất hiện. isLoadingSubtitle: true nghĩa là địa chỉ vẫn đang tải. |
didRequestPlaceDetail(_:placeId:) | Fired before the SDK fetches POI detail. Useful for pre-loading UI or showing a skeleton screen.Được gọi trước khi SDK lấy chi tiết POI. Có thể dùng để hiển thị trạng thái đang tải. |
didUpdateCalloutSubtitle(_:subtitle:) | Fired when the resolved address string is available. Update the callout or bottom sheet subtitle here.Được gọi khi đã có địa chỉ. Cập nhật subtitle của callout hoặc bottom sheet tại đây. |
didUpdateCalloutCategory(_:type:) | Fired when the SDK resolves the place category string (e.g. "restaurant"). Update the category icon here.Được gọi khi đã có loại địa điểm. Cập nhật icon loại địa điểm tại đây. |
didLoadPOIDetail(_:detail:PlaceDetailModel) | Fired when full PlaceDetailModel is available (name, address, phone, types, hours, etc.). Populate a detail bottom sheet.Được gọi khi đã có PlaceDetailModel đầy đủ như tên, địa chỉ, số điện thoại, loại địa điểm và giờ mở cửa. |
gtelMapViewDidRemoveCallout(_:) | Fired when the callout is dismissed. Reset the host preview panel.Được gọi khi callout đóng. Dùng để reset phần xem trước của ứng dụng. |
POI callout action helpersHelpers xử lý action của POI callout
When the host app renders a custom button inside the callout (e.g. "Navigate" or "Call"), call these helpers so the SDK coordinates the internal state properly.Khi ứng dụng hiển thị nút riêng trong callout, ví dụ "Dẫn đường" hoặc "Gọi", hãy gọi các hàm này để SDK cập nhật trạng thái đúng.
// User tapped the primary action button in the POI callout
func userDidTapCalloutPrimary() {
mapView.handlePOICalloutTap()
}
// User tapped the direction button in the POI callout
func userDidTapCalloutDirection() {
mapView.handlePOICalloutDirection()
}
PlaceDetailModelPlaceDetailModel
PlaceDetailModel returned in didLoadPOIDetail is the same model used by the .placeDetail input flow. Key fields:PlaceDetailModel nhận được trong didLoadPOIDetail là cùng model với input .placeDetail. Các trường chính:
| FieldTrường | DescriptionMô tả |
|---|---|
name | Display name of the place.Tên hiển thị của địa điểm. |
formattedAddress / adrFormatAddress | Full address string. Prefer adrFormatAddress when available.Chuỗi địa chỉ đầy đủ. Ưu tiên adrFormatAddress khi có. |
types | [CatetoryPlaceType] — place category list.danh sách loại địa điểm. |
internationalPhoneNumber | Phone number for the "Call" action.Số điện thoại cho chức năng gọi điện. |
didLoadPOIDetail and didLoadPlaceDetail: the first is fired automatically when the user taps a map POI; the second is fired when the host app explicitly sends .placeDetail(placeId) input.Phân biệt didLoadPOIDetail và didLoadPlaceDetail: didLoadPOIDetail tự chạy khi người dùng chạm POI trên bản đồ; didLoadPlaceDetail chạy khi ứng dụng gửi input .placeDetail(placeId).
Geocoding & SearchGeocoding & tìm kiếm
The search flow uses GtelMapView inputs; the result list and errors are returned via delegate. The host app debounces text and manages the result list UI.Tìm kiếm dùng input của GtelMapView. Danh sách kết quả và lỗi được trả qua delegate. Ứng dụng tự quản lý ô nhập và danh sách kết quả.
func autocomplete(_ text: String, focus: CLLocationCoordinate2D) {
mapView.apply(input: .autocomplete(text: text, focusLat: focus.latitude, focusLng: focus.longitude, size: 8))
}
func search(_ text: String, focus: CLLocationCoordinate2D) {
mapView.apply(input: .forwardGeocoding(text: text, focusLat: focus.latitude, focusLng: focus.longitude, size: 10))
}
func reverse(_ coordinate: CLLocationCoordinate2D) {
mapView.apply(input: .reversePoint(coordinate: coordinate, showMarker: true, zoom: 18, size: 1))
}
func nearby(category: CatetoryPlaceType, center: CLLocationCoordinate2D) {
mapView.apply(input: .nearbySearch(category: category, location: center, radius: 1000, size: 20))
}
func openPlaceDetail(_ placeId: String) {
mapView.apply(input: .placeDetail(placeId))
}
| CallbackCallback | When receivedKhi nhận |
|---|---|
didLoadAutocompleteResults | Autocomplete returns a suggestion list.Autocomplete trả danh sách gợi ý. |
didFailAutocomplete | Autocomplete failed. Show inline error or clear suggestions.Autocomplete thất bại. Hiển thị lỗi inline hoặc xóa gợi ý. |
didLoadSearchResults | Forward search returns a result list.Forward search trả danh sách kết quả. |
didFailSearch | Forward search failed.Forward search thất bại. |
didLoadReversePoint(place:coordinate:) | Reverse via .reversePoint input. place is nil when no result is found at that coordinate.Trả kết quả từ input .reversePoint. place là nil nếu không tìm thấy địa điểm tại tọa độ đó. |
didLoadPinPlace(place:) | Fired after a long-press pin resolves to an address. Unlike didLoadReversePoint, place is guaranteed non-nil.Được gọi sau khi nhấn giữ bản đồ và SDK tìm được địa chỉ. Khác didLoadReversePoint, place luôn có giá trị. |
didFailPinPlace | Pin reverse failed (no result or network error).Pin reverse thất bại (không có kết quả hoặc lỗi mạng). |
didLoadNearbySearch | Nearby returns annotations by category.Nearby trả danh sách marker theo danh mục. |
didFailNearbySearch | Nearby search failed for the given category.Nearby search thất bại cho category đã cho. |
didLoadPlaceDetail(_:detail:GtelMapPlaceDetail) | Fired when host app sends .placeDetail(placeId) input. Different from didLoadPOIDetail which is auto-fired on map tap.Được gọi khi ứng dụng gửi input .placeDetail(placeId). Khác với didLoadPOIDetail, callback này không tự chạy khi người dùng chạm POI. |
Direct reverse geocoding helperHàm lấy địa chỉ trực tiếp
Use GtelMapClient.shared.reversePoint when the host app needs the address directly (e.g. for a form field) without rendering a marker or going through the map delegate.Dùng GtelMapClient.shared.reversePoint khi ứng dụng cần địa chỉ trực tiếp, ví dụ điền vào form, mà không cần hiển thị marker hoặc đi qua delegate của bản đồ.
GtelMapClient.shared.reversePoint(
pointLat: coordinate.latitude,
pointLon: coordinate.longitude,
zoom: 18,
size: 1,
region: nil,
localadmin: nil
) { geocoding, message in
guard message.onCheckSuccess(), let address = geocoding?.subtitle else { return }
destinationField.text = address
}
region and localadmin parameters bias results to a specific province or district code. Leave nil for unbiased results.Tham số tùy chọn region và localadmin giúp ưu tiên kết quả theo mã tỉnh hoặc quận. Để nil nếu không cần ưu tiên khu vực.
Host app flowLuồng xử lý phía ứng dụng
- Keep the latest map center from
didChangeRegionand use it as the search focus.Lưu tâm bản đồ mới nhất từdidChangeRegionđể ưu tiên kết quả quanh khu vực đang xem. - Debounce user text before sending
.autocompleteor.forwardGeocoding.Chờ người dùng dừng nhập rồi mới gửi.autocompletehoặc.forwardGeocoding. - Render the result list in host UI, then select a result with
.searchResultor load details with.placeDetail.Hiển thị danh sách kết quả trong giao diện của ứng dụng, rồi chọn kết quả bằng.searchResulthoặc lấy chi tiết bằng.placeDetail. - Use
.clearSearchwhen the query is empty or the search screen closes.Dùng.clearSearchkhi ô tìm kiếm rỗng hoặc màn hình tìm kiếm đóng.
Road · OtherĐường · dịch vụ khác
A group of auxiliary tasks corresponding to Android Road · Other: snap to roads, matrix route, isochrone, geofencing, weather, and static map. Use GtelMapClient.shared for data-only calls and GtelMapView.apply(input:) when the result must be rendered on the map.Nhóm tính năng phụ gồm snap to roads, matrix route, isochrone, geofencing, weather và static map. Dùng GtelMapClient.shared khi chỉ cần lấy dữ liệu; dùng GtelMapView.apply(input:) khi cần hiển thị kết quả lên bản đồ.
Snap to roads
GtelMapClient.shared.snapToRoads, .snapToRoads, .snapToRoadsPlayback, .clearSnapToRoads.
Matrix route
.matrixRoute to request a matrix and .matrixCandidateRoutes to render candidate routes..matrixRoute để yêu cầu ma trận tuyến và .matrixCandidateRoutes để hiển thị các tuyến đề xuất.
Isochrone
GtelMapClient.shared.isochrone, .isochrone, .clearIsochrone.
Geofencing
.geofencingPolygon, callbacks didLoadGeofencingResult and didFailGeofencing..geofencingPolygon trả kết quả qua didLoadGeofencingResult và lỗi qua didFailGeofencing.
Weather
GtelMapClient.shared.getWeather for the host app to show its own weather UI.GtelMapClient.shared.getWeather giúp ứng dụng hiển thị giao diện thời tiết riêng.
Static Map
GtelMapClient.shared.getStaticMap returns a UIImage for preview/thumbnails.GtelMapClient.shared.getStaticMap trả UIImage cho preview/thumbnail.
func loadStaticPreview(center: CLLocationCoordinate2D) {
let request = StaticMapRequest(
center: center,
zoom: 14,
size: StaticMapSize(width: 640, height: 360)
)
GtelMapClient.shared.getStaticMap(request: request) { image, message in
guard message.onCheckSuccess(), let image else { return }
previewImageView.image = image
}
}
func checkFence(pointId: String, coordinate: CLLocationCoordinate2D, geometry: PolygonGeometryModel) {
mapView.apply(input: .geofencingPolygon(pointId: pointId, coordinate: coordinate, geometry: geometry))
}
Service referenceTham khảo service public
| Capability | Use through | Result path |
|---|---|---|
| Snap to roads | GtelMapClient.shared.snapToRoads or .snapToRoads | Callback response or map-rendered snapped route.Nhận kết quả qua callback hoặc hiển thị tuyến đã khớp đường trên bản đồ. |
| Isochrone | GtelMapClient.shared.isochrone then .isochrone | Callback response, then public input for map overlay.Nhận kết quả qua callback, sau đó dùng input public để hiển thị lớp phủ. |
| Geofencing | .geofencingPolygon | didLoadGeofencingResult, didFailGeofencing |
| Weather | GtelMapClient.shared.getWeather | Callback returns data for host-owned UI.Callback trả dữ liệu cho giao diện do ứng dụng quản lý. |
| Static map | GtelMapClient.shared.getStaticMap | Callback returns a preview UIImage.Callback trả ảnh preview dạng UIImage. |
UIKit ComponentsUIKit Components public
The SDK includes native UIKit components for common host UI flows. These components do not replace GtelMapView; the host app still applies map changes through GtelMapView.apply(input:) and handles selected data through closures or delegates.SDK cung cấp một số UIKit component cho các giao diện phổ biến. Các component này không thay thế GtelMapView; ứng dụng vẫn gửi thay đổi lên bản đồ bằng GtelMapView.apply(input:) và nhận lựa chọn của người dùng qua closure hoặc delegate.
| ComponentComponent | InputInput | CallbackCallback |
|---|---|---|
GtelPlaceSearchViewController | Initial text and optional center coordinate.Text ban đầu và tọa độ trung tâm nếu có. | Selected place model.Model địa điểm được chọn. |
GtelMapStylePickerViewController | [GtelMapStyleModel], selectedStyle | onSelect or GtelMapStylePickerDelegate |
GtelNearbyCategoryView | [CatetoryPlaceType] | onSelect or GtelNearbyCategoryViewDelegate |
GtelWeatherBottomSheetViewController | WeatherResponseModel | onClose or GtelWeatherBottomSheetDelegate |
GtelRouteDirectionViewController | Route summary, transport modes, maneuvers.Route summary, danh sách transport mode và maneuver. | GtelRouteDirectionDelegate |
GtelMultiStopPointViewController | [MultiStopPointItem] | GtelMultiStopPointDelegate |
// The style catalog is served locally by the SDK — no network call needed
let mapStyles = GtelMapClient.shared.mapStyles
let picker = GtelMapStylePickerViewController(items: mapStyles, selectedStyle: currentStyle)
picker.onSelect = { [weak self, weak picker] style in
picker?.dismiss(animated: true)
self?.mapView.apply(input: .mapStyle(style))
}
present(picker, animated: true)
let categoryView = GtelNearbyCategoryView()
categoryView.onSelect = { [weak self] category in
self?.mapView.apply(input: .nearbySearch(category: category, location: center))
}
GtelMapClient — Independent ServicesGtelMapClient — Service độc lập
GtelMapClient.shared is the public service facade for host-owned UI and background workflows that do not need a GtelMapView instance. Configure the SDK once with GtelMapConfig.configure before the first service call.GtelMapClient.shared dùng để lấy dữ liệu cho giao diện riêng hoặc xử lý nền khi không cần GtelMapView. Cấu hình SDK một lần bằng GtelMapConfig.configure trước lần gọi đầu tiên.
GtelMapClient to fetch data. Use GtelMapView.apply(input:) to render data on the map. Use GtelMapViewDelegate to receive map events and map-render callbacks.Dùng GtelMapClient để lấy dữ liệu. Dùng GtelMapView.apply(input:) để hiển thị dữ liệu lên bản đồ. Dùng GtelMapViewDelegate để nhận sự kiện bản đồ và callback hiển thị.
SetupCấu hình
import GtelMapSDK
GtelMapConfig.configure(GtelMapConfiguration(
apiVersion: "1.1",
weatherApiKey: "YOUR_WEATHER_API_KEY"
))
GtelMapClient.shared.reversePoint(
pointLat: 21.0278,
pointLon: 105.8342
) { place, message in
guard message.onCheckSuccess(), let place else { return }
showAddress(place)
}
Choose the right entry pointChọn đúng entry point
| Use caseUse case | UseDùng |
|---|---|
| Read the built-in map style catalog for a custom style picker (served locally, no network call).Lấy danh sách style dựng sẵn cho bộ chọn style riêng (trả về cục bộ, không gọi mạng). | GtelMapClient.shared.mapStyles |
| Load autocomplete or geocoding results for a custom list UI.Lấy kết quả autocomplete hoặc geocoding cho danh sách riêng. | GtelMapClient.shared |
| Calculate route, matrix, weather, static map, snap to roads, isochrone, or geofencing result outside a live map screen.Tính tuyến đường, matrix, thời tiết, static map, snap to roads, isochrone hoặc geofencing ngoài màn hình bản đồ. | GtelMapClient.shared |
| Render markers, route polylines, polygons, isochrone zones, or snapped roads on the map.Hiển thị marker, tuyến đường, polygon, vùng isochrone hoặc snap road lên bản đồ. | GtelMapView.apply(input:) |
| React to map gestures, marker taps, POI taps, and map-render lifecycle events.Nhận thao tác kéo/chạm bản đồ, marker, POI và sự kiện hiển thị bản đồ. | GtelMapViewDelegate |
Available service methodsCác service method hiện có
| GroupNhóm | MethodsMethod | Typical host useCách dùng thường gặp |
|---|---|---|
| Geocoding | reversePoint, autocomplete, forwardGeocoding, getLocationDetail, getMatrixRoute | Search, address forms, place detail screens, ETA tables.Search, form địa chỉ, màn chi tiết địa điểm, bảng ETA. |
| Places | nearbySearch | Find places of a given type around a location for a host-owned list or picker.Tìm địa điểm theo loại quanh một vị trí cho danh sách hoặc bộ chọn riêng. |
| Map styles | mapStyles | Read the local built-in style catalog to build a host-owned style switcher (no network call).Lấy danh sách style dựng sẵn cục bộ để ứng dụng tự làm bộ đổi style (không gọi mạng). |
| Administrative | getProvincePolygon, getWardPolygon | Load administrative boundaries before rendering or checking a region.Lấy ranh giới hành chính trước khi hiển thị hoặc kiểm tra khu vực. |
| Navigation | getRoutes, getDoorToDoorRoute | Calculate routes for host-owned summary UI or then render with .route.Tính tuyến cho phần tóm tắt riêng hoặc hiển thị lại bằng .route. |
| Weather | getWeather | Show weather cards, sheets, or alerts managed by the host app.Hiển thị thẻ thời tiết, sheet hoặc cảnh báo do ứng dụng quản lý. |
| Road tools | snapToRoads, isochrone | Process tracks, delivery zones, accessibility ranges, or analytics flows.Xử lý vết GPS theo tim đường, vùng giao hàng, vùng đẳng thời (Isochrone) hoặc dữ liệu phân tích. |
| Static map | getStaticMap, getStaticMapData | Generate previews, thumbnails, or share images without showing a live map.Tạo ảnh preview, thumbnail hoặc ảnh chia sẻ mà không cần mở bản đồ live. |
| Geofencing | checkPointInsidePolygon | Check whether a coordinate belongs to a known polygon.Kiểm tra một tọa độ có nằm trong polygon đã biết hay không. |
Examples for every methodVí dụ cho từng hàm
The snippets below use the callback overloads so UIKit host screens can receive results without creating Task blocks. The callback returns the response model plus ResponseMessage.Các ví dụ bên dưới dùng callback để màn UIKit nhận kết quả mà không cần tạo Task. Callback trả model kết quả kèm ResponseMessage.
let center = CLLocationCoordinate2D(latitude: 21.0278, longitude: 105.8342)
let destination = CLLocationCoordinate2D(latitude: 21.0368, longitude: 105.8342)
GtelMapClient.shared.reversePoint(
pointLat: center.latitude,
pointLon: center.longitude
) { reverse, reverseMessage in
guard reverseMessage.onCheckSuccess(), let reverse else { return }
updateAddress(reverse)
}
GtelMapClient.shared.autocomplete(
text: "Ho Guom",
focusLat: center.latitude,
focusLng: center.longitude,
size: 10
) { suggestions, autocompleteMessage in
guard autocompleteMessage.onCheckSuccess() else { return }
updateSuggestions(suggestions?.features ?? [])
}
GtelMapClient.shared.forwardGeocoding(
text: "Ho Guom",
focusLat: center.latitude,
focusLng: center.longitude,
size: 10
) { searchResult, searchMessage in
guard searchMessage.onCheckSuccess() else { return }
updateSearchResult(searchResult)
}
if let placeId = selectedPlaceId {
GtelMapClient.shared.getLocationDetail(id: placeId) { detail, detailMessage in
guard detailMessage.onCheckSuccess(), let detail else { return }
showPlaceDetail(detail)
}
}
GtelMapClient.shared.nearbySearch(
location: center,
types: "restaurant",
radius: 1000,
size: 20
) { nearby, nearbyMessage in
guard nearbyMessage.onCheckSuccess(), let nearby else { return }
updateNearbyPlaces(nearby)
}
let origin = CLLocationCoordinate2D(latitude: 21.0278, longitude: 105.8342)
let destination = CLLocationCoordinate2D(latitude: 21.0368, longitude: 105.8342)
let matrixRequest = MatrixRouteRequest(
sources: [origin],
targets: [destination],
mode: .driving
)
GtelMapClient.shared.getMatrixRoute(request: matrixRequest) { matrix, matrixMessage in
guard matrixMessage.onCheckSuccess(), let matrix else { return }
updateMatrixSummary(matrix)
}
let routeRequest = EstimateTimeDataRequest(
criteria: CriteriaDataRequest(locations: [
LocationDataRequest(coordinate: origin),
LocationDataRequest(coordinate: destination)
]),
costing: "auto"
)
GtelMapClient.shared.getRoutes(request: routeRequest) { route, routeMessage in
guard routeMessage.onCheckSuccess(), let route else { return }
updateRouteSummary(route)
}
let doorToDoorRequest = EstimateTimeDataRequest(
criteria: CriteriaDataRequest(locations: [
LocationDataRequest(coordinate: origin),
LocationDataRequest(coordinate: destination)
]),
costing: "auto",
doorToDoor: true
)
GtelMapClient.shared.getDoorToDoorRoute(
request: doorToDoorRequest
) { doorToDoorRoute, doorToDoorMessage in
guard doorToDoorMessage.onCheckSuccess(), let doorToDoorRoute else { return }
updateDoorToDoorSummary(doorToDoorRoute)
}
let center = CLLocationCoordinate2D(latitude: 21.0278, longitude: 105.8342)
GtelMapClient.shared.getProvincePolygon(code: "01") { province, provinceMessage in
guard provinceMessage.onCheckSuccess(), let province else { return }
updateProvinceBoundary(province)
}
GtelMapClient.shared.getWardPolygon(code: "00001") { ward, wardMessage in
guard wardMessage.onCheckSuccess(), let ward else { return }
updateWardBoundary(ward)
}
let polygon = PolygonGeometryModel(
type: "Polygon",
coordinates: [[[
[105.80, 21.00],
[105.88, 21.00],
[105.88, 21.06],
[105.80, 21.06],
[105.80, 21.00]
]]]
)
GtelMapClient.shared.checkPointInsidePolygon(
pointId: "hanoi-center",
coordinate: center,
geometry: polygon
) { isInside, geofenceMessage in
guard geofenceMessage.onCheckSuccess(), let isInside else { return }
updateGeofenceStatus(isInside)
}
let center = CLLocationCoordinate2D(latitude: 21.0278, longitude: 105.8342)
let destination = CLLocationCoordinate2D(latitude: 21.0368, longitude: 105.8342)
GtelMapClient.shared.getWeather(
lat: center.latitude,
lon: center.longitude
) { weather, weatherMessage in
guard weatherMessage.onCheckSuccess(), let weather else { return }
showWeather(weather)
}
let snapRequest = SnapToRoadsRequest(
coordinates: [center, destination],
interpolate: true
)
GtelMapClient.shared.snapToRoads(request: snapRequest) { snappedRoad, snapMessage in
guard snapMessage.onCheckSuccess(), let snappedRoad else { return }
updateSnappedRoad(snappedRoad)
}
let isochroneRequest = IsochroneRequest(
coordinate: center,
metric: .time,
contours: [5, 10, 15],
mode: .driving,
colors: ["2E86DE", "10AC84", "FF9F43"]
)
GtelMapClient.shared.isochrone(request: isochroneRequest) { isochrone, isochroneMessage in
guard isochroneMessage.onCheckSuccess(), let isochrone else { return }
updateIsochrone(isochrone)
}
let staticMapRequest = StaticMapRequest(
center: center,
zoom: 14,
size: StaticMapSize(width: 640, height: 360),
markers: [StaticMapMarker(coordinate: center)],
path: StaticMapPath(coordinates: [center, destination])
)
GtelMapClient.shared.getStaticMap(request: staticMapRequest) { previewImage, imageMessage in
guard imageMessage.onCheckSuccess(), let previewImage else { return }
showPreview(previewImage)
}
GtelMapClient.shared.getStaticMapData(request: staticMapRequest) { previewData, dataMessage in
guard dataMessage.onCheckSuccess(), let previewData else { return }
cachePreviewData(previewData)
}
// Built-in style catalog is local — read it synchronously, no callback needed
let styles = GtelMapClient.shared.mapStyles
updateStyleSwitcher(styles)
Callback result styleNhận kết quả bằng callback
For host apps, prefer the callback overloads. They do not require Task at the call site and return both the model and ResponseMessage; the service facade does not throw.Với ứng dụng UIKit, nên dùng dạng callback. Cách này không cần tạo Task tại nơi gọi và trả về cả model lẫn ResponseMessage; service facade không ném lỗi (throw).
GtelMapClient.shared.autocomplete(
text: "Ha Noi",
focusLat: 21.0278,
focusLng: 105.8342,
size: 10
) { model, message in
guard message.onCheckSuccess() else {
showError(message)
return
}
results = model?.features ?? []
}
Fetch first, render laterLấy dữ liệu trước, hiển thị sau
A host screen can calculate data with GtelMapClient, then pass the result into GtelMapView.apply(input:) only when the user opens a map.Một màn hình có thể lấy dữ liệu bằng GtelMapClient trước. Khi người dùng mở bản đồ, truyền kết quả vào GtelMapView.apply(input:).
GtelMapClient.shared.getRoutes(request: request) { route, message in
guard message.onCheckSuccess(), let route else { return }
// Later, on the map screen:
mapView.apply(input: .route(route))
}
GtelPlaceSearchViewControllerGtelPlaceSearchViewController
GtelPlaceSearchViewController is the UIKit v1 search UI. It debounces text input, loads suggestions through GtelMapClient.shared.autocomplete, and reports selection through GtelPlaceSearchDelegate.GtelPlaceSearchViewController là màn hình tìm kiếm UIKit v1. Controller tự chờ người dùng dừng nhập, lấy gợi ý qua GtelMapClient.shared.autocomplete và trả lựa chọn qua GtelPlaceSearchDelegate.
extension MapViewController: GtelPlaceSearchDelegate {
func showSearch() {
let searchVC = GtelPlaceSearchViewController()
searchVC.delegate = self
searchVC.focusCoordinate = currentMapCenter
searchVC.searchSize = 10
present(searchVC, animated: true)
}
func placeSearch(_ controller: GtelPlaceSearchViewController, didSelect item: SearchResultItemDataSource) {
controller.dismiss(animated: true)
mapView.apply(input: .searchResult(item))
}
func placeSearchDidCancel(_ controller: GtelPlaceSearchViewController) {
controller.dismiss(animated: true)
}
}
Current limitsGiới hạn hiện tại
Search UI
The first public search UI is UIKit-only. SwiftUI search UI is deferred.Search UI public đầu tiên chỉ hỗ trợ UIKit. Search UI SwiftUI được để sau.
Map styles
Style loading remains a map flow through GtelMapView.apply(input: .mapStyles) and delegate callbacks.Tải style vẫn đi qua GtelMapView.apply(input: .mapStyles) và nhận kết quả bằng delegate callback.
Nearby search
Nearby search remains a map-render flow through .nearbySearch because the SDK converts places into map annotations.Nearby search vẫn đi qua .nearbySearch vì SDK chuyển địa điểm thành marker trên bản đồ.
Rendering
GtelMapClient never renders UI. Any map output still goes through GtelMapView.GtelMapClient không hiển thị UI. Mọi nội dung trên bản đồ vẫn đi qua GtelMapView.
Result, error & lifecycleKết quả, lỗi & vòng đời
Unlike Android which uses Resource<T>, the iOS guide receives map results via GtelMapViewDelegate and direct service results via GtelMapClient.Trên iOS, kết quả từ bản đồ được trả qua GtelMapViewDelegate. Kết quả lấy trực tiếp được trả qua GtelMapClient.
func gtelMapView(_ mapView: GtelMapView, didLoadSearchResults items: [SearchResultItemDataSource]) {
results = items
}
func gtelMapView(_ mapView: GtelMapView, didFailSearch message: ResponseMessage) {
showError(message)
}
func gtelMapViewDidFinishLoading(_ mapView: GtelMapView) {
isMapReady = true
}
GtelMapView inside UIViewRepresentable and use a coordinator so the delegate is not released prematurely.UIKit và SwiftUI quản lý vòng đời của view. Với SwiftUI, đặt GtelMapView trong UIViewRepresentable và dùng coordinator để delegate không bị giải phóng sớm.
Error callback groupsNhóm callback lỗi
| GroupNhóm | CallbacksCallback |
|---|---|
| Style | didFailMapStyles, didFailMapStyle, didFailCustomStyleContent(_:message:ResponseMessage), didFailCustomStyleContent(_:error:GtelMapCustomStyleContentError) |
| Search | didFailAutocomplete, didFailSearch, didFailNearbySearch, didFailPinPlace, didFailReversePoint |
| Route | didFailNavigation, didFailMatrixRoute |
| Overlay | didFailGeofencing |
didFailCustomStyleContent has two overloads. The ResponseMessage version handles network/server errors. The typed GtelMapCustomStyleContentError version handles validation errors (invalid ids, duplicate ids, missing sources, etc.) before any network call is made.didFailCustomStyleContent có hai dạng. Dạng ResponseMessage xử lý lỗi chung. Dạng GtelMapCustomStyleContentError xử lý lỗi dữ liệu như id sai, id trùng hoặc thiếu source.
CheatsheetTra nhanh
The most commonly used inputs, helpers, and callbacks when integrating the host app.Các input, hàm hỗ trợ và callback thường dùng nhất khi tích hợp SDK.
GtelMapViewInput
| GroupNhóm | Input |
|---|---|
| Search | .autocomplete, .forwardGeocoding, .reversePoint, .nearbySearch, .searchResult, .placeDetail, .clearSearch |
| Map | .mapStyles, .mapStyle, .mapStyleSource |
| Annotation | .marker, .annotations, .pinnedPlace, .clearRouteAndMarker |
| Route | .navigationAvailableModes, .navigationRoute, .route, .multiStopRoute, .matrixRoute, .matrixCandidateRoutes, .clearRoute |
| Overlay | .polygon, .clearPolygon, .geofencingPolygon, .isochrone, .clearIsochrone, .snapToRoads, .snapToRoadsPlayback, .clearSnapToRoads |
| Custom style | .customStyleImage, .removeCustomStyleImage, .customStyleContent, .updateCustomStyleSource, .updateCustomStyleFeature, .removeCustomStyleFeature, .removeCustomStyleContentById, .removeCustomStyleContent, .clearCustomStyleContent, .setCustomStyleLayerVisibility, .setCustomStyleLayerFilter, .clearCustomStyleLayerFilter |
GtelMapView helpers
| HelperHelper | PurposeMục đích |
|---|---|
setCameraZoomToAt | Focus on a coordinate.Đưa camera tới một tọa độ. |
setCameraToUserLocation | Focus on user location.Đưa camera tới vị trí người dùng. |
setCameraBoundsInVietNam | Default Vietnam viewport.Vùng bản đồ mặc định Việt Nam. |
setCameraDefaultMap(sw:ne:edgePadding:) | Fit to custom bounds.Đưa camera vừa với vùng tùy chỉnh. |
visiableBounds | Current visible bounds (read-only).Vùng bản đồ đang hiển thị. |
onSetVisiableBounds(annotations:) / onSetVisiableBounds(points:) | Fit camera to show all annotations or coordinates.Đưa camera vừa đủ để thấy tất cả marker hoặc tọa độ. |
removeAllAnnotations · deselectAllCallout | Clear markers or callout.Xóa marker hoặc callout. |
isValidCoordinate | Validate before camera or marker calls.Kiểm tra tọa độ trước khi gọi camera hoặc marker. |
getRoutes · getDoorToDoorRoute | Fetch route data without rendering.Lấy dữ liệu tuyến đường mà chưa hiển thị lên bản đồ. |
getWeather · snapToRoads · isochrone · getStaticMap | Direct service helpers with callback.Các hàm lấy dữ liệu trực tiếp và trả kết quả qua callback. |
reversePoint(pointLat:pointLon:callback:) | Direct reverse geocoding without delegate.Lấy địa chỉ từ tọa độ mà không đi qua delegate. |
handlePOICalloutTap · handlePOICalloutDirection | Respond to POI callout button taps.Xử lý nút trong callout của POI. |
calloutAnchorPoint(for:) | Anchor point for custom overlays aligned to callout.Lấy vị trí để căn overlay theo callout. |
scheduleOverlayPositionUpdate | Trigger overlay position recalculation.Yêu cầu tính lại vị trí overlay. |
showUserCurrentLocation | Show the user location dot on the map.Hiển thị chấm vị trí người dùng trên bản đồ. |
GtelMapViewDelegateGtelMapViewDelegate
| GroupNhóm | CallbacksCallback |
|---|---|
| Lifecycle & style | gtelMapViewDidFinishLoading, gtelMapViewDidFinishLoadingStyle, gtelMapViewRegionIsChanging, didChangeRegion, regionWillChangeWith, regionDidChangeWith |
| Interaction | didTapCoordinate, didPinCoordinate, didTouchAnnotation, gtelMapViewDidBeginGesturePan, gtelMapViewDidEndGesturePan |
| Callout | canShowCalloutFor, annotationViewFor, markerImageFor, leftCalloutAccessoryViewFor, rightCalloutAccessoryViewFor, didShowCallout, didUpdateCalloutSubtitle, didUpdateCalloutCategory, gtelMapViewDidRemoveCallout, didRequestCalloutPositionUpdate |
| POI | didRequestPlaceDetail, didLoadPOIDetail, didTapCustomFeature |
| Search | didLoadMapStyles, didLoadSearchResults, didLoadAutocompleteResults, didLoadNearbySearch, didLoadPlaceDetail, didLoadReversePoint, didLoadPinPlace |
| Routing | didLoadNavigationModes, didLoadNavigationRoute, didSelectNavigationRoute, didSelectMainTrip, didRequestDirection, didLoadMatrixRoute |
| Geofencing | didLoadGeofencingResult, didFailGeofencing |
TroubleshootingXử lý sự cố
Quick checklist when integrating the SDK into the host app.Danh sách kiểm tra nhanh khi tích hợp SDK.
| SymptomHiện tượng | CheckKiểm tra |
|---|---|
| Map blank or style not loadingBản đồ trắng hoặc style không tải | Verify the SDK is configured before the map is created, GTELMapAccessToken is set in Info.plist, and the device has network. Call GtelMapConfig.hasAPIKey to verify.Kiểm tra SDK đã được cấu hình trước khi tạo bản đồ, GTELMapAccessToken đã có trong Info.plist và thiết bị có mạng. Có thể gọi GtelMapConfig.hasAPIKey để kiểm tra. |
| Delegate callbacks not receivedKhông nhận callback từ delegate | Ensure gtelMapDelegate is alive and set before sending any input.Đảm bảo gtelMapDelegate còn tồn tại và đã được gắn trước khi gửi input. |
| Search not updating UITìm kiếm không cập nhật giao diện | Implement the correct success/fail callbacks, debounce input text, and clear search when the query is empty.Cài đặt đúng callback thành công/lỗi, chờ người dùng dừng nhập rồi mới tìm kiếm, và gọi .clearSearch khi ô tìm kiếm rỗng. |
| Marker or callout not visibleMarker hoặc callout không hiển thị | Check the AnnotationModel, the custom icon returned from the delegate, and the callout deselect state.Kiểm tra AnnotationModel, icon tùy chỉnh trả về từ delegate và trạng thái chọn callout. |
| Route / navigation failsTuyến đường hoặc dẫn đường bị lỗi | Verify the location list has enough valid waypoints, a travel mode is selected, and check the didFailNavigation callback.Kiểm tra danh sách có đủ điểm hợp lệ, đã chọn phương tiện di chuyển và xem callback didFailNavigation. |
| Location not workingVị trí không hoạt động | Check the Info.plist usage description, device permission, and the coordinate value before calling the camera.Kiểm tra mô tả quyền trong Info.plist, quyền trên thiết bị và tọa độ trước khi gọi camera. |
Custom style content fails with rendererNotReadyCustom style content báo lỗi rendererNotReady | Wait for gtelMapViewDidFinishLoading before sending .customStyleContent. For style switches, use gtelMapViewDidFinishLoadingStyle.Chờ gtelMapViewDidFinishLoading rồi mới gửi .customStyleContent. Khi đổi style, dùng gtelMapViewDidFinishLoadingStyle. |
| Custom content id / layer id validation errorCustom content id hoặc layer id không hợp lệ | All host app ids and image names must start with host_. See GtelMapCustomStyleContentError for the specific error type.Tất cả id và tên hình do ứng dụng đặt phải bắt đầu bằng host_. Xem GtelMapCustomStyleContentError để biết lỗi cụ thể. |
| POI tap does not trigger detailChạm POI nhưng không có chi tiết | Verify the didLoadPOIDetail callback is implemented on the delegate. POI detail requires network and a valid API key.Kiểm tra delegate đã cài đặt didLoadPOIDetail. Chi tiết POI cần mạng và API key hợp lệ. |
GtelRouteNavigationViewController does not load routeGtelRouteNavigationViewController không tải tuyến đường | Ensure at least 2 valid coordinates are passed in stops. Check the API key and network.Đảm bảo truyền ít nhất 2 tọa độ hợp lệ vào stops. Kiểm tra API key và mạng. |
Your first mapHiển thị bản đồ đầu tiên
Minimal example: configure the SDK, create GtelMapView, assign the delegate, and move the camera to the default viewport.Ví dụ tối thiểu: cấu hình SDK, tạo GtelMapView, gắn delegate và đưa camera về vùng mặc định.
Integration stepsCác bước tích hợp
- Configure the SDK once during app launch.Cấu hình SDK một lần khi app khởi động.
- Create
GtelMapViewin the screen.TạoGtelMapViewtrong màn hình. - Assign
gtelMapDelegatebefore sending any input.GắngtelMapDelegatetrước khi gửi input. - Wait for map loading callback before moving to the default viewport.Chờ callback báo bản đồ đã tải xong rồi mới đưa camera về vùng mặc định.
final class FirstMapViewController: UIViewController, GtelMapViewDelegate {
private let mapView = GtelMapView()
override func viewDidLoad() {
super.viewDidLoad()
mapView.gtelMapDelegate = self
view.addSubview(mapView)
mapView.frame = view.bounds
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
func gtelMapViewDidFinishLoading(_ mapView: GtelMapView) {
mapView.setCameraBoundsInVietNam()
}
}
Next stepsBước tiếp theo
Switch style at runtimeĐổi style
Load the style catalog once, show a picker in the host UI, then apply the selected style.Tải danh sách style một lần, hiển thị bộ chọn trong giao diện ứng dụng, rồi áp dụng style được chọn.
func prepareStylePicker() {
mapView.apply(input: .mapStyles)
}
func gtelMapView(_ mapView: GtelMapView, didLoadMapStyles items: [GtelMapStyleModel]) {
styleItems = items
}
func userDidSelectStyle(_ style: GtelMapStyleModel) {
mapView.apply(input: .mapStyle(style))
}
Custom style (dynamic)Custom style
Add a custom content block, then update individual features without re-adding the entire block. Handle taps on custom features via the delegate.Thêm một custom content block, sau đó cập nhật từng feature khi dữ liệu thay đổi. Khi người dùng chạm feature, xử lý qua delegate.
// 1. Register icon and add content block once
func setupVehicleLayer(vehicles: [Vehicle]) {
mapView.apply(input: .customStyleImage(name: "host_ic_vehicle", image: UIImage(named: "ic_vehicle")!))
let features = vehicles.map { v in
GtelMapCustomFeature(
id: v.id,
geometry: .point(v.coordinate),
title: v.name,
properties: ["status": v.status]
)
}
let source = GtelMapCustomSource(id: "host_vehicles_source", features: features)
let layer = GtelMapCustomLayer(
id: "host_vehicles_layer",
sourceId: "host_vehicles_source",
kind: .symbol,
style: GtelMapCustomLayerStyle(iconScale: 1.2, showsTitle: true)
)
let content = GtelMapCustomStyleContent(
id: "host_vehicles",
sources: [source],
layers: [layer]
)
mapView.apply(input: .customStyleContent(content: content))
}
// 2. Update a single vehicle position without re-adding everything
func updateVehicle(_ vehicle: Vehicle) {
let updated = GtelMapCustomFeature(
id: vehicle.id,
geometry: .point(vehicle.coordinate),
title: vehicle.name,
properties: ["status": vehicle.status]
)
mapView.apply(input: .updateCustomStyleFeature(
contentId: "host_vehicles",
sourceId: "host_vehicles_source",
feature: updated
))
}
// 3. Handle taps
func gtelMapView(_ mapView: GtelMapView, didTapCustomFeature feature: GtelMapCustomFeature, layerId: String?) {
guard let vehicleId = feature.id else { return }
showVehicleDetail(id: vehicleId)
}
// 4. Clean up when leaving the screen
func cleanup() {
mapView.apply(input: .removeCustomStyleContentById(contentId: "host_vehicles"))
}
Markers + callout from a listMarker + callout từ danh sách
Render a list of places as annotations and adapt the host app UI based on marker/callout callbacks.Hiển thị danh sách địa điểm thành marker. Cập nhật giao diện theo callback của marker hoặc callout.
func renderPlaces(_ places: [AnnotationModel]) {
mapView.apply(input: .annotations(places, layerId: "nearby_places", visibleLayerIds: ["nearby_places"], iconScale: 1.0))
mapView.onSetVisiableBounds(annotations: places)
}
func gtelMapView(_ mapView: GtelMapView, didShowCallout annotation: AnnotationModel, isLoadingSubtitle: Bool) {
showPlacePreview(annotation)
}
Autocomplete + debounceGợi ý tìm kiếm tự động (Debounce Autocomplete)
The host app debounces text by about 250 ms, uses the current center as the focus, then renders the suggestion list from the delegate.Ứng dụng nên chờ khoảng 250 ms sau khi người dùng dừng nhập. Sau đó dùng tâm bản đồ hiện tại để lấy gợi ý và hiển thị danh sách nhận từ delegate.
func searchTextDidChange(_ text: String, focus: CLLocationCoordinate2D) {
searchDebouncer.run { [weak self] in
guard !text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
self?.mapView.apply(input: .clearSearch)
return
}
self?.mapView.apply(input: .autocomplete(text: text, focusLat: focus.latitude, focusLng: focus.longitude, size: 8))
}
}
func gtelMapView(_ mapView: GtelMapView, didLoadAutocompleteResults items: [SearchResultItemDataSource]) {
suggestions = items
}
Selecting a suggestionChọn một gợi ý
func userDidSelectSuggestion(_ item: SearchResultItemDataSource) {
mapView.apply(input: .searchResult(item))
if !item.placeId.isEmpty {
mapView.apply(input: .placeDetail(item.placeId))
}
}
Tap / long-press → reverse geocodeChạm / nhấn giữ → Địa mã hóa nghịch (Reverse Geocoding)
When the user taps or pins a coordinate, send the reverse point input so the SDK resolves the place and renders a marker if needed.Khi người dùng chạm hoặc nhấn giữ một tọa độ, gửi input reverse point để SDK tìm địa điểm và hiển thị marker nếu cần.
func gtelMapView(_ mapView: GtelMapView, didPinCoordinate coordinate: CLLocationCoordinate2D) {
mapView.apply(input: .reversePoint(coordinate: coordinate, showMarker: true, zoom: 18, size: 1))
}
func gtelMapView(_ mapView: GtelMapView, didLoadReversePoint place: GeocodingResponseModel?, coordinate: CLLocationCoordinate2D) {
pinnedPlace = place
}
POI tap flowLuồng chạm POI trên bản đồ
Handle the full lifecycle of a map POI tap: callout → loading → detail → action buttons.Khi người dùng chạm POI, SDK hiển thị callout, tải dữ liệu, trả chi tiết và cho phép xử lý các nút thao tác.
// No input needed — SDK handles POI tap automatically.
// The host app just implements delegate callbacks.
extension MapViewController: GtelMapViewDelegate {
// Step 1: callout appears with title from map data
func gtelMapView(_ mapView: GtelMapView, didShowCallout annotation: AnnotationModel, isLoadingSubtitle: Bool) {
showCalloutView(title: annotation.title ?? "", isLoading: isLoadingSubtitle)
}
// Step 2: subtitle (address) resolves asynchronously
func gtelMapView(_ mapView: GtelMapView, didUpdateCalloutSubtitle subtitle: String) {
calloutView.subtitleLabel.text = subtitle
}
// Step 3: category resolves (update icon in callout)
func gtelMapView(_ mapView: GtelMapView, didUpdateCalloutCategory type: String) {
calloutView.categoryIcon.image = categoryIcon(for: type)
}
// Step 4: full detail available — populate bottom sheet
func gtelMapView(_ mapView: GtelMapView, didLoadPOIDetail detail: PlaceDetailModel) {
bottomSheet.populate(
name: detail.name,
address: detail.adrFormatAddress ?? detail.formattedAddress,
phone: detail.internationalPhoneNumber,
types: detail.types
)
bottomSheet.show()
}
// Step 5: user taps "Navigate" button in host UI
@IBAction func navigateButtonTapped() {
mapView.handlePOICalloutDirection()
}
// Step 6: callout dismissed
func gtelMapViewDidRemoveCallout(_ mapView: GtelMapView) {
bottomSheet.hide()
}
}
Route A → BTuyến đường A → B
Request a route from two valid points, auto-render the route, and clear it when leaving the flow.Gửi hai điểm hợp lệ để SDK tìm tuyến đường. SDK sẽ hiển thị tuyến tự động; khi rời màn hình, gọi lệnh xóa tuyến.
func route(from origin: LocationDataRequest, to destination: LocationDataRequest) {
mapView.apply(input: .navigationRoute(locations: [origin, destination], costing: .auto))
}
func gtelMapView(_ mapView: GtelMapView, didLoadNavigationRoute route: RouteResponseModel, selectedTrip: TripModel?) {
routeInfo = selectedTrip
}
func clearRouteFlow() {
mapView.apply(input: .clearRoute)
}
Common variantsBiến thể thường dùng
| GoalMục tiêu | UseCách dùng |
|---|---|
| Render only, no network requestChỉ hiển thị, không gọi mạng | .route(response) |
| Clear route when closing screenXóa route khi đóng màn hình | .clearRoute or .clearRouteAndMarker |
| Show a multi-stop routeHiển thị tuyến đường nhiều điểm trung chuyển (Multi-stop Route) | .multiStopRoute(response:stops:) |
Turn-by-turn navigationDẫn đường từng ngã rẽ (Turn-by-turn)
Present GtelRouteNavigationViewController to launch the full navigation UI. The SDK handles map tracking, voice instructions, and the summary panel. Use .demo mode during development to simulate movement without a physical drive.Present GtelRouteNavigationViewController để mở giao diện dẫn đường đầy đủ. SDK tự theo dõi bản đồ, đọc hướng dẫn và hiển thị tóm tắt. Dùng .demo khi phát triển để giả lập di chuyển.
func startNavigation(from origin: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) {
let navVC = GtelRouteNavigationViewController(
stops: [origin, destination],
profile: .car,
language: "vi",
mode: .live
)
navVC.modalPresentationStyle = .fullScreen
present(navVC, animated: true)
}
// Demo mode — useful for testing in Simulator
func startDemoNavigation(from origin: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) {
let navVC = GtelRouteNavigationViewController(
stops: [origin, destination],
profile: .car,
language: "vi",
mode: .demo
)
navVC.modalPresentationStyle = .fullScreen
present(navVC, animated: true)
}
// Multi-stop
func startMultiStopNavigation(stops: [CLLocationCoordinate2D]) {
let navVC = GtelRouteNavigationViewController(
stops: stops,
profile: .car,
language: "vi",
mode: .live
)
present(navVC, animated: true)
}
Door-to-door routeĐịnh tuyến điểm đầu - điểm cuối toàn diện (Door-to-Door Routing)
Fetch a door-to-door route (includes last-mile walking legs) and show the summary before the user starts navigation.Định tuyến điểm đầu - điểm cuối toàn diện (Door-to-Door Routing), tự động bổ sung các đoạn đi bộ kết nối và hiển thị tóm tắt trước khi bắt đầu dẫn đường.
func loadDoorToDoorPreview(origin: LocationDataRequest, destination: LocationDataRequest) {
let request = EstimateTimeDataRequest(
origin: origin,
destination: destination,
costing: .auto
)
GtelMapClient.shared.getDoorToDoorRoute(request: request) { [weak self] response, message in
guard let self, message.onCheckSuccess(), let trip = response?.trip else {
self?.showError(message.getDes())
return
}
self.showDoorToDoorSummary(
totalDistance: trip.summary?.length,
totalTime: trip.summary?.time,
legs: trip.legs
)
if let response { self.mapView.apply(input: .route(response)) }
}
}
User Location + focus cameraVị trí người dùng + camera
After the host app requests location permission and receives a coordinate, validate it and focus the camera.Sau khi ứng dụng xin quyền vị trí và nhận tọa độ, kiểm tra tọa độ rồi đưa camera tới vị trí đó.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let coordinate = locations.last?.coordinate, mapView.isValidCoordinate(coordinate) else {
mapView.setCameraBoundsInVietNam()
return
}
mapView.setCameraToUserLocation(coordinate: coordinate, zoomLevel: 16)
}
Geofencing checkKiểm tra hàng rào địa lý ảo (Geofencing)
Check whether a point is inside a polygon boundary and render the fence on the map. The SDK fires didLoadGeofencingResult with an isInside flag.Kiểm tra một điểm có nằm trong polygon hay không và hiển thị vùng đó trên bản đồ. SDK trả kết quả qua didLoadGeofencingResult với cờ isInside.
func checkGeofence(vehicleId: String, vehicleCoordinate: CLLocationCoordinate2D, zone: PolygonGeometryModel) {
mapView.apply(input: .geofencingPolygon(
pointId: vehicleId,
coordinate: vehicleCoordinate,
geometry: zone
))
}
func gtelMapView(_ mapView: GtelMapView, didLoadGeofencingResult pointId: String, isInside: Bool) {
if isInside {
showAlert("\(pointId) is inside the zone")
} else {
showAlert("\(pointId) has left the zone")
}
}
func gtelMapView(_ mapView: GtelMapView, didFailGeofencing message: ResponseMessage) {
showError(message.getDes())
}
Isochrone zonesVùng đẳng thời (Isochrone)
Fetch reachability polygons for a given origin and travel times, then render them as overlays on the map.Lấy các vùng có thể tiếp cận từ một điểm xuất phát theo thời gian di chuyển, rồi hiển thị chúng thành lớp phủ trên bản đồ.
func showIsochroneZones(from coordinate: CLLocationCoordinate2D) {
let request = IsochroneRequest(
lat: coordinate.latitude,
lng: coordinate.longitude,
contours: [5, 10, 15], // minutes
costing: .auto
)
GtelMapClient.shared.isochrone(request: request) { [weak self] response, message in
guard let self, message.onCheckSuccess(), let response else { return }
self.mapView.apply(input: .isochrone(
response: response,
originCoordinate: coordinate,
callouts: nil
))
}
}
func clearZones() {
mapView.apply(input: .clearIsochrone)
}