Applications may encounter issues where the native Geocoder class fails to resolve latitude and longitude coordinates into address information on Android 8.0 and later versions. When this occurs, a viable alternative is to leverage the Baidu Maps Web Service API for reverse geocoding.
To use the Baidu Maps API, you first need a developer account to obtain an API Key (AK). The process for obtaining an AK is straightforward and can be done through the Baidu Developer Platform.
The URL for the reverse geocoding request is as follows:
String baiduApiUrl = String.format(
"http://api.map.baidu.com/geocoder/v2/?ak=%s&location=%s,%s&output=json&pois=1&coordtype=wgs84ll&mcode=%s",
baiduApiKey,
latitude,
longitude,
securitySignature
);
In this URL:
ak: Your unique Baidu API Key.location: A string containing the latitude and longitude, separated by a comma.output: Specifies the desired response format, typicallyjson.pois: A flag to indicate whether to include Point of Interest (POI) data.1enables POI retrieval,0disables it.coordtype: Defines the coordinate system of the provided latitude and longitude.wgs84llis used for standard GPS coordinates.mcode: The security signature associated with your application, essential for secure API access.
Detailed information regarding request parameters and their meanings can be found in the official Baidu Maps API documentation. Key parameters include:
location: (Required) The latitude and longitude for the reverse geocoding query.coordtype: (Optional) Specifies the coordinate system (e.g.,bd09ll,gcj02ll,wgs84ll). Defaults to Baidu's internal coordinate system.pois: (Optional) Controls the inclusion of nearby POI data.1for inclusion,0for exclusion.radius: (Optional) The search radius in meters for POIs, ranging from 0 to 1000.ak: (Required) Your Baidu API Key.sn: (Required if SN verification is enabled for your AK) The security signature for the request.output: (Optional) The format of the response (jsonorxml). Defaults toxml.extensions_road: (Optional) Set totrueto retrieve nearby road information.extensions_town: (Optional) Set totrueto include township-level administrative data.language: (Optional) Specifies the language for administrative division names.
Up on a successful request, the API returns a JSON object containing detailed address components, location information, business districts, and nearby POIs. The status field indicates the succes or failure of the request (0 for success).
When dealing with different coordinate systems, such as converting between WGS84 (GPS), GCJ-02 (China's national standard), and BD-09 (Baidu's standard), a coordinate transformation utility class can be implemanted.
public class CoordinateConverter {
private static final double PI = Math.PI;
private static final double EARTH_A = 6378245.0;
private static final double EARTH_EE = 0.00669342162296594323;
private static final double X_PI = PI * 3000.0 / 180.0;
/**
* Converts WGS-84 coordinates to Baidu coordinates.
* @param latitude The WGS-84 latitude.
* @param longitude The WGS-84 longitude.
* @return An array containing Baidu latitude and longitude.
*/
public static double[] wgs84ToBaidu(double latitude, double longitude) {
double[] gcjCoords = wgs84ToGcj02(latitude, longitude);
return gcj02ToBaidu(gcjCoords[0], gcjCoords[1]);
}
/**
* Converts GCJ-02 coordinates to Baidu coordinates.
* @param lat GCJ-02 latitude.
* @param lon GCJ-02 longitude.
* @return An array containing Baidu latitude and longitude.
*/
public static double[] gcj02ToBaidu(double lat, double lon) {
double x = lon, y = lat;
double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * X_PI);
double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * X_PI);
double bdLon = z * Math.cos(theta) + 0.0065;
double bdLat = z * Math.sin(theta) + 0.006;
return new double[] { bdLat, bdLon };
}
/**
* Converts Baidu coordinates to GCJ-02 coordinates.
* @param lat Baidu latitude.
* @param lon Baidu longitude.
* @return An array containing GCJ-02 latitude and longitude.
*/
public static double[] baiduToGcj02(double lat, double lon) {
double x = lon - 0.0065, y = lat - 0.006;
double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * X_PI);
double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * X_PI);
double gcjLon = z * Math.cos(theta);
double gcjLat = z * Math.sin(theta);
return new double[] { gcjLat, gcjLon };
}
/**
* Converts WGS-84 coordinates to GCJ-02 coordinates.
* @param lat WGS-84 latitude.
* @param lon WGS-84 longitude.
* @return An array containing GCJ-02 latitude and longitude.
*/
public static double[] wgs84ToGcj02(double lat, double lon) {
double dLat = transformLat(lon - 105.0, lat - 35.0);
double dLon = transformLon(lon - 105.0, lat - 35.0);
double radLat = lat * PI / 180.0;
double magic = Math.sin(radLat);
magic = 1 - EARTH_EE * magic * magic;
double sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((EARTH_A * (1 - EARTH_EE)) / (magic * sqrtMagic) * PI);
dLon = (dLon * 180.0) / (EARTH_A / sqrtMagic * Math.cos(radLat) * PI);
double mgLat = lat + dLat;
double mgLon = lon + dLon;
return new double[] { mgLat, mgLon };
}
private static double transformLat(double x, double y) {
double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
return ret;
}
private static double transformLon(double x, double y) {
double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
return ret;
}
}