当传入参数为非Activity类型时,如果使用FusedLocationProviderClient实例调用定位服务接口发生异常,就不会弹出UI交互界面提示用户处理,只会返回错误码。例如:当HMS Core不符合定位服务的版本要求时,便会返回错误码907135003,此时需要手动升级HMS Core。如果需要拉起升级引导界面,建议传入Activity类型参数替代Context类型,创建FusedLocationProviderClient实例。更多错误码,请参见错误码。
要使用定位服务API,需要确保您的设备已经下载并安装了HMS Core服务组件,并将Location Kit的SDK集成到您的项目中。有关详细信息,请参见开发准备。以下仅为代码片段,详情请参见示例代码。
<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" />
// Android SDK<=28 所需权限动态申请 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) { Log.i(TAG, "android sdk <= 28 Q"); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { String[] strings = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}; ActivityCompat.requestPermissions(this, strings, 1); } } else { // Android SDK>28 所需权限动态申请,需添加“android.permission.ACCESS_BACKGROUND_LOCATION”权限 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, "android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) { String[] strings = {android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION, "android.permission.ACCESS_BACKGROUND_LOCATION"}; ActivityCompat.requestPermissions(this, strings, 2); } }
在您的项目中使用到定位服务的Activity中的onCreate()方法中创建一个FusedLocationProviderClient实例,通过该实例调用定位相关接口。
// 定位交互接入对象 private FusedLocationProviderClient fusedLocationProviderClient; // 定位请求信息对象 private LocationRequest mLocationRequest; protected void onCreate(Bundle savedInstanceState) { fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this); }
当传入参数为非Activity类型时,如果使用FusedLocationProviderClient实例调用定位服务接口发生异常,就不会弹出UI交互界面提示用户处理,只会返回错误码。例如:当HMS Core不符合定位服务的版本要求时,便会返回错误码907135003,此时需要手动升级HMS Core。如果需要拉起升级引导界面,建议传入Activity类型参数替代Context类型,创建FusedLocationProviderClient实例。更多错误码,请参见错误码。
设备的相关定位设置会影响定位服务的定位结果,例如位置开关选项处于关闭状态时,将无法获取到位置信息。因此,建议您在持续获取位置信息之前,先检查设备设置是否满足定位条件。定位服务提供了检查设备定位相关设置的能力,通过LocationServices的getSettingsClient(Activity activity)获取SettingsClient实例,然后调用checkLocationSettings(LocationSettingsRequest locationSettingsRequest)接口获取定位设置结果,当设置不满足定位条件时,您可以调用startResolutionForResult接口用于弹框提示用户打开对应的权限(HMS Core 定位权限必须打开,Android Q版本必须选择“始终允许”)。
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder(); mLocationRequest = new LocationRequest(); builder.addLocationRequest(mLocationRequest); LocationSettingsRequest locationSettingsRequest = builder.build(); // 检查设备定位设置 settingsClient.checkLocationSettings(locationSettingsRequest) // 检查设备定位设置接口成功监听回调 .addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() { @Override public void onSuccess(LocationSettingsResponse locationSettingsResponse) { // 设置满足定位条件,再发起位置请求 fusedLocationProviderClient .requestLocationUpdates(mLocationRequest, mLocationCallback,Looper.getMainLooper()) // 请求位置更新接口成功监听回调 .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { // ... } }); } }) // 检查设备定位设置接口失败监听回调 .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // 设置不满足定位条件 int statusCode = ((ApiException) e).getStatusCode(); switch (statusCode) { case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: try { ResolvableApiException rae = (ResolvableApiException) e; // 调用startResolutionForResult可以弹窗提示用户打开相应权限 rae.startResolutionForResult(MainActivity.this, 0); } catch (IntentSender.SendIntentException sie) { // ... } break; } } });
如果您希望应用可以持续获取设备位置,可以使用定位服务提供的requestLocationUpdates()接口。该接口根据入参形式的不同,将以两种不同的形式将位置信息返回。一种是通过调用您已经定义的LocationCallback类中onLocationResult()回调方法返回一个包含位置信息的LocationResult对象,另一种是将位置信息置于PendingIntent扩展信息中返回。
当您的应用程序不再需要接收位置更新时,应当停止位置更新,以便于降低功耗。要停止位置更新,可以调用removeLocationUpdates(),传入与requestLocationUpdates()接口相对应的LocationCallback或PendingIntent对象。这里以回调方式作为样例,代码如下。详细的参数说明请参见LocationService接口说明。
LocationRequest mLocationRequest = new LocationRequest(); // 设置位置更新的间隔(单位为毫秒) mLocationRequest.setInterval(10000); // 设置定位类型 mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationCallback mLocationCallback; mLocationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { if (locationResult != null) { // 处理位置回调结果 } } };
fusedLocationProviderClient .requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper()) .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { // 接口调用成功的处理 } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // 接口调用失败的处理 } });
如果接口调用成功,获取位置信息失败,请参见接口调用成功,但获取不到位置信息?。
// 注意:停止位置更新时,mLocationCallback必须与requestLocationUpdates方法中的LocationCallback参数为同一对象。 fusedLocationProviderClient.removeLocationUpdates(mLocationCallback) // 停止位置更新成功监听回调 .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { // ... } }) // 停止位置更新失败监听回调 .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // ... } });
您的应用可以调用getLastLocation()方法获取设备最后的已知位置,大多情况下,该位置即为设备的当前位置。代码样例如下:
// 获取最后的已知位置 Task<Location> task = fusedLocationProviderClient.getLastLocation() // 获取最后的已知位置成功监听回调 .addOnSuccessListener(new OnSuccessListener<Location>() { @Override public void onSuccess(Location location) { if (location == null) { return; } // 成功时Location对象处理逻辑 // ... } }) // 获取最后的已知位置失败监听回调 .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // ... } });
getLastLocation()方法是从系统缓存中获取位置信息的。如果获取的位置信息为null,则可能是系统缓存已经被清除;此时先调用requestLocationUpdates()方法获取位置信息以刷新缓存,再调用getLastLocation()方法即可以获取到位置信息。
具体操作步骤:打开“开发人员选项”,请执行如下操作: ,连续点击“版本号”7次,“开发人员选项”会出现在“系统与更新”页面,再重复上述操作),代码开发步骤如下:
(如果没有发现<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" tools:ignore="MockLocation,ProtectedPermissions" />
// 设置mock模式,参数传入ture:模拟模式;false:正常状态 boolean mockFlag = true; fusedLocationProviderClient.setMockMode(mockFlag) .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { Log.i(TAG, "setMockMode onSuccess"); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { Log.i(TAG, "setMockMode onFailure:" + e.getMessage()); } });
// 设置模拟位置信息 final Location mockLocation = new Location(LocationManager.GPS_PROVIDER); mockLocation.setLongitude(118.76); mockLocation.setLatitude(31.98); fusedLocationProviderClient.setMockLocation(mockLocation) // 设置模拟位置信息成功监听回调 .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { Log.i(TAG, "setMockLocation onSuccess"); } }) // 设置模拟位置信息失败监听回调 .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { Log.i(TAG, "setMockLocation onFailure:" + e.getMessage()); } });