升级VS2017后System.Device.Location.Portable与monoandroid81不兼容问题
解决System.Device.Location.Portable与MonoAndroid81不兼容的问题
这个问题我之前帮不少开发者解决过,本质是你用的System.Device.Location.Portable是个比较老旧的移植包,完全没适配新版Xamarin.Android对应的Android 8.1(也就是报错里的monoandroid81),所以NuGet会直接抛出兼容性错误。下面给你一套完整的替代方案,比继续用旧包靠谱多了:
第一步:卸载旧的NuGet包
先把出问题的System.Device.Location.Portable从项目里彻底移除:
- 在VS的解决方案资源管理器里,右键你的Xamarin.Forms项目 → 管理NuGet程序包
- 切换到“已安装”标签,找到
System.Device.Location.Portable,点击卸载,确认移除所有相关引用
第二步:替换为官方维护的位置API
新版Xamarin生态已经有官方的跨平台位置解决方案了,推荐用下面两个选项之一:
选项1:使用Xamarin.Essentials(最推荐)
这是微软官方推出的跨平台工具包,专门封装了位置、传感器等常用原生功能,比旧第三方包稳定得多:
- 安装Xamarin.Essentials NuGet包:在NuGet管理器里搜索
Xamarin.Essentials,安装适配你当前Xamarin版本的稳定版 - 用Geolocation类获取位置的示例代码:
using Xamarin.Essentials; public async Task<Location> GetCurrentLocation() { try { // 配置位置请求的精度和超时时间 var locationRequest = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromSeconds(10)); var currentLocation = await Geolocation.GetLocationAsync(locationRequest); if (currentLocation != null) { Console.WriteLine($"纬度: {currentLocation.Latitude}, 经度: {currentLocation.Longitude}, 海拔: {currentLocation.Altitude}"); } return currentLocation; } catch (FeatureNotSupportedException) { // 处理设备不支持位置服务的情况 } catch (FeatureNotEnabledException) { // 提示用户开启位置服务 } catch (PermissionException) { // 提示用户授予位置权限 } catch (Exception ex) { // 处理其他未知错误 } return null; }
选项2:用DependencyService调用原生API(适合自定义需求多的场景)
如果你需要更定制化的位置逻辑,可以用Xamarin.Forms的DependencyService来分别调用Android和iOS的原生位置API:
- 先在共享项目里定义一个位置服务接口:
public interface ILocationService { Task<(double Latitude, double Longitude)> GetCurrentLocation(); }
- 在Android项目里实现这个接口(记得处理权限):
[assembly: Dependency(typeof(AndroidLocationService))] namespace YourAppName.Droid { public class AndroidLocationService : ILocationService { public async Task<(double Latitude, double Longitude)> GetCurrentLocation() { // 先检查动态权限(Android 6.0+需要) if (await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>() != PermissionStatus.Granted) { var status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>(); if (status != PermissionStatus.Granted) { throw new PermissionException("位置权限未授予"); } } var locationManager = (LocationManager)Android.App.Application.Context.GetSystemService(Context.LocationService); var lastKnownLocation = await locationManager.GetLastKnownLocationAsync(LocationManager.GpsProvider); if (lastKnownLocation == null) { // 可以添加逻辑等待位置更新,这里简化处理 throw new Exception("无法获取当前位置"); } return (lastKnownLocation.Latitude, lastKnownLocation.Longitude); } } }
- 在iOS项目里实现对应的原生逻辑(同样要配置权限描述)
第三步:配置必要的权限
不管用哪个方案,都得给平台配置位置权限:
- Android:在
AndroidManifest.xml里添加权限声明:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- iOS:在
Info.plist里添加权限描述(告诉用户为什么需要位置权限):
<key>NSLocationWhenInUseUsageDescription</key> <string>需要访问您的位置来提供相关服务</string> <key>NSLocationAlwaysUsageDescription</key> <string>需要始终访问您的位置来提供相关服务</string>
为什么旧包会报错?
System.Device.Location.Portable是很早的一个第三方移植包,只适配了早期的Xamarin版本和低版本Android API。当你升级到Xamarin.Android 8.3.0.18后,项目默认的目标框架是Android 8.1(对应monoandroid81),这个旧包完全没有针对这个API级别做适配,所以NuGet的兼容性检测直接就报错了,根本没法安装。
内容的提问来源于stack exchange,提问作者Shambhavi
相关产品推荐
相关产品推荐

