I. Overview:
1.1 Android natively has a positioning API, but the stability and accuracy are far from enough, so it is usually necessary to obtain location information with the help of a third-party SDK
1.2 Domestic SDKs have many choices. Baidu, Tencent, AutoNavi and other positioning apis all need to build applications on the platform and configure keys, including basic positioning.
1.3 The google positioning api and google map are widely used in foreign countries. Google positioning is free, but the map needs a key, including the geocoding webapi interface.
1.4 Let’s not talk about domestic ones, there is basically no restriction, you can use any manufacturer’s SDK, we mainly talk about the solution that does not use domestic SDKs
2. Android native positioning
2.1 Positioning generally adopts network positioning or GPS positioning, and the difference between the two is relatively large
GPS positioning accuracy is high; but it can only be used outdoors, the speed of obtaining positioning information is slow, and consumes battery.
Network positioning can be used indoors and outdoors, with fast positioning speed and low power consumption; but the accuracy is not very high
2.2 Native Positioning Practice
public class AndroidLocationActivity extends Activity {
private static final String TAG = "MainActivity";
private Button btnLocation;
private TextView tvResult;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location);
btnLocation = (Button) findViewById(R.id.btn_location);
tvResult = (TextView) findViewById(R.id.tv_result);
btnLocation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
checkLocationServiceOpen();
}
});
}
//检查定位服务是否开启
private void checkLocationServiceOpen() {
if (isLocServiceEnable(this) && isLocServiceEnable(this, 1)) {
initLocation();
} else {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, LOCATION_SERVICCE);
}
}
/**
* 手机是否开启位置服务,如果没有开启那么所有app将不能使用定位功能
*/
private final static int LOCATION_SERVICCE = 1;// 定位
private final int REQUEST_CHECK_SETTINGS = 2;//google权限设置
public boolean isLocServiceEnable(Context context) {
int locationMode = 0;
String locationProviders;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
return false;
}
return locationMode != Settings.Secure.LOCATION_MODE_OFF;
} else {
locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
return !TextUtils.isEmpty(locationProviders);
}
}
/**
* 手机是否开启位置服务,如果没有开启那么所有app将不能使用定位功能
*/
public boolean isLocServiceEnable(Context context, int type) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (gps || network) {
return true;
}
return false;
}
public void initLocation() {
AndPermission.with(this)
.runtime()
.permission(Permission.Group.LOCATION)
.onGranted(new Action<List<String>>() {
@Override
public void onAction(List<String> permissions) {
Log.e(TAG, "onAction: " + "开始定位");
startLocation();
}
})
.onDenied(new Action<List<String>>() {
@Override
public void onAction(@NonNull List<String> permissions) {
Log.e(TAG, "onAction: " + "定位失败");
startLocation();
// // 判断用户是不是不再显示权限弹窗了,若不再显示的话进入权限设置页
// if (AndPermission.hasAlwaysDeniedPermission(mContext, permissions)) {
// // 打开权限设置页
// AndPermission.permissionSetting(mContext).start();
// return;
// }
}
})
.start();
}
private LocationManager locationManager;
public void startLocation() {
try {
if (locationManager == null) {
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
}
Criteria criteria = new Criteria();
criteria.setAltitudeRequired(true);
String bestProvider = locationManager.getBestProvider(criteria, false);
Log.e(TAG, "最佳的定位方式:" + bestProvider);
//最佳定位方式LocationManager.GPS_PROVIDER LocationManager.NETWORK_PROVIDER
locationManager.requestLocationUpdates(bestProvider, 0, 0, myLocationListener);
} catch (SecurityException e) {
e.printStackTrace();
}
}
private LocationListener myLocationListener = new LocationListener() {
@Override
public void onLocationChanged(final Location location) {
locationManager.removeUpdates(myLocationListener);
setLocationResult(location);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
};
private void setLocationResult(Location location) {
if (location == null) {
tvResult.setText("定位失败");
return;
}
long time = location.getTime();
float accuracy = location.getAccuracy();//获取精确位置
double altitude = location.getAltitude();//获取海拔
double latitude = location.getLatitude();//获取纬度,平行
double longitude = location.getLongitude();//获取经度,垂直
StringBuffer sb = new StringBuffer();
sb.append("time : ");
sb.append(time);
sb.append("\nlatitude : ");
sb.append(latitude);
sb.append("\nlontitude : ");
sb.append(longitude);
Log.e(TAG, "Android定位:\n"+sb.toString() + "\n\n");
tvResult.setText("Android定位:\n"+sb.toString() + "\n\n");
geocoderAddress(location);
}
//获取地址信息:城市、街道等信息
public void geocoderAddress(Location location) {
try {
if (location != null) {
Geocoder gc = new Geocoder(this, Locale.getDefault());
List<Address> result = gc.getFromLocation(location.getLatitude(),
location.getLongitude(), 1);
Log.e(TAG, "获取地址信息:" + result.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == LOCATION_SERVICCE) {//开启定位服务
if (isLocServiceEnable(this) && isLocServiceEnable(this, 1)) {
checkLocationServiceOpen();
}
} else if (requestCode == REQUEST_CHECK_SETTINGS) {
switch (resultCode) {
case Activity.RESULT_OK:
// All required changes were successfully made
Log.e("locationSettingCallback", "RESULT_OK");
startLocation();
break;
case Activity.RESULT_CANCELED:
Log.e("locationSettingCallback", "RESULT_CANCELED");
// The user was asked to change settings, but chose not to
// googleLocationStar();
// checkLocationPermission();
break;
default:
break;
}
}
}
}
Notice:
Use of Geocoder
1. Geocoder This class is used to obtain the forward encoding and reverse encoding of the geographic location. The forward encoding is to obtain the latitude and longitude according to the address; the reverse encoding is to obtain the corresponding detailed address according to the latitude and longitude
2. Geocoder requests a background service, but this service is not included in the standard android framework, so if the current device does not contain location services, the address or latitude and longitude returned by Geocoder is empty. Most mobile phones may not be usable, and those that do not support will flash back, and handle exceptions well
Listening settings
After the setting is successful, you need to cancel the monitoring, otherwise the location will not be updated after downloading and relocating.
locationManager.removeUpdates(myLocationListener);
Three google positioning practice
3.1 There are relatively large restrictions on using Google
- First of all, mobile phones must support Google services, but domestic mobile phones are basically not equipped with Google services by default due to the serious customization of various manufacturers.
- The mobile network needs a VPN, otherwise you can't use foreign services
3.2 Ways to work around limitations
Install the google three-piece set, google service framework, store and google account management program, the method can be searched by yourself. At the same time, install the flipping tool, and search for this by yourself
3.2 Examples
Module-level build.gradle adds location dependencies
implementation 'com.google.android.gms:play-services-location:18.0.0'
Add permission to manifest file
<!-- 位置信息 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
java source code
public class GoogleLocationActivity extends Activity {
private static final String TAG = "MainActivity";
private Button btnLocation;
private TextView tvResult;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location);
btnLocation = (Button) findViewById(R.id.btn_location);
tvResult = (TextView) findViewById(R.id.tv_result);
btnLocation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
checkLocationServiceOpen();
}
});
}
//检查定位服务是否开启
private void checkLocationServiceOpen() {
if (isLocServiceEnable(this) && isLocServiceEnable(this, 1)) {
initLocation();
} else {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, LOCATION_SERVICCE);
}
}
/**
* 手机是否开启位置服务,如果没有开启那么所有app将不能使用定位功能
*/
private final static int LOCATION_SERVICCE = 1;// 定位
private final int REQUEST_CHECK_SETTINGS = 2;//google权限设置
public boolean isLocServiceEnable(Context context) {
int locationMode = 0;
String locationProviders;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
return false;
}
return locationMode != Settings.Secure.LOCATION_MODE_OFF;
} else {
locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
return !TextUtils.isEmpty(locationProviders);
}
}
/**
* 手机是否开启位置服务,如果没有开启那么所有app将不能使用定位功能
*/
public boolean isLocServiceEnable(Context context, int type) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (gps || network) {
return true;
}
return false;
}
public void initLocation() {
AndPermission.with(this)
.runtime()
.permission(Permission.Group.LOCATION)
.onGranted(new Action<List<String>>() {
@Override
public void onAction(List<String> permissions) {
Log.e(TAG, "onAction: " + "开始定位");
initGooglePlayService();
}
})
.onDenied(new Action<List<String>>() {
@Override
public void onAction(@NonNull List<String> permissions) {
Log.e(TAG, "onAction: " + "定位失败");
initGooglePlayService();
// // 判断用户是不是不再显示权限弹窗了,若不再显示的话进入权限设置页
// if (AndPermission.hasAlwaysDeniedPermission(mContext, permissions)) {
// // 打开权限设置页
// AndPermission.permissionSetting(mContext).start();
// return;
// }
}
})
.start();
}
//连接google服务
private void initGooglePlayService() {
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.e(TAG, "onConnected");
initGoogleLocation();
}
@Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "onConnectionSuspended" + "---i");
//startBaiduLocation();
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed---" + connectionResult.getErrorCode() + "---" + connectionResult.getErrorMessage());
//startBaiduLocation();
}
})
.build();
mGoogleApiClient.connect();
}
private LocationRequest locationRequest;
private void initGoogleLocation() {
try {
locationRequest = LocationRequest.create();
// locationRequest.setInterval(20000);
// locationRequest.setFastestInterval(10000);
// locationRequest.setNumUpdates(1);
// locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.e(TAG, "onSuccess");
startLocation();
}
});
task.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.e(TAG, "onFailure");
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(GoogleLocationActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
}
});
} catch (Exception e) {
}
}
private Location lastKnownLocation;
private FusedLocationProviderClient locationProviderClient;
private void startLocation() {
// Construct a FusedLocationProviderClient.
if (locationProviderClient == null) {
locationProviderClient = LocationServices.getFusedLocationProviderClient(this);
}
/*
* Get the best and most recent location of the device, which may be null in rare
* cases when a location is not available.
*/
try {
Task<Location> locationResult = locationProviderClient.getLastLocation();
locationResult.addOnCompleteListener(this, new OnCompleteListener<Location>() {
@Override
public void onComplete(Task<Location> task) {
if (task.isSuccessful()) {
// Set the map's camera position to the current location of the device.
lastKnownLocation = task.getResult();
if(lastKnownLocation!=null){
updateLocation();
}else {
startNewLocation();
}
} else {
Log.d(TAG, "Current location is null. Using defaults.");
Log.e(TAG, "Exception: %s", task.getException());
}
}
});
} catch (SecurityException e) {
Log.e(TAG, e.getMessage());
}
}
//开始google定位
private void startNewLocation() {
if (locationProviderClient == null) {
locationProviderClient = LocationServices.getFusedLocationProviderClient(this);
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
Log.e(TAG, "startGoogleLocation11: " + "开始Google定位");
locationProviderClient.requestLocationUpdates(locationRequest,
locationCallback,
Looper.getMainLooper())
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void unused) {
Log.e(TAG, "onSuccess: ");
}
});
}
//定期接受位置信息
LocationCallback locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
locationProviderClient.removeLocationUpdates(locationCallback);
lastKnownLocation=locationResult.getLastLocation();
updateLocation();
}
@Override
public void onLocationAvailability(@NonNull LocationAvailability locationAvailability) {
super.onLocationAvailability(locationAvailability);
Log.e(TAG, "数量3:"+locationAvailability.isLocationAvailable());
}
};
private void updateLocation(){
if (lastKnownLocation != null) {
StringBuffer sb = new StringBuffer();
sb.append("time : ");
sb.append(lastKnownLocation.getTime());
sb.append("\nlatitude : ");
sb.append(lastKnownLocation.getLatitude());
sb.append("\nlontitude : ");
sb.append(lastKnownLocation.getLongitude());
Log.e(TAG, "google定位:\n"+sb.toString() + "\n\n");
tvResult.setText("google定位:\n"+sb.toString() + "\n\n");
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == LOCATION_SERVICCE) {//开启定位服务
if (isLocServiceEnable(this) && isLocServiceEnable(this, 1)) {
checkLocationServiceOpen();
}
} else if (requestCode == REQUEST_CHECK_SETTINGS) {
switch (resultCode) {
case Activity.RESULT_OK:
// All required changes were successfully made
Log.e("locationSettingCallback", "RESULT_OK");
startLocation();
break;
case Activity.RESULT_CANCELED:
Log.e("locationSettingCallback", "RESULT_CANCELED");
// The user was asked to change settings, but chose not to
// googleLocationStar();
// checkLocationPermission();
break;
default:
break;
}
}
}
}
3.3 Note:
In the process, you can first adjust the native Android -> then adjust the last location of Google -> update the location without the last location to ensure that the location information can be obtained.
3.4 Be sure to request the location permission first, otherwise it will report no permission
3.5 The positioning accuracy can be removed, and if you try to add it, the indoor loading will always fail
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
Four summary
Any one in China can be used, and the original one can be shared with Google abroad. After all, Google has many restrictions. If the positioning requirements are not high, you can use the original one. If you have high requirements, you can only use Google positioning.