Sukha地图 Android SDK 开发文档
文档核对:2026-10-08 · 本次源码编译 API · Java 接口。
本文面向接入地图、定位、搜索、路线与导航的 Android 开发者,按“入门、开发指南、接口参考、常见问题”的方式组织。方法与包名以本次Sukha SDK 为准;熟悉高德的开发者可以沿用相似的接入思路,但不能直接替换二进制或照搬全部高德参数。
1. 概述
1.1 产品能力
| 类别 | 本版本提供的能力 | 使用入口 |
|---|---|---|
| 基础地图 | 地图显示、生命周期、相机、手势、主题、截图 | MapView、SukhaMap |
| 覆盖物 | 点、线、面、圆、三点弧线、信息窗 | Marker、Polyline、Polygon、Circle、Arc |
| 数据可视化 | 热力图、点聚合、瓦片覆盖物 | HeatmapTileProvider、ClusterOverlay、TileOverlay |
| 图形工具 | 点选绘制、线面顶点及中点编辑、距离和面积 | MouseTool、PolylineEditor、PolygonEditor、MapUtils |
| 定位 | 单次、连续、定位质量控制、地址补充 | SukhaLocationClient |
| 搜索 | 关键词、周边、ID、输入联想、正逆地理编码 | PoiSearch、Inputtips、GeocodeSearch |
| 路线 | 驾车、步行、距离/时间/几何及步骤 | RouteSearch |
| 导航 | 驾车控制器、模拟导航、步行控制器、完整服务多语言录音 | NavigationClient、WalkingNavi |
| 完整界面 | 自带地图、搜索、路线与导航 UI | SukhaMapFragment |
| 可选业务组件 | 配送定位及配送导航界面 | maps-delivery;基础地图无需依赖 |
地图与路线的覆盖范围取决于授权数据集及已发布数据。存在方法不代表任意地点都有对应数据。骑行、完整省市区门牌地址、行政区划边界不在本次范围;公交、货车、实时交通等也不作为已支持能力交付。
1.2 SDK 模块与版本
Maven 坐标前缀 cn.sukha.maps: |
固定版本 | 内容 |
|---|---|---|
| maps-core | 0.1.0-alpha.23 | 基础地图、覆盖物与工具 |
| maps-services | 0.1.0-alpha.19 | 授权会话、搜索、地理编码、路线 |
| maps-location | 0.1.0-alpha.21 | 定位 |
| maps-navigation | 0.1.0-alpha.32 | 导航模型、引擎、录音资源 |
| maps-navigation-services | 0.1.0-alpha.36 | 在线导航服务及控制器 |
| maps-ui | 0.1.0-alpha.79 | 完整地图界面 |
| maps-delivery | 0.1.0-alpha.30 | 可选配送组件 |
SDK 安装包由平台提供,需与本次文档的 API 基线匹配。解压保留 Maven 仓库、POM 和 AAR,通过本地 Maven 解析依赖,不要只取单个 AAR。历史包即使 Maven 版本号相同,也可能缺少后续接口,详见版本与交付。
2. 入门指南
2.1 环境准备与获取 Key
工程基线为 JDK 17、Gradle 8.7、Android Gradle Plugin 8.5.2、compileSdk 34、minSdk 23;源码使用 Java 11,开启 desugaring。客户工程可使用经自行验证的其他兼容版本。
申请Sukha Android Key 时提供:应用 applicationId、实际 APK 签名证书 SHA1、授权数据集及地图/搜索/路线/导航能力。调试证书和正式证书分别登记。高德 Key 不可用于Sukha服务。
2.2 配置工程
将解压出的 maven 放到客户工程根目录的 vendor/sukha/maven。
// settings.gradle
dependencyResolutionManagement {
repositories {
maven { url = uri("$rootDir/vendor/sukha/maven") }
google()
mavenCentral()
}
}
// app/build.gradle
android {
compileSdk 34
defaultConfig { minSdk 23 }
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
coreLibraryDesugaringEnabled true
}
}
dependencies {
implementation 'cn.sukha.maps:maps-core:0.1.0-alpha.23'
implementation 'cn.sukha.maps:maps-services:0.1.0-alpha.19'
implementation 'cn.sukha.maps:maps-location:0.1.0-alpha.21'
// 自定义导航时引入
implementation 'cn.sukha.maps:maps-navigation-services:0.1.0-alpha.36'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
}
若采用完整地图界面,选择 maps-ui:0.1.0-alpha.79,由 POM 引入其依赖。不要混用不同批次模块。第三方 AndroidX、MapLibre 等依赖仍由 Google/Maven Central 获取。
2.3 配置 Manifest
<!-- manifest 节点下 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 使用定位才需要以下权限;还需宿主进行运行时申请 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- application 节点内,替换成自己的授权信息 -->
<meta-data android:name="cn.sukha.maps.API_KEY" android:value="YOUR_ANDROID_KEY" />
<meta-data android:name="cn.sukha.maps.SERVICE_URL" android:value="https://map.sukha.cn" />
<meta-data android:name="cn.sukha.maps.DATASET_ID" android:value="YOUR_DATASET_ID" />
示例经纬度位于演示数据范围;YOUR_DATASET_ID 由提供方分配,不能用示例坐标推断覆盖全国或全球。
2.4 显示第一张地图
下面是 Activity 的最小结构,在宿主完成所需的授权流程后进入此页。它不主动申请或启动定位。
package example;
import android.app.Activity;
import android.os.Bundle;
import cn.sukha.mapsdk.maps.MapView;
import cn.sukha.mapsdk.maps.CameraUpdateFactory;
import cn.sukha.mapsdk.maps.model.LatLng;
import cn.sukha.mapsdk.services.core.MapsInitializer;
public class QuickStartActivity extends Activity {
private MapView mapView;
@Override public void onCreate(Bundle state) {
super.onCreate(state);
MapsInitializer.initialize(this);
mapView = new MapView(this);
setContentView(mapView);
mapView.onCreate(state);
mapView.getMapAsync(map -> map.moveCamera(
CameraUpdateFactory.newLatLngZoom(
new LatLng(21.67623, 100.02228), 16)));
}
@Override protected void onStart() { super.onStart(); mapView.onStart(); }
@Override protected void onResume() { super.onResume(); mapView.onResume(); }
@Override protected void onPause() { mapView.onPause(); super.onPause(); }
@Override protected void onStop() { mapView.onStop(); super.onStop(); }
@Override protected void onSaveInstanceState(Bundle out) {
super.onSaveInstanceState(out); mapView.onSaveInstanceState(out);
}
@Override public void onLowMemory() { super.onLowMemory(); mapView.onLowMemory(); }
@Override protected void onDestroy() { mapView.onDestroy(); super.onDestroy(); }
}
宿主还需在 Manifest 声明此 Activity。getMapAsync 表示地图控制对象可用,不保证所有网络数据已加载。通过 MapView.setOnMapLoadListener 的 onMapLoadError(SdkException) 接收数据加载失败。
2.5 示例约定
后续示例为方法体片段,context 为 Activity/Context,map 是 getMapAsync 得到的 SukhaMap,report(value) 表示宿主更新界面或记录日志。示例并非全部顺序执行。常用 imports:
import cn.sukha.mapsdk.maps.*;
import cn.sukha.mapsdk.maps.model.*;
import cn.sukha.mapsdk.services.core.*;
import cn.sukha.mapsdk.services.poisearch.*;
import cn.sukha.mapsdk.services.inputtips.*;
import cn.sukha.mapsdk.services.geocoder.*;
import cn.sukha.mapsdk.services.route.*;
import cn.sukha.mapsdk.location.SukhaLocationClient;
import cn.sukha.mapsdk.location.SukhaLocationClientOption;
3. 基础概念与坐标
| 数据 | 顺序 / 单位 | 约定 |
|---|---|---|
| LatLng / LatLonPoint / SukhaLatLng | 纬度、经度;度 | 默认 WGS84 |
| Android Location | 原始 WGS84 | 即便地图使用 GCJ02,也不预先偏移传感器位置 |
| 路线距离 / 定位 accuracy | 米 | accuracy 越小,水平不确定性通常越小 |
| 路线 time / duration | 秒 | 不要当毫秒 |
| 定位时间戳、间隔、超时、动画时长 | 毫秒 | 时间戳使用实际采样时间 |
| 屏幕坐标、控件边距 | 物理像素 | dp 由宿主换算 |
| Android 颜色 | ARGB int | 例如 0xff1268e5 |
默认使用 WGS84,缅甸数据建议保留此模式。迁移 GCJ02 业务可在创建任何地图/服务前选择模式:
MapsInitializer.initialize(context, "https://map.sukha.cn", "YOUR_DATASET_ID",
"zh-CN", CoordinateMode.System.GCJ02);
此时地图、搜索及路线公开坐标使用 GCJ02;后台仍使用 WGS84。不要再次手动偏移返回值。模式不允许在已创建地图上切换,保存状态也不能跨模式恢复。独立实例使用 AndroidSdkClient.create(context, base, dataset, language, coordinateSystem),在 MapView.onCreate 前 setServiceClient(client),搜索服务共享同一 client。
转换支持算法区间为经度 73.66–135.05、纬度 3.86–53.55,区间外报错;它不是行政边界数据。手工 GeoJSON、覆盖物、聚合点应已属于选定公开坐标系。第三方栅格瓦片不会自动重投影。原始定位回调保持 WGS84;NavigationClient.toNavigationPosition(fix) 可转换为导航公开坐标。
4. 创建地图与主题
| 接口 | 用途 | 注意事项 |
|---|---|---|
MapView(context) |
基础地图容器 | 宿主负责生命周期 |
getMapAsync(callback) |
获取 SukhaMap | 获取后再操作地图 |
getCameraPosition() |
相机状态 | target、zoom、tilt、bearing |
getBounds() |
当前可视包围范围 | 不是精确可视四边形 |
getProjection().toScreenLocation(point) |
经纬度转屏幕像素 | 相对地图控件 |
getProjection().fromScreenLocation(pixel) |
屏幕转经纬度 | 整数像素有舍入误差 |
setTheme(MapTheme.DAY/NIGHT/AUTO) |
白天、夜间、跟随宿主 | AUTO 根据宿主实际 Android 主题,不读取时间或地理位置;固定浅色宿主保持白天 |
完整 UI 是另一种入口,需要 AndroidX Fragment 宿主:
cn.sukha.mapsdk.api.SukhaMapConfig config =
new cn.sukha.mapsdk.api.SukhaMapConfig.Builder(context)
.serverBaseUrl("https://map.sukha.cn")
.language("en-US").voiceLanguage("zh-CN")
.build();
// 使用 SukhaMapFragment.newInstance(config) 后提交到宿主 Fragment 容器。
基础 MapView 用于自定义页面;完整 Fragment 自带地图交互和导航界面,不需要再叠加另一套 SDK 地图容器。
5. 与地图交互
5.1 相机、缩放与范围适配
map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(21.67623, 100.02228), 17));
map.animateCamera(CameraUpdateFactory.zoomTo(18), 300, null);
LatLngBounds bounds = LatLngBounds.builder()
.include(new LatLng(21.67623, 100.02228))
.include(new LatLng(21.68, 100.03)).build();
map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 24, 80, 24, 220));
四边距顺序为左、上、右、下。适配范围前确保控件已布局且可用宽高大于边距总和。动画时长 1–60000 毫秒,回调为 SukhaMap.CancelableCallback 或 null;stopAnimation() 取消动画。
5.2 控件与手势
UiSettings ui = map.getUiSettings();
ui.setCompassEnabled(true);
ui.setZoomControlsEnabled(true);
ui.setScaleControlsEnabled(true);
ui.setMyLocationButtonEnabled(true);
ui.setRotateGesturesEnabled(true);
ui.setTiltGesturesEnabled(false);
setAllGesturesEnabled 控制全部手势,setScrollGesturesEnabled、setZoomGesturesEnabled 可分别控制。显示定位按钮不等于已获得定位权限或真实位置。
5.3 地图与覆盖物事件
map.setOnMapClickListener(point -> report(point));
map.setOnMarkerClickListener(marker -> { report(marker.getId()); return true; });
map.setOnInfoWindowClickListener(marker -> report(marker.getId()));
map.setOnCameraChangeListener(new SukhaMap.OnCameraChangeListener() {
public void onCameraChange(CameraPosition p) { report(p.target); }
public void onCameraChangeFinish(CameraPosition p) { report(p.zoom); }
});
map.setOnMapTouchListener(event -> report(event.getActionMasked()));
同种 setter 会替换旧监听,传 null 解绑。Marker 点击返回 true 表示业务已处理。MotionEvent 仅在回调内使用,回调后回收。触摸监听是观察接口,不用于拦截手势。另有地图长按、Marker 拖拽与截图等接口,详见接口索引。
6. 在地图上绘制
6.1 点标记与信息窗
Marker marker = map.addMarker(new MarkerOptions()
.position(new LatLng(21.67623, 100.02228)).title("门店").rotateAngle(0));
marker.setPosition(new LatLng(21.677, 100.023));
marker.setRotateAngle(90);
marker.showInfoWindow();
// marker.setVisible(false); marker.remove();
position 必填;旋转角按顺时针屏幕角度归一化至 0–360。setInfoWindowAdapter 支持自定义信息窗 View。图片通过 BitmapDescriptorFactory.fromBitmap(bitmap) 或 fromResource(context, resourceId) 转成图标后交给 MarkerOptions.icon / Marker.setIcon。矢量资源先绘制为 Bitmap;避免每次定位都重新构建图标。
6.2 折线、面与圆
LatLng a = new LatLng(21.67623, 100.02228);
LatLng b = new LatLng(21.678, 100.024);
LatLng c = new LatLng(21.680, 100.022);
Polyline line = map.addPolyline(new PolylineOptions().add(a, b, c)
.color(0xff1268e5).width(5));
Polygon polygon = map.addPolygon(new PolygonOptions().add(a, b, c)
.fillColor(0x221268e5).strokeColor(0xff1268e5));
Circle circle = map.addCircle(new CircleOptions().center(a).radius(100)
.fillColor(0x221268e5).strokeColor(0xff1268e5));
折线至少 2 点,面至少 3 点;圆半径单位米。更新图形使用对应 setPoints、setCenter、setRadius,删除用 remove()。已删除对象不再复用。
6.3 三点弧线
Arc arc = map.addArc(new ArcOptions()
.point(new LatLng(21.676, 100.020), new LatLng(21.679, 100.022),
new LatLng(21.676, 100.024))
.strokeColor(0xff1268e5).strokeWidth(5));
// arc.remove();
三点依次为起点、经过点、终点;三点应能定义有效弧线。底层通过几何采样显示,不承诺与其他厂商的曲线插值完全一致。
6.4 热力图
HeatmapTileProvider heat = new HeatmapTileProvider.Builder()
.data(java.util.Arrays.asList(new LatLng(21.676, 100.022),
new LatLng(21.677, 100.023)))
.radius(20).opacity(0.6).build();
TileOverlay heatLayer = map.addTileOverlay(new TileOverlayOptions().tileProvider(heat));
// 更新 heat.setData(newPoints) 后调用 heatLayer.clearTileCache()。
// heatLayer.remove();
| 参数 | 默认 / 范围 | 说明 |
|---|---|---|
| data / weightedData | 必填其中之一 | 点集合 / WeightedLatLng 权重点集合 |
| radius | 20;10–50 像素 | 热力核显示半径 |
| opacity | 0.6;0–1 | 透明度 |
| gradient | SDK 默认渐变 | Gradient 颜色及分段位置 |
6.5 点聚合
java.util.List<ClusterItem> items = new java.util.ArrayList<>();
items.add(() -> new LatLng(21.676, 100.022));
items.add(() -> new LatLng(21.6761, 100.0221));
ClusterOverlay clusters = new ClusterOverlay(map, items, 60, context);
clusters.setMaxZoom(20);
clusters.setOnClusterClickListener((marker, members) -> report(members.size()));
// clusters.setData(updatedItems); clusters.onDestroy();
clusterRadius 是屏幕网格边长,1–1024 物理像素,不是点间严格距离半径。输入最多 20000 项;setMaxZoom 范围 0–24,默认 20,达到后逐点显示。setClusterRenderer 返回自定义 Drawable。大规模数据仍需目标机性能测试,不保证任意机型固定帧率。
6.6 绘制与编辑
MouseTool tool = new MouseTool(map);
tool.setOnDrawListener(overlay -> report(overlay));
tool.polyline(new PolylineOptions().color(0xff1268e5).width(5));
// 用户逐点点击;宿主的完成按钮调用 tool.finish(),撤销调用 tool.undo()。
PolylineEditor editor = new PolylineEditor(map, line);
editor.open();
// editor.addMidpoint(0); editor.close(); editor.destroy();
MouseTool 支持 marker、polyline、polygon、circle、rectangle。Android 线/面显式 finish();圆与矩形两次点选完成。线面编辑支持顶点拖动和边中点插入;面包含闭合边。close(false) 保留已完成图形,close(true) 同时删除工具创建的图形;工具 destroy 不等于删除目标图形。map.clear() 会释放地图上的工具。
7. 定位
7.1 单次定位
调用前由宿主完成实际的定位权限与隐私授权。userHasConsented 是宿主保存的真实结果。
SukhaLocationClient location = new SukhaLocationClient(context);
location.setPrivacyConsent(userHasConsented);
location.setLocationOption(new SukhaLocationClientOption()
.setOnceLocation(true).setLocationTimeout(15000));
location.setLocationListener(fix -> {
if (fix.getErrorCode() != 0) { report(fix.getError()); return; }
report(fix.getLatitude()); report(fix.getLongitude());
});
location.startLocation();
单次结果后自动停止采集,实例仍应在结束使用后 onDestroy()。成功错误码是 0;它不同于搜索服务的成功码 1000。不要使用失败对象中的无效坐标。
7.2 连续定位与参数
location.stopLocation();
location.setLocationOption(new SukhaLocationClientOption()
.setOnceLocation(false).setInterval(2000)
.setLocationMode(SukhaLocationClientOption.SukhaLocationMode.Hight_Accuracy)
.setNeedAddress(false));
location.startLocation();
| 配置方法 | 默认 | 有效值与含义 |
|---|---|---|
| setOnceLocation | false | true 单次,false 连续 |
| setInterval | 2000 | 1000–3600000 毫秒,期望间隔 |
| setLocationTimeout / setHttpTimeOut | 15000 | 1000–120000 毫秒 |
| setLocationMode | Hight_Accuracy | Hight_Accuracy、Battery_Saving、Device_Sensors;拼写按真实枚举 |
| setMaximumAccuracy | 正无穷 | 大于 0 的米数;默认保留基础质量过滤 |
| setOnceLocationLatest | false | 有限观察窗口内选择较优位置 |
| setBestLocationTimeout | 3000 | 1000–10000 毫秒 |
| setLocationCacheEnable | false | 是否复用有效缓存 |
| setLastLocationLifeCycle | 10000 | 缓存寿命 0–60000 毫秒 |
| setNeedAddress | false | 异步补充地址,独立地址监听接收 |
| setSensorAssistEnabled | false | 可选方向辅助 |
setAddressListener 接收后续地址结果;首次坐标不应等待地址。地址字段缺失时显示业务占位语,不拼接假省市区。方向或速度必须检查 hasBearing() / hasSpeed();缺失方向不是朝北。
7.3 显示定位蓝点
map.setMyLocationStyle(new MyLocationStyle()
.myLocationType(MyLocationStyle.LOCATION_TYPE_SHOW)
.dotColor(0xff1268e5).radiusFillColor(0x221268e5));
map.setMyLocationEnabled(true);
// 成功定位回调内:fix 为真实 SukhaLocation
android.location.Location raw = new android.location.Location("sdk");
raw.setLatitude(fix.getLatitude()); raw.setLongitude(fix.getLongitude());
raw.setAccuracy(fix.getAccuracy()); raw.setTime(fix.getTime());
map.updateMyLocation(raw);
SHOW 仅显示,LOCATE 首次回中,FOLLOW 持续跟随。输入是原始 WGS84;GCJ02 模式由地图内部转换显示。
7.4 前台服务与释放
SukhaLocationClient 自身不是前台服务,也没有可照搬的高德 enableBackgroundLocation 方法。后台持续场景由宿主合法启动并维持 location 类型前台服务,或选用 SDK 的导航/配送前台组件;权限、通知和启动时机需按目标 Android 版本处理。系统停止进程后不能保证持续定位。
停止采集调用 stopLocation();最终释放调用 onDestroy()。页面关闭是否结束持续定位由业务会话拥有者决定,不应销毁仍在服务中使用的对象。
8. 搜索与地址
8.1 POI 关键词、周边与详情
PoiSearch.Query query = new PoiSearch.Query("酒店", "", "");
query.setPageNum(1); query.setPageSize(20);
PoiSearch search = new PoiSearch(context, query);
search.setOnPoiSearchListener(new PoiSearch.OnPoiSearchListener() {
public void onPoiSearched(PoiResult result, int code) {
if (code == SdkException.SUCCESS) report(result.getPois());
else report(search.getLastError());
}
public void onPoiItemSearched(PoiItem item, int code) { report(item); }
});
search.searchPOIAsyn();
// 周边查询:先 setBound,再发起查询。
// search.setBound(new PoiSearch.SearchBound(new LatLonPoint(21.67623,100.02228),1000));
// 已获取Sukha POI ID 后:search.searchPOIIdAsyn(id);
| 参数 | 约束 | 说明 |
|---|---|---|
| keyword | 字符串 | 关键词 |
| type | 字符串,可空 | Sukha数据类别,不保证与高德分类码一致 |
| city | 空字符串或 null | 当前不提供行政城市筛选 |
| pageNum | 1–5,默认 1 | 页号 |
| pageSize | 1–50,默认 20 | 页大小 |
| SearchBound.range | 0–5000 米 | 周边范围 |
| ID | Sukha ID | 不接受高德 POI ID |
同一服务实例的新请求会取消旧请求。需要并行独立查询时分别创建服务对象,共享 SdkClient 即可。
8.2 输入联想
Inputtips tips = new Inputtips(context, new InputtipsQuery("酒店", "").setLimit(10));
tips.setInputtipsListener((items, code) -> {
if (code == SdkException.SUCCESS) report(items); else report(tips.getLastError());
});
tips.requestInputtipsAsyn();
关键词去空白后不能为空,最多 200 字符;limit 为 1–50。下拉 UI 由宿主绘制。监听回调后不要持有已退出 Activity;退出时 destroy。
8.3 正地理编码与逆地理编码
GeocodeSearch geocoder = new GeocodeSearch(context);
geocoder.setOnGeocodeSearchListener(new GeocodeSearch.OnGeocodeSearchListener() {
public void onRegeocodeSearched(RegeocodeResult result, int code) {
if (code == SdkException.SUCCESS) report(result.getRegeocodeAddress());
else report(geocoder.getLastError());
}
public void onGeocodeSearched(GeocodeResult result, int code) {
if (code == SdkException.SUCCESS) report(result.getGeocodeAddressList());
}
});
geocoder.getFromLocationNameAsyn(new GeocodeQuery("门店名称", ""));
// 独立执行下面逆查询;不要与上面的正查询同时在同一个对象上执行。
RegeocodeQuery rq = new RegeocodeQuery(new LatLonPoint(21.67623,100.02228),
1000, GeocodeSearch.GPS);
rq.setExtensions("all");
// geocoder.getFromLocationAsyn(rq);
正查询匹配已发布地点/建筑名称,不是完整国内地址解析。逆查询 radius 为 0–3000 米;extensions 为 base/all,默认 base。latLonType 当前只接受 GPS,不能传 AMAP 常量;坐标模式仍由 client 配置。逆查询包含 formattedAddress、匹配信息、POI 和道路,完整省市区门牌不作保证。
同步 getFromLocationName / getFromLocation 只能在工作线程调用。界面优先使用异步接口。
9. 出行路线规划
9.1 驾车与步行
RouteSearch routes = new RouteSearch(context);
routes.setRouteSearchListener(new RouteSearch.OnRouteSearchListener() {
public void onDriveRouteSearched(DriveRouteResult result, int code) {
if (code == SdkException.SUCCESS) report(result.getPaths());
else report(routes.getLastError());
}
public void onWalkRouteSearched(WalkRouteResult result, int code) {
if (code == SdkException.SUCCESS) report(result.getPaths());
else report(routes.getLastError());
}
});
RouteSearch.FromAndTo endpoints = new RouteSearch.FromAndTo(
new LatLonPoint(21.67623,100.02228), new LatLonPoint(21.68,100.03));
routes.calculateDriveRouteAsyn(new RouteSearch.DriveRouteQuery(
endpoints, RouteSearch.DRIVING_TIME));
// 步行另行调用:routes.calculateWalkRouteAsyn(new RouteSearch.WalkRouteQuery(endpoints));
| 查询参数 | 值 | 说明 |
|---|---|---|
| 驾车策略 | DRIVING_TIME=0、DRIVING_DISTANCE=1 | 时间优先、距离优先;不能透传其他高德枚举 |
| passedByPoints | 最多 16 点 | 驾车途经点 |
| avoidpolygons | 最多 32 个,每个 3–16 点 | 驾车避让区域 |
| avoidRoad | 最多 200 字符 | 避让道路名称;指定时优先于区域 |
| 步行策略 | WALK_DEFAULT=0 | 当前步行默认策略 |
高级驾车参数使用五参数 DriveRouteQuery(endpoints, mode, passedByPoints, avoidpolygons, avoidRoad)。服务端必须支持相应规划能力;本次 SDK 发布没有自动升级所有客户后台。若服务返回不支持,不能静默退化为忽略约束。
9.2 结果模型
DriveRouteResult.getPaths() / WalkRouteResult.getPaths() 返回路径;路径提供距离、耗时、polyline、steps。步骤包含道路名称、分段几何、距离及服务返回的指令/动作/耗时等。缺少可选字段时不得拼造导航指令。路线预览不能直接视为真实导航会话;导航应使用下一章控制器。
10. 导航
内置导航页与 Sukha 自有地图共用导航布局、转向图标和版权组件。通过当前 Activity 调用 SukhaNaviPage.createIntent(...) 或 showRouteActivity(...),页面跟随宿主实际主题:未适配夜间的宿主保持浅色,适配 DayNight 的宿主按其当前设置显示;不按时间或 GPS 切换。已移除内置导航参数中的独立 theme(...) 设置。嵌入式地图仍支持 DAY / NIGHT / AUTO。
导航地图左下角保留版权并避让底部卡片:中文 © 苏哈出行、英文 © Sukha Go、缅文 © သုခ,跟随界面语言,在横竖屏及深浅主题下均显示。
10.1 驾车控制器调用顺序
类:cn.sukha.mapsdk.navi.services.NavigationClient。
- 创建客户端,设置
NavigationClient.Listener,调用initialize()。 - 收到
onReady(datasetVersion)后,调用startLocation(),等待有效位置。 - 调用
calculateDriveRoute(destination),或显式传起终点;等待onCalculateRouteSuccess。 - 宿主开始按钮调用
startNavi();onNaviInfoUpdate更新自定义导航界面。 - 结束时
stopNavi(),会话销毁时close()/onDestroy()。
| 方法 / 回调 | 参数或结果 | 说明 |
|---|---|---|
| calculateDriveRoute(start, destination, heading) | SukhaLatLng、可空 Float | 公开坐标模式;heading 为方向角 |
| calculateDriveRoute(destination) | SukhaLatLng | 使用最近有效定位 |
| startNavi() | 无 | 真导航需要 10 秒内、accuracy ≤50 米的位置 |
| startNavi(mode) | GPSNaviMode / EmulatorNaviMode | 模拟仅用于开发验证 |
| setEmulatorNaviSpeed(kph) | 1–120 | 停止导航后配置 |
| setVoiceEnabled(enabled) | boolean | 控制导航录音播放 |
| onCalculateRouteFailure(message) | String | 算路失败 |
| onError(code, message) | String、String | 初始化/定位等错误 |
| onArriveDestination(side) | 目的地侧向信息 | 到达事件 |
不要在开始导航时用常量坐标、过期位置或虚构精度绕过质量检查。NavigationClient 管理连续定位和导航,不自动等同于一个可长期后台运行的 Activity;后台使用前台导航服务或完整导航页的对应接入方式。
10.2 步行导航
类:cn.sukha.mapsdk.navi.services.WalkingNavi,构造 WalkingNavi(context, client)。设置 Listener 后依次 calculateWalkRoute(start,end) → 成功回调 → startNavi()。宿主在有效定位回调里调用 updateLocation(android.location.Location),传原始 WGS84。结束 stopNavi(),最终 close()。步行不提供骑行行为替代。
10.3 多语言与语音
Android 服务初始化可传 zh-CN、en-US、my-MM;完整 SukhaMapConfig.Builder.language 控制显示语言,voiceLanguage 控制完整导航流程的语音语言。宿主应显式匹配系统或用户选择,不假设所有入口都自动读取系统语言。
当前 Android 完整导航流程已具备中文、英文和缅文预录音资源及对应语言入口。NavigationForegroundService 可设置显示与语音语言;低层 NavigationClient 没有同名语言配置方法,不能混用入口。资源随对应构建交付,不将旧 AAR 的版本号视为语音更新证明。动态地名是否有译名取决于后台数据。原始 instruction 可能为中文,完整 SDK UI 使用显示翻译;自定义 UI 可用 cn.sukha.mapsdk.i18n.SdkLanguage.instruction(language, raw)。
11. 地图计算与工具
double meters = MapUtils.calculateLineDistance(
new LatLng(21.67623,100.02228), new LatLng(21.68,100.03));
结果为球面直线距离,单位米,不是沿路距离。面积和坐标转换使用 SDK 工具,勿将这些近似计算用于测绘级承诺。经纬度转像素用 Projection;WGS84/GCJ02 转换使用 CoordinateConverter 或初始化坐标模式,二者不要重复执行。
12. 错误码、线程与资源管理
12.1 服务错误码
| 数字码 | 名称 | 处理建议 |
|---|---|---|
| 1000 | SUCCESS | 服务调用成功;仍检查是否有结果 |
| 2001 | NETWORK_ERROR | 检查网络;有界重试 |
| 2002 | AUTH_ERROR | 核对 Key、包名、签名、数据集、能力 |
| 2003 | INVALID_ARGUMENT | 修正参数,勿无限重试 |
| 2004 | NO_ROUTE | 换起终点或提示暂无路线 |
| 2005 | SERVER_ERROR | 记录 requestId 联系服务方 |
| 2006 | CANCELLED | 已取消;通常不提示故障 |
getLastError() 提供 SdkException,可读取 getCode()、getRequestId()、getHttpStatus()、getRetryAfterMillis()。httpStatus=0 表示无 HTTP 响应,retryAfterMillis=-1 表示未取得有效 Retry-After。参数校验也可能同步抛 IllegalArgumentException,不能只依赖异步回调。
SdkLogger.setErrorLogger((source, code, requestId) ->
android.util.Log.w("MapSDK", source + " / " + code + " / " + requestId));
// 宿主日志代理不再需要时:SdkLogger.setErrorLogger(null);
12.2 定位错误码
| 原始码 | 统一代码 | 含义 |
|---|---|---|
| 0 | 成功 | 可使用位置 |
| 1 | PERMISSION_DENIED | 缺定位权限 |
| 2 | PROVIDER_DISABLED | 系统定位关闭 |
| 3 | TIMEOUT | 定位超时 |
| 4 | SOURCE_FAILURE | 位置源失败 |
| 5 | STOPPED | 定位已停止 |
| 6 | PRIVACY_DENIED | 未同意或已撤销授权 |
| 7 | ACCURACY_INSUFFICIENT | 无位置达到设定精度 |
定位错误通过 SukhaLocation.getError() 取得结构化信息,与搜索的 1000/200x 码分开处理。
12.3 线程与生命周期
地图、覆盖物、定位及导航控制器在主线程操作;异步服务回调也不要执行阻塞工作。同步网络方法只能在工作线程调用。共享 client 的销毁顺序:先停止定位/导航 → 销毁工具及服务 → MapView.onDestroy → 最后由拥有者 client.close。使用 MapsInitializer 的进程级默认会话时,只有全部使用者退出后才调用 MapsInitializer.destroy。
搜索对象可 cancel() 取消请求并继续复用;destroy() 后不可再调用。map.clear() 只清理地图相关对象,不能代替停止独立定位和搜索。Activity 重建后要重新绑定监听器。
13. API 分类索引
| 分类 | 包路径 | 主要类 |
|---|---|---|
| 地图与交互 | cn.sukha.mapsdk.maps | MapView、SukhaMap、CameraUpdateFactory、UiSettings、Projection |
| 覆盖物 | cn.sukha.mapsdk.maps | Marker、Polyline、Polygon、Circle、Arc、TileOverlay |
| 参数与几何 | cn.sukha.mapsdk.maps.model | LatLng、LatLngBounds、CameraPosition、各 Options、BitmapDescriptorFactory |
| 热力与聚合 | maps.model / maps | HeatmapTileProvider、WeightedLatLng、Gradient、ClusterOverlay、ClusterItem |
| 编辑 | cn.sukha.mapsdk.maps | MouseTool、PathEditor、PolylineEditor、PolygonEditor |
| 定位 | cn.sukha.mapsdk.location | SukhaLocationClient、SukhaLocationClientOption、SukhaLocation、LocationError |
| 授权与诊断 | cn.sukha.mapsdk.services.core | MapsInitializer、AndroidSdkClient、SdkClient、SdkException、SdkLogger |
| 搜索联想 | services.poisearch / services.inputtips | PoiSearch、PoiResult、PoiItem、Inputtips、InputtipsQuery、Tip |
| 地理编码 | cn.sukha.mapsdk.services.geocoder | GeocodeSearch、GeocodeQuery、RegeocodeQuery、结果与地址模型 |
| 路线 | cn.sukha.mapsdk.services.route | RouteSearch、DriveRouteResult、WalkRouteResult、Path/Step 模型 |
| 导航服务 | cn.sukha.mapsdk.navi.services | NavigationClient、WalkingNavi、NavigationForegroundService |
| 完整地图配置 | cn.sukha.mapsdk.api | SukhaMapConfig |
| 完整地图 Fragment | cn.sukha.mapsdk | SukhaMapFragment |
详细公开声明见随本文交付的 Android API 声明索引,最终签名以固定版本 AAR 的公开接口为准。索引按公开声明提取,不交付 internal、测试实现或 SDK 核心源码。
14. 从高德迁移与常见问题
| 常见迁移点 | 本 SDK 对应规则 |
|---|---|
| AMap 控制对象 | 使用 SukhaMap,包名 cn.sukha.mapsdk.* |
| Key | 使用Sukha Android Key,不能复用高德 Key |
| 默认坐标 | WGS84;GCJ02 必须明确配置 |
| 高德策略整数 | 只映射本文支持的策略,不直接透传 |
| 国内城市/区划码 | 不作为搜索过滤和完整地址能力提供 |
| 位置成功码 | 定位 0;搜索/路线 1000 |
| 高德示例点聚合 | 使用 ClusterOverlay;分组结果不承诺相同 |
| 导航与预览 | RouteSearch 预览与 NavigationClient 会话分开 |
地图白屏:检查 Key/签名、数据集、网络、加载错误回调、控件尺寸和生命周期。地图点偏移:先查经纬度顺序及是否重复坐标转换。定位精度不足:检查真实 accuracy、系统精确定位权限、环境及业务阈值;不要把低质量结果改写为高精度。路线无结果:确认覆盖范围及后台规划能力。连续搜索丢旧结果:同实例主动取消旧请求是既定行为。
15. 版本说明与参考来源
本次以 2026-10-08 当前源码重新编译的 SDK 核对 API 和 Java 示例。后台地图与路由数据分别发布。取得历史包时请先核对接口,不能仅凭 Maven 版本号判断内容相同。详见版本与交付。
栏目结构参考高德 Android SDK 指南,本文接口与示例根据本项目编写。